GRPO 的形式以及解决的问题

在开始推导之前,仍然先把我们考虑的核心目标列出:

J(θ)=EqD,oπ[R(q,o)]J(\theta) = \mathbb{E}_{q\sim D,o\sim \pi}[R(q,o)]

这里的 qq 代表的是我们的 Prompt,而这里的 oo 则代表模型对于这个 Prompt 的输出序列:(o1,o2,,oT)(o_1,o_2,\dots,o_T),这里我们的奖励 RR 则代表了最后回答的奖励以及 KL 散度约束。

根据策略梯度的原理,我们可以写出最基本的梯度估计:

θJ(θ)=E[R(q,o)1Tθlogπθ(otq,o<t)]\nabla_\theta J(\theta)=\mathbb{E}\left[ R(q,o)\sum_1^T \nabla_\theta \log \pi_\theta(o_t|q,o_{<t}) \right]

在我们实际的训练中,由于单纯使用 RR 会遇到方差难以控制的问题,所以现有的方法都会减去一个 Baseline:

θJ(θ)=E[(R(q,o)b)1Tθlogπθ(otq,o<t)]\nabla_\theta J(\theta)=\mathbb{E}\left[ \left(R(q,o)-b\right)\sum_1^T \nabla_\theta \log \pi_\theta(o_t|q,o_{<t}) \right]

而 PPO 和 GRPO 的核心区别就是当前减去的 Baseline 或优势函数是如何计算出来的。

PPO 的优势函数计算

PPO 往往通过 GAE 的计算方法来得到优势函数:

δt=rt+γVψ(st+1)Vψ(st)\delta_t = r_t+\gamma V_\psi(s_{t+1})-V_\psi(s_t) A^tGAE=l=0Tt(γλ)lδt+l\hat A_t^{\mathrm{GAE}} = \sum_{l=0}^{T-t} (\gamma\lambda)^l\delta_{t+l}

而一般 PPO 的优化目标是:

JPPO(θ)=E[1Tt=1Tmin(ρtA^t,clip(ρt,1ε,1+ε)A^t)]J_{\mathrm{PPO}}(\theta) = \mathbb E \left[ \frac{1}{T} \sum_{t=1}^{T} \min \left( \rho_t\hat A_t,\, \operatorname{clip} (\rho_t,1-\varepsilon,1+\varepsilon) \hat A_t \right) \right]

其中,ρ\rho 代表的是当前策略和更新前 Old 策略的概率比:

ρt=πθ(otq,o<t)πold(otq,o<t)\rho_t = \frac{\pi_\theta(o_t|q,o_{<t})}{\pi_{old}(o_t|q,o_{<t})}

但是在 PPO 的训练中我们需要同步训练一个 Value Model 用于随时计算优势,这会带来额外的不稳定性以及开销。

GRPO 的解决方法

GRPO 不训练价值模型,对于同一个问题 qq,我们可以 Rollout 多条回答:

o1,o2,,oGπoldo_1,o_2,\dots,o_G \sim \pi_{old}

并分别计算出他们各自的奖励 ri=R(q,oi)r_i = R(q,o_i),这样可以得到一组奖励 r=(r1,r2,,rG)r = (r_1,r_2,\dots,r_G)。而我们就可以计算组内的平均值和标准差:

μr=1GiGri, σr=1GiG(riμr)2\mu_r = \frac{1}{G} \sum_i^G r_i,\ \sigma_r = \sqrt{\frac{1}{G}\sum_i^G(r_i - \mu_r)^2}

我们就可以把一个回答的优势表示为:

A^i=riμrσr\hat{A}_i = \frac{r_i - \mu_r}{\sigma_r}

在实际的操作中,我们会给标准差加上一个微小的值来防止除零。

实际的 GRPO 目标函数和 PPO 几乎一致,可以完整的写成:

JGRPO(θ)=E[1Gi=1G1Tit=1Ti(min[ρi,t(θ),clip(ρi,t,1ϵ,1+ϵ)]A^i,tβDKL(πθπref)i,t)]J_{GRPO}(\theta) = \mathbb{E}\left[ \frac{1}{G}\sum_{i=1}^G \frac{1}{T_i} \sum_{t=1}^{T_i} \left( \min \left[ \rho_{i,t}(\theta) ,\text{clip}(\rho_{i,t},1-\epsilon,1+\epsilon) \right] \cdot\hat{A}_{i,t} -\beta D_{KL}(\pi_\theta||\pi_{\text{ref}})_{i,t} \right) \right]

其实除了加入了组(GG)这个维度,以及将优势函数的计算替换掉,其余部分和 PPO 没有本质的区别。需要关注的是,在计算 KL 散度的时候,传统的 PPO 往往会让逐 Token 的 KL 散度融合到每一个 Token 的奖励里,但是在 GRPO 中往往 KL 散度作为一个单独的项进行计算。

DeepSeekMath 论文中的 GRPO

在实际的 DSM 的论文中,他们使用了过程奖励模型,也就是不仅仅在一个 Rollout 的末尾 Token 才给奖励,而是在中间分多个阶段进行奖励,这样可以让整体的奖励变得更加密集。

我们可以把一次 Rollout 中的一个回答 oi=(a1,a2,,aT)o_i = (a_1,a_2,\dots,a_T) 分为 KK 个阶段,每一个阶段就给一个奖励:

riindex(1),riindex(2),,riindex(Ki).r_i^{\operatorname{index}(1)}, r_i^{\operatorname{index}(2)}, \ldots, r_i^{\operatorname{index}(K_i)}.

接下来就可以对每一个步骤的奖励进行组内的归一化:

r~iindex(j)=riindex(j)mean(R)std(R).\widetilde r_i^{\operatorname{index}(j)} = \frac{ r_i^{\operatorname{index}(j)} -\operatorname{mean}(\mathbf R) }{ \operatorname{std}(\mathbf R) }.

接下来就可以通过 γ=1\gamma =1 的设置,来把阶段性的奖励扩散到前面的时间步去:

A^i,t=index(j)tr~iindex(j)\hat A_{i,t} = \sum_{\operatorname{index}(j)\ge t} \widetilde r_i^{\operatorname{index}(j)}

这样就得到了每一个位置的优势分数,而不必再进行像 PPO 那样的复杂计算。


back to the post list