我觉得网上关于 score function centering 的解释或多或少都有些绕,不够直接。我希望写这篇文章给大家提供一种从 intuition 讲起,对 score function centering 最直接的解释。这篇文章是我纯手搓,不是 AI 写的,当然如果你读的是英文版,很抱歉,它是 AI 翻译的。
这篇文章需要你知道 PPO 或者 GRPO 的使用方法(loss 长什么样)和一些简单的概率论知识(就够了)。如果你还没读过,请你花十分钟读一下这一篇文章 。
如果你满足以下任意一条,这篇文章应该是适合你的:
只会用 GRPO,但是不知道其内在原理
对 trainer-generator mismatch 想要进一步加深理解
做 async RL 并且 long rollout 训练但是还不确定该如何提升算法稳定性
不知道 score function centering 是个啥(甚至不知道这里的 score 是个啥)但是想了解的
Score Function Centering 并不是一个专有名词,我知道各家 frontier lab 对于这个技术有自己不同的叫法,alternative token、covariance optimization 等等,你想叫什么都行,这篇文章也会解释这些所谓的名字是怎么来的。
太长不看版:
读完第一章你会知道 score function 是计算 policy gradient 的一个重要桥梁,以及我们能从 auto-differentiation 中得到的最直接的产物。
读完第二章,你会知道 score function 的重要性质:它本身是中心化过了的,所以它的期望是 0,我们需要这个期望一直是 0,才能在 policy gradient 中用所谓的 advantage 来代替 reward,以及 trainer-generator mismatch 如何破坏了这个性质。你还会知道这个性质被破坏以后的实际后果:平均 advantage 会额外产生一个把当前 trainer 往旧 generator 拉的 gradient,所以我们需要修复它。
读完第三章,你会知道 score function centering 本质是在干什么,它为什么修复了这个 0 期望属性;以及实际在工程上我们应该如何使用它,以及在这个领域灌水的一个方向。
1. 我们从 score function 讲起,score 是啥?为啥要用它?
1.1 GRPO/PPO 里我们到底在求什么梯度?
下面我们对 policy gradient 做一个快速推导,如果你对这一部分相当熟悉,请跳过这一小节。
假设在某个 state,也就是 LLM 某个 prefix x x x 上,policy 是:
p θ ( a ∣ x ) p_\theta(a|x) p θ ( a ∣ x ) (1)
为了简单,下面暂时把 x x x 省略,写成:
p θ ( a ) . p_\theta(a). p θ ( a ) . (2)
我们的目标非常自然:
“让高 reward 的 action 更容易被模型采到。”
因此可以写一个最简单的目标:
J ( θ ) = E a ∼ p θ [ R ( a ) ] . J(\theta) = \mathbb E_{a\sim p_\theta}[R(a)]. J ( θ ) = E a ∼ p θ [ R ( a )] . (3)
这句话的意思就是:“从当前模型 p θ p_\theta p θ 里 sample action,计算 reward,希望它的期望越来越高。”
问题是:∇ θ E a ∼ p θ [ R ( a ) ] \nabla_\theta \mathbb E_{a\sim p_\theta}[R(a)] ∇ θ E a ∼ p θ [ R ( a )] 怎么求?这里有一个麻烦:θ \theta θ 并不直接出现在 R ( a ) R(a) R ( a ) 里面。它藏在 a ∼ p θ a\sim p_\theta a ∼ p θ 这个 sampling distribution 里面。也就是说,我们不是在求 ∇ θ R ( a ) \nabla_\theta R(a) ∇ θ R ( a ) 。事实上,RL 里的 reward 完全可以不可导。比如:数学题答对给 1 分否则给 0 分,或者某个人类专家直接给打分。这都没关系。真正依赖 θ \theta θ 的,是 p θ ( a ) p_\theta(a) p θ ( a ) 。
把 expectation 写开:
J ( θ ) = ∑ a p θ ( a ) R ( a ) . J(\theta) = \sum_a p_\theta(a)R(a). J ( θ ) = a ∑ p θ ( a ) R ( a ) . (4)
求导:
∇ θ J ( θ ) = ∑ a R ( a ) ∇ θ p θ ( a ) . \nabla_\theta J(\theta) = \sum_a R(a)\nabla_\theta p_\theta(a). ∇ θ J ( θ ) = a ∑ R ( a ) ∇ θ p θ ( a ) . (5)
然后用一个非常简单但极其重要的恒等式:
∇ θ p θ ( a ) = p θ ( a ) ∇ θ log p θ ( a ) . \nabla_\theta p_\theta(a) = p_\theta(a) \nabla_\theta\log p_\theta(a). ∇ θ p θ ( a ) = p θ ( a ) ∇ θ log p θ ( a ) . (6)
因为:
∇ log p = 1 p ∇ p . \nabla \log p = \frac{1}{p}\nabla p. ∇ log p = p 1 ∇ p . (7)
于是:
∇ θ J ( θ ) = ∑ a p θ ( a ) R ( a ) ∇ θ log p θ ( a ) . \nabla_\theta J(\theta) = \sum_a p_\theta(a) R(a) \nabla_\theta\log p_\theta(a). ∇ θ J ( θ ) = a ∑ p θ ( a ) R ( a ) ∇ θ log p θ ( a ) . (8)
重新写成 expectation:
∇ θ J ( θ ) = E a ∼ p θ [ R ( a ) ∇ θ log p θ ( a ) ] . \nabla_\theta J(\theta) = \mathbb E_{a\sim p_\theta} \left[ R(a) \nabla_\theta\log p_\theta(a) \right]. ∇ θ J ( θ ) = E a ∼ p θ [ R ( a ) ∇ θ log p θ ( a ) ] . (9)
这里终于出现了 policy gradient 中最关键的东西:
s θ ( a ) = ∇ θ log p θ ( a ) . s_\theta(a) = \nabla_\theta\log p_\theta(a). s θ ( a ) = ∇ θ log p θ ( a ) . (10)
这个东西叫做 score function 。注意这里的 score 不是 reward score。不是“这个回答得了多少分”。它是概率统计中的一个专门术语:
score = ∇ θ log p θ ( a ) . \text{score} = \nabla_\theta\log p_\theta(a). score = ∇ θ log p θ ( a ) . (11)
也就是 某个被 sample 出来的 action 的 log probability,对模型参数的梯度。
1.2 为什么我们要研究 score?
因为 policy gradient 最核心的结构其实就是:
reward × \times × score
(我知道你想说我们实际用的都是 Advantage × score \text{Advantage}\times\text{score} Advantage × score ,但你先别急)。
如果换成我们训练 LLM 时更熟悉的写法:
g = R ( a ) ∇ θ log p θ ( a ) . g=R(a)\nabla_\theta\log p_\theta(a). g = R ( a ) ∇ θ log p θ ( a ) . (12)
所以可以把两部分理解成:R ( a ) R(a) R ( a ) 告诉我们 “这个 action 应该被强化还是削弱?强化多少?” 而 ∇ θ log p θ ( a ) \nabla_\theta\log p_\theta(a) ∇ θ log p θ ( a ) 告诉我们:“如果我要提高或者降低这个 action 的 probability,参数应该朝哪个方向走?”
这也是为什么我认为理解 policy gradient 最重要的一句话是:
Score function 是把(你怎么也算不出来的)“概率分布期望的梯度”转化成“可以通过采样计算的梯度估计”的桥梁。
更准确一点:
distribution-level differentiation → \rightarrow → sample-level gradient estimation
我们原来想算:
∇ θ E a ∼ p θ [ R ( a ) ] . \nabla_\theta \mathbb E_{a\sim p_\theta}[R(a)]. ∇ θ E a ∼ p θ [ R ( a )] . (13)
它看起来需要对整个 action distribution 求导。
但 score-function trick 把它变成:先 sample 一个 action
a ∼ p θ , a\sim p_\theta, a ∼ p θ , (14)
然后算:
R ( a ) ∇ θ log p θ ( a ) . R(a)\nabla_\theta\log p_\theta(a). R ( a ) ∇ θ log p θ ( a ) . (15)
多 sample 几次平均:
∇ θ J ≈ 1 N ∑ i = 1 N R ( a i ) ∇ θ log p θ ( a i ) . \nabla_\theta J\approx\frac1N\sum_{i=1}^NR(a_i)\nabla_\theta\log p_\theta(a_i). ∇ θ J ≈ N 1 i = 1 ∑ N R ( a i ) ∇ θ log p θ ( a i ) . (16)
这就是 REINFORCE / policy gradient 最核心的计算机制。而 GRPO 虽然加入了 group-relative advantage、importance ratio、clipping 等机制,它里面真正产生 policy gradient 的基本对象,仍然绕不开:
∇ θ log p θ ( a ) . \nabla_\theta\log p_\theta(a). ∇ θ log p θ ( a ) . (17)
同时,你会发现这个东西是你在真正使用 GRPO 的时候,一次 backward 给你的最直接的东西。
2. score function 与 trainer-generator mismatch
2.1 score function 有什么美好的性质?这个性质为什么重要?
我们现在来讨论讨论 advantage。我们都知道,在 GRPO/PPO 里,我们不会直接使用 reward,我们使用的是 advantage(为什么? )。advantage 就是 reward 减去一个常数:
A ( a ) = R ( a ) − b , A(a)=R(a)-b, A ( a ) = R ( a ) − b , (18)
这里的 b b b 可以是 value function,可以是一个 group mean,也可以是任何只和当前 state 有关、但是和具体 action 无关的 baseline。比如在 GRPO 里面,我们最熟悉的事情就是:同一个 prompt 采样很多条 response,然后用某种 group-relative 的 reward 作为 advantage。先不管具体 normalization 怎么做,本质上都是在做一件事情:从 raw reward 里减掉一个“大家共同拥有的部分”,只留下这个 action 相对平均水平好还是差。但是这里有一个非常基础、也非常容易被忽略的问题:
我们凭什么能随便减这个 baseline?
原来的 policy gradient 是:
g = E a ∼ p θ [ R ( a ) s θ ( a ) ] . g=\mathbb E_{a\sim p_\theta}[R(a)s_\theta(a)]. g = E a ∼ p θ [ R ( a ) s θ ( a )] . (19)
如果我们把 reward 换成 advantage:
A ( a ) = R ( a ) − b , A(a)=R(a)-b, A ( a ) = R ( a ) − b , (20)
那么新的 gradient 就是:
g ′ = E a ∼ p θ [ ( R ( a ) − b ) s θ ( a ) ] . g'=\mathbb E_{a\sim p_\theta}[(R(a)-b)s_\theta(a)]. g ′ = E a ∼ p θ [( R ( a ) − b ) s θ ( a )] . (21)
把它展开:
E a ∼ p θ [ R ( a ) s θ ( a ) ] − b E a ∼ p θ [ s θ ( a ) ] . \mathbb E_{a\sim p_\theta}[R(a)s_\theta(a)] -b\mathbb E_{a\sim p_\theta}[s_\theta(a)]. E a ∼ p θ [ R ( a ) s θ ( a )] − b E a ∼ p θ [ s θ ( a )] . (22)
第一项就是我们原来的 policy gradient。也就是说,如果我们希望减掉 baseline 以后,policy gradient 的期望完全不变,那么第二项必须消失:
b E a ∼ p θ [ s θ ( a ) ] = 0. b\mathbb E_{a\sim p_\theta}[s_\theta(a)] = 0. b E a ∼ p θ [ s θ ( a )] = 0. (23)
而 b b b 显然不一定等于 0,所以我们真正需要的是:
E a ∼ p θ [ s θ ( a ) ] = 0. \mathbb E_{a\sim p_\theta}[s_\theta(a)] = 0. E a ∼ p θ [ s θ ( a )] = 0. (24)
这就是 score function 在 policy gradient 里面一个非常重要的性质。你可以先完全不管这个性质为什么成立,只需要记住它的现实意义:
只要 score 的 expectation 是 0,我们就可以给 reward 减一个和 action 无关的 baseline,而不改变 expected policy gradient。
这就是为什么我们可以把 reward 写成 advantage,也是为什么 PPO / GRPO 里面各种 reward centering、value baseline、group-relative baseline 能够成立。有些文章 会从 covariance 开始解释这件事情,比如写:
E a ∼ p θ [ R ( a ) s θ ( a ) ] = Cov ( R ( a ) , s ( a ) ) + E [ R ( a ) ] E [ s ( a ) ] , \mathbb E_{a\sim p_\theta}[R(a)s_\theta(a)] = \operatorname{Cov}(R(a),s(a)) + \mathbb E[R(a)]\mathbb E[s(a)], E a ∼ p θ [ R ( a ) s θ ( a )] = Cov ( R ( a ) , s ( a )) + E [ R ( a )] E [ s ( a )] , (25)
然后因为 E [ s ] = 0 \mathbb E[s]=0 E [ s ] = 0 ,所以最后只剩 covariance。这个写法当然没有问题,但是我个人觉得它反而把一件很简单的事情写绕了。我们真正关心的其实就是一句话:我想把 reward 减掉一个 baseline,但是我又不想让这个 baseline 本身产生 gradient。那自然就要求 E [ s ] = 0 \mathbb E[s]=0 E [ s ] = 0 。就这么简单。
而且这个性质其实非常符合 intuition。假设两个 action 的 reward 是:
R ( A ) = 101 , R ( B ) = 99. R(A)=101,\qquad R(B)=99. R ( A ) = 101 , R ( B ) = 99. (26)
和:
R ′ ( A ) = 2 , R ′ ( B ) = 0. R'(A)=2,\qquad R'(B)=0. R ′ ( A ) = 2 , R ′ ( B ) = 0. (27)
从 policy optimization 的角度,这两组 reward 表达的是完全一样的信息:A A A 都比 B B B 好 2 分。我们显然不希望仅仅因为给所有 reward 同时加了 99,模型的 expected update direction 就发生变化。所有 reward 同时加减一个常数,都不会改变 expected policy gradient。这也是为什么 baseline 本质上是一个非常自然的操作,而不只是一个数学 trick。
好了,现在问题来了:
为什么 score 的 expectation 恰好会等于 0?
为了回答这个问题,我们终于需要看看 score 的庐山真面目到底是什么。
2.2 Score Function 到底是什么?
接下来,我们对 score function 做一些上过微积分就会做的推导,我们前面定义:
s θ ( a ) = ∇ θ log p θ ( a ) . s_\theta(a)=\nabla_\theta\log p_\theta(a). s θ ( a ) = ∇ θ log p θ ( a ) . (28)
假设当前模型在某一个 prefix 上输出 vocabulary 中所有 token 的 logits:
z θ ( 1 ) , z θ ( 2 ) , … , z θ ( V ) . z_\theta(1),z_\theta(2),\ldots,z_\theta(V). z θ ( 1 ) , z θ ( 2 ) , … , z θ ( V ) . (29)
我们默认输出的分布由 Softmax 给出:
p θ ( a ) = e z θ ( a ) ∑ v e z θ ( v ) . p_\theta(a) = \frac{e^{z_\theta(a)}}{\sum_v e^{z_\theta(v)}}. p θ ( a ) = ∑ v e z θ ( v ) e z θ ( a ) . (30)
所以:
s θ ( a ) = ∇ θ z θ ( a ) − ∇ θ log ∑ v e z θ ( v ) . s_\theta(a) = \nabla_\theta z_\theta(a) - \nabla_\theta \log\sum_v e^{z_\theta(v)}. s θ ( a ) = ∇ θ z θ ( a ) − ∇ θ log v ∑ e z θ ( v ) . (31)
现在给上式的第一项起一个好听点的名字,叫 logit Jacobian 吧:
J θ ( v ) = ∇ θ z θ ( v ) . J_\theta(v)=\nabla_\theta z_\theta(v). J θ ( v ) = ∇ θ z θ ( v ) . (32)
这个 J θ ( v ) J_\theta(v) J θ ( v ) 可以理解成:如果我稍微改变当前 trainer 的模型参数,token v v v 的 raw logit 会朝哪个方向变化。
举个直观的例子。假设模型参数从 θ \theta θ 变成:
θ + Δ θ , \theta+\Delta\theta, θ + Δ θ , (33)
那么一阶近似下:
z θ + Δ θ ( v ) ≈ z θ ( v ) + J θ ( v ) T Δ θ . z_{\theta+\Delta\theta}(v)
\approx
z_\theta(v)
+
J_\theta(v)^T\Delta\theta. z θ + Δ θ ( v ) ≈ z θ ( v ) + J θ ( v ) T Δ θ . (34)
所以 J θ ( v ) J_\theta(v) J θ ( v ) 本质上就是 token v v v 在参数空间里的一个“logit sensitivity direction”。它告诉我们:参数往哪里走,会把这个 token 的 logit 往上推或者往下拉。
接着我们处理上式的第二项:
∇ θ log ∑ v e z θ ( v ) \nabla_\theta
\log\sum_v e^{z_\theta(v)} ∇ θ log v ∑ e z θ ( v ) (35)
这里只需要用两次链式法则。先对最外层的 log 求导,得到的分母就是 log 里面的那个求和:
∇ θ log ∑ v e z θ ( v ) = 1 ∑ u e z θ ( u ) ∇ θ ∑ v e z θ ( v ) . \nabla_\theta\log\sum_v e^{z_\theta(v)}=\frac{1}{\sum_u e^{z_\theta(u)}}\nabla_\theta\sum_v e^{z_\theta(v)}. ∇ θ log v ∑ e z θ ( v ) = ∑ u e z θ ( u ) 1 ∇ θ v ∑ e z θ ( v ) . (36)
然后把梯度放进求和里面,再对每一个 e z θ ( v ) e^{z_\theta(v)} e z θ ( v ) 用一次链式法则:
∇ θ ∑ v e z θ ( v ) = ∑ v ∇ θ e z θ ( v ) = ∑ v e z θ ( v ) ∇ θ z θ ( v ) . \nabla_\theta\sum_v e^{z_\theta(v)}=\sum_v\nabla_\theta e^{z_\theta(v)}=\sum_v e^{z_\theta(v)}\nabla_\theta z_\theta(v). ∇ θ v ∑ e z θ ( v ) = v ∑ ∇ θ e z θ ( v ) = v ∑ e z θ ( v ) ∇ θ z θ ( v ) . (37)
把这两步合起来,就得到:
∑ v e z θ ( v ) ∇ θ z θ ( v ) ∑ u e z θ ( u ) . \frac{
\sum_v \color{orange}{e^{z_\theta(v)}} \color{blue}{\nabla_\theta z_\theta(v)}
}{
\color{orange}{\sum_u e^{z_\theta(u)}}
}. ∑ u e z θ ( u ) ∑ v e z θ ( v ) ∇ θ z θ ( v ) . (38)
而我们恰好有:
p θ ( v ) = e z θ ( v ) ∑ u e z θ ( u ) , J θ ( v ) = ∇ θ z θ ( v ) . p_\theta(v) = \color{orange}{\frac{e^{z_\theta(v)}}{\sum_u e^{z_\theta(u)}}}, \quad J_\theta(v)= \color{blue}{\nabla_\theta z_\theta(v)}. p θ ( v ) = ∑ u e z θ ( u ) e z θ ( v ) , J θ ( v ) = ∇ θ z θ ( v ) . (39)
所以上式第二项可以写作:
∑ v p θ ( v ) J θ ( v ) . \sum_v p_\theta(v)J_\theta(v). v ∑ p θ ( v ) J θ ( v ) . (40)
也就是:
E v ∼ p θ [ J θ ( v ) ] . \mathbb E_{v\sim p_\theta}[J_\theta(v)]. E v ∼ p θ [ J θ ( v )] . (41)
因此:
s θ ( a ) = J θ ( a ) − E v ∼ p θ [ J θ ( v ) ] . s_\theta(a) = J_\theta(a)-\mathbb E_{v\sim p_\theta}[J_\theta(v)]. s θ ( a ) = J θ ( a ) − E v ∼ p θ [ J θ ( v )] . (42)
这个式子特别重要,因为它告诉我们 在 score function 里,Softmax 自己就在给 logit Jacobian 做 centering 。J θ ( a ) J_\theta(a) J θ ( a ) 是当前 sample 到的 action 的 logit gradient,而 E v ∼ p θ [ J θ ( v ) ] \mathbb E_{v\sim p_\theta}[J_\theta(v)] E v ∼ p θ [ J θ ( v )] 是按照当前 policy p θ p_\theta p θ 加权以后,所有 action 的平均 logit gradient。
所以 score 其实就是被采样到的 action 的 logit Jacobian,减去当前 policy 下平均的 logit Jacobian 。
有了上边这个式子,score 的 expectation 为 0 这件事情几乎都不用证明了。因为 action 本身就是从:
a ∼ p θ a\sim p_\theta a ∼ p θ (43)
采样出来的,所以:
E a ∼ p θ [ s θ ( a ) ] = E a ∼ p θ [ J θ ( a ) − E v ∼ p θ [ J θ ( v ) ] ] . \mathbb E_{a\sim p_\theta}[s_\theta(a)]=\mathbb E_{a\sim p_\theta}\left[J_\theta(a)-\mathbb E_{v\sim p_\theta}[J_\theta(v)]\right]. E a ∼ p θ [ s θ ( a )] = E a ∼ p θ [ J θ ( a ) − E v ∼ p θ [ J θ ( v )] ] . (44)
把 expectation 拆开:
= E a ∼ p θ [ J θ ( a ) ] − E v ∼ p θ [ J θ ( v ) ] . =\mathbb E_{a\sim p_\theta}[J_\theta(a)]-\mathbb E_{v\sim p_\theta}[J_\theta(v)]. = E a ∼ p θ [ J θ ( a )] − E v ∼ p θ [ J θ ( v )] . (45)
这里的 a a a 和 v v v 只是两个名字不同的 dummy variable,它们都来自完全相同的 distribution p θ p_\theta p θ ,所以这两项就是同一个东西:
E a ∼ p θ [ s θ ( a ) ] = E p θ [ J θ ] − E p θ [ J θ ] = 0. \mathbb E_{a\sim p_\theta}[s_\theta(a)]=\mathbb E_{p_\theta}[J_\theta]-\mathbb E_{p_\theta}[J_\theta]=0. E a ∼ p θ [ s θ ( a )] = E p θ [ J θ ] − E p θ [ J θ ] = 0. (46)
所以我们现在可以把整件事情串起来了:Softmax score 本身是 centered 的 ,因此:
E a ∼ p θ [ s θ ( a ) ] = 0 , \mathbb E_{a\sim p_\theta}[s_\theta(a)] = 0, E a ∼ p θ [ s θ ( a )] = 0 , (47)
而这个 zero-mean property 又保证了:我们可以在 policy gradient 中使用 reward 减 baseline 来代替原始的 reward,而不改变 expected policy gradient。
到这里其实一切都非常美好。但是注意,上面整个推导里有一个我们一直在偷偷使用、但是还没有认真强调的假设:
计算 expectation 的 distribution,和生成 action 的 distribution,都是 p θ p_\theta p θ 。
也就是说,我们默认:
产生 rollout 的 generator,就是现在正在 backward 的 trainer。
一旦这个假设不成立,后面的故事才真正开始。
2.3 trainer-generator mismatch 后到底破坏了什么?
肯定是破坏了 E a ∼ p θ [ s θ ( a ) ] = 0 \mathbb E_{a\sim p_\theta}[s_\theta(a)] = 0 E a ∼ p θ [ s θ ( a )] = 0 这个 score function 的 zero-mean property 啊,不然我们上边讨论那么多不就白费功夫了。
但是这里最重要的问题不是“它被破坏了”,而是:到底是哪一步发生了变化?
我们先把 trainer 和 generator 明确区分开。假设当前正在做 backward、准备更新参数的 trainer policy 是:
p θ ( a ) . p_\theta(a). p θ ( a ) . (48)
而真正生成 rollout 的 generator 是一个稍微旧一点的 policy:
q ϕ ( a ) . q_\phi(a). q ϕ ( a ) . (49)
这里我故意用了不同的参数 θ \theta θ 和 ϕ \phi ϕ 。你可以把 θ \theta θ 理解成 trainer 当前的参数,而 ϕ \phi ϕ 是 generator 拿去做 rollout 时的那一版参数。在同步训练里,我们近似有:
q ϕ ≈ p θ , q_\phi \approx p_\theta, q ϕ ≈ p θ , (50)
甚至可以直接认为:
q ϕ = p θ . q_\phi=p_\theta. q ϕ = p θ . (51)
但在 async RL 里,尤其是 rollout 很长、generator 很多、trainer 又一直在更新的时候,这两个分布很自然就会开始产生 mismatch:
q ϕ ≠ p θ . q_\phi\neq p_\theta. q ϕ = p θ . (52)
现在回忆一下我们刚才证明 zero-mean property 时用的公式:
E a ∼ p θ [ s θ ( a ) ] = E a ∼ p θ [ J θ ( a ) ] − E v ∼ p θ [ J θ ( v ) ] = 0. \mathbb E_{a\sim p_\theta}[s_\theta(a)]=\mathbb E_{a\sim p_\theta}[J_\theta(a)]-\mathbb E_{v\sim p_\theta}[J_\theta(v)]=0. E a ∼ p θ [ s θ ( a )] = E a ∼ p θ [ J θ ( a )] − E v ∼ p θ [ J θ ( v )] = 0. (53)
为什么等于 0?本质上就是因为左右两边的 expectation 都是在同一个 p θ p_\theta p θ 上算的。第一个 expectation 里,action a a a 是从 p θ p_\theta p θ sample 出来的;第二个 expectation 里,Softmax 本身又是用 p θ p_\theta p θ 对所有 logit Jacobian 做 centering。所以两项正好完全一样。
但是现在 generator 换成了 q ϕ q_\phi q ϕ 。真正送到 trainer 里的 action 已经不再满足:
a ∼ p θ , a\sim p_\theta, a ∼ p θ , (54)
而是:
a ∼ q ϕ . a\sim \color{red}{q_\phi}. a ∼ q ϕ . (55)
注意,trainer 并没有因此改变自己计算 score 的方式。我们 backward 的仍然是当前 trainer 的:
s θ ( a ) = J θ ( a ) − E v ∼ p θ [ J θ ( v ) ] . s_\theta(a)=J_\theta(a)-\mathbb E_{v\sim p_\theta}[J_\theta(v)]. s θ ( a ) = J θ ( a ) − E v ∼ p θ [ J θ ( v )] . (56)
这里的 J θ J_\theta J θ 仍然来自当前 trainer,Softmax centering 用的也仍然是当前 trainer distribution p θ p_\theta p θ 。真正变化的只有一件事情:外边这个 action 到底是从哪个 distribution sample 出来的。
所以现在我们真正应该看的,不再是:
E a ∼ p θ [ s θ ( a ) ] , \mathbb E_{a\sim p_\theta}[s_\theta(a)], E a ∼ p θ [ s θ ( a )] , (57)
而是:
E a ∼ q ϕ [ s θ ( a ) ] . \mathbb E_{a\sim \color{red}{q_\phi}}[s_\theta(a)]. E a ∼ q ϕ [ s θ ( a )] . (58)
把 score 展开:
E a ∼ q ϕ [ s θ ( a ) ] = E a ∼ q ϕ [ J θ ( a ) − E v ∼ p θ [ J θ ( v ) ] ] . \mathbb E_{a\sim \color{red}{q_\phi}}[s_\theta(a)]=\mathbb E_{a\sim \color{red}{q_\phi}}\left[J_\theta(a)-\mathbb E_{v\sim p_\theta}[J_\theta(v)]\right]. E a ∼ q ϕ [ s θ ( a )] = E a ∼ q ϕ [ J θ ( a ) − E v ∼ p θ [ J θ ( v )] ] . (59)
把 expectation 拆开:
= E a ∼ q ϕ [ J θ ( a ) ] − E v ∼ p θ [ J θ ( v ) ] . =\mathbb E_{a\sim \color{red}{q_\phi}}[J_\theta(a)]-\mathbb E_{v\sim p_\theta}[J_\theta(v)]. = E a ∼ q ϕ [ J θ ( a )] − E v ∼ p θ [ J θ ( v )] . (60)
现在问题就非常明显了。原来我们是:
E a ∼ p θ [ J θ ( a ) ] − E v ∼ p θ [ J θ ( v ) ] , \mathbb E_{a\sim p_\theta}[J_\theta(a)]-\mathbb E_{v\sim p_\theta}[J_\theta(v)], E a ∼ p θ [ J θ ( a )] − E v ∼ p θ [ J θ ( v )] , (61)
左右两个 expectation 的 distribution 一样,所以等于 0。现在变成了:
E a ∼ q ϕ [ J θ ( a ) ] − E v ∼ p θ [ J θ ( v ) ] . \mathbb E_{a\sim \color{red}{q_\phi}}[J_\theta(a)]-\mathbb E_{v\sim p_\theta}[J_\theta(v)]. E a ∼ q ϕ [ J θ ( a )] − E v ∼ p θ [ J θ ( v )] . (62)
左边在 generator distribution q ϕ q_\phi q ϕ 下取平均,右边却仍然在 trainer distribution p θ p_\theta p θ 下取平均。只要:
q ϕ ≠ p θ , q_\phi\neq p_\theta, q ϕ = p θ , (63)
我们一般就不能再指望:
E a ∼ q ϕ [ J θ ( a ) ] = E v ∼ p θ [ J θ ( v ) ] . \mathbb E_{a\sim q_\phi}[J_\theta(a)]=\mathbb E_{v\sim p_\theta}[J_\theta(v)]. E a ∼ q ϕ [ J θ ( a )] = E v ∼ p θ [ J θ ( v )] . (64)
所以最终:
E a ∼ q ϕ [ s θ ( a ) ] = E q ϕ [ J θ ] − E p θ [ J θ ] ≠ 0. \mathbb E_{a\sim \color{red}{q_\phi}}[s_\theta(a)]=\mathbb E_{q_\phi}[J_\theta]-\mathbb E_{p_\theta}[J_\theta]\neq 0. E a ∼ q ϕ [ s θ ( a )] = E q ϕ [ J θ ] − E p θ [ J θ ] = 0. (65)
这就是 trainer-generator mismatch 对 score function 最直接的影响。
你会发现,这件事情其实一点都不神秘。Score 自己没有突然变坏,Softmax 的公式也没有变,trainer 计算出来的 J θ J_\theta J θ 也没有变。真正发生变化的,只是 sample action 的 distribution 从 p θ p_\theta p θ 换成了 q ϕ q_\phi q ϕ 。
而 zero-mean property 恰好又依赖于“sample action 的 distribution”和“score 里面做 centering 的 distribution”是同一个 distribution。现在这两个东西不一样了:
a ∼ q ϕ ⏟ generator sampling distribution , E v ∼ p θ [ J θ ( v ) ] ⏟ trainer centering distribution . \underbrace{a\sim \color{red}{q_\phi}}_{\text{generator sampling distribution}},\qquad \underbrace{\mathbb E_{v\sim p_\theta}[J_\theta(v)]}_{\text{trainer centering distribution}}. generator sampling distribution a ∼ q ϕ , trainer centering distribution E v ∼ p θ [ J θ ( v )] . (66)
所以原来那个:
E p θ [ J θ ] − E p θ [ J θ ] = 0 \mathbb E_{p_\theta}[J_\theta]-\mathbb E_{p_\theta}[J_\theta]=0 E p θ [ J θ ] − E p θ [ J θ ] = 0 (67)
就变成了:
E q ϕ [ J θ ] − E p θ [ J θ ] ≠ 0. \mathbb E_{\color{red}{q_\phi}}[J_\theta]-\mathbb E_{p_\theta}[J_\theta]\neq 0. E q ϕ [ J θ ] − E p θ [ J θ ] = 0. (68)
到这里,我们其实已经把 trainer-generator mismatch 最关键的一层问题讲清楚了:
在同步 RL 里,generator 和 trainer 是同一个 distribution,所以标准 score 天然是 zero-mean 的;而在 async RL 里,action 来自旧 generator q ϕ q_\phi q ϕ ,score 却仍然由当前 trainer p θ p_\theta p θ 来 center,于是这个 zero-mean property 被破坏了。
2.4 这个 non-zero mean 到底会造成什么实际后果?
到这里你可能会觉得,E q ϕ [ s θ ] ≠ 0 \mathbb E_{q_\phi}[s_\theta]\neq 0 E q ϕ [ s θ ] = 0 听起来还是有点抽象。我们前面说它会破坏 baseline invariance,但是它到底会给训练带来一个什么样的 gradient?
这件事情如果直接放到 logit space 里看,会非常直观。对于 Softmax,某个 action a a a 的 log probability 对整条 logit vector z z z 的梯度是:
∇ z log p θ ( a ) = e a − p θ , \nabla_z\log p_\theta(a)=e_a-p_\theta, ∇ z log p θ ( a ) = e a − p θ , (69)
其中 e a e_a e a 是 action a a a 对应的 one-hot vector。在同步训练里 a ∼ p θ a\sim p_\theta a ∼ p θ ,所以对它取 expectation:
E a ∼ p θ [ ∇ z log p θ ( a ) ] = p θ − p θ = 0. \mathbb E_{a\sim p_\theta}[\nabla_z\log p_\theta(a)]=p_\theta-p_\theta=0. E a ∼ p θ [ ∇ z log p θ ( a )] = p θ − p θ = 0. (70)
但是现在 action 是由旧 generator q ϕ q_\phi q ϕ sample 出来的:
E a ∼ q ϕ [ ∇ z log p θ ( a ) ] = q ϕ − p θ . \mathbb E_{a\sim q_\phi}[\nabla_z\log p_\theta(a)]=q_\phi-p_\theta. E a ∼ q ϕ [ ∇ z log p θ ( a )] = q ϕ − p θ . (71)
这个式子就比 E q [ J ] − E p [ J ] \mathbb E_q[J]-\mathbb E_p[J] E q [ J ] − E p [ J ] 更容易看出背后的 intuition 了:如果某个 token 在旧 generator 里比在当前 trainer 里更常见,也就是 q ϕ ( v ) > p θ ( v ) q_\phi(v)>p_\theta(v) q ϕ ( v ) > p θ ( v ) ,这个方向就会把它的 logit 往上推。反过来,如果 q ϕ ( v ) < p θ ( v ) q_\phi(v)<p_\theta(v) q ϕ ( v ) < p θ ( v ) ,这个方向就会把它往下拉。
现在再回到我们前面一直在讨论的 baseline。假设你给所有 reward 或者 advantage 同时加了一个和 action 无关的常数 c c c 。在正常的 on-policy setting 里,这个常数不应该产生任何 expected gradient。但是在 trainer-generator mismatch 以后,它会额外产生:
Δ g z = c E a ∼ q ϕ [ ∇ z log p θ ( a ) ] = c ( q ϕ − p θ ) . \Delta g_z=c\,\mathbb E_{a\sim q_\phi}[\nabla_z\log p_\theta(a)]=c(q_\phi-p_\theta). Δ g z = c E a ∼ q ϕ [ ∇ z log p θ ( a )] = c ( q ϕ − p θ ) . (72)
如果 c > 0 c>0 c > 0 ,这条 gradient 做的事情非常直接:把当前 trainer p θ p_\theta p θ 往旧 generator q ϕ q_\phi q ϕ 的 distribution 拉。
反过来,如果 c < 0 c<0 c < 0 ,trainer 就会被推向远离 generator 的方向。这是一件非常不好的事情,因为 c c c 在这里扮演的其实就是 baseline 的角色,而 baseline 在理论上本来就有正有负。这就相当于我们在 trainer 和 generator 之间的距离上加了一个扰动,而这个扰动的方向和大小完全取决于 baseline 的取值。
这个方向还可以换一个角度来看。假设我们真的拿旧 generator 的 sample 去最大化当前 trainer 的 log likelihood:
E a ∼ q ϕ [ log p θ ( a ) ] , \mathbb E_{a\sim q_\phi}[\log p_\theta(a)], E a ∼ q ϕ [ log p θ ( a )] , (73)
它在 logit space 里的 gradient 恰好就是:
∇ z E a ∼ q ϕ [ log p θ ( a ) ] = q ϕ − p θ . \nabla_z\mathbb E_{a\sim q_\phi}[\log p_\theta(a)]=q_\phi-p_\theta. ∇ z E a ∼ q ϕ [ log p θ ( a )] = q ϕ − p θ . (74)
换句话说:
q ϕ − p θ = − ∇ z D K L ( q ϕ ∥ p θ ) . q_\phi-p_\theta=-\nabla_zD_{\mathrm{KL}}(q_\phi\|p_\theta). q ϕ − p θ = − ∇ z D KL ( q ϕ ∥ p θ ) . (75)
所以当 mean reward 或者 mean advantage 是正的时候,那个本来应该只是“大家共同拥有的常数部分”,居然会偷偷变成一个方向上和对旧 generator 做 behavior cloning 完全一致的 gradient 。这件事情其实很奇怪:一个和 action 之间谁好谁坏都没有关系的平均值,凭什么能决定我们要不要往旧 generator 靠近,以及靠近多少?
用我们前面在参数空间里的写法来看,结论也是一样的。把 advantage 拆成:
A ( a ) = ( A ( a ) − A ˉ q ) + A ˉ q , A ˉ q = E q ϕ [ A ] . A(a)=(A(a)-\bar A_q)+\bar A_q,\qquad \bar A_q=\mathbb E_{q_\phi}[A]. A ( a ) = ( A ( a ) − A ˉ q ) + A ˉ q , A ˉ q = E q ϕ [ A ] . (76)
那么:
E q ϕ [ A ( a ) s θ ( a ) ] = E q ϕ [ ( A ( a ) − A ˉ q ) s θ ( a ) ] + A ˉ q E q ϕ [ s θ ( a ) ] . \mathbb E_{q_\phi}[A(a)s_\theta(a)]=\mathbb E_{q_\phi}[(A(a)-\bar A_q)s_\theta(a)]+\bar A_q\,\mathbb E_{q_\phi}[s_\theta(a)]. E q ϕ [ A ( a ) s θ ( a )] = E q ϕ [( A ( a ) − A ˉ q ) s θ ( a )] + A ˉ q E q ϕ [ s θ ( a )] . (77)
而第二项就是:
A ˉ q ( E q ϕ [ J θ ] − E p θ [ J θ ] ) . \bar A_q\left(\mathbb E_{q_\phi}[J_\theta]-\mathbb E_{p_\theta}[J_\theta]\right). A ˉ q ( E q ϕ [ J θ ] − E p θ [ J θ ] ) . (78)
这就是 zero-mean 被破坏以后最实际的后果之一:真正描述 token 之间相对好坏的是第一项,但是 mean advantage 又额外乘上了一个 trainer-generator mismatch direction。
现在再看 Score Function Centering,动机就更直接了。我们不只是想让一个数学 expectation 看起来重新等于 0,更是想把这个由“平均 reward 水平”偷偷控制的 old-policy cloning direction 从 reward gradient 里拿掉。至于 trainer 和 generator 到底应该允许差多远,那是另外一个问题,不应该让 A ˉ q \bar A_q A ˉ q 在这里顺手替我们做决定。
3. Score Function Centering 到底在做什么?
答案呼之欲出了对不对!Score Function Centering 就是想让原本被破坏的 score function 的 zero-mean property 重新被满足,所以我们就又可以愉快地使用 baseline 啦!
我们刚才已经看到,在 trainer-generator mismatch 之后,真正的问题变成了:
E a ∼ q ϕ [ s θ ( a ) ] = E q ϕ [ J θ ] − E p θ [ J θ ] ≠ 0. \mathbb E_{a\sim q_\phi}[s_\theta(a)]=\mathbb E_{q_\phi}[J_\theta]-\mathbb E_{p_\theta}[J_\theta]\neq 0. E a ∼ q ϕ [ s θ ( a )] = E q ϕ [ J θ ] − E p θ [ J θ ] = 0. (79)
这里为什么不等于 0?原因非常简单:action 是 generator 的 q ϕ q_\phi q ϕ sample 出来的,但是 score 里面减掉的“中心”却还是 trainer 的 p θ p_\theta p θ 。
想要更正这一点,既然外边的 action 已经来自 a ∼ q ϕ a\sim q_\phi a ∼ q ϕ ,那最直接的办法当然就是:不要再用 p θ p_\theta p θ 做 centering,而是改成用真正生成这些 action 的 distribution q ϕ q_\phi q ϕ 做 centering。
也就是说,把原来的标准 score:
s θ ( a ) = J θ ( a ) − E v ∼ p θ [ J θ ( v ) ] s_\theta(a)=J_\theta(a)-\mathbb E_{v\sim p_\theta}[J_\theta(v)] s θ ( a ) = J θ ( a ) − E v ∼ p θ [ J θ ( v )] (80)
改成:
s ~ θ , ϕ ( a ) = J θ ( a ) − E v ∼ q ϕ [ J θ ( v ) ] . \tilde s_{\theta,\phi}(a)=J_\theta(a)-\mathbb E_{v\sim \color{red}{q_\phi}}[J_\theta(v)]. s ~ θ , ϕ ( a ) = J θ ( a ) − E v ∼ q ϕ [ J θ ( v )] . (81)
这就是 Score Function Centering 最核心的一步。
注意这里有两个 distribution / model parameter,不要混在一起。J θ ( v ) J_\theta(v) J θ ( v ) 仍然是:
J θ ( v ) = ∇ θ z θ ( v ) , J_\theta(v)=\nabla_\theta z_\theta(v), J θ ( v ) = ∇ θ z θ ( v ) , (82)
所以它还是当前 trainer 的 logit Jacobian。我们并不是回到旧 generator 上去算 gradient,也不是要更新 ϕ \phi ϕ 。真正变化的只有 centering 时使用的 probability distribution:
E v ∼ p θ [ J θ ( v ) ] ⟶ E v ∼ q ϕ [ J θ ( v ) ] . \mathbb E_{v\sim p_\theta}[J_\theta(v)]\quad\longrightarrow\quad\mathbb E_{v\sim \color{red}{q_\phi}}[J_\theta(v)]. E v ∼ p θ [ J θ ( v )] ⟶ E v ∼ q ϕ [ J θ ( v )] . (83)
你可以把这句话记成:generator 决定“怎么平均”,trainer 决定“往哪个参数方向更新”。
这样一改,zero-mean property 马上就回来了。因为真正的 action 本来就是:
a ∼ q ϕ , a\sim q_\phi, a ∼ q ϕ , (84)
所以:
E a ∼ q ϕ [ s ~ θ , ϕ ( a ) ] = E a ∼ q ϕ [ J θ ( a ) ] − E v ∼ q ϕ [ J θ ( v ) ] . \mathbb E_{a\sim q_\phi}[\tilde s_{\theta,\phi}(a)]=\mathbb E_{a\sim q_\phi}[J_\theta(a)]-\mathbb E_{v\sim q_\phi}[J_\theta(v)]. E a ∼ q ϕ [ s ~ θ , ϕ ( a )] = E a ∼ q ϕ [ J θ ( a )] − E v ∼ q ϕ [ J θ ( v )] . (85)
a a a 和 v v v 还是两个 dummy variable,而且这一次它们终于又来自同一个 distribution 了:
E a ∼ q ϕ [ s ~ θ , ϕ ( a ) ] = E q ϕ [ J θ ] − E q ϕ [ J θ ] = 0. \mathbb E_{a\sim q_\phi}[\tilde s_{\theta,\phi}(a)]=\mathbb E_{q_\phi}[J_\theta]-\mathbb E_{q_\phi}[J_\theta]=0. E a ∼ q ϕ [ s ~ θ , ϕ ( a )] = E q ϕ [ J θ ] − E q ϕ [ J θ ] = 0. (86)
于是我们重新得到:
E a ∼ q ϕ [ ( R ( a ) − b ) s ~ θ , ϕ ( a ) ] = E a ∼ q ϕ [ R ( a ) s ~ θ , ϕ ( a ) ] . \mathbb E_{a\sim q_\phi}[(R(a)-b)\tilde s_{\theta,\phi}(a)]=\mathbb E_{a\sim q_\phi}[R(a)\tilde s_{\theta,\phi}(a)]. E a ∼ q ϕ [( R ( a ) − b ) s ~ θ , ϕ ( a )] = E a ∼ q ϕ [ R ( a ) s ~ θ , ϕ ( a )] . (87)
也就是说,在真正产生 rollout 的 distribution q ϕ q_\phi q ϕ 下 ,baseline 又不会自己产生一个额外的 expected gradient 了。
这就是 Score Function Centering 最本质的 intuition:让 score 的 centering distribution 和真正生成 action 的 distribution 对齐。
3.1 但是现实里有一个很大的问题:我们怎么得到 E q ϕ [ J θ ] \mathbb E_{q_\phi}[J_\theta] E q ϕ [ J θ ] ?
你如果真的在训练 LLM,使用上边的方法,马上就会碰到一个非常现实的问题:
E v ∼ q ϕ [ J θ ( v ) ] = ∑ v ∈ V q ϕ ( v ) J θ ( v ) . \mathbb E_{v\sim q_\phi}[J_\theta(v)]=\sum_{v\in\mathcal V}q_\phi(v)J_\theta(v). E v ∼ q ϕ [ J θ ( v )] = v ∈ V ∑ q ϕ ( v ) J θ ( v ) . (88)
假设 vocabulary 有 128K 个 token,那么这个 expectation 看起来要求我们知道 generator 在这个 prefix 上对所有 128K 个 token 的 probability:
q ϕ ( 1 ) , q ϕ ( 2 ) , … , q ϕ ( V ) . q_\phi(1),q_\phi(2),\ldots,q_\phi(V). q ϕ ( 1 ) , q ϕ ( 2 ) , … , q ϕ ( V ) . (89)
问题是,这些信息是在 generator 生成 token 的那一刻才有的,而真正做 backward 的 trainer 可能在另外一台机器、另外一个 pipeline stage,甚至已经过了几十个 train step。
当然你可以说,那我就把 generator 的整个 vocabulary distribution 都存下来,再发给 trainer 不就完了?
理论上可以,但是工程上不可以。
因为对于 rollout 里的每一个 token position ,你都要额外保存一个长度为 vocabulary size 的 distribution。假设 vocab 是 128K,一个 rollout 又有几千甚至几万个 token,再乘上 batch size、generator 数量和并行 rollout 数,这个 communication 和 memory overhead 很快就会变得完全不可接受。
所以现实问题变成了:
我们想知道 q ϕ q_\phi q ϕ 下的 expectation,但是又不能把完整的 q ϕ q_\phi q ϕ 搬到 trainer。怎么办?
答案还是 Monte Carlo:既然 expectation 本来就是对 q ϕ q_\phi q ϕ 求平均,那我们就在 generator 端从 q ϕ q_\phi q ϕ 里多 sample 几个 token。
3.2 Alternative Tokens:不要把整个 distribution 给 trainer,给我几个 sample 就够了
假设真正被 generator 选中、进入 rollout 的 token 是:
a ∼ q ϕ . a\sim q_\phi. a ∼ q ϕ . (90)
除了这个 primary action 以外,我们在完全相同的 prefix 上,再额外从 generator distribution 里 sample K K K 个 token:
v 1 , v 2 , … , v K ∼ q ϕ . v_1,v_2,\ldots,v_K\sim q_\phi. v 1 , v 2 , … , v K ∼ q ϕ . (91)
这些 token 不会真的被 append 到 trajectory 里,也不会改变后续 generation。它们只是在告诉 trainer:
“我当时在这个 prefix 上的 distribution 大概长这样。”
不同地方会给这些 token 起不同的名字,alternative tokens、alter tokens、negative tokens、auxiliary samples……它们本质上都是在做同一件事情:用少量 sample 来描述 generator 当时的 local action distribution。
如果这些 v k v_k v k 真的是 IID 从 q ϕ q_\phi q ϕ 里 sample 出来的,那么:
E v ∼ q ϕ [ J θ ( v ) ] ≈ 1 K ∑ k = 1 K J θ ( v k ) . \mathbb E_{v\sim q_\phi}[J_\theta(v)]\approx\frac{1}{K}\sum_{k=1}^KJ_\theta(v_k). E v ∼ q ϕ [ J θ ( v )] ≈ K 1 k = 1 ∑ K J θ ( v k ) . (92)
于是 SFC score 就可以近似成:
s ^ θ , ϕ ( a ) = J θ ( a ) − 1 K ∑ k = 1 K J θ ( v k ) . \hat s_{\theta,\phi}(a)=J_\theta(a)-\frac{1}{K}\sum_{k=1}^KJ_\theta(v_k). s ^ θ , ϕ ( a ) = J θ ( a ) − K 1 k = 1 ∑ K J θ ( v k ) . (93)
而且这个 Monte Carlo estimator 对我们真正想要的 behavior-centered score 是 unbiased 的:
E v 1 , … , v K ∼ q ϕ [ 1 K ∑ k = 1 K J θ ( v k ) ] = E v ∼ q ϕ [ J θ ( v ) ] . \mathbb E_{v_1,\ldots,v_K\sim q_\phi}\left[\frac{1}{K}\sum_{k=1}^KJ_\theta(v_k)\right]=\mathbb E_{v\sim q_\phi}[J_\theta(v)]. E v 1 , … , v K ∼ q ϕ [ K 1 k = 1 ∑ K J θ ( v k ) ] = E v ∼ q ϕ [ J θ ( v )] . (94)
所以 generator 不需要把整个 q ϕ q_\phi q ϕ 传给 trainer。它只需要在每一个 token position 附带一小撮额外的信息,比如:
[ a , v 1 , v 2 , … , v K ] . [a,v_1,v_2,\ldots,v_K]. [ a , v 1 , v 2 , … , v K ] . (95)
更实际一点,还会把这些 token 在 generator 下的 log probability 一起保存下来:
[ log q ϕ ( a ) , log q ϕ ( v 1 ) , … , log q ϕ ( v K ) ] . [\log q_\phi(a),\log q_\phi(v_1),\ldots,\log q_\phi(v_K)]. [ log q ϕ ( a ) , log q ϕ ( v 1 ) , … , log q ϕ ( v K )] . (96)
然后这些信息跟着 rollout 一路从 generator 传到 trainer。所以你可以把一个普通 RL rollout token 想成原来只携带:
token id + reward/advantage + log q ϕ ( a ) , \text{token id}+\text{reward/advantage}+\log q_\phi(a), token id + reward/advantage + log q ϕ ( a ) , (97)
而 SFC 之后,它还额外携带了一个非常小的 local policy sketch :
{ v k , log q ϕ ( v k ) } k = 1 K . \{v_k,\log q_\phi(v_k)\}_{k=1}^K. { v k , log q ϕ ( v k ) } k = 1 K . (98)
这个 local policy sketch 就是在告诉 trainer:generator 当时除了真正选中的 action 以外,还认为哪些 token 是可能的。
聪明的你发现了,如果想去灌水几篇学术会议,这个 generator distribution 的采样方法,你去换上几种,试一试谁比谁好,又是几篇 paper (LoL)。
3.3 等一下,我们真的要在 trainer 里显式计算 J θ ( v ) J_\theta(v) J θ ( v ) 吗?
看到这里你可能又要有点头大了,因为:
J θ ( v ) = ∇ θ z θ ( v ) J_\theta(v)=\nabla_\theta z_\theta(v) J θ ( v ) = ∇ θ z θ ( v ) (99)
可是 θ \theta θ 是整个 LLM 的所有参数。70B 模型的话,J θ ( v ) J_\theta(v) J θ ( v ) 本身就是一个几十 billion 维的 vector。
难道我们真的要给每一个 alternative token 都 materialize 一个巨大的 Jacobian,然后再算:
J θ ( a ) − 1 K ∑ k J θ ( v k ) ? J_\theta(a)-\frac{1}{K}\sum_kJ_\theta(v_k)? J θ ( a ) − K 1 k ∑ J θ ( v k )? (100)
当然不是。J θ J_\theta J θ 在这里主要是一个帮助我们理解算法的数学对象 。真正写代码的时候,我们只需要构造一个 scalar surrogate,然后让 autograd 帮我们把它求导。先回到 SFC 想要的 gradient:
J θ ( a ) − E v ∼ q ϕ [ J θ ( v ) ] . J_\theta(a)-\mathbb E_{v\sim q_\phi}[J_\theta(v)]. J θ ( a ) − E v ∼ q ϕ [ J θ ( v )] . (101)
因为:
J θ ( v ) = ∇ θ z θ ( v ) , J_\theta(v)=\nabla_\theta z_\theta(v), J θ ( v ) = ∇ θ z θ ( v ) , (102)
所以:
J θ ( a ) − E v ∼ q ϕ [ J θ ( v ) ] = ∇ θ ( z θ ( a ) − E v ∼ q ϕ [ z θ ( v ) ] ) . J_\theta(a)-\mathbb E_{v\sim q_\phi}[J_\theta(v)]=\nabla_\theta\left(z_\theta(a)-\mathbb E_{v\sim q_\phi}[z_\theta(v)]\right). J θ ( a ) − E v ∼ q ϕ [ J θ ( v )] = ∇ θ ( z θ ( a ) − E v ∼ q ϕ [ z θ ( v )] ) . (103)
于是我们真正需要构造的 scalar 非常简单:
c θ , ϕ ( a ) = z θ ( a ) − E v ∼ q ϕ [ z θ ( v ) ] . c_{\theta,\phi}(a)=z_\theta(a)-\mathbb E_{v\sim q_\phi}[z_\theta(v)]. c θ , ϕ ( a ) = z θ ( a ) − E v ∼ q ϕ [ z θ ( v )] . (104)
如果用刚才的 K K K 个 alternative samples:
c ^ θ , ϕ ( a ) = z θ ( a ) − 1 K ∑ k = 1 K z θ ( v k ) . \hat c_{\theta,\phi}(a)=z_\theta(a)-\frac{1}{K}\sum_{k=1}^Kz_\theta(v_k). c ^ θ , ϕ ( a ) = z θ ( a ) − K 1 k = 1 ∑ K z θ ( v k ) . (105)
然后像普通 policy gradient 一样乘上 advantage:
L S F C = − A ( a ) c ^ θ , ϕ ( a ) . L_{\mathrm{SFC}}=-A(a)\hat c_{\theta,\phi}(a). L SFC = − A ( a ) c ^ θ , ϕ ( a ) . (106)
对它做一次普通 backward:
∇ θ L S F C = − A ( a ) ( J θ ( a ) − 1 K ∑ k = 1 K J θ ( v k ) ) . \nabla_\theta L_{\mathrm{SFC}}=-A(a)\left(J_\theta(a)-\frac{1}{K}\sum_{k=1}^KJ_\theta(v_k)\right). ∇ θ L SFC = − A ( a ) ( J θ ( a ) − K 1 k = 1 ∑ K J θ ( v k ) ) . (107)
这就是我们想要的 SFC gradient,所以在实际代码里,也是这样,大概逻辑是:
generator 告诉 trainer:primary token 是谁,另外几个 alternative token 是谁;
trainer 正常 forward 当前模型;
从当前 trainer 的 logits 里 gather 出这几个 token 对应的 logits;
算一个 primary_logit - mean(alternative_logits);
乘 advantage;
backward。
3.4 为什么这里甚至连完整的 log-softmax 都不需要?
我们前面明明一直在讲 score:
∇ θ log p θ ( a ) , \nabla_\theta\log p_\theta(a), ∇ θ log p θ ( a ) , (108)
为什么到了 SFC 实现的时候突然变成直接操作 logit z θ ( a ) − E q ϕ [ z θ ( v ) ] z_\theta(a)-\mathbb E_{q_\phi}[z_\theta(v)] z θ ( a ) − E q ϕ [ z θ ( v )] ?
原因是 Softmax 的 normalization term 正好会被 cancel。我们可以先从下面这个 quantity 出发:
log p θ ( a ) − E v ∼ q ϕ [ log p θ ( v ) ] . \log p_\theta(a)-\mathbb E_{v\sim q_\phi}[\log p_\theta(v)]. log p θ ( a ) − E v ∼ q ϕ [ log p θ ( v )] . (109)
因为:
log p θ ( v ) = z θ ( v ) − log Z θ , \log p_\theta(v)=z_\theta(v)-\log Z_\theta, log p θ ( v ) = z θ ( v ) − log Z θ , (110)
其中:
Z θ = ∑ u e z θ ( u ) , Z_\theta=\sum_u e^{z_\theta(u)}, Z θ = u ∑ e z θ ( u ) , (111)
所以:
log p θ ( a ) − E v ∼ q ϕ [ log p θ ( v ) ] = z θ ( a ) − log Z θ − E v ∼ q ϕ [ z θ ( v ) − log Z θ ] . \log p_\theta(a)-\mathbb E_{v\sim q_\phi}[\log p_\theta(v)]=z_\theta(a)-\log Z_\theta-\mathbb E_{v\sim q_\phi}[z_\theta(v)-\log Z_\theta]. log p θ ( a ) − E v ∼ q ϕ [ log p θ ( v )] = z θ ( a ) − log Z θ − E v ∼ q ϕ [ z θ ( v ) − log Z θ ] . (112)
对于固定 prefix,log Z θ \log Z_\theta log Z θ 和 sample 到哪个 v v v 没有关系,所以:
E v ∼ q ϕ [ log Z θ ] = log Z θ . \mathbb E_{v\sim q_\phi}[\log Z_\theta]=\log Z_\theta. E v ∼ q ϕ [ log Z θ ] = log Z θ . (113)
于是两个 normalization term 直接消掉:
log p θ ( a ) − E v ∼ q ϕ [ log p θ ( v ) ] = z θ ( a ) − E v ∼ q ϕ [ z θ ( v ) ] . \log p_\theta(a)-\mathbb E_{v\sim q_\phi}[\log p_\theta(v)]=z_\theta(a)-\mathbb E_{v\sim q_\phi}[z_\theta(v)]. log p θ ( a ) − E v ∼ q ϕ [ log p θ ( v )] = z θ ( a ) − E v ∼ q ϕ [ z θ ( v )] . (114)
这件事情在工程上非常 nice:为了这条 SFC loss path,我们只需要 selected token 的 logits,不需要为了它额外 materialize 整个 vocabulary 的 log-softmax。
这里要稍微严谨一点:这并不代表 LLM forward 从此完全不需要 full vocabulary logits。它只意味着 SFC 这一条 loss / gradient path 本身可以只依赖少量被选中的 token logits。
3.5 纯随机 sample 还不够好:为什么实际会用 Head + Tail?
如果只是最简单地从 q ϕ q_\phi q ϕ 里随机 sample:
v 1 , … , v K ∼ q ϕ , v_1,\ldots,v_K\sim q_\phi, v 1 , … , v K ∼ q ϕ , (115)
当然已经可以得到一个 unbiased estimator。但是 LLM 的 next-token distribution 往往非常不均匀:少量 top tokens 可以占掉绝大部分 probability mass,而后面是一个非常长的 tail。
假设某个 prefix 下:
q ϕ ( A ) = 0.40 , q ϕ ( B ) = 0.25 , q ϕ ( C ) = 0.15 , q_\phi(A)=0.40,\qquad q_\phi(B)=0.25,\qquad q_\phi(C)=0.15, q ϕ ( A ) = 0.40 , q ϕ ( B ) = 0.25 , q ϕ ( C ) = 0.15 , (116)
光前三个 token 就已经占了 80% 的 probability mass。
这时候如果我们还把所有 token 都当成普通 Monte Carlo sample 来处理,就有点浪费:明明 A / B / C A/B/C A / B / C 几乎每次都很重要,我们却还在随机决定“这次有没有抽到它”。
所以一个很自然的做法是:高概率的 head 直接精确计算,只有 long tail 用 Monte Carlo sample。
假设 generator 选出 top-H H H token 组成 head set:
H = TopH ( q ϕ ) , \mathcal H=\operatorname{TopH}(q_\phi), H = TopH ( q ϕ ) , (117)
它们的总 probability mass 是:
α = ∑ h ∈ H q ϕ ( h ) . \alpha=\sum_{h\in\mathcal H}q_\phi(h). α = h ∈ H ∑ q ϕ ( h ) . (118)
那么任意一个 expectation 都可以拆成:
E v ∼ q ϕ [ f ( v ) ] = ∑ h ∈ H q ϕ ( h ) f ( h ) + ( 1 − α ) E v ∼ q ϕ ( ⋅ ∣ v ∉ H ) [ f ( v ) ] . \mathbb E_{v\sim q_\phi}[f(v)]=\sum_{h\in\mathcal H}q_\phi(h)f(h)+(1-\alpha)\mathbb E_{v\sim q_\phi(\cdot\mid v\notin\mathcal H)}[f(v)]. E v ∼ q ϕ [ f ( v )] = h ∈ H ∑ q ϕ ( h ) f ( h ) + ( 1 − α ) E v ∼ q ϕ ( ⋅ ∣ v ∈ / H ) [ f ( v )] . (119)
第一项直接精确计算,第二项从 conditional tail distribution 里 sample M M M 个 token:
t 1 , … , t M ∼ q ϕ ( ⋅ ∣ v ∉ H ) . t_1,\ldots,t_M\sim q_\phi(\cdot\mid v\notin\mathcal H). t 1 , … , t M ∼ q ϕ ( ⋅ ∣ v ∈ / H ) . (120)
于是:
E v ∼ q ϕ [ f ( v ) ] ≈ ∑ h ∈ H q ϕ ( h ) f ( h ) + ( 1 − α ) 1 M ∑ m = 1 M f ( t m ) . \mathbb E_{v\sim q_\phi}[f(v)]\approx\sum_{h\in\mathcal H}q_\phi(h)f(h)+(1-\alpha)\frac{1}{M}\sum_{m=1}^Mf(t_m). E v ∼ q ϕ [ f ( v )] ≈ h ∈ H ∑ q ϕ ( h ) f ( h ) + ( 1 − α ) M 1 m = 1 ∑ M f ( t m ) . (121)
在 SFC 里,把:
f ( v ) = J θ ( v ) f(v)=J_\theta(v) f ( v ) = J θ ( v ) (122)
代进去就行。
你可以把这个方法理解成一句朴素的话:
最重要的几个 token 我全都要;剩下概率很小但是数量巨大的 long tail,我再用几个 sample 来代表。
这个 head/tail sampling 本身并不是什么新东西,本质上就是 stratified Monte Carlo。但对于 LLM 这种 vocabulary 很大、概率又高度集中的分布来说,它非常实用。
3.6 所以 SFC 在实际系统里到底需要做什么?
到这里我们可以把整个操作过程用非常具体的方式重新说一遍。
Generator 在某个 prefix x t x_t x t 上有自己的 behavior policy:
q ϕ ( ⋅ ∣ x t ) . q_\phi(\cdot|x_t). q ϕ ( ⋅ ∣ x t ) . (123)
它正常 sample 一个真正进入 trajectory 的 token:
a t ∼ q ϕ . a_t\sim q_\phi. a t ∼ q ϕ . (124)
与此同时,它额外保留少量能够描述当前 distribution 的 token。最简单可以直接从 q ϕ q_\phi q ϕ sample K K K 个 alternative tokens;更实际一点,可以保存 top-H H H head tokens,再从 conditional tail 里 sample 几个 token。
然后 generator 把这些 token id、对应的 q ϕ q_\phi q ϕ probability / log probability,以及自己当时的 model version 一起随着 rollout 传给 trainer。
Trainer 收到这些数据以后,用当前参数 θ \theta θ 正常 forward,然后只 gather:
z θ ( a t ) , z θ ( v t , 1 ) , … , z θ ( v t , K ) . z_\theta(a_t),\qquad z_\theta(v_{t,1}),\ldots,z_\theta(v_{t,K}). z θ ( a t ) , z θ ( v t , 1 ) , … , z θ ( v t , K ) . (125)
再用这些 selected logits 构造对:
E q ϕ [ z θ ( v ) ] \mathbb E_{q_\phi}[z_\theta(v)] E q ϕ [ z θ ( v )] (126)
的 sparse estimator,最后形成:
z θ ( a t ) − E ^ q ϕ [ z θ ( v ) ] . z_\theta(a_t)-\widehat{\mathbb E}_{q_\phi}[z_\theta(v)]. z θ ( a t ) − E q ϕ [ z θ ( v )] . (127)
乘上 advantage:
L t = − A t ( z θ ( a t ) − E ^ q ϕ [ z θ ( v ) ] ) , L_t=-A_t\left(z_\theta(a_t)-\widehat{\mathbb E}_{q_\phi}[z_\theta(v)]\right), L t = − A t ( z θ ( a t ) − E q ϕ [ z θ ( v )] ) , (128)
然后正常 backward。
Autograd 自然就会给出:
− A t ( J θ ( a t ) − E ^ q ϕ [ J θ ( v ) ] ) . -A_t\left(J_\theta(a_t)-\widehat{\mathbb E}_{q_\phi}[J_\theta(v)]\right). − A t ( J θ ( a t ) − E q ϕ [ J θ ( v )] ) . (129)
所以如果非要用一句话总结,Score Function Centering 就是:Generator 不再只告诉 trainer“我最后选了哪个 token”,而是顺手带回来一点“我当时的 local distribution 长什么样”的信息;trainer 再利用这些 sparse samples,把原本以 p θ p_\theta p θ 为中心的 score,改成以真正生成数据的 q ϕ q_\phi q ϕ 为中心。 它解决的问题是:
我们想计算 E q ϕ [ J θ ] \mathbb E_{q_\phi}[J_\theta] E q ϕ [ J θ ] ,但是我们不可能把完整的 q ϕ q_\phi q ϕ 从 generator 搬到 trainer。
所以我们只能想办法在 generator 端保存一个足够便宜、但又足够有信息量的 sparse approximation。
最后再强调一个很重要的边界:SFC 恢复的是:
E a ∼ q ϕ [ s ~ θ , ϕ ( a ) ] = 0 , \mathbb E_{a\sim q_\phi}[\tilde s_{\theta,\phi}(a)]=0, E a ∼ q ϕ [ s ~ θ , ϕ ( a )] = 0 , (130)
也就是 behavior distribution 下的 zero-mean / baseline-invariance property。它并不意味着:
s ~ θ , ϕ ( a ) = ∇ θ log p θ ( a ) . \tilde s_{\theta,\phi}(a)=\nabla_\theta\log p_\theta(a). s ~ θ , ϕ ( a ) = ∇ θ log p θ ( a ) . (131)
只要:
q ϕ ≠ p θ , q_\phi\neq p_\theta, q ϕ = p θ , (132)
这两个东西一般就不是同一个 quantity。所以 SFC 不是“我们把 off-policy bias 修好了”。更准确地说,它做的是:
在 trainer-generator mismatch 已经存在的情况下,重新构造一个和真实 sampling distribution q ϕ q_\phi q ϕ 对齐的 centered gradient signal,让我们至少重新拿回 zero-mean score 以及 baseline invariance 这两个非常重要的结构。