在开始推导之前,仍然先把我们考虑的核心目标列出:
J(θ)=Eq∼D,o∼π[R(q,o)]
这里的 q 代表的是我们的 Prompt,而这里的 o 则代表模型对于这个 Prompt 的输出序列:(o1,o2,…,oT),这里我们的奖励 R 则代表了最后回答的奖励以及 KL 散度约束。
根据策略梯度的原理,我们可以写出最基本的梯度估计:
∇θJ(θ)=E[R(q,o)1∑T∇θlogπθ(ot∣q,o<t)]
在我们实际的训练中,由于单纯使用 R 会遇到方差难以控制的问题,所以现有的方法都会减去一个 Baseline:
∇θJ(θ)=E[(R(q,o)−b)1∑T∇θlogπθ(ot∣q,o<t)]
而 PPO 和 GRPO 的核心区别就是当前减去的 Baseline 或优势函数是如何计算出来的。
PPO 的优势函数计算
PPO 往往通过 GAE 的计算方法来得到优势函数:
δt=rt+γVψ(st+1)−Vψ(st)
A^tGAE=l=0∑T−t(γλ)lδt+l
而一般 PPO 的优化目标是:
JPPO(θ)=E[T1t=1∑Tmin(ρtA^t,clip(ρt,1−ε,1+ε)A^t)]
其中,ρ 代表的是当前策略和更新前 Old 策略的概率比:
ρt=πold(ot∣q,o<t)πθ(ot∣q,o<t)
但是在 PPO 的训练中我们需要同步训练一个 Value Model 用于随时计算优势,这会带来额外的不稳定性以及开销。
GRPO 的解决方法
GRPO 不训练价值模型,对于同一个问题 q,我们可以 Rollout 多条回答:
o1,o2,…,oG∼πold
并分别计算出他们各自的奖励 ri=R(q,oi),这样可以得到一组奖励 r=(r1,r2,…,rG)。而我们就可以计算组内的平均值和标准差:
μr=G1i∑Gri, σr=G1i∑G(ri−μr)2
我们就可以把一个回答的优势表示为:
A^i=σrri−μr
在实际的操作中,我们会给标准差加上一个微小的值来防止除零。
实际的 GRPO 目标函数和 PPO 几乎一致,可以完整的写成:
JGRPO(θ)=E[G1i=1∑GTi1t=1∑Ti(min[ρi,t(θ),clip(ρi,t,1−ϵ,1+ϵ)]⋅A^i,t−βDKL(πθ∣∣πref)i,t)]
其实除了加入了组(G)这个维度,以及将优势函数的计算替换掉,其余部分和 PPO 没有本质的区别。需要关注的是,在计算 KL 散度的时候,传统的 PPO 往往会让逐 Token 的 KL 散度融合到每一个 Token 的奖励里,但是在 GRPO 中往往 KL 散度作为一个单独的项进行计算。
DeepSeekMath 论文中的 GRPO
在实际的 DSM 的论文中,他们使用了过程奖励模型,也就是不仅仅在一个 Rollout 的末尾 Token 才给奖励,而是在中间分多个阶段进行奖励,这样可以让整体的奖励变得更加密集。
我们可以把一次 Rollout 中的一个回答 oi=(a1,a2,…,aT) 分为 K 个阶段,每一个阶段就给一个奖励:
riindex(1),riindex(2),…,riindex(Ki).
接下来就可以对每一个步骤的奖励进行组内的归一化:
riindex(j)=std(R)riindex(j)−mean(R).
接下来就可以通过 γ=1 的设置,来把阶段性的奖励扩散到前面的时间步去:
A^i,t=index(j)≥t∑riindex(j)
这样就得到了每一个位置的优势分数,而不必再进行像 PPO 那样的复杂计算。