第一遍:这篇论文到底在解决什么
这篇论文讨论的不是一个新的模型结构,也不是一个新的 reward,而是一个在 RL 训练系统里经常被忽略的记账问题:生成 rollout 的模型,和计算策略梯度的模型,可能不是同一个概率分布。
在理想化的 on-policy RL 里,这两个东西是同一个策略 \(\pi_\theta\):我们用 \(\pi_\theta\) 采样一条轨迹,再用同一个 \(\pi_\theta\) 计算 \(\log \pi_\theta(a\mid h)\) 和梯度。此时策略梯度有一个漂亮的性质:对任意 prefix \(h\),score 在策略自身分布下的期望为零。也就是说,如果 reward 和 token 的选择没有关联,梯度平均下来应该不动。
但真实的大模型 RL 系统很少这么干净。生成通常交给 vLLM、SGLang 这类推理引擎,训练则在 Megatron、FSDP 或 JAX 训练栈里完成。两边即使加载同一个 checkpoint,也可能因为量化、kernel、并行方式、tokenizer、采样参数或异步更新,产生不同的下一 token 分布。论文把这种现象称为 training-inference mismatch(TIM)。
论文的核心观察是:TIM 下,score 的期望不再为零。这个非零的期望会像一个固定的方向,持续把参数往采样器的分布上推;它和 reward 无关,因此即使所有样本拿到同样的奖励,模型仍然会更新。作者把这种现象叫做 drift。Drift 每一步都很小,但在线 RL 会反复采样、反复更新,误差会累积,最终表现为训练崩溃、输出分布变窄或 reward 停滞。
这里的 score 不是 attention score,也不是 reward model 的分数,而是策略对数概率对参数的梯度:\(s_v=\nabla_\theta \log p_v\)。它回答的是“如果想让 token \(v\) 的概率变大,参数应该往哪个方向走”。
论文的论证顺序
作者的推进很克制,基本是四步。
- 先把 trainer 和 sampler 的下一 token 分布分别记为 \(p\) 和 \(q\),定义每个 token 的 score \(s_v\),证明 on-policy 时 \(\mathbb{E}_p[s_v]=0\),而 TIM 下 \(\mathbb{E}_q[s_v]\neq 0\)。
- 把 off-policy 的梯度分解成“均值奖励乘 drift”和“奖励与 score 的协方差”两部分,指出 drift 是那个与奖励无关、但会持续累积的坏项。
- 提出 score centering(SC):对每个 prefix,从采样 token 的 score 里减去采样分布下的期望 score。这个操作是加性的、确定性的、没有超参数;它不改变奖励,也不引入 importance ratio。
- 把 SC 和已有的 importance sampling(IS)方法对比,并给出 top-k 词表上的高效实现;然后在 0.6B 到 30B 的模型上,用合成噪声、量化和 staleness 三类 mismatch 做实验。
论文报告了什么
实验的主线是 Qwen3 系列:0.6B 的 Countdown 任务、1.7B 的 toy reward 任务,以及 30B-A3B 的 INTELLECT-2 数学任务。所有方法共享同一套 REINFORCE 加 group-centered reward 的骨架,每个 batch 只做一步 SGD;作者刻意没有比较完整的 PPO、DAPO、GRPO 工程配方,而是把“校正规则”单独拿出来看。
在最温和的 FP8 量化设置下,普通策略梯度可以稳定训练到约 58% 的训练准确率,SC 和 TIS 的表现与它接近。真正拉开差距的是更严重的 mismatch:在 FP8 权重/激活加 FP4 KV cache 的设置里,普通策略梯度在 200 步内崩溃,MIS 在后期崩溃,而 SC 和 TIS 分别稳定在 52% 和 51%;在 INT8 权重/激活加 INT4 KV cache 的设置里,SC 仍有 30%,TIS 降到 12%,其余方法大多低于 5%。
作者还报告了 staleness 的结果:当推理引擎每 64 步才同步一次参数时,SC 单独使用不如 SC 加 TIS/MIS 的组合;组合能同时利用 IS 对采样分布的修正和 SC 对剩余 drift 的消除。与之相对,PPO/DAPO 能扛住 staleness,但在量化和权重噪声下崩溃,因为它们的 clip 针对的是策略更新的幅度,而不是数值误差造成的分布偏移。
作者最后落到哪里
论文的结论不是“SC 可以替代 PPO”,而是一个更窄、更可靠的判断:当 mismatch 是系统性的、且你能够记录采样器的概率时,减去期望 score 是一个便宜且有效的偏差修正。作者也明确承认,温和 mismatch 下短训练很难把差异跑显著,所以很多实验故意放大了 mismatch,把严重设置当作长训练的代理; headline 数字是训练准确率,不是 held-out benchmark;30B 的种子数量也不均衡。
以上是按论文原意做的连续讲解。下面进入本文自己的结构化抽象、公式推导、证据审计与工程判断。
核心判断:SC 修的是“没有奖励也会走”的那一部分
如果把整篇论文压缩成一句话:SC 不是把 off-policy 变成 on-policy,而是把 off-policy 梯度里那个与奖励无关、却会持续累积的系统性漂移拿掉。它留下的是采样分布下的奖励- score 协方差;这部分仍然不是 on-policy 的目标,但至少是“有奖励信号”的部分。
不是奖励均值
要减的是 \(\mathbb{E}_q[s]\),一个和参数同维的向量;不是把 reward 减去 batch 均值。奖励基线解决的是另一个问题。
不是乘性权重
SC 对每个样本做减法,不乘 importance ratio;因此不会出现 ratio 爆炸、截断偏差或 mask 丢样本的问题。
不是万能方差缩减
SC 去掉 drift,但剩余项仍在 \(q\) 下取期望;\(q\neq p\) 时它不是 on-policy 的无偏梯度,也不保证方差一定下降。
这三个判断决定了它的适用边界:如果 mismatch 很轻,drift 很小,SC 的收益也小;如果 mismatch 很重,SC 能让训练不崩,但它不能把采样器变好,所以最终能力上限仍受 \(q\) 的限制;如果 mismatch 主要来自 staleness,单靠 SC 不够,需要和 TIS/MIS 组合。
问题背景:同一个 checkpoint,为什么会有两个分布
很多人第一次听到“生成模型和计算 \(\pi_{old}\) 的模型不同”会觉得奇怪:不就是同一个模型吗?问题在于,“模型”在工程上不是只有权重,还包括计算图、数值精度、kernel、并行方式和采样参数。任意一项改变,下一 token 的概率都会变。
| 来源 | trainer 侧 \(p\) | sampler 侧 \(q\) | 后果 |
|---|---|---|---|
| 量化 | bf16 / fp32 权重与激活 | FP8、INT8、FP4 KV cache | logits 有系统偏差,q 是 p 的低精度近似 |
| 推理/训练引擎 | Megatron、FSDP、JAX | vLLM、SGLang | kernel、融合方式、reduction 顺序不同 |
| 并行方式 | 序列并行、张量并行 | 自回归 decoding、continuous batching | 浮点非结合性导致微小 logit 差异 |
| tokenizer / chat template | 训练侧模板 | 推理侧模板 | 同一段文本可能被切成不同 token |
| 采样参数 | 通常看原始 softmax | temperature、top-p、top-k、repetition penalty | q 是处理后的行为分布,不是原始 p |
| 异步 / staleness | 当前参数 \(\theta_t\) | 若干步之前的 \(\theta_{t-k}\) | q 是旧策略,甚至同一 batch 内混有多个版本 |
这就是为什么“同一个 checkpoint”不等于“同一个分布”。在监督学习里,这种差异通常只表现为一点点数值噪声;在 RL 里,它会被 importance ratio、log-prob 梯度和多步反馈放大。论文的实验之所以要故意放大 mismatch,就是因为温和设置下这点差异在短训练里很难被稳定观测到。
\(\pi_{old}\) 到底是什么
PPO 的 ratio 通常写成:
在很多实现里,\(\pi_{old}\) 是“这一批 rollout 开始时 trainer 侧保存的参数快照”。它是一个名义上的旧策略,用来限制新策略不要一步走太远。问题在于,真正生成数据的并不是这个快照,而是推理引擎里的 \(q\):如果推理引擎做了量化,\(q\) 是量化模型的分布;如果推理引擎滞后,\(q\) 是更旧参数的分布。
于是有三种常见做法,它们对应的数学对象不同:
| 做法 | 分母是什么 | 优点 | 风险 |
|---|---|---|---|
| trainer 重算旧策略 | full-precision 的 \(\pi_{old}\) | 定义干净,PPO 语义稳定 | 和实际 behavior \(q\) 不一致,drift 仍在 |
| 直接用采样器 logprob | 实际 behavior \(q\) | 对 sampled token 的 IS 修正是精确的 | q 可能只有 top-k、可能被量化、可能很旧 |
| 记录 q 并使用 SC/TIS/MIS | q,但额外做校正 | 承认 mismatch,并用统计方法处理 | 需要额外 logprob、存储和工程支持 |
如果你把“旧策略”定义成实际 behavior distribution,那么 \(\pi_{old}=q\),PPO 的 ratio 就是 \(p/q\)。但很多系统里的 \(\pi_{old}\) 是 trainer 侧重算的名义旧策略,而 \(q\) 是推理引擎真正执行的分布;两者只在采样器完全忠实执行 \(\pi_{old}\) 时才相等。
为什么在线 RL 比 SFT 更敏感
论文用一个对比来解释:离线 SFT 即使数据来自完全不同的模型,用 +1/0 奖励做 policy gradient 也往往稳定,因为数据分布是固定的,模型只是在拟合这些数据;而在线 RL 的采样器是当前策略的有偏副本,并且会周期性同步。模型学到的东西会改变下一轮采样,采样误差又回到训练里,形成 feedback loop。
可以把这想象成“老师”和“学生”的关系。离线蒸馏里,老师是固定的,即使老师有偏差,学生也不会把偏差放大;在线 RL 里,老师就是学生的有偏副本,学生越学越像老师,老师的偏差也被一起学进去。drift 正是这个 feedback loop 的数学表达。
机制推导:从 naive PG 到 score centering
记号与 score 的定义
固定一个 prefix \(h\),也就是已经生成的上下文。记:
策略梯度的基本形式是:
在 on-policy 且 \(q=p\) 时,对任意 prefix:
这一步是整个方法的地基:score 在策略自己的分布下均值为零,不是因为奖励均值为零,而是因为概率之和恒为 1。如果 \(q\neq p\),同样的求和就不再是 \(\nabla_\theta 1\),而是一个非零向量。
off-policy 多出来的两项
把 naive 梯度在 \(q\) 下展开:
第一项是“平均 advantage 乘 drift”。如果 \(A\) 是常数,第二项为零,第一项就是全部;如果 \(A\) 随 token 变化,第二项才包含“奖励和 token 选择相关”的信息。SC 只减掉 \(\mathbb{E}_q[s_a]\),因此:
这就是论文的核心恒等式。它说明 SC 去掉的是 drift,留下的是 \(q\) 下的协方差;当 \(p=q\) 时,SC 是 no-op,因为 \(\mathbb{E}_q[s]=0\)。当 \(p\neq q\) 时,剩下的协方差一般不等于 on-policy 的 \(\operatorname{Cov}_p(A,s)\),所以 SC 不是“完全无偏的 off-policy 修正”。
两 token 的最小例子
设词表只有两个 token,trainer 和 sampler 的分布分别是:
在 logit 坐标下,score 是 \(s_v=e_v-p\),所以:
采样分布下的期望 score 是:
| 采样到的 token | naive 更新 \(A s_a\) | SC 更新 \(A(s_a-\mathbb{E}_q[s])\) | 采样概率 |
|---|---|---|---|
| token 1 | \((0.3,\;-0.3)\) | \((0.5,\;-0.5)\) | 0.5 |
| token 2 | \((-0.7,\;0.7)\) | \((-0.5,\;0.5)\) | 0.5 |
| 按 \(q\) 平均 | \((-0.2,\;0.2)\) | \((0,\;0)\) | 1.0 |
这就是“采样到 token 1 时,SC 是 \((0.3,-0.3)-(-0.2,0.2)=(0.5,-0.5)\)”的来源。单条样本的更新不是零,按 \(q\) 平均才是零。naive 的平均是 \((-0.2,0.2)\),正好等于 \(q-p\);SC 把这个漂移减掉了。
但如果 \(A\) 不是常数,SC 的平均就不是零。例如奖励只在 token 1 上为 1,SC 会留下 \(0.5\times(0.5,-0.5)=(0.25,-0.25)\),而 on-policy 的目标是 \(0.7\times(0.3,-0.3)=(0.21,-0.21)\)。两者不相等,因为采样分布是 \(q\) 而不是 \(p\)。这正是“SC 是偏差修正,不是无偏估计”的具体含义。
从 logit 看:\(e_a-q\) 是什么
上面的例子把 logits 当成参数,所以 \(s_v=e_v-p\)。真实模型里 logits 是参数的函数,但在 logit 空间看会更清楚。设 \(z\) 是 logits,\(p=\operatorname{softmax}(z)\),则:
因此 SC 在 logit 空间的更新是:
这句话可以读成:采样到的 token 加 1,所有 token 减 \(q\)。它不是“减一个标量”,而是减一个和词表同维的向量;在真实模型里,这个向量还会通过 Jacobian 映射到参数空间。
| 量 | 含义 | 方向 |
|---|---|---|
| \(q-p\) | 采样分布相对 trainer 的 drift | 从 p 指向 q;naive 更新会往这个方向走 |
| \(p-q\) | drift 的修正量 | 从 q 指回 p;SC 把它加回去 |
| \(e_a-q\) | SC 在 logit 空间的最终方向 | 采样 token 上加 1,所有 token 减 q |
从参数空间看:为什么要乘 \(J^\top\)
\(e_a-q\) 是 logit 空间的梯度,不是参数空间的梯度。设 \(z=f_\theta(h)\),\(J=\partial z/\partial\theta\),则:
所以参数更新是 \(A J^\top(e_a-q)\),而 loss 对参数的梯度是它的相反数 \(-A J^\top(e_a-q)\)。如果 logits 本身就是参数(\(z=\theta\)),那么 \(J=I\),两者数值相同;真实模型里 \(J\neq I\),必须区分“logit 梯度”和“参数梯度”。
loss 是怎么反推出来的
我们想要优化器产生更新 \(A(s_a-\sum_v q_v s_v)\)。优化器做的是 \(\theta\leftarrow\theta-\eta\nabla_\theta L\),所以需要:
利用 \(\nabla_\theta \log p_a=s_a\) 和 \(\nabla_\theta \sum_v q_v\log p_v=\sum_v q_v s_v\)(把 \(q\) 冻结),可以得到:
其中 \(\operatorname{sg}(\cdot)\) 是 stop-gradient。这个 loss 的数值没有直接的物理意义,它只是一个“梯度生成器”;真正要学的是它的梯度。实现时 \(q\)、\(\rho\)、\(A\) 都必须 detach,否则会对它们求导,得到完全不同的更新。
top-k 词表上的实现
真实词表有 15 万到 20 万 token,保存完整 \(q\) 很贵。论文只记录 sampler 的 top-k logprobs,默认 \(k=128\)。记 head 集合为 \(H\),head 质量为:
tail 的概率用 trainer 分布按 sampler 的 tail 质量重标:
于是期望 score 可以写成 head 上的求和:
对应的 loss 是:
这里有几个实现细节,错一个就会把方法做坏:
- head 不重新归一化。\(q_v\) 和 \(p_v\) 都用原始概率;如果把 head 归一化,tail 质量就被伪装成 full support,\(\rho\) 也失去意义。
- 采样 token 的 logprob 必须保留。即使它不在 top-k 里,第一项 \(\log p_a\) 仍然需要;IS 组合还需要 \(q_a\)。
- tail 只用 \(\rho p_v\) 近似。\(k=128\) 时 head 覆盖大多数 sampler mass;\(k=V-1\) 时 tail 只剩一个 token,近似是精确的。
- 系数全部 stop-gradient。q、\(\rho\)、A 是统计量,不是要优化的参数。
为什么 group-centered reward 不能替代 SC
GRPO 之类的 group-centered reward 会让同一个 prompt 下所有轨迹的 advantage 之和为零。这消掉的是“prompt 级别”的均值,不是“prefix 级别”的均值。SC 需要的是对每个 prefix \(h\) 都有 \(\mathbb{E}_q[A\mid h]=0\);group centering 通常做不到这一点。
论文特别指出,drift 恰恰在有学习信号的 prefix 上最强:如果某个 prefix 下所有采样都得到同样的奖励,group centering 会把 advantage 变成零,这个 prefix 反而不贡献梯度;而在那些奖励有差异的 prefix 上,\(\mathbb{E}_q[A\mid h]\) 通常非零,drift 仍然存在。因此“组内减均值”不是 SC 的替代品。
和 value baseline 的关系
如果有一个精确的 \(V_q(h)\),用 \(A=V_q(h)-R\) 之类的 baseline 也能在期望上消掉 drift,因为减去的正是 \(\mathbb{E}_q[A\mid h]\cdot\mathbb{E}_q[s]\)。但 value baseline 需要 critic,critic 本身也有误差;SC 不需要 critic,它直接用采样分布 \(q\) 算期望 score。两者不是互斥的:SC 是“用已知的 q 做无 critic 的 drift 修正”,value baseline 是“用学到的 V 做方差缩减和 drift 修正”。
TIS、MIS、PPO:它们各自在修什么
要理解 SC 的位置,最好把它和 importance sampling 放在一张桌子上。它们都在处理 \(q\neq p\),但处理的对象不同:IS 改的是“每个样本的权重”,SC 改的是“每个样本的 score 减去什么”。
Importance sampling 的基本恒等式
对于从 \(q\) 采样的 token \(a\),如果 \(q_a\gt 0\),有:
令 \(r_a=p_a/q_a\),IS 更新就是 \(r_a A s_a\)。在没有截断、full support 的情况下,它是无偏的;问题是方差。稀有 token 的 \(r_a\) 可能非常大,一个样本就能主导整个 batch。
TIS:把 ratio 砍到上限
Truncated importance sampling 用:
论文的实现里 \(C=2\)。它把高 ratio 压到 2,方差降下来了,但高 ratio 样本的贡献被低估,因而引入偏差。TIS 在温和 mismatch 下通常够用;在严重 mismatch 下,大量样本的 ratio 会超过上限,截断偏差变成主要问题。
用前面的两 token 例子:\(r_1=0.7/0.5=1.4\),\(r_2=0.3/0.5=0.6\)。如果 \(C=2\),两个都没被截断,期望为零;如果 \(C=1\),token 1 的权重被压到 1,按 \(q\) 平均会留下 \((-0.06,0.06)\) 的残差。这就是“截断重新引入 drift”的最小演示。
MIS:区间外直接丢掉
Masked importance sampling 用:
论文的实现里区间是 \([0.5,5]\)。它比 TIS 更激进:区间外的样本不是被压权重,而是完全不贡献梯度。好处是极端 ratio 不会污染更新;坏处是可能丢掉大量样本,尤其在严重 mismatch 下,留下的是被截断的、非随机的子集,偏差可能更大。
还是两 token 例子:区间 \([0.5,1.5]\) 会保留两个 token;区间 \([0.8,1.2]\) 会把两个都丢掉,更新为零。零更新不是“无偏”,只是“没有学习信号”。这也解释了为什么 MIS 在严重 mismatch 下可能后期崩溃:它不是修好了分布,而是把大部分数据扔掉了。
PPO 的 ratio 在修什么
PPO 的目标通常写成:
这个 ratio 的目的是限制“新策略相对旧策略走多远”,它是一个 trust region 机制。它并不是为“trainer 和 sampler 数值不一致”设计的。若 \(\pi_{old}=q\),PPO ratio 和 IS ratio 是同一个东西;若 \(\pi_{old}\) 是 trainer 重算的名义旧策略,而数据来自量化后的 \(q\),那么 clip 只能约束 \(p/\pi_{old}\),约束不了 \(p/q\) 的漂移。
DPPO 用 total variation 做二值 mask,试图把“变化太大”的 token 去掉;但它仍然依赖 IS ratio,仍然假设分母是 behavior distribution。它能在 staleness 下工作,不代表它能处理量化误差。
SC 和 IS 的组合:先加权,再中心化
SC 可以和 TIS/MIS 组合。给定权重 \(w_v\),正确的更新是:
注意顺序:先对 score 加权,再减加权后的期望。如果反过来,先减期望再加权,减掉的不是 \(w\) 下的均值,会留下残差。用 full-vocab 的 loss 写就是:
top-k 版本里,tail 的权重是常数 \(w(1/\rho)\),因为 tail 上 \(r_v=p_v/q_v=1/\rho\)。令:
则 head 的系数是 \(q_v w_v-\alpha p_v\),loss 为:
这解释了论文里的一个细节:SC 和 IS 不是二选一。SC 去掉剩余 drift,IS 把采样分布往 trainer 拉近;在 staleness 场景下,两者组合通常比单独 SC 更好。
为什么不能直接用生成器的 logprob 当 \(\pi_{old}\)
生成器当然可以在生成时算 sampled token 的 logprob,但那是 \(q_a\),不是 trainer 的 \(\pi_{old,a}\)。如果你把 \(q\) 当 \(\pi_{old}\),你做的其实是 behavior IS:ratio 变成 \(p/q\),这在数学上是合法的,但它不再是“trainer 名义旧策略”的 PPO。两者的区别不是符号游戏,而是分母代表的对象不同。
工程上还有三个现实约束:第一,推理引擎未必暴露完整 logprob,通常只有 top-k 或不给;第二,top-k 的排序、序列化和传输有成本,尤其在高并发下;第三,q 可能是量化后的、滞后的,直接拿它做分母会把数值误差带进 ratio。论文的选择是:记录 q 的 top-k,用 SC/TIS/MIS 显式处理 mismatch,而不是假装 q 就是 \(\pi_{old}\)。
| 方法 | 对样本做什么 | 用到的信息 | 超参数 | 主要问题 |
|---|---|---|---|---|
| naive PG | 直接用 \(A s_a\) | p、a、A | 无 | q 下的 drift 会累积 |
| SC | 减 \(\mathbb{E}_q[s]\) | p、q 的 top-k | k | 剩余协方差仍在 q 下,不是无偏 |
| TIS | 乘 \(\min(r,C)\) | p、q、a | C | 截断偏差;ratio 方差 |
| MIS | 区间内乘 r,区间外置零 | p、q、a | \(\ell,u\) | 丢数据;严重 mismatch 下信号稀疏 |
| PPO | clip \(p/\pi_{old}\) | p、\(\pi_{old}\)、a | \(\epsilon\) | 不直接修 trainer/sampler 的数值差 |
| SC + TIS/MIS | 先加权,再减加权均值 | p、q、a、w | k、C 或区间 | 实现复杂;需要 q 的覆盖 |
实验证据:数字说明了什么,又没说明什么
论文的实验设计有一个明确取舍:它不比较完整的 PPO/GRPO 配方,而是固定一个简单的 REINFORCE 骨架,把不同的校正规则单独加上去。这样做的好处是能隔离变量,坏处是结论不能直接外推到所有 RL 系统。
设置
- 模型:Qwen3-0.6B-Instruct 做 Countdown;Qwen3-30B-A3B-Base 做 INTELLECT-2 数学;另有 1.7B 的 toy reward 任务。
- 算法:REINFORCE 加 group-centered rewards,每个 batch 一个 SGD step;所有 importance ratio 用 sampler 记录的 logprob。
- mismatch 来源:合成 Gaussian 权重噪声、只量化 sampler 的 FP8/INT8/FP4 KV、以及推理引擎每 64 步才同步一次的 staleness。
- 作者刻意放大 mismatch,因为温和设置下短训练很难把方法差异跑显著;严重设置被当作长训练的代理。
30B 的主要数字
| 设置 | naive PG | TIS | MIS | SC | 读法 |
|---|---|---|---|---|---|
| FP8 温和 | 约 58% | 接近 naive | 接近 naive | 接近 naive | mismatch 轻,普通 PG 就够 |
| FP8 W/A + FP4 KV | 200 步内崩 | 51% | 后期崩 | 52% | SC/TIS 能稳住,SC 略高 |
| INT8 W/A + INT4 KV | 低于 5% | 12% | 低于 5% | 30% | 严重 mismatch 下只有 SC 类方法有明显信号 |
这些数字最容易被误读的地方是“52% 对 58%”或“30% 对 58%”。它们不是同一个面板里的对照:FP8 温和面板的 58% 是 naive 的稳定值,FP4/INT4 面板则是更严重的失配设置;不同面板的绝对准确率不能直接横比。论文想说明的是同一面板内,哪种方法能稳住训练,而不是“SC 普遍比 naive 高 18 个百分点”。
合成噪声与 staleness
在合成 Gaussian 权重噪声下,SC、TIS、MIS 及其组合普遍优于 naive;噪声最大时,只有 SC 和 SC+TIS/MIS 稳定。DPPO 在三个噪声档大约第 160、80、20 步崩溃,TIS 在小噪声下稳定、大噪声下约第 180 或 40 步崩溃。这里的“崩溃步数”是论文图上的近似读数,不是精确的算法常数。
staleness 的结果方向相反:SC 单独使用不如 SC+TIS/MIS。作者的解释是,SC 的剩余协方差是在 \(q\) 下算的;TIS/MIS 先把 \(q\) 往 \(p\) 拉近,SC 再消掉剩余 drift。PPO/DAPO 能扛住 staleness,但在量化和权重噪声下崩溃,因为它们的 clip 不是为数值误差设计的。
top-k 的质量与成本
| 项目 | 报告值 | 含义 |
|---|---|---|
| 默认 k | 128 | head 覆盖大多数 sampler mass |
| k=32/128 | 在所测设置与 full SC 相当 | 不是所有任务都保证,但至少这些实验够用 |
| k=V−1 | tail 只剩一个 token,近似精确 | 单元测试常用的 toy 情形 |
| head 平均质量 | 除最重 30B 外均高于 99.9% | INT8+INT4 为 99.45%,最差 batch 95.8% |
| full logprob 成本 | 152K 词表、fp32 约 608KB/token;1024×32K 约 20TB | 不现实,所以必须 top-k |
| wall-clock | 匹配硬件上相对 baseline 低于 1% | 作者的自定义 JAX sampler;vLLM/SGLang 开销未测 |
top-k 的边界要说清楚:head 覆盖 99.9% 不等于 tail 的 shape 一定对。论文用的是“tail 按 trainer 分布重标”的近似;如果任务 entropy 很高、tail 很重,或者 top-k 之外的概率不可忽略,这个近似会有残差。官方单元测试只覆盖了 \(k=V-1\) 的 toy 情形,不能证明大词表 tail 一定无误。
种子与证据强度
30B 的种子并不均衡:FP8 面板全是单 seed;FP4 KV 面板是 SC 5、TIS 4、MIS 3、vanilla IS 2;INT4 KV 面板是 SC 4、TIS 3、MIS 3、vanilla IS 1;0.6B/1.7B 每个方法 3 seeds。作者先跑单 seed,再给最有希望的方法补种子。这在小模型上问题不大,但在 30B 上意味着“绝对准确率”的置信区间并不对称。
此外,序列长度是 512/1024,训练步数有限;没有 replay MoE router indices(作者说实践中最好 replay);headline 是训练准确率,不是独立 held-out benchmark。所有这些都限制了“SC 在真实长训练里一定更好”的外推。
它最强的是“机制 + 严重 mismatch 下的稳定性”:在同一个面板里,naive 崩了而 SC 没崩,这个对比很难用随机波动解释。它较弱的是“普遍性能提升”:不同面板、不同种子、短序列、训练准确率,都不足以支持“SC 在所有 RL 任务上都能涨点”的说法。
工程实现:怎么把它接进现有 RL 栈
SC 的数学很简单,工程上却有几个容易踩的坑。下面按“数据要什么、框架怎么接、上线前怎么验”三层说。
数据层:你需要保存什么
- 采样 token 的 \(q_a\)。即使它不在 top-k 里,IS 组合也需要;SC 单独用时间接需要 \(\rho\) 和 head 质量。
- sampler top-k 的 ids 与 logprobs。默认 \(k=128\);不要只存概率,存 logprob 更稳。
- trainer 侧对应 head 的 logprobs。用原始值,不要重新归一化;需要和 sampler 的 tokenizer、模板对齐。
- 采样参数。temperature、top-p、top-k 会改变 \(q\);如果训练侧用原始 softmax,必须知道这个差异。
框架层:不同栈的接入条件
| 框架 | 默认 | 关键条件 | 备注 |
|---|---|---|---|
| verl | 关闭 | 需 bypass mode、REINFORCE loss、rollout IS 为 None 或 token、不做 batch normalize、topk_log_probs 大于 0、FSDP actor | 不兼容 fused kernels、distillation;只支持 single-turn agent loop |
| TRL AsyncGRPO | 实验性,默认开启 | 记录 sampler top logprobs,按 IS clip 区间 mask | top logprobs 的序列化成本可能很高;vLLM 新版多 API server 可缓解 |
| NeMo-RL | 实验性,默认关闭 | loss_fn.score_centering、top_logprobs、SingleController + Gym + vLLM + token capture | filters 需要 sampler replay 的 shared support;不是所有 PPO 路径都精确等价 |
| Tinker | stable_reinforce 的 alpha | 需要 record_stability_info 和 sequence provenance | 公开文档没有给出 SC 的逐项等式,不能当作独立复现 |
这里最值得记住的不是“哪个框架支持”,而是“支持”往往有条件。verl 的 score centering 需要特定的 bypass 路径;TRL 默认开启但把成本转移到了 logprob 序列化;NeMo-RL 仍是 experimental;Tinker 的 stable_reinforce 是产品接口,不是论文公式的逐项实现。上线前要读自己版本的文档,不要只看 README 的“支持”二字。
成本层:full logprob 为什么不可行
Qwen3 的词表约 152K。一个 token 的 fp32 全词表 logprob 约 608KB;如果 batch 1024、序列 32K,单是 logprob 就约 20TB。这就是论文只存 top-k 的原因。top-k 把存储降到 \(k\) 个数,但带来两个成本:排序/选择本身的算力,以及从推理引擎到训练侧的传输。
论文在自定义 JAX sampler 上报告相对 baseline 低于 1% 的 wall-clock;这不等于 vLLM/SGLang 的实际开销。TRL 文档报告过:默认单 API server、top-8 时生成吞吐可能减半;vLLM 0.32 以上、8 个 API server 可以降到 3% 以下;v0.31 仍有 20% 到 40% 的损失。部署时要按自己的引擎版本和并发量实测。
验证层:上线前的五个检查
- 常数奖励测试。固定所有样本奖励相同,naive 应该出现非零更新,SC 的期望应该接近零;如果 SC 也更新,说明 q 或 stop-gradient 有问题。
- q 的覆盖率。记录 head mass \(q_H\) 和 tail 比例;如果 \(q_H\) 很低,top-k 近似不可信。
- \(\rho\) 的数值稳定性。当 \(p_H\) 接近 1 时,\(\rho\) 的分母会很小;需要 clamp 或回退到 full/更小的 k。
- 采样 token 是否在 head 内。两种路径都要测;不要假设它一定在 top-k 里。
- 组合顺序。先 weight 再 center;用有限差分或玩具分布验证梯度方向,不要只看 loss 曲线。
术语表
边界与风险:它不保证什么
它不是无偏的 off-policy 梯度
SC 去掉 drift 后,剩下的是 \(\operatorname{Cov}_q(A,s)\),而不是 on-policy 的 \(\operatorname{Cov}_p(A,s)\)。如果 \(q\) 和 \(p\) 差得很远,这个协方差本身也可能有偏。SC 让训练“不漂”,不等于让训练“朝着正确的目标走”。
它不是通用的方差缩减
论文明确说 SC 是 bias correction,不是 variance reduction。减掉一个随机向量的均值,有时会降低方差,有时会增加方差;没有普遍保证。把它当成“免费降方差”会失望。
top-k 是近似,不是精确
tail 用 \(\rho p_v\) 重标,假设 tail 的形状和 trainer 一致。如果采样器 tail 很重、任务 entropy 很高,或者 top-k 覆盖不足,这个假设会失效。单元测试只覆盖 \(k=V-1\) 的 toy 情形,不能替代真实词表上的验证。
实验外推有限
headline 是训练准确率,不是 held-out benchmark;30B 种子不均衡;序列长度 512/1024;没有 MoE router replay;严重 mismatch 是长训练的代理,不是真实长训练本身。作者自己承认温和 mismatch 下短训练差异小,所以不能把“SC 在严重设置下稳定”外推成“SC 在所有任务上涨点”。
工程约束
需要 sampler 的 top-k logprobs、需要 trainer 侧对齐的 head logprobs、需要处理 tokenizer/模板/采样参数差异;推理引擎可能不暴露 logprob,或者暴露成本很高;框架支持往往是 experimental,且有 bypass、FSDP、single-turn 等限制。SC 不是一个“加一行 loss 就能用”的方法。
理论边界
SC 的推导是 prefix 条件的;group-centered reward 只保证 prompt 级别的均值为零,不保证 prefix 条件均值为零。精确的 value baseline 也能消 drift,但需要 critic。IS 组合在 full support 下更干净,但实际系统往往只有 top-k,support 不完整。所有这些都意味着:SC 是一个有明确适用条件的工具,不是 RL 的通用解药。
SC 能让“没有奖励也会走”的漂移消失,但它不能把采样器变成 trainer,也不能保证剩下的协方差就是你要的 on-policy 目标。它是稳定器,不是修正一切的万能公式。
研究启发:把“分布记账”当成一等公民
这篇论文最有价值的地方,可能不是那个减法本身,而是它逼着我们把 RL 系统里的三个分布分开:
- \(p\):trainer 当前策略,决定梯度;
- \(q\):sampler 实际行为,决定数据从哪来;
- \(\pi_{old}\):PPO 名义旧策略,决定 trust region 的分母。
很多 RL 的“玄学不稳定”,追根溯源是这三个对象被混用了:数据来自 q,梯度按 p 算,ratio 却除以 π_old。把这三个对象显式记录、对齐、监控,比换一个更复杂的 loss 更有用。
如果你在做训练系统
- 先测量,不要假设。记录 sampled token 的 \(\log p_a-\log q_a\)、top-k head mass、以及不同 checkpoint 之间的 logprob 差。
- 把 q 的来源写清楚:是量化模型、旧 checkpoint,还是带 temperature/top-p 的采样分布。不要用一个模糊的“old policy”覆盖三种东西。
- 在玩具分布上做常数奖励测试。naive 应该漂,SC 应该不漂;如果不符合,先修实现,不要调超参。
- SC 和 TIS/MIS 不是互斥的。量化严重时先看 SC;staleness 严重时看组合;用同一面板、同等算力比较。
- 不要用 PPO clip 掩盖数值 mismatch。Clip 约束的是策略移动,不是 trainer/sampler 的精度差。
如果你在做研究
- 报告 held-out 指标、多 seed、等算力比较;训练准确率不能替代泛化。
- 把 top-k 的 tail 误差单独审计:高 entropy 任务、长尾词表、不同 k 的敏感性。
- 研究 prefix 条件的 baseline 和 SC 的组合;group centering 不是 prefix centering。
- 在 MoE 模型上 replay router indices,否则 expert routing 的 mismatch 会混进结论。
- 区分“稳定性”和“最终能力”:SC 能让曲线不崩,但不一定让上限更高。
三个常见误解
| 误解 | 纠正 |
|---|---|
| SC 就是减去 reward 的均值 | 不是。减的是 \(\mathbb{E}_q[s]\),一个和参数同维的向量;reward baseline 是另一件事。 |
| SC 就是 importance sampling | 不是。SC 是加性校正,不乘 ratio;IS 是乘性重加权,方差和截断偏差是它的问题。 |
| \(e_a-q\) 就是参数更新 | 不是。它是 logit 空间的梯度;参数更新还要乘 \(J^\top\),即 \(A J^\top(e_a-q)\)。 |
| SC 是无偏的 on-policy 梯度 | 不是。它只去掉 drift,剩下的是 q 下的协方差,不是 p 下的协方差。 |
| group centering 等于 prefix centering | 不是。组内均值零不代表每个 prefix 的条件均值零,drift 仍可能存在。 |
最后回到一个更一般的教训:RL 的很多问题不是“优化器不够强”,而是“我们以为自己在优化 p,实际上数据来自 q,分母却是 \(\pi_{old}\)”。Score centering 用一个很小的加法,把这个记账错误的一部分显式化了。它的价值不在于复杂,而在于它把问题说清楚了。
证据边界与资料索引
本文以论文 v1 的正文与附录为主,结合官方代码、框架文档和两篇独立分析。论文数字均为作者报告;本文没有运行 30B 训练,也没有独立复现论文的 JAX 实验。官方单元测试只覆盖小词表、\(k=V-1\) 的 toy 情形,不能证明真实大词表 tail 的精确性。
实验部分的“训练准确率”不是 held-out benchmark;30B 种子数量不均衡;序列长度为 512/1024;没有 replay MoE router indices;严重 mismatch 是作者故意放大的设置,用来代理长训练。框架接入条件来自 2026 年 11 月的公开文档,具体版本可能变化;TRL 的吞吐数字是文档报告,不是本文实测。
- Score Centering Stabilizes Off-policy Reinforcement Learning(arXiv 摘要)
- 论文 HTML 全文与附录
- 官方参考实现(JAX,含 full/top-k 与 IS 组合)
- verl:rollout correction 与 score centering 配置
- TRL:AsyncGRPO 与 score centering
- NeMo-RL:score centering 指南
- Tinker:stable_reinforce 文档
- Fei Tian:What score function centering fixes
- Logit gradient 视角的独立分析
- Bellman Policy Optimization(相关但不同的出发点)
未确认事项:SC 在更长训练、更多 seed、held-out 任务上的增益;top-k 在超高 entropy 词表上的 tail 误差;不同推理引擎暴露 top-k logprobs 的真实吞吐成本;MoE router replay 与 SC 的交互。这些问题不改变论文的机制结论,但会影响工程选型。