1. 首页
  2. 精选文章
  3. RL 为什么不如 SFT 稳定?以及 RL 各种 Trick

RL 为什么不如 SFT 稳定?以及 RL 各种 Trick

  • 发布于 2025-11-12
  • 21 次阅读

作者:ybq
https://zhuanlan.zhihu.com/p/1966609550032475890

这篇文章随便聊聊 LLM RL 的一些想法。文章的灵感来自于,每次和好哥们 @真中合欢 交流 RL 训练的时候,都会被他批评一顿说不要乱加各种技巧。他成功说服了我,我也来试试看能不能说服一些其他同学。

SFT 与 RL

现如今有太多的同学对 SFT 持以偏见,认为 SFT 就是洗数据,是没技术含量的代表。这个观点对吗?某种意义上确实是对的,但前提你得是 infra 同学,RL 框架对代码能力的需求确实是远高于 SFT 框架对代码能力的需求。

至于算法和数据同学,我们的 RL 日常其实就是把那些已知的 RL 技巧排列组合起个实验而已,我不认为这种工作有比 SFT 更高的技术含量。更重要的是,算法不能把 SFT 和 RL 割裂开来,RL 时的 explore space 基本都是 SFT 所提供的,好的 SFT(cold start)正是 RL 取得较大收益的前提。

闲话扯完了,我想先捋一下基础知识: RL 的 loss 和 SFT 的 loss

​\text{REINFORCE} 单个 step 的 loss 是 ​\ell_t(\theta) = - A_t \cdot \log \pi_{\theta}(a_t)

已知 transformer 的每个 step 的输出是一个 logits 向量,对这个 logits 做一次 softmax 函数就得到了每个 token 被选中的概率。

如果记 ​z 为 logits 向量,那么 ​\pi = \text{softmax}(z)

令 loss 对 logits 向量 ​z 求导得: ​\nabla_{z_{t,k}} \ell_t = A_t \cdot (\pi_\theta(k) - \mathbf{1}[k=a_t])

  • ​k=a_t(被选中的 token) ​\pi(k) - 1 < 0 所以如果 ​A_t>0 ,这个 logit 被推高
  • ​k \neq a_t(未选中的 token) ​\pi(k) - 0 > 0 所以如果 ​A_t>0,这个 logit 被推低

换言之,RL 的优化动力可以概括为:如果 Advantage 大于零,logits 向量在当前 token 维度的梯度是负数,这个 logit 会朝增大的方向优化,logits 向量在其他所有维度的梯度都是正数,剩余的 vocab_size - 1 个 logit 都会朝着减小的方向优化;反之亦然。

再来说 SFT,我们都知道 SFT 的 loss 是目标分布和模型分布的交叉熵函数。

给定目标分布 ​q(通常是 one-hot),模型预测分布 ​\pi_\theta

交叉熵定义为:

\ell^{\text{CE}}(q, \pi_\theta) = - \sum_{k} q(k) \, \log \pi_\theta(k)

在 SFT 中,我们有一个 参考答案 ​a_t ,所以目标分布是: ​q(k) = \mathbf{1}[k=a_t]

综上, SFT 的单个 token 的loss 是:

\ell_t^{\text{SFT}}(\theta) = - \sum_k \mathbf{1}[k=a_t] \log \pi_\theta(k) = - \log \pi_\theta(a_t)

令 loss 对 logits 向量 ​z 求导得: ​\nabla_{z_{t,k}} \ell_t^{\text{SFT}} = \pi_\theta(k) - \mathbf{1}[k=a_t]

为了一叠醋包的饺子可算包完了,整这么多基础知识,我其实就想说一句话:SFT loss 和 RL loss 在形式上没有区别,SFT 仅仅是 RL advantage 全为 1 时的一个特例罢了。更准确的说法是:SFT 是一种全部样本都为 off_policy,只计算正例 loss,且 advantage 均为 1 的 RL。

俞扬老师在评论区指出了我这里的一个理解错误:RL 中的 ​A_t 并不是一个加权常数,​A_t 的“完整”写法是 ​A_t(\pi),这是一个随着 ​\pi 的变化而发生变化的函数,更麻烦的是,这是一个黑箱函数,无法对 ​A_t(\pi) 求导,而只能通过采样来评估,采样必然存在误差,进而导致训练不稳定。与之相对的,SFT 的 ​A_t 实打实就是常数 1。

我指出 RL 和 SFT 在 loss 形式上的统一其实只是个引子 —— loss 形式一致但训练差异性较大,说明我们应该聚焦在两种训练方式的数据分布究竟有何差异。

RL 为什么不如 SFT稳定

那么问题来了,既然 SFT 和 RL 的在 loss 形式上没有本质区别,且 SFT 还是完全的 off_policy。为什么 SFT 会那么稳定,一套祖传超参数可以用一年都不带换的,而 RL却是一训就崩?

说下个人想法吧:

一方面,infra 上的难度 RL 确实较之于 SFT高了不止一个档次,系统级的 bug 存在于训练框架的各个角落。训推一致性修复的时候,计算 logprob 的时候考虑 temperature、top_p、top_k 这些了吗?reward shaping 的时候,reward 从 0 / 1 变成小数,剔除全零全一样本时会兼容这些吗?模型 rollout 的时候,出现了多个“”的时候,有考虑过怎么处理这种数据吗?这些都是常见的小 bug,megatron、vllm、sglang 的 bug 角度更是刁钻,我不太懂 infra 就不在这里瞎说了。

另一方面,数据的干净程度相差过远。SFT 的数据筛选会有一套较为复杂的流程,利用各种规则加模型来进行过滤,甚至会人工一条条的进行 review。相比之下, RL 给数据打 reward 的时候通常没有如此复杂的清洗流程,往往只是外挂了一个 reward model 去比较 model_response 与 ground_truth 是否一致。一旦遇到较为困难的 prompt,ground_truth 非常复杂,一致性判别的准确率能有个 90% 都已经算很好了。

最后再补一条个人的暴论,我认为 LLM 中的 RL 算法如逆水行舟,不进则退,它的每条训练样本都是带有一些“毒性”的,如果这些样本没有 explore 到有价值的信息,模型便会朝崩溃更进一步。

具体来说,RL 的每条正样本,都在让语言模型朝着过拟合的方向去学习,即进一步强化那些本就是高概率的语料;RL 的每条负样本,则都是在破坏语言模型的分布,将某个 token 的概率分给其他所有的 token,会将语言模型的分布引向一个未知的方向(负样本的存在也可能是 RL 容易崩溃的关键)。反观 SFT ,每条语料都是我们精心构造的,我们不仅知道这些语料的分布情况,也会想方设法的调超参数来避免模型在这些语料上过拟合。

这里也抛出一个自己的疑惑,负样本到底在做什么?某个 token 的概率分给所有其他 token 到底会让模型学到什么东西?我们到底该如何正确的利用负样本?

RL 的各种 Trick

继续往下聊,既然 RL 容易训崩溃,那都有哪些技巧可以稳定训练呢,这里简单罗列一下:

1、entropy collapse:训练的时候加不加 entropy loss,至今仍未达成共识。
2、CLIP:至少一半的强化工作都围绕 clip 做文章,这些工作分析的非常有道理,实际用起来却乏善可陈。
3、Token Mask:对高熵 / 低熵 token 做特殊的逻辑,或鼓励某些 token 的学习,或阻止某些 token 的更新,也是重点雕花区域。
4、Reward Shape:

  • 控制 reward 样本中 0 / 1 的分布在一个区间范围内;
  • 用 pass@K 代替 pass@1 作为优化目标;
  • 用 test case 的通过率作为 reward;
  • length penalty;
  • ……
    5、训推一致性:当下最热的话题,以 tis、icepop 最为火热,但可以说和算法没啥关系,全看 infra 功底。

怎么说呢,我个人不喜欢加太多技巧,尤其是 entropy_loss、kl_loss 这种不太知道会对模型产生什么影响的技巧。完全是为了在 RL 的过程中控制模型不去崩溃,让那条训练曲线更好看。大多数实验中,熵炸、grad_norm 炸都属于表象,阻止它不如去分析它,以熵为例:

  • 为什么会熵增?按理说训练是一个确定性增加的过程应该熵减,但是你的模型确实在增,那就说明训练的过程中:高概率 token 常被当作负例,或者是低概率 token 被常当作正例;
  • 为什么会熵减过快?rollout 多样性差呗。是不是调整下 rollout temperature 和 rollout prompt 要比加一个 entropy loss 更合理些。

总结下来,任何技巧的本质,都是在帮助模型寻找一个适合它的训练数据分布。因此,分析 rollout 数据分布的变化,优先级要始终领先于尝试引入某个稳定训练的技巧。这些技巧在稳定某次训练的同时,也会掩盖训练崩溃的原因。

但同时,若某个技巧确实有用,也可以反过来推哪种数据分布“有利于/有损于”模型的学习:例如, off_policy 和训推不一致会引起崩溃,是不是在间接说明“一个整体上与模型分布很接近,但却在个别 token 上和模型分布差异很大的样本”可能是一种不太适合模型的数据。

引入训练技巧必然会引起训练数据分布的变化,有些分布的变化是在我们预期之内的,有些分布的变化则是我们预期之外且不知情的。CISPO 的作者就曾分享过:在 off_policy 的时候, 被 clip 掉的 token 是具有多重分布的,概率值与当前模型的分布不一致只是其所具有的一个分布,“概率低但影响 long cot涌现”则是这些 token 的另外一个分布。作为训练者,我们往往不能留意到所有分布的变化,从而总结出一些错误的结论。

这里我并不是反对所有技巧,而是认为:在使用技巧的时候,我们需要知道自己设计的新的loss 会让哪种分布的 token 得到促进 / 抑制?如果无法得知,那就别加。

RL 数据

那么话说回来了,RL 到底有没有任何时候都有效且毫无副作用的技巧呢?有的,兄弟,有的。洗数据!训 reward model!

先说数据吧,今年大家普遍进入了 post train 深水区之后(从 math、gsm8k 进阶到 aime、imo),一个很严重的问题就是:训模型者看不懂数据了,没有办法通过肉眼看解题过程来判断数据质量了。而训模型者日常批量清洗数据的手段,往往都存在一个问题:“无法区分难题和错题”。

  • 难题有什么特点?模型多次采样后,屡屡犯错,偶尔灵机一动,做对了。
  • 错题有什么特点?模型多次采样后,基本都做对,但是因为和 ground_truth 不一致屡屡被判错,偶尔脑子抽风做错了,好巧不巧和 ground_truth 一致了。

不要以为错题的答案是离谱到一眼就能看出来的那种,事实上,错题往往是十分接近 ground_truth 且非常具有迷惑性的。这里我举几个例子:

  • 一张票 2 块钱,9 块钱能买几张票?我们以为错题的答案会是 356 张这种离谱的数字,其实是 4.5 张;
  • 一个一元七次方程,错题的答案给了 3 个实数解,我们 review 的时候,反代入进去发现是对的,留下了这道题目。但在训练的时候,模型拿着 3 个实数解和 4 个复数解,高高兴兴的去找 reward_model 要奖励的时候,反手被打了 0 分,这对模型是多大的心理阴影呀。
  • ……

目前的开源 RL 数据的质量真的是一言难尽。没辙,要么请专业的硕博理科生去标注,要么用启发式的规则去清洗,在不够干净的数据上只能得到错误的实验结论。

再说 reward model,千万不要以为所谓的 rule_based reward model 真的就是靠 rule 来打分的,或者是靠 math_verify 这种规则库 。有很多情况下,靠 rule 几乎无解:

  • 问题是盈利__%?标准答案是 96,而模型输出了“盈利96%”,模型活该拿 0 分吗?
  • 标准答案是 3.14,模型输出了 \pi、圆周率、3.1415926,模型活该拿 0 分吗?
  • ……

reward 要准,我建议使用 generate reward,而且得是能力巨强的那种。这个模型需要读的懂题目要求的输出格式、 ground_truth 的等价变换,以及各种复杂的高阶公式。除了较强的知识能力外,模型还要具备很强的指令遵循能力,否则它容易自己亲自下场解题。

这篇就聊到这里吧,再次感谢 @真中合欢 对我的 RL 指点。顺带提一句,最近他带着我读了一下 TRPO 的论文,确实是一篇神作。目前 LLM 的 RL 脱离传统 RL 太远了,TRPO 这种传统 RL 的巅峰之作,值得被翻出来反复品鉴,它的思路会给当下的 RL 工作带来很多指点。