什么叫训推一致
在做 LLM 的 RL post-training 时,我们常常默认一个前提:rollout 时模型采样到的行为,和训练时重新计算 log probability 的模型,是同一个模型。只有这样,on-policy RL 的假设才成立,像 PPO、GRPO 这类方法里的 importance ratio、KL 约束、old policy reference 才是有意义的。
但在实际情况下,为了提高采样效率,我们会在训练时使用更吞吐的推理引擎,例如 vLLM, SGLang,而训练时使用更精确的训练引擎,例如 FSDP、Megatron。这种差异导致训练和推理时,两边的 kernel、数值精度、并行切分策略、batching 方式都不同。结果导致同样的 token 序列,训练引擎和推理引擎给出的 logits 并不相同 —— 这就是 RL 中的训推不一致问题。
我们可以如下定义: \[ \pi_\theta^{rollout}(y_t \mid x, y_{<t}) = \pi_\theta^{train}(y_t \mid x, y_{<t}) \]
这里有三个关键前提:
- 输入是同一个 prompt 和同一段前缀 token 序列
- 比较的是 rollout 引擎和 train 引擎
- 两边输出的 logits 或对应概率分布一致
如果同样的序列,进入训练引擎和推理引擎后得到的 logits 不同,那么训推就不一致。这个差异表面上只是“两个 logprob 不一样”,但在 RL 里它会直接污染梯度估计。
为什么会发生不一致
第一层是数值计算本身。GPU 浮点运算不是严格结合的,累加顺序一旦变化,结果就可能不同。虽然 LLM 前向并不总是依赖 atomic add,但只要 reduction 顺序、tile 切分方式、内存布局或 kernel 选择发生变化,就可能带来细微数值偏移。
第二层是系统级实现差异。即使单个 kernel 在固定输入上是 deterministic 的,整个 serving system 仍然可能不是 batch invariant 的。比如动态 batch size 不同,attention 在 decode 阶段可能选择不同的 split-KV 策略;不同的 batch shape 也可能让 compiler 选择不同的 tile 或 warp 划分。于是同一个请求,只因为旁边拼了不同数量的请求,最后就可能得到不同的 logits。
第三层是训练和推理栈的目标本来就不同。推理引擎追求的是 tokens/sec,会更积极地使用低精度、batch-variant kernel、speculative decoding 等优化;训练框架更关心梯度计算的稳定性和反向传播,因此往往保留更高精度或不同的实现路径。这种“优化目标不一致”,会自然演化成“行为分布不一致”。
为什么 MoE 上这个问题更严重
在 dense 模型的结构是连续的,所以影响比较小;单对于 MoE 模型来说,由于 Expert Router 的存在,不同的路由选择会激活不同的专家,导致严重的训练不稳定。也即,在相同的误差程度下,MoE 多了一个放大误差的离散路由层。
这会带来两个后果。
第一,router 对数值误差极度敏感。对于 dense 模型,训推之间哪怕 logits 有一点偏移,通常也只是 token 概率略微变化;而对 MoE 来说,哪怕 router score 只发生很小的扰动,也可能让 top-k expert 发生切换。一旦 expert 变了,后续整层 FFN 路径都变了。
第二,路径切换会让 RL 里的 off-policy 问题陡然恶化。采样时你是沿着 rollout engine 选中的 expert 路径生成数据,但训练时重算 old logprob 时,training engine 可能激活的是另一组 experts。于是你以为自己在做 on-policy correction,实际上是在拿一条路径上的样本,去估另一条路径下的概率。这会让 importance sampling ratio 变得不可靠,甚至完全失真。
所以在 MoE 模型里,训推不一致,直接导致了 KL 指标变差,还会引发一系列 cascading effect:
- router 的微小误差会被离散路由放大
- 不同 expert 激活会导致更严重的分布偏移
- importance sampling 的估计方差和偏差都会迅速变坏
- 最终表现为 reward、entropy、gradient norm、PPL 等指标出现尖峰甚至训练崩溃
为什么训推不一致导致 RL 训练不稳定
如果从 RL 的角度看,train-infer mismatch 的本质是:你用采样分布 \(\mu\) 拿到了数据,但训练时优化的是另一个分布 \(\pi\) 下的目标,而且这两个分布之间的差异并不小。
当这种差异存在时,问题通常分成两类:
Bias 训练得到的梯度不再指向真实优化目标,优化器会系统性地朝错误方向更新。
Variance importance ratio 变得很大,梯度噪声暴涨。即便训练不立刻崩,也会被迫把学习率压得很低,训练几乎停滞。
这也是为什么很多系统里你会看到一种表面矛盾的现象:训练指标没有马上 explode,但 reward 上不去,或者一旦进入更长响应、更复杂 agent rollout、多轮 tool use 场景就开始不稳定。不是算法突然失效,而是 mismatch 被长序列和复杂状态分布放大了。
解决方案
主流方案大致分成三类。
1. 修基础设施,让训推尽量一致
直接对齐 training stack 和 inference stack,让两边在 kernel 层和系统层尽可能得到一致结果。
这类工作的核心关键词通常是 deterministic inference 和 batch-invariant kernels。它的目标不是“平均差不多”,而是同一个请求在不同 batch 条件下,仍然尽量得到相同结果。
典型思路包括:
- 固定 reduction 顺序
- 避免 batch size 改变时触发不同的 split 策略
- 为 matmul、RMSNorm、attention 提供 batch-invariant 实现
- 在训练侧补齐与推理侧一致的前向/反向路径
但代价也很明显:
- 工程复杂
- 适配不同模型和后端的成本高
- 往往会损失部分性能
2. 允许训推不一致,在算法侧做校准
第二条路线更现实:既然训推完全对齐太贵,那就承认 rollout distribution 和 training distribution 不一样,然后在算法侧做 off-policy correction。主要包括对 importance sampling 做改进。
- TIS,truncated importance sampling
- MIS,masked importance sampling
- GSPO,sequence-level importance sampling
- rejection sampling 或 geometric mean rejection
3. 对 MoE 做 routing replay / keep routing
对 MoE 模型来说,除了 logprob 偏差,在 MoE 还包括 expert 激活不同。所以很自然的做法是在推理时记录激活的专家,在训练时复用,强制训练侧走和推理侧相同的 expert 路径。这类方法通常被称为 keep routing 或 routing replay。MIMO R3 和 DeepSeek V3.2 都采用了相近方向的思路。
总结
RL 的 train-infer mismatch 在 MoE 模型里则会因为动态路由而被进一步放大,最终从 logprob 偏差升级为 expert path mismatch,直接破坏 on-policy 假设与训练稳定性。
所以解决这个问题,要同时看三层:
- Infra:尽量做 deterministic / batch-invariant inference
- Importance Sampling:使用更合理的 sequence-level correction,而不是只做 token-level patch
- MoE-Specific:Keep routing / routing replay 强制训推一致的路径选择