RL POST-TRAINING · 训练推理不一致 · TIS

同一个模型,
两个概率

名义上的 on-policy,实际已经变成 off-policy

现代 LLM RL 框架被拆成两半:rollout 跑推理引擎(vLLM / SGLang),训练用训练引擎(Megatron / FSDP)。两边加载同一份权重,理论上是同一个策略 π;但 kernel、归约顺序、并行切分与 MoE 门控的细微差异叠加后,推理引擎实际对应另一个策略 μ——数据从 μ 采样,梯度按 π 计算。Sea AI Lab 的论文(arXiv:2510.26788)把根源归到 BF16 的 7 位尾数:换 FP16 后两个引擎几乎重合,「修正不一致」的算法失去修正对象。

本报告为博客正文配套的交互版 · 正文:njx-njx.github.io/posts/tis-train-inference-mismatch/ · 论文 arXiv:2510.26788 · 工程路线 LMSYS Unified FP8
证据分级:论文一手 > 工程博客一手 > 二手转述(Notion 报告)> 推算/作者判断 [已标注] · 图内数字可点击下钻 · 点击画布在 BF16 / FP16 两种计算精度间切换

SCROLL

§0 · 关键结论

问题不在于算法,而在于数值精度:生成数据的引擎与计算梯度的引擎使用了两套数值不同的分布

2025 年下半年,几个团队分别报告了同一种现象:GRPO 训练前期一切正常,奖励稳步上涨,之后突然持续恶化直至崩溃。崩溃前没有梯度尖峰,超参没有问题,更换训练 query 后重新运行,崩溃仍会在某个时间点出现。Defog 的技术报告给出了解释:你以为自己在做 on-policy 训练,但 rollout 数据实际对应的分布已经偏离你正在优化的策略。

解释机制只需关注六个数字:推理引擎 vLLM / SGLang 与训练引擎 Megatron / FSDP 加载同一份权重,却分别对应数值上不同的策略 μ 和 π;根本原因不在算法,而在 BF16 的 7 位尾数——精度余量不足;将精度统一为 FP16 后,失败程度降至约 1/24;采用 FP16 后,各算法性能差异近乎消失,最朴素的 PG-IS 也登上榜首;至于用于修复该问题的 token 级补丁,需要额外支付 25% 的训练开销,并导致训练崩溃延迟发生。

下表是「算法 × 精度 × 指标」的完整对照——一张表说明补丁路线的天花板:序列级 MIS 是 BF16 下唯一不崩的补丁,训练峰值 95%,但部署引擎上的 AIME 只有 34%——部署差距原样存在;换 FP16 后同样是它,99% / 39%。灰格是公开材料里未见数字的格子,不编。

报告按论证链展开:§1 看同一个模型为什么算出两个概率(五条差异来源),§2 拆两个后果——有偏梯度与部署差距,§3 梳理算法补丁谱系及其局限,§4 考察 BF16 的 7 位尾数如何成为根本原因,§5 与本周前两篇(DAPO Clip-Higher、GSPO)形成四层防线对照,§6 给出三个判断与三条未决问题。

on-policy 与 off-policy 的边界,最终落在 kernel 的浮点行为上。

— 本报告 · 机制小结

语境数据从推理引擎 μ 采样,梯度却按训练引擎 π 的假设来算。 为何重要on-policy 不是一个单纯的算法命题——算法定义为「从当前策略采样」,而工程实现只能从「当前策略在某个 kernel 实现下的数值近似」采样。

§1 · 机制

同一份权重,两条前向路径

现代 LLM RL 框架被拆成两半:rollout 侧是推理引擎,为高吞吐做了大量 kernel 级优化;训练侧是训练引擎,负责计算每个 token 的 log 概率和梯度。Sea AI Lab 把两边数值对不上的来源清单化——五条,条条落在工程实现上。

下图中,同一份权重 W 从左侧分出两条前向路径:上方为训练引擎的并行计算路径(teacher-forcing 整段并行前向),下方为推理引擎的逐 token 计算路径(自回归逐个生成)。五条差异各对应一个阶段;点击任一阶段可查看其成因。推理引擎实际对应一个与训练引擎数值上不同的策略,记作 μ。昨天介绍的 GSPO 中,其 10% 的专家漂移发生在「更新前与更新后」的时间维度上;这里指的是「同一权重、两种引擎」的空间维度——门控敏感性会在两个分类维度上分别引发一次差异。

为什么是五条而不是一条。前四条(自回归 vs 并行的归约顺序、专门调优的 kernel、不同的并行切分、MoE top-k 门控的敏感性)每一条单独看都是「微小数值差」。第五条——BF16 只有 7 位尾数——决定这些微小差异会在多大程度上被放大为可观测偏差。它是根源项,§4 专门拆。

工程处理的对照。本地教材 hands-on-modern-rl 附录 B.1 记录了 rollout old logprob 的两种处理方式:直接用推理端返回的 logprob,或训练端重算并核对——后者正是 token-TIS 那 +25% 开销的来源。

§2 · 两个后果

梯度有偏,部署打折

后果一是训练过程本身出错:理论上的策略梯度要求从正在优化的策略 π 采样,实际样本却来自 μ。后果二是即使把训练偏差完全矫正,部署和评测跑的还是推理引擎。两条后果各有数学形式。

理论形式——期望在 π 下求:

∇θJ(x,θ) = 𝔼y∼π(·|x,θ) [ ∇θ log π(y|x,θ) · R(x,y) ]

实际实现——期望的计算分布发生偏移,等式不再成立,这就是论文的有偏梯度公式(3)。点击公式的四个组成部分,逐个查看解释:

∇θJbiased(x,θ) = 𝔼y∼μ(·|x,θ) [ ∇θ log π(y|x,θ) · R(x,y) ] ≠ ∇θJ(x,θ)

FORMULA ANATOMY · 公式(3)· 有偏梯度

点击公式上方的部件

四个部件对应「样本来自哪里 / 对数概率依据哪个策略求导 / 奖励如何加权 / 为什么不再相等」。偏差平时很小,但 RL 会反复将分布推向同一侧——μ 和 π 的小差异会随训练逐步放大。

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

arg maxθ 𝔼y∼μ R(x,y) ≠ arg maxθ 𝔼y∼π R(x,y)

在 π 下最优的参数,在 μ 下不一定最优。论文实验中,这一差距有实测结果:采用 BF16 时,表现最稳定的补丁(序列级 MIS)在训练时达到 95% 的峰值,在 AIME 2024 上的得分却只有 34%;采用 FP16 时则达到 99% 和 39%。所有算法补丁在这一指标上的改善幅度均为零——它们只修复训练过程中的偏差,而这种部署差距存在于训练之后。

凡是最终崩溃的训练,崩溃前训推差都在持续扩大;极端时同一份权重下同一个 token,一个引擎里概率趋近 1,另一个趋近 0。

— FP16 论文 · 预警信号观察,arXiv:2510.26788

语境训练曲线正常、loss 正常,只有训推 logprob 差在不声不响地发散。 为何重要这是论文给出的可操作预警指标:崩溃前不是无迹可循,而是没有监测正确的指标。

§3 · 算法补丁谱系

需求是「从 μ 采样却按 π 求期望」,教科书解法是重要性采样

给每个样本乘一个训推概率比 π/μ。2025 年下半年的改进主要分两步:token 级与序列级。两个补丁都承认 μ ≠ π,逐样本进行补偿,既带来额外的算力开销并提高方差,也都无法解决部署差距。阶梯的四个维度(额外算力开销、在 BF16 下的稳定性、收敛速度、部署差距修复)为报告归纳的定性档位。

补丁一,token 级截断校正(Defog,2025-08):对每个 token 算 ρt = π(yt|x,y<t) / μ(yt|x,y<t),截断到上限 C = 3 后乘进 GRPO 的每一项梯度。分母 μ 是推理引擎的概率,所以训练引擎必须对同一条样本重算一次前向来取得分子——按反向传播所需的计算量约为前向计算的 2 倍估算,额外带来约 25% 的开销。效果:崩溃被推迟,峰值 82%(VeRL)/ 88%(Oat)后仍然崩溃。

补丁二,序列级掩码校正(《When Speed Kills Stability》,Liu 等):论文指出,token 级校正的梯度有偏,因而改为对整条序列只计算一个比率 ρ = π(y|x) / μ(y|x),超过 C 就把整条序列的梯度掩掉。思路与 GSPO 一脉相承——只是 GSPO 的 si 仍是优化对象,这里的 ρ 是校正因子。它是 BF16 下唯一未崩溃的补丁,代价是序列级比率方差大、收敛慢,部署差距同样原样存在。

两个补丁的共同点。都接受 μ ≠ π 的事实并逐样本补偿:引入新的算力成本与方差,且部署差距一律原样存在。这是补丁路线的天花板,也是 §4 中精度路线的切入点。DS 指标即「部署差距改善」:两个补丁在此维度均为零。

§4 · 根源:BF16 的 7 位尾数

同样 16 位,分配方式决定训练是否为数值误差留出足够的精度余量

Sea AI Lab 没有继续沿着补丁方向推进,而是直接检查了数值格式。BF16 用 8 位指数 + 7 位尾数,动态范围与 FP32 同级——预训练不怕溢出、不用 loss scaling,这是它成为标配的原因。FP16 用 5 位指数 + 10 位尾数:范围小得多,但相邻可表示数密度是 BF16 的 8 倍。

论文的判断:RL 微调阶段的需求变了。权重和激活的动态范围在预训练已经定型,BF16 的 FP32 级范围在这里没有实际用途;训练和推理过程中 kernel 的每一处差异,都需要 FP16 多出的 3 位尾数来容纳。将精度统一为 FP16 后,两个引擎的输出在绝大多数 token 上数值一致,μ 与 π 重新重合。离线分析显示:BF16 的序列级训推失配随生成长度指数放大,FP16 将失配压到约 1/24。

精度消融里还有一个对照:「训练 BF16 + 推理 FP32」的组合也完全稳定——但推理慢 3 倍。全部使用 FP16 是兼顾稳定性与效率的最佳组合。

最能说明问题的是后一组实验:采用 FP16 后,各算法性能差异几乎消失——BF16 下差异明显的 GRPO、token-TIS、GSPO、序列级 MIS,在 FP16 下彼此接近,连最朴素、不带任何修正的重要性采样策略梯度(PG-IS)也登上榜首。原因不难理解:μ 与 π 的差接近零后,训练回到近似 on-policy,所有「修正不一致」的算法都失去了修正对象。

补充一个细节:GSPO 在 VeRL 上 1200 步后梯度变成 NaN——数值问题没解决的时候,算法层改进可能白调。工程路线印证了同一结论:SGLang 手工对齐两条计算路径的 kernel 实现(2025-11 Unified FP8)、Miles/slime 从系统层一次性对齐训练与推理;二者都有效,但需要深入的 kernel 知识与大量工程投入,难以移植。数值格式是所有方案里成本最低的一条:只需改几行配置,并沿用现成的 loss scaling 机制。

§5 · 本周三篇的四层防线对照

同一个问题,四层解法:从算法内部到消灭不一致

本周三篇文章恰好能从四个层面看待同一问题。层次越深,离「不一致」的根源越近——L1 假定它不存在,L2 容忍它带来的波动,L3 逐样本补偿,L4 消灭它本身。对照这个脉络,GSPO §5.4「序列级似然对训推精度差异的高容忍度」不再只是附带好处,而是算法层对 TIS 的直接回应。

§6 · 三个判断与未决问题

on-policy 是数值命题,精度路线要重新认真对待,部署差距研究最少

三条判断是博客作者基于全部证据给出的操作结论;未决问题是证据本身留下的三个缺口。

判断一

ON-POLICY 是工程上的数值命题

两边差到一定量级,理论分析所依据的前提便不再成立,而现有的报警机制无法监测到这种差异。

训练曲线正常、loss 正常,只有训练侧与推理侧的 logprob 差在不声不响地发散。实操建议很直接:把训推 logprob 差(或 KL)设为常规监控项,成本接近于零——论文展示出的预警价值有实测结果支持。

Hover for the full story

判断二

FP16 结论不宜过度推广

证据扎实,但论文自己也声明不主张普适;行业往 FP8 走的话问题还会回来。

证据覆盖 1.5B 到 30B MoE、两个框架、LoRA、两个模型家族,是扎实的。但超大模型用 FP16 需要管理溢出;FP8 尾数只有 3~4 位,训推不一致会以另一种形式回归。目前 FP8 RL 路线(LMSYS、NVIDIA)是两边统一 FP8,而不是回到 FP16。要么把精度问题重新认真对待,要么以其变种形式再遇到一次。

Hover for the full story

判断三

部署差距:研究最少的一环

梯度偏差可矫正,不一致可消灭,但「训练得到的参数对部署引擎不是最优」没有消失。

统一打补丁、统一精度格式、统一对齐 kernel 之后,部署差距只是变小不是归零。评测换推理引擎跑,报告的分数到底属于哪个策略?多引擎混合部署时,差距如何核算?目前没有看到系统研究。

Hover for the full story

未决问题

  • 一 ·FP16 下仍然存在的少量训推差异,在数千步的超长训练中会否重新累积成问题。
  • 二 ·FP8 统一精度路线与 FP16 路线在同等算力预算下的最终性能,目前没有公开的直接对比。
  • 三 ·部署差距并非消失,只是有所减小:用与训练不同的引擎评测时,分数归谁——目前没有看到系统研究。

右栏仪表盘随章节切换:训推差监控(示意曲线)、四层防线状态、位域对照与本章关键数字;全部可点击下钻。