4、精度异常现象:损失爆炸、梯度消失、NaN/Inf 出现、训练不收敛、验证指标波动等典型表现
混合精度训练并不是“把 float32 换成 float16”这么简单。一旦缩放策略、算子支持或数值范围处理不当,训练过程会以非常典型的方式“报警”。本节聚焦五类最常见的精度异常现象,帮助你从日志、曲线和参数状态中快速识别问题类型,并判断它属于数值溢出、梯度尺度失衡,还是优化过程本身不稳定。
一、核心原理:五类异常背后的数值机制
混合精度训练中,前向与反向通常使用 FP16/BF16 计算,而参数更新仍保留 FP32 主权重。异常往往出现在“计算精度”与“更新精度”之间的交界处。理解下面三条机制,就能把现象和原因对应起来:
- 动态范围溢出:FP16 的最大有限值约为 65504,最小正规数约为 6.1e-5。激活值、梯度或损失一旦超过上限,就会变成 Inf;低于下限则下溢为 0。
- 损失缩放失配:缩放系数过大,反向梯度被放大后溢出;缩放系数过小,小梯度在 FP16 中直接下溢为 0,表现为“梯度消失”。
- 累加与归约误差:FP16 累加器在长序列、大 batch 或小梯度场景下会丢失低位信息,导致梯度方向偏差,训练看似在跑,实则不收敛。
判断口诀:看损失曲线定“爆炸/不收敛”,看梯度范数定“消失/溢出”,看参数与激活值定“NaN/Inf 来源”。
二、方法流程:从现象到根因的排查顺序
面对异常,不要一上来就调学习率。建议按“先看数值、再看缩放、最后看优化”的顺序排查:
- 确认异常类型:在训练循环中打印 loss、grad_norm、loss_scale 和当前学习率,观察异常首次出现的位置。
- 定位首个非有限数:使用
torch.autograd.set_detect_anomaly(True)或逐层 hook,找到第一个产生 Inf/NaN 的算子。 - 检查缩放策略:若 loss_scale 频繁减半,说明梯度溢出;若长期不增长且 grad_norm 极小,说明缩放不足。
- 验证精度模式:临时切换为纯 FP32 或 BF16 对照,判断问题是否由 FP16 动态范围引起。
- 调整优化配置:确认梯度裁剪、权重衰减、学习率 warmup 是否与混合精度匹配。
# 典型排查日志片段
step 1200 | loss 2.31 | grad_norm 0.87 | loss_scale 65536.0
step 1201 | loss 3.02 | grad_norm 1.24 | loss_scale 65536.0
step 1202 | loss nan | grad_norm nan | loss_scale 32768.0 <-- 首次异常
step 1203 | loss nan | grad_norm nan | loss_scale 16384.0
从日志可见,异常发生在 loss_scale 回退之前,说明是梯度先溢出,随后缩放器才被动降级。此时应优先检查反向传播中是否存在大激活值或未裁剪的梯度。
三、案例/场景:三类真实训练异常
| 现象 | 常见根因 | 典型日志/曲线特征 | 优先处理 |
|---|---|---|---|
| 损失爆炸 | 学习率过大 + FP16 梯度溢出 | loss 从 2.x 跳到 1e4 或 Inf | 降低学习率,开启梯度裁剪 |
| 梯度消失 | loss_scale 过小或激活饱和 | grad_norm 长期 < 1e-6 | 提高初始 loss_scale,检查激活函数 |
| NaN/Inf | 除零、log(0)、FP16 上溢 | 参数中出现 nan,loss 直接 nan | 定位首个异常算子,加 eps 保护 |
| 训练不收敛 | FP16 累加误差 + 优化器状态未用 FP32 | loss 下降极慢或平台期 | 使用 FP32 主权重与 FP32 优化器状态 |
| 验证指标波动 | 数值不稳定导致参数更新抖动 | val_acc 上下跳动,无上升趋势 | 稳定缩放策略,增加 warmup |
一个实用技巧:在验证集上单独跑一次 FP32 前向,与混合精度前向的 logits 做余弦相似度对比。若相似度低于 0.99,说明数值偏差已经影响模型输出。
四、误区与复盘:不要把所有异常都归因于“精度”
实际排障中,很多团队会把训练不收敛直接归咎于混合精度,但真实原因可能是数据、学习率或代码逻辑。以下误区值得警惕:
- 误区一:看到 NaN 就关闭混合精度。NaN 可能来自数据中的异常样本、除零操作或自定义算子未注册 FP16 支持,关闭混合精度只是掩盖问题。
- 误区二:只调 loss_scale,不看梯度分布。缩放系数只是补偿手段,若梯度本身已经爆炸,再大的缩放也救不回来。
- 误区三:忽略优化器状态精度。Adam 的动量与方差若用 FP16 存储,小梯度更新会被舍入误差吞掉,表现为“训练不动”。
- 误区四:验证指标波动就频繁调参。波动可能只是 batch 间方差,应先固定随机种子、扩大验证集,再判断是否由精度引起。
复盘建议:每次精度异常都应记录“首次异常 step、异常前 loss_scale、grad_norm、学习率、当前 batch 数据哈希”。这些信息能帮助你在下一次复现时快速定位,而不是凭感觉调参。
总结来看,损失爆炸、梯度消失、NaN/Inf、不收敛和验证指标波动并不是孤立现象,它们分别对应 FP16 上溢、下溢、非有限数传播、累加误差和数值抖动。掌握“现象—机制—排查动作”的对应关系,才能在混合精度训练中做到快速定位、精准修复,而不是盲目降精度或反复重启训练。