Skip to content

Loss Spike 排查:训练发散问题定位 ​

摘要:训练跑到一半 loss 突然暴涨或跳成 NaN,是千卡训练最贵的问题——每一次发散都可能意味着数小时算力白费。本文给出四层排查框架(数据 / 数值 / 通信 / 硬件),按序定位,每层都有明确判据与处置。

1. 先给现象分类:不同 spike 不同根因 ​

现象特征最可能方向
瞬间 NaN/Infloss 一步内变成 NaN,之后全是 NaN数值层:梯度溢出、坏样本、优化器状态异常
单点尖刺后恢复单个 step 暴涨,随后回到正常数据层:异常 batch;通信层:瞬时重传
尖刺后不回暴涨后持续高位或继续涨学习率/数据分布突变、检查点损坏恢复
缓慢爬升无尖刺,loss 趋势向上数据顺序变化(RNG 未恢复)、精度问题、LR 策略

第一步永远是记录:训练日志里必须有 step / loss / lr / grad_norm / gpu 温度 / 网络重传 的可视化,否则任何排查都是盲猜。

2. 四层排查框架(按序执行) ​

2.1 第一层:数据层——是不是喂进去的东西坏了 ​

排查动作:
1. 定位 spike 对应的 global step → 找到该 step 的 batch(data_loader 状态)
2. 检查该 batch:是否有损坏样本(损坏图片/超长文本/空样本)
3. 检查数据 shuffle 是否在恢复检查点后"换序"(RNG 未恢复)
4. 检查数据加载是否有错位(分布式下各 rank batch 不一致)
  • 分布式数据错位是隐蔽杀手:某个 rank 的数据文件损坏/读取失败,该 rank 梯度变成垃圾,AllReduce 后全集群污染。
  • 验证:grad_norm 突变 + 单 rank 显存异常波动 → 在 dataloader 里加 torch.distributed.barrier() 与采样 seed 校验。

2.2 第二层:数值层——梯度是不是爆了 ​

排查动作:
1. 开启 grad clip(先保命):max_grad_norm 1.0 起步
2. 检查 grad_norm 曲线:spike 前 grad_norm 是否先爆
3. torch.autograd.detect_anomaly() 定位 NaN 产生算子
4. 检查 LR 是否过大(spike 后降 LR 0.3× 测试恢复)
5. 检查 FP16 Loss Scaling:scale 崩到极小 → 梯度下溢
python
# 定位 NaN 源头(debug 用,慢,只跑少量步)
with torch.autograd.detect_anomaly():
    loss.backward()

# 生产:记录 grad_norm 与 NaN 标记
grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
if not torch.isfinite(grad_norm):
    logger.error(f"NaN grad at step {step}")
  • BF16 通常不会下溢,若 BF16 训练出 NaN,优先怀疑数据/算子实现,而非精度本身。
  • Inf 输入:tokenizer 特殊 token 溢出、embedding 层初始化异常也会产出 Inf。

2.3 第三层:通信层——是不是同步出了问题 ​

排查动作:
1. NCCL_DEBUG=INFO 重跑,观察 spike 时刻是否有重传/超时(TME 报错)
2. 交换机侧:ethtool -S 看 pause 帧/丢包在 spike 时刻是否同步上涨
3. 确认通信算子与并行策略匹配(PP 的 send/recv 是否错位)
4. 检查是否混用了不同 NCCL 版本的镜像
  • 通信层异常的特征是"全场同时变差":所有 rank 的 loss 同时跳,且伴随网络计数上涨。
  • 与数据层区分:数据错位是"个别 rank 异常",通信异常是"全体同步异常"。

2.4 第四层:硬件层——是不是机器坏了 ​

排查动作:
1. nvidia-smi -q -d ECC:spike 时刻前后 ECC 错误计数是否增长
2. dmesg / nvidia-smi -q -d XID:Xid 79/45/63 等错误
3. 温度/功耗曲线:是否有节点过热降频(吞吐掉但 loss 不该跳)
4. IB 链路:ibstatus 速率协商、SM lid 变化(链路闪断)
  • 硬件故障的典型特征:spike 与特定节点强相关(换掉该节点的 rank 映射后不再出现)。
  • 处置:先隔离节点,不要边查边训——故障节点可能继续污染全局梯度。

3. 快速处置矩阵 ​

现象保命动作根因确认恢复
瞬间 NaN停训练,留现场detect_anomaly + grad_norm 曲线修根因后从最近完好 checkpoint 恢复
单点尖刺记录,继续观察 50 步是否复现 + 网络计数不复发继续;复发进数据层排查
尖刺后不回降 LR 0.3× 试跑是否改善改善=LR 问题;无改善=数据/检查点
恢复后爬升校验 RNG 恢复对比未中断 loss 曲线修正 dataloader/RNG 恢复逻辑

4. 生产案例:千卡训练反复 NaN 的真凶 ​

现象:千卡集群 LLM 训练,每 2~3 天出现一次全局 NaN,重启后训练正常,约 1 天后再现。

排查过程:

步骤动作发现
1定位 NaN 前 grad_norm前 10 步 grad_norm 缓慢爬升后爆表
2detect_anomaly指向某个 attention 层 matmul 输出 Inf
3数据层检查该 batch 含一个超长文本样本(token 数异常)
4复现验证单独喂该样本,单卡必现 NaN
5修复数据管线加长度过滤 + max_length 截断 + 采样去重

根因:上游清洗管道漏过一个损坏的超长样本,attention 计算量随序列长度平方增长,超出数值范围。数据层问题伪装成数值层故障,是最高频的误判——所以四层框架必须从数据层开始查。

5. 防复发清单 ​

  • [ ] 训练日志含 step/loss/lr/grad_norm/温度/网络计数,且可视化
  • [ ] 数据管线有长度过滤、空样本过滤、去重校验
  • [ ] 分布式采样 RNG seed 校验,恢复检查点后数据顺序一致
  • [ ] grad clip 开启(1.0 起步),grad_norm 监控告警
  • [ ] ECC/Xid 监控接入告警,故障节点自动隔离
  • [ ] 所有恢复都从"最近完好 checkpoint"(含校验和)出发
  • [ ] 定期用少量步做"健康跑"(无通信、无数据变化的纯计算基准)作为对照组

延伸阅读:混合精度训练与断点续训(精度与恢复的稳定性基础)、NCCL 网络调优实战(通信层深度排查)。

AI-HPC 智算超算专家 · Contact: openaihpc@gmail.com