混合精度训练的核心思想是:在训练过程中同时使用低精度和高精度,让计算用低精度加速、让关键状态用高精度保持稳定。
FP16 和 BF16 都是 16 位浮点数,但它们的位分配不同,导致动态范围和精度不同。大模型训练更倾向于 BF16,主要是因为 BF16 的动态范围更大,不容易溢出,训练更稳定。Loss Scaling 则是 FP16 训练中为了防止梯度下溢而引入的一种技巧。
FP16 是半精度浮点数,总共 16 位:
BF16 是 Brain Floating Point 16,也是 16 位:
指数位决定动态范围。FP16 只有 5 位指数,BF16 有 8 位指数,和 FP32 的指数位一样多。
所以:
这意味着 BF16 能表示非常大和非常小的数,不容易上溢或下溢。
尾数位决定精度。FP16 有 10 位尾数,BF16 只有 7 位尾数。
所以:
FP16 是“精度高但范围窄”,BF16 是“范围宽但精度低”。
大模型参数量大、层数深、激活值范围广,训练过程中容易出现:
FP16 的动态范围窄,最大值只有 $65504$,稍不注意就会溢出,产生 NaN 或 Inf。BF16 的动态范围和 FP32 一样,基本不会因为范围问题溢出。
FP16 训练通常必须配合 Loss Scaling,否则梯度容易下溢。BF16 因为动态范围大,通常不需要 Loss Scaling,训练流程更简单。
BF16 的指数位和 FP32 一样,都是 8 位。所以 FP32 转 BF16 基本就是截断尾数,硬件实现简单,转换开销小。
NVIDIA A100、H100、H800 等大模型训练常用 GPU 都对 BF16 有良好支持,Tensor Core 可以直接加速 BF16 计算。Google TPU 也原生支持 BF16。
大模型训练成本极高,一次训练可能几周甚至几个月。BF16 因为不容易溢出,训练稳定性更好,减少了中途失败的风险。
虽然 BF16 尾数少、精度低,但大模型训练对精度损失的容忍度相对较高。很多实验表明,BF16 混合精度训练和 FP32 训练的最终效果差距很小。
FP16 的动态范围窄,很多梯度值非常小,比如 $10^{-8}$。FP16 能表示的最小正数大约是 $6 \times 10^{-5}$,所以这些梯度在 FP16 下会变成 0,也就是下溢。
梯度下溢会导致参数无法更新,训练失效。
Loss Scaling 的做法是:
用公式表示,假设原始 Loss 为 $L$,缩放后的 Loss 为:
$$ L' = S \cdot L $$
反向传播得到缩放后的梯度:
$$ g' = S \cdot g $$
更新参数前再还原:
$$ g = \frac{g'}{S} $$
固定缩放因子可能不合适,所以实际中常用动态 Loss Scaling:
这样可以在防止下溢和避免上溢之间自动平衡。
BF16 的动态范围和 FP32 一样,最小正数大约是 $10^{-38}$,梯度下溢的风险极小。所以 BF16 训练通常不需要 Loss Scaling,流程更简单、更稳定。
这是一道很好的大模型训练基础面试题,适合用来考察候选人对混合精度训练的系统理解。它更适合作为基础题或热身题,真正区分水平还需要配合追问实际调参和排错经验。如果候选人能把 FP16 和 BF16 的位分配、动态范围、精度差异、Loss Scaling 原理以及大模型训练中的实际选择都讲清楚,基本可以判断其具备混合精度训练的扎实基础。
评论专区
评论加载中...登录后即可发表评论