本文有配套的交互报告,含可下钻的双引擎机制图、补丁谱系对比与精度位域拆解。

同一类难以解释的崩溃

2025 年下半年有几个团队分别报告了同一种现象:GRPO 训练前期一切正常,奖励稳步上涨,然后在某个时间点突然掉头向下直至崩溃。崩溃前没有梯度尖峰,超参没有问题,换一批训练 query 重跑,崩溃换个时间还是会来。

Defog(Feng Yao,字节 Seed)2025 年 8 月的技术报告《Your Efficient RL Framework Secretly Brings You Off-Policy RL Training》给出了一个让不少人意外的解释:你以为自己在做 on-policy 训练,但 rollout 数据实际对应的分布已经偏离你正在优化的策略。问题不在算法,在数值——生成数据的引擎算出的概率,与训练数据引擎算出的概率不一致。

同一个模型为什么算出两个概率

现代 LLM RL 框架被拆成两半。rollout 侧使用推理引擎(vLLM、SGLang),为高吞吐做了大量 kernel 级优化;训练侧使用训练引擎(Megatron、PyTorch FSDP、DeepSpeed),负责计算每个 token 的 log 概率和梯度。两边加载同一份权重,理论上应该是同一个策略 $\pi$。

但由于工程实现不同,各引擎的计算结果并不完全一致。Sea AI Lab 的 FP16 论文(arXiv:2510.26788)总结了差异的来源:

  • 计算方式不同。推理是自回归逐 token 生成;训练是 teacher-forcing 下将整段序列并行前向计算。对于同一串 token,不同的计算过程采用不同的浮点归约顺序,误差累积方式也不一样。
  • kernel 实现不同。推理引擎的 RMSNorm、RoPE、attention kernel 针对延迟和吞吐量做过专门调优,与训练侧实现存在微小数值差。
  • 并行切分不同。训练和推理采用不同的 tensor 并行与数据并行切分,跨卡归约的顺序不同会改变浮点结果。
  • MoE 的 top-k 门控对细微变化敏感。专家选择对 logits 的微小波动敏感,使用同一权重、两种引擎各计算一遍,选出的专家也可能不同。昨天介绍的 GSPO,其 10% 专家漂移出现在“更新前与更新后”的时间维度上;这里指的是“同一权重、两种引擎”的空间维度。门控敏感性会在两个维度分别引发一次差异。
  • 精度格式的尾数太短。默认的 BF16 只有 7 位尾数,这些引文涉及的各处微小差异都没有足够的数值精度余量,最终造成明显偏差。这一条是全文关键,后面细说。

于是推理引擎实际对应一个与训练引擎数值上不同的策略,记作 $\mu$。数据从 $\mu$ 采样,梯度却按 $\pi$ 的假设来算。on-policy 与 off-policy 的边界,最终取决于 kernel 的浮点行为。

两个后果:梯度有偏,部署打折

后果一:梯度有偏。理论上的策略梯度要求从正在优化的策略 $\pi$ 采样:

$$\nabla_\theta\mathcal{J}(x,\theta)=\mathbb{E}{y\sim\pi(\cdot|x,\theta)}\left[\nabla\theta\log\pi(y|x,\theta)\cdot R(x,y)\right]$$

$\pi(y|x,\theta)$ 是训练前向中该回答的似然,$R(x,y)$ 是奖励,期望需要在 $\pi$ 的分布下计算。但实际样本来自 $\mu$:

$$\nabla_\theta\mathcal{J}{biased}(x,\theta)=\mathbb{E}{y\sim\mu(\cdot|x,\theta)}\left[\nabla_\theta\log\pi(y|x,\theta)\cdot R(x,y)\right]\neq \nabla_\theta\mathcal{J}(x,\theta)$$

期望值所基于的分布突然发生了变化,等式不再成立。偏差平时很小,但 RL 是个把分布往一侧持续推的迭代过程,$\mu$ 和 $\pi$ 的小差异会随训练逐步放大。论文还观察到一个可作预警信号的现象:凡是最终崩溃的训练,崩溃前 $\pi$ 和 $\mu$ 的差都在持续扩大,极端时同一份权重下同一个 token 在一个引擎里概率趋近 1、在另一个里趋近 0。

后果二:部署差距(deployment gap)。哪怕训练过程的梯度偏差被完全修正,优化目标仍是训练引擎的概率分布,而部署和评测跑在推理引擎上:

$$\arg\max_\theta \mathbb{E}{y\sim\mu}R \neq \arg\max\theta \mathbb{E}_{y\sim\pi}R$$

在 $\pi$ 下最优的参数,在 $\mu$ 下不一定最优。论文实验里这个差距是可见的:BF16 下表现最稳定的算法补丁(序列级掩码校正),训练准确率峰值 95%、AIME 2024 得分 34%;FP16 下是 99% 和 39%。所有算法补丁在这一指标上的差距都为零——它们只解决训练过程中的偏差,无法解决这种部署差距。

算法补丁及其局限

本质是“从 $\mu$ 采样却按 $\pi$ 求期望”,教科书解法是做重要性采样校正:给每个样本乘一个训推概率比 $\pi/\mu$。2025 年下半年的改进主要分两步:

补丁一,token 级截断校正(Defog)。对每个 token 计算训练概率与推理概率之比 $\rho_t = \pi(y_t|x,y_{<t},\theta’)/\mu(y_t|x,y_{<t},\theta’)$,截断到上限 $C$(实验取 3)后,乘进 GRPO 的每一项梯度。注意分母 $\mu$ 是推理引擎的概率,因此必须让训练引擎对同一条样本重新进行一次前向计算,才能得到分子,额外带来约 25% 的训练开销(按照反向传播的计算量约等于 2 倍前向计算量来估算)。效果:崩溃被推迟,峰值到 82%(VeRL)/ 88%(Oat)后照崩。

补丁二,序列级掩码校正(《When Speed Kills Stability》,Liu 等)。作者指出 token 级校正的梯度有偏,将校正方式改为对整条序列只计算一个比率 $\rho = \pi(y|x,\theta’)/\mu(y|x,\theta’)$,超过 $C$ 就把整条序列的梯度掩掉。思路与昨天介绍的 GSPO 一脉相承(不过,GSPO 的 $s_i$ 只作为优化对象,这里的 $\rho$ 则是校正因子)。它是 BF16 下唯一未崩溃的算法补丁,代价是序列级比率方差大、收敛慢,部署差距同样原样存在——峰值只有 95%/34%。

两个补丁的共同点:都接受 $\mu \neq \pi$ 的事实并逐样本补偿,而要付出新的算力成本并引入方差,而且都无法解决部署差距。

根源:BF16 的 7 位尾数

Sea AI Lab 这篇论文没有继续沿着补丁方向推进,而是直接检查了数值格式。

BF16 与 FP16 同样 16 位,分配不同。BF16 用 8 位指数 + 7 位尾数,动态范围与 FP32 同级:预训练不怕溢出、不用 loss scaling,这是它成为标配的原因。FP16 用 5 位指数 + 10 位尾数:动态范围小得多(要靠 loss scaling 防梯度下溢),但相邻可表示数的密度是 BF16 的 8 倍($2^{10}$ 对 $2^7$),精度更高。

论文的判断:RL 微调阶段的需求变了。权重和激活的动态范围在预训练已经定型,BF16 的 FP32 级范围在这里已经没有实际用途;训练与推理中每处 kernel 差异,都需要 FP16 多出的 3 位尾数提供足够的数值精度余量。将精度统一设为 FP16 后,两个引擎的输出在绝大多数 token 上数值一致,$\mu$ 与 $\pi$ 重新重合。离线分析显示:BF16 的序列级训推失配会随生成长度呈指数放大,FP16 将失配显著降低,约至 BF16 的 1/24。精度消融实验里,“训练 BF16 + 推理 FP32” 的组合也能完全稳定,但推理慢 3 倍;全部使用 FP16 是兼顾稳定性和效率的最佳组合。

最能说明问题的是后一组实验:采用 FP16 后,各算法性能差异几乎消失。BF16 下差异明显的 GRPO、token 级 TIS、GSPO、序列级 MIS,采用 FP16 后彼此接近,连最朴素、不带任何修正的重要性采样策略梯度也能取得最好的表现。原因不难理解:$\mu$ 与 $\pi$ 的差接近零后,训练回到近似 on-policy 状态,所有“修正不一致”的算法都失去了修正对象。(补充一个细节:GSPO 在 VeRL 上 1200 步后梯度变成 NaN,这说明在数值问题没有解决的情况下,算法层面的改进可能没有作用。)文中引用的工程路线也印证了这一点:SGLang 团队手工对齐两条计算路径的 kernel 实现(2025 年 11 月 Unified FP8 工作)、Miles/slime 从系统层面一次性对齐训练与推理:二者都有效,但需要深入的 kernel 知识和大量工程投入,且难以移植。数值格式是所有解决方案中成本最低的一条:只需修改几行配置,同时沿用现有的 loss scaling 机制。

与前两篇对照着看

本周三篇文章恰好能从四个层面看待同一问题:

  • DAPO Clip-Higher(前天):在假定训练与推理一致的前提下,调整算法内部的 clip 边界来解决熵坍缩;
  • GSPO(昨天):将优化目标改为使用序列级单位,并对 $\mu$ 的差异具有天然鲁棒性,同时还能容忍 MoE 路由漂移;
  • TIS 算法补丁(今天上半篇):接受 $\mu \neq \pi$ 的事实,逐样本做重要性采样补偿;
  • FP16 与 kernel 对齐(今天下半篇):让 $\mu \approx \pi$,直接消除不一致。

对照这个脉络,GSPO §5.4 “序列级似然对训练与推理的精度差异有很高容忍度”不再只是附带好处——它是算法层面对训练与推理不一致(TIS)问题的直接回应。

我的三个判断

一、从工程上看,on-policy 是一个数值问题。算法定义写“从当前策略采样”,工程上你只能从“当前策略在某个 kernel 实现下的数值近似”采样。两者差到一定量级,理论分析采用的前提已不再成立,而且现有的报警机制无法据此发出警报:训练曲线正常、loss 正常,只有训练侧与推理侧的 logprob 差在不声不响地发散。实操建议很直接:把训推 logprob 差(或 KL)设置为常规监控项,成本接近于零,而论文展示的预警价值是实测的。

二、BF16 的默认地位值得被质疑,但 FP16 的结论不宜过度推广。证据覆盖 1.5B 到 30B MoE、两个框架、LoRA、两个模型家族,是扎实的;论文自己也声明不主张普适:超大模型用 FP16 需要管理溢出,而行业往 FP8 走的话(尾数只有 3~4 位),训练与推理不一致的问题还会再次出现。目前 FP8 RL 路线(LMSYS、NVIDIA)是训练和推理两边统一使用 FP8,而不是回到 FP16。精度问题要么重新得到认真对待,要么以另一种形式再次出现。

三、部署差距是此背后最直接、研究最少的问题。虽然梯度偏差也可以修正,训练与推理不一致也可以通过同时对齐两侧的 kernel 和精度格式消除,但“训练得到的参数对部署引擎不是最优”这一问题没有消失,只是有所减小。评测时换用推理引擎,报告的分数到底属于哪个策略?多引擎混合部署时,差距如何计算?我目前没有看到系统研究。

未决问题

  • FP16 下仍然存在的少量训推差异,在数千步的超长训练中会否重新累积成问题;
  • FP8 统一精度路线与 FP16 路线在同等算力预算下的最终性能,目前没有公开的直接对比;
  • 部署差距还会出现,只是有所减小:使用与训练环境不同的引擎评测时,分数应该归因于哪个策略。

参考来源