程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

搞懂大模型实用训练秘籍——混合精度训练

balukai 2025-03-29 15:06:54 文章精选 9 ℃

混合精度训练(Mixed Precision Training)是一种通过结合单精度(FP32)和半精度(FP16)来提升深度学习模型训练效率的技术。其核心思想是在保证模型精度的同时,充分利用FP16和FP32的优势,从而加速训练过程。

  • FP16 :计算速度快、显存占用少,能够显著提升训练效率并降低内存需求。
  • FP32 :以高精度保存关键数据,避免因数值范围有限导致的计算不稳定问题。

一、前言:什么是精度?

1.基本概念

常见的浮点数格式包括FP64(双精度浮点数)FP32(单精度浮点数)和FP16(半精度浮点数),它们的核心区别在于位数分配与数值表示范围/精度。以FP32和FP16为例,均由三部分组成:

  • sign:符号位,表示正负数,0为正数,1为负数。
  • exponent:指数位,表示浮点数的幂次(以2为基数的幂次),用于控制数值的范围。
  • fraction:分数位,表示浮点数的小数部分,决定数值的精度。

2.表示范围(FP16举例)

exponent:5bit,表示整数部分,范围为00000(0)到11111(31),实际使用中,指数位通过偏移量(Bias)调整,偏移值为 15,那我们就可以将~分为30个大区间([, ],...,[, ])。

fraction:10bit,表示分数部分,范围为0000000000(0)到1111111111(1023),那我们就可以将上面提到的一个每个大区间可以分为1024个小区间。

0 11110 1111111111 = =65504,那我们测试输入65505会不会溢出呢?其实是不会的,还是会输出65504,很明显是造成了精度损失,但为什么不会溢出呢?因为1023-1024之间还有一部分数据。那超过多少会溢出呢【上溢出】?

0 00001 0000000000 = ≈6.10 *

具体FP32的范围是多少呢?大家可以根据这个方式计算一下。

二、混合精度训练

2018年,百度与NVIDIA联合发表论文:MIXED PRECISION TRAINING,提出了混合精度训练的方法。发现神经网络训练没必要一直用FP32,可以适当使用FP16。

为什么要使用FP16进行计算?

1.加速计算

  • FP16的位宽为16位(FP32为32位),内存占用减半,可提升数据吞吐量。
  • 现代GPU(如NVIDIA的Tensor Core)针对FP16计算高度优化,FP16矩阵乘法的吞吐量是FP32的2-8倍,显著加快训练速度。

2.降低显存占用

  • FP16的占用的空间是FP32的一半,因此权重等参数所占用的显存也是原来的一半,节省下来的显存可以放更大的网络模型或者使用更多的数据进行训练。

为什么要用FP32进行存储?

1.避免累积误差

  • FP16的低精度在连续计算(如梯度累加、权重更新)中会导致舍入误差(Rounding Error),误差逐层积累可能破坏模型收敛性。
  • FP32的23位尾数能更精确表示小数值(如梯度、权重更新量),确保训练稳定。

2.优化器需要高精度

  • 优化算法(如Adam)中的动量项、二阶矩估计等涉及小数值计算(如10-810-8量级),FP16无法有效表示这些值,而FP32可以避免信息丢失。

3.主权重(Master Weights)的作用

  • 混合精度训练中,模型参数和优化器状态(如动量、方差)始终以FP32存储(称为“主权重”),仅在计算时转换为FP16。
  • 前向传播和反向传播使用FP16加速,但最终的梯度更新在FP32空间中完成,确保高精度调整。

FP32权重备份

模型的权重使用FP32来表示,保证了数值准确性。在前向和反向计算时,先将FP32权重转化成FP16,同时还保留一份FP32的Master Copy。最后将梯度更新到Master Copy上。那么计算时可以获得FP16的速度提升,而权重这样重要的数据仍然以FP32的高精度来保存。

Loss Scale

FP16的精度范围有限,在训练某些模型时,梯度数值可能会因为太小而无法用FP16表示,直接变成0。这会导致梯度更新失效,影响模型训练效果。为了解决这个问题,可以在计算Loss的时候,给Loss乘上一个放大系数(称为Loss Scale)。比如把Loss放大1024倍,这样一些原本接近0的极小梯度值就可能被FP16表示出来。

Loss Scale有两种设置方法:

  • 选择一个固定的放大系数,比如在8到32000之间。这种方法简单直接。
  • 初始时将Loss Scale设置为一个较大的值(比如65536),然后根据训练过程中的情况动态调整。如果发现梯度出现上溢(值太大)或下溢(值太小),就适当增加或减少Loss Scale的值。

混合精度训练流程

1.参数存储与初始化

  • 所有模型参数(如权重、梯度)以FP32格式存储
  • 设置初始缩放系数,用于放大损失值以防止FP16梯度下溢

2.前向传播

  • 将FP32参数转换为FP16格式,作为前向计算的输入
  • 使用FP16进行矩阵乘法、卷积等计算密集型操作
  • 对于一些数值敏感的计算(如Softmax)强制使用FP32,以保证精度

3.损失缩放

  • 前向传播得到的损失值(Loss)乘以缩放因子s,得到放大后的损失,防止反向传播时FP16梯度因数值过小而下溢

4.反向传播

  • 使用FP16进行梯度计算,基于放大后的损失,通过链式法则计算梯度。所有梯度值被s放大,避免下溢
  • 将FP16梯度转换为FP32格式,并除以缩放因子s,恢复真实梯度值
  • 若检测到梯度溢出(NaN或Inf),则跳过本次更新并减小s;若多次未溢出,则逐步增大s以提升精度

5.参数更新

  • 使用还原后的FP32梯度更新原始参数,确保参数更新的数值稳定性
  • 多次小批量(mini-batch)的FP16梯度累加到FP32缓冲区中,避免多次转换引入误差

今天的分享就到这里,如果对您有帮助,请顺手点个关注呗~

Tags:

最近发表
标签列表