RRLforge
闯关预计 45 分钟

闯关:五种炸法

熵崩塌、reward hacking、长度爆炸、KL 跑飞、OOM。每一种给现场证据,你来判断和处置。

学完这节你能做到

  • 看到日志和曲线就能认出是哪一种失效
  • 对每种失效给出第一步处置动作,而不是把所有参数都动一遍
  • 知道哪些失效是必须重启训练的,哪些可以边跑边救

五种炸法

RL 训练失败的方式远多于成功的方式。好消息是:常见的就那五种,而且每种都有特征指纹。

这一节给你现场证据,你来判断和处置。原则贯穿全节:

先看曲线,再改代码。 不要一次动三个参数。

先把 L2 那八个指标的诊断价值列成一张表——这是全站最该记住的一张表

指标健康异常时指向
reward缓升平 = 没学;暴涨 = 可能在刷分
acc(只看答案对错)与 reward 同向与 reward 背离 = reward hacking
entropy缓慢下降趋近 0 = 熵崩塌
kl缓慢上行陡增 = 跑飞
adv_std0.5 ~ 1.2趋近 0 = 大量组退化,白跑
clip_frac几个百分点> 20% = 单步太猛
ratio_mean≈ 1.0偏离 = 权重没同步
len稳定或与 acc 同向单调暴涨而 acc 不动 = 长度作弊
如果你还没记 entropy,现在补上

熵是「输出分布有多分散」,直接反映探索能力。它是唯一能提前警告熵崩塌的指标。

# 在算 logprob 的地方顺手算
probs = torch.softmax(logits.float(), dim=-1)
entropy = -(probs * torch.log(probs + 1e-10)).sum(-1)   # [B, T]
ent = (entropy * mask).sum() / mask.sum()

炸法一:熵崩塌

症状:熵单调下降到接近 0。所有回答变得几乎一样,reward 卡在某个值不动。

机制:RL 是正反馈系统。某个模式偶然拿了高分 → 概率被提高 → 更容易被采到 → 又拿高分 → 概率更高……最后模型只会输出这一种模式,探索完全停止

一旦熵塌了,组内没有差异,adv_std 也跟着趋近 0,训练实质上停了。而且不可逆——概率分布已经收缩,你降学习率也回不来。

处置(按顺序试):

动作说明
提高 temperature最直接。1.0 → 1.1/1.2
加熵奖励损失里加 - entropy_coef × entropy,从 0.001 起
降学习率减慢正反馈的速度
从更早的 checkpoint 重启熵已经塌了就救不回来了,只能回滚
!熵崩塌要提前防,不能事后救

所以 entropy 必须记进日志,而且要在它掉到 0.3 以下时就干预,不要等它到 0。

slime 有 --entropy-coef 参数(默认 0.00)就是为这个准备的。

炸法二:reward hacking

症状reward 稳步上升,acc 不动甚至下降。

机制:你的 reward 有一条不解决问题就能拿分的捷径,模型找到了。

L2 那节我们主动找过一遍作弊路径,但真实任务里的捷径往往没那么显眼。常见形态:

形态具体行为
刷格式分套标签但答案是空的或随便填
赌答案列举多个候选,赌抽取器取到对的那个
复述题目把题目抄一遍凑长度和关键词
钻抽取器利用「取最后一个数字」之类的兜底规则
讨好判分器用 LLM-as-judge 时,输出判分模型偏好的风格而非更好的内容

处置

  1. 先定位:把 reward 拆成分项记录(reward_correctreward_format 分开),看是哪一项在涨
  2. 抽样看原文:打印 reward 最高的 10 条回答,肉眼看它在干什么
  3. 堵漏:收紧抽取规则、降低作弊项的权重、加针对性惩罚
×reward hacking 是设计问题,不是超参问题

调学习率、调 KL 都救不了它。唯一的修法是改 reward。

而且它会反复出现:你堵了一个洞,模型会找下一个。这就是 RL 工程里最耗时的部分——某种程度上,RL 调试就是和自己的 reward 函数博弈。

炸法三:长度爆炸

症状len 单调上涨直到全部顶到 max_tokenstrunc 比例飙升,acc 不涨或下降。

机制:有三个可能来源,要分清:

  1. per-token 归一化(L2 讲过):长回答的 token 多,对损失贡献大,变相奖励写长
  2. 长回答恰好更容易对:模型学到「多写几步更可能算对」——这是真实的正相关,不算作弊
  3. 纯粹的作弊:写一堆无关内容凑长度,钻长度相关的 reward
i怎么区分「正常变长」和「长度作弊」

acclen 的关系:

  • len 涨、acc 也涨 → 正常。写得更详细确实带来了更高正确率(L2 那次训练就是这样:len 78→152,acc 21%→57%)
  • len 涨、acc 平 → 有问题。多写的部分没有价值
  • len 涨、acc 降 → 确定是问题。而且可能因为大量截断导致答案缺失

只看 len 判断不了,必须两个一起看。

处置

动作说明
换成序列平权归一化治来源 1,最干净
加长度惩罚超过某长度线性扣分。但要小心:惩罚太重会压制正常的推理
提高 max_tokens如果截断率高,先排除「被截断导致误判」
检查截断样本的 reward截断的样本要不要给负分?给多少?

炸法四:KL 跑飞

症状kl 陡增(不是缓升),输出开始出现胡话、重复、乱码、混语言。

机制:模型为了刷 reward,把「说人话」的能力训丢了。KL 度量的正是「离训练前那个模型有多远」。

单卡上很常见的一个诱因:beta=0 且不带参考模型——完全没有约束,也完全看不见漂移。

处置

  1. 确认参考模型加载对了(KL 应该恒 ≥ 0,如果出现负值是 bug,不是跑飞)
  2. beta 从 0 提到 0.001 ~ 0.01
  3. 降学习率
  4. 回滚到 KL 陡增之前的 checkpoint
β=0 不等于「不用管 KL」

现代配方确实常把 KL 系数设 0(slime 的入门例子就是 --kl-loss-coef 0.00),但它同时开着 --use-kl-loss——KL 不进损失,但作为监控指标记录

单卡上如果你为了省 1.1 GiB 而完全不要参考模型,就失去了这个预警。建议留着它。

炸法五:OOM

症状:不用说。

机制与处置已经在 L0 显存账本和 L3 colocate 那两节讲透了。这里只放一张速查表:

traceback 在 vLLM 栈    → 采样侧不够 → 降 max_model_len / 降并发 / 提 util
traceback 在 transformers 栈 → 训练侧不够 → 降 micro batch / 开检查点 / 降 util
×OOM 发生在第 150 步而不是第 1 步

这种情况尤其恼人,原因通常是:某一批采样出了特别长的回答,峰值显存超了。

对策:

  1. max_completion_length 而不是平均长度做显存预算
  2. 留 10%~15% 余量
  3. 加 checkpoint,这样至少不用从头再来

闯关

下面是六份现场。先自己判断,再敲命令看诊断。

rl@forge
目标 0/6
  1. 1.认出熵崩塌
  2. 2.认出 reward hacking
  3. 3.认出权重同步失效
  4. 4.认出长度爆炸
  5. 5.认出 KL 跑飞
  6. 6.认出健康的训练,并说出它唯一需要留意的地方
六份训练日志,每份是一种失效(有一份是健康的)。
用 cat 打开,自己判断是哪一种炸法,再用 diagnose 对答案。
输入 goals 看目标,hint 要提示。
[rl@forge ~/rlforge/logs]$
help 查看用法 · goals 看目标 · hint 要提示 · ↑↓ 翻历史

通用处置流程

不管遇到哪种,按这个顺序:

1. 别改代码。先把八个指标画成图看一遍
2. 确定是哪一种失效(用上面的指纹表)
3. 找拐点:从第几步开始不对的?
4. 从那一步之前的 checkpoint 重启
5. 只改一个参数
6. 跑 20 步冒烟,确认方向对了再放长
×最常见的错误处置:一次改三个参数

「降学习率 + 提 temperature + 加 KL」一起上,然后训练好了——你不知道是哪个起了作用,下次遇到还是要重来。

一次一个。RL 实验本来就贵,别把它变得更贵。

检查点单选

entropy 单调降到 0.01,8 条采样完全一样,reward 和 acc 都冻结。这是什么,怎么办?

检查点单选

`len` 从 78 涨到 152,`acc` 从 21% 涨到 57%。这是长度爆炸吗?

检查点单选

`ratio_mean` 从 1.0 单调跌到 0.54,`clip_frac` 涨到 66%,但 `adv_std` 正常。指向什么?

检查点多选

遇到失效时,下面哪些是正确的处置原则?(多选)

这节课的落点

  • 八个指标的诊断表是全站最该记住的一张表
  • 熵崩塌:entropy → 0,输出同质,不可逆,要在 < 0.3 时干预
  • reward hacking:reward 涨而 acc 不涨;必须拆分项记录;只能改 reward
  • 长度爆炸:len 涨且 acc 不涨;trunc > 15% 要处理;根因常是 per-token 归一化
  • KL 跑飞:KL 陡增 + entropy 上升 + 输出变噪声;与熵崩塌方向相反
  • OOM:看 traceback 在哪一侧;按 max 长度而非平均长度做预算
  • 用正常的指标做排除(adv_std 正常 → 排除数据侧)
  • 处置纪律:先看图 → 定失效 → 找拐点 → 回滚 → 只改一个参数 → 冒烟 20 步

延伸资料