本节摘要:训练现场最常见的四种"翻车",各有其特征与排除方向。本节按现象索引式给出排错流程——发散、损失不降、NaN、慢到无语——每种都用"症状→追问→排查→修复"的方式展开。
阅读完本节,你应当能够:
前面把训练装上了仪表盘,现在谈它在仪表盘上最常见的几种坏表情。别一看到异常就删重跑——每次翻车都在告诉你一个具体的事,教你把"现象"翻译成"原因",是排错真正的价值。
这里先给你一个正确的态度:训练日志里的每一次"异常"都指向某一个被违反的前提,不存在无缘无故的翻车。你的工作不是把日志清空重来(那只是把问题推迟到下一轮),而是顺着现象追出那个前提,一次性修掉。下面四种现象几乎覆盖了绝大多数现场,每一种我们都按"症状→追问→排查→修复"展开。
症状:训练损失不降反升,甚至冲向无穷/NaN。
追问顺序:
首查学习率,因为它性价比最高;稳住之后再看是不是数据极端。
症状:训练损失几乎不动,或长期在一个偏高位置徘徊。
追问顺序:
注意把"不降"和"还在慢下"分清楚,前者是真欠拟合,后者可能只是没到。
症状:训练某一步损失变成 NaN,参数/梯度出现非数。
追问顺序:
症状:epoch 长得让人怀疑人生,吞吐低得离谱。
追问顺序:
# 概念:把一次训练拆成可定位的几段,逐段量时间找瓶颈 for segment in ["load", "forward", "backward", "step"]: print(segment, time_this(segment)) # 盯最慢的那段再专项排查
把上面四张速查放在一起,会发现它们并不孤立,而是同一棵"现象 → 病根"决策树的四个分支。当你面对一条不对劲的曲线时,别急着选某个现象硬套,先按这个顺序缩小范围:先看损失是往上涨、几乎不动、还是跳成非数,再想保住"数据/结构/数值"三层里最容易出问题的那个。真正的高手不是背四条清单,而是知道这三步——先读形态、再定方向、最后用一两个廉价改动去验证猜想。
这里尤其要提醒的是:排错要"一次改一点",而不是一把梭。一个现象背后常是多因叠加,你若同时把学习率调小、又加正则、又换网络结构,即便运气好收敛了,你也不知道到底是哪一步起效。更糟的是,若没收敛,你想回退都不知道回退到哪一步。所以正确姿势是:用一个最便宜的改动(比如首查学习率时先降一档)做一次最小验证,若有效就收手、无效才进入到下一步。这不仅省时间,更保住了你对"是什么修好了它"的判断力——这正是本册反复强调的单因子纪律,在排错现场同样成立。
这套"先读形态、再定方向、单因子验证"的流程,和本章最后一节的端到端案例其实是同一件事的两面:排错是逆向的——你从"现象"往回追"病根",而日常调参是正向的——你从"假设"往前推"该动哪个旋钮"。(那节案例会把你一路调参时踩的坑串成一遍完整旅程)。所以真正的排错高手,往往也是真正的调参高手,反之亦然:他们共用同一套"用证据缩小范围"的思考。如果你发现自己一到排错就手忙脚乱,多半不是手法不够,而是缺少这种"把一次改动当一次实验"的稳定心智。
| 现象 | 首查 | 次查 | 三查 |
|---|---|---|---|
| 损失发散 | 学习率 | 初始化 | 数据极端值 |
| 损失不降 | 容量/特征 | 学习率太小 | 鞍点静区 |
| NaN | 数据含空 | 学习率/爆炸 | 结构/精度 |
| 极慢 | 数据加载 | 参数量 | 批大小/设备 |
⚠️ 常见坑:一个现象背后常是多个原因叠加(比如"NaN 且卡死"),只钉一个原因就开改,容易白费一轮。先用小步一处处排除(A/B),别同时改三四个变量。
💡 直觉:排错最有力的武器是"二分法"——把一条长训练链切成两半,看哪一半出的问题;把"一大堆改动"拆成"单因子最小复现",问题瞬间可定位。实验舱纪律在这里直接救命。
现象、病根都对上了,下一节收拢成几条能当规矩用的"调参心法"。