在之前的 PPO 细节探讨中,我们详细介绍了 PPO 算法和 GAE 优势估计。今天我们来深入探讨 GRPO(Group Relative Policy Optimization)算法,这是 PPO 在大语言模型训练中的一个重要改进版本。
GRPO 算法概述
在 LLM 的 RLHF 训练中,PPO 虽然表现良好,但仍存在一些可以改进的地方:
- GAE 的复杂性:PPO 使用 GAE 计算每个 token 的优势,涉及多个超参数($\lambda$、$\gamma$)的调优
- 价值函数的需求:PPO 需要训练一个 Critic 模型来估计状态价值,增加计算和内存成本
- 训练不稳定:在某些场景下,GAE 估计的方差仍然较大,导致训练波动
GRPO 通过一个更直接的方法来解决这些问题:将序列级的奖励直接分配到 token 级别,然后通过组内相对比较来计算优势。这种方法在实践中被证明更加稳定高效。
GRPO 的核心创新:
- 简化优势计算:不使用 GAE,而是通过组内相对奖励直接计算优势
- 减少计算负担:虽然仍需要参考模型,但优势计算逻辑更简洁
- 提高训练稳定性:通过序列奖励的分解和组内比较,减少方差
- Token 级别的精细控制:在每个 token 级别进行重要性采样和裁剪
GRPO 的动机
GRPO 相比 PPO 的改进方向:
| 问题 | PPO 解法 | GRPO 改进 |
|---|---|---|
| 优势计算 | 需要 Critic 估计价值,使用 GAE | 不需要 Critic,直接使用组内相对比较 |
| 方差 | GAE 通过多步累积,仍有较大方差 | 通过组内比较,方差更小 |
| 超参数 | $\lambda, \gamma$ 需要调优 | 更少的超参数 |
| 计算成本 | 需要训练两个模型 | 只需要一个模型+参考模型 |
GRPO 的三个核心模型
与 PPO 不同,GRPO 只需要三个模型:
| 模型 | 作用 | 参数更新 | 备注 |
|---|---|---|---|
| Actor | 生成回答的策略模型 | ✓ 需要 | 最终要部署的模型 |
| Reference | 参考模型,计算 KL 约束 | ✗ 不需要 | 通常是 SFT 模型的初始状态 |
| Reward Model | 评分函数,评估整体质量 | ✗ 不需要 | 在 RLHF 第一阶段提前训练好 |
关键区别:GRPO 相比 PPO 不需要 Critic 模型,这大大减少了训练的计算和内存成本。
GRPO 的算法原理
1. 序列奖励的分解
GRPO 的核心创新是如何将序列级的奖励分配到token 级别。
奖励分配机制
对于长度为 $T$ 的生成序列,Reward Model 给出一个标量奖励 $r_{\text{RM}}$。GRPO 将这个奖励分配到每个 token:
即:只有最后一个 token(序列终止位置)获得奖励,中间所有 token 的奖励为 0。
这与 PPO 中的 KL 惩罚方式不同(PPO 中每个 token 都有 的惩罚)。
为什么这样分配
- 简洁性:不需要为每个 token 计算即时奖励和 KL 惩罚的组合
- 合理性:反映了现实情况——我们只在完整回答后评分
- 直观性:整个序列的质量用一个数字衡量,然后均等分配(或按距离衰减)
2. Token 级别的重要性采样与裁剪
这是 GRPO 与 PPO 最重要的区别之一。
PPO 的做法(token 级别)
PPO 对每个 token 计算重要性采样比率:
然后进行裁剪和加权:
特点:重要性采样是 token 级别的,优势 $A_t$ 也是 token 级别的。
GRPO 的做法(仍是 token 级别,但优势不同)
GRPO 同样对每个 token 计算重要性采样比率:
然后进行裁剪和加权:
其中 $\tilde{A}_t$ 是 token 级别的归一化优势(见下一节)。
重要:GRPO 仍然是 token 级别的重要性采样和裁剪,但优势的计算方式不同。
3. 组内相对优势计算
这是 GRPO 最核心的创新。
序列优势(第一步)
对于生成的每个序列 $i$,根据其奖励计算序列级优势:
其中:
- $r_i$:第 $i$ 个序列的 RM 奖励
- $\bar{r} = \frac{1}{G} \sum_{j=1}^{G} r_j$:组内(所有 $G$ 个序列)的平均奖励
含义:这个序列相对于组内平均水平的相对优势。
Token 级优势(第二步)
GRPO 将序列优势分配给序列中的每个 token。最简单的做法是均等分配:
其中 $T_i$ 是第 $i$ 个序列的长度。
也可以使用折扣分配(越靠近末端权重越高):
其中 $\gamma \in [0,1]$ 是折扣因子(通常 0.99)。折扣分配的好处是给予序列末端(生成过程的最后)更高的权重,这更符合直觉:序列的最后部分对最终质量影响更大。
优势归一化
为了稳定训练,对组内的优势进行归一化:
其中:
- $\mu_A = \frac{1}{G \cdot T} \sum_i \sum_t \tilde{A}_t^{(i)}$:所有 token 优势的平均值
- $\sigma_A$:所有 token 优势的标准差
- $\epsilon$:小常数防止除零
4. 完整的损失函数
GRPO 的损失函数包含两部分:
策略损失
或者使用 PPO 风格的裁剪:
KL 约束损失
注意:GRPO 仍然保留 KL 约束,防止策略偏离参考模型太远。
GRPO 与 PPO 的详细对比
模型架构对比
| 维度 | PPO | GRPO |
|---|---|---|
| Actor | ✓ 需要训练 | ✓ 需要训练 |
| Critic | ✓ 需要训练 | ✗ 不需要 |
| Reference | ✓ 需要冻结 | ✓ 需要冻结 |
| Reward Model | ✓ 需要冻结 | ✓ 需要冻结 |
| 总体模型数 | 4 个 | 3 个 |
| 可训练参数 | Actor + Critic | 仅 Actor |
优势计算对比
| 维度 | PPO | GRPO |
|---|---|---|
| 信息来源 | 单个序列的 token 奖励 + Critic 价值估计 | 组内序列的相对奖励 |
| 计算方式 | GAE(加权累加多步 TD 误差) | 组内平均 - 单序列奖励 |
| 需要模型 | Critic 模型 | 无需额外模型 |
| 超参数 | $\lambda, \gamma, \beta_{\text{vf}}$ 等 | 组大小 $G$、折扣 $\gamma$、权重 $\beta$ |
| 方差 | 中等(GAE 加权后) | 较低(组内比较) |
| 偏差 | 低(无模型依赖) | 中等(依赖同组其他序列) |
重要性采样对比
| 维度 | PPO | GRPO |
|---|---|---|
| 采样粒度 | Token 级别 | Token 级别(与 PPO 相同) |
| 参考模型 | $\pi{\theta{\text{old}}}$(旧策略) | $\pi_{\text{ref}}$(参考模型) |
| 裁剪范围 | Token 级别 | Token 级别(与 PPO 相同) |
| 损失聚合 | 先平均 token 再平均序列 | 先平均 token 再平均序列(相同) |
关键相同点:GRPO 和 PPO 都在 token 级别进行重要性采样和裁剪,区别在于优势的计算来源。
优缺点对比
PPO 的优势
- 原理清晰:基于价值函数的强化学习理论
- 广泛应用:在各种 RL 任务中都有良好表现
- 灵活性强:可以适应各种奖励结构
- 理论支持:GAE 有深厚的理论基础
PPO 的缺陷
- 模型多:需要训练两个大模型(Actor + Critic)
- Critic 不准确:Critic 的价值估计可能不准确,导致优势估计有偏差
- 超参数多:GAE 的 $\lambda, \gamma$ 需要调优
- 计算成本高:训练 Critic 占用显存和计算力
GRPO 的优势
- 模型少:无需额外训练 Critic,只需 Actor
- 方差小:组内比较天然降低方差,不依赖模型准确性
- 简洁直接:优势计算逻辑简单明了
- 计算成本低:节省 Critic 的计算和内存
GRPO 的缺陷
- 需要分组:必须采样一个组的序列,组大小 $G$ 需要调优
- 依赖组质量:如果组内所有序列都很差,相对优势可能无法有效指导
- 序列奖励稀疏:不能充分利用中间步骤的反馈信息
- 较少应用:目前应用不如 PPO 广泛
GRPO 的实现细节
1. 分组采样
GRPO 的关键是在每次更新时采样一个组的序列。
采样策略
- 输入:一个 batch 的 prompts,共 $B$ 个
- 采样:对每个 prompt,采样 $G$ 个序列(即 $G$ 个不同的回答)
- 结果:得到 $B \times G$ 个序列
组大小选择
- $G = 4$:计算效率高,但相对优势估计可能不够准确
- $G = 8 \sim 16$:平衡效率和准确性(推荐)
- $G = 32$:优势估计准确,但计算成本大
实践建议:根据显存和计算资源选择,通常 $G = 8$ 或 $G = 16$。
2. 奖励获取与归一化
奖励获取流程
对每个序列:
- Actor 生成:Actor 生成完整序列
- RM 评分:将序列输入 RM,得到标量奖励 $r_{\text{RM}}$
- 记录:保存奖励值
奖励归一化
1 | # 对每个 prompt 的 G 个序列的奖励进行归一化 |
为什么归一化:
- 不同的 prompt 可能有不同的奖励尺度
- 归一化后的优势在 0 附近,梯度更稳定
3. Token 优势计算
算法步骤
对于第 $i$ 个序列(长度 $T_i$,奖励 $r_i$):
步骤 1:计算序列优势
步骤 2:分配到每个 token(选择一种)
方式 A:均等分配
方式 B:折扣分配
步骤 3:全局归一化
Python 伪代码
1 | def compute_advantages(rewards, sequence_lengths, discount=0.99): |
4. 损失计算与反向传播
Token 级别的损失计算
对于第 $i$ 个序列的第 $t$ 个 token:
重要性采样比率:
PPO 风格的裁剪损失:
其中 $\epsilon = 0.2$(裁剪范围)。
KL 约束
计算方式(对于语言模型):
在实际实现中,通常只计算被生成 token 处的 KL:
总体损失
单个序列的损失(先 token 后序列平均):
整个组的损失(序列平均):
Python 伪代码
1 | def compute_loss(logits, reference_logits, advantages, token_ids, beta=0.05, epsilon=0.2): |
5. 超参数设置
关键超参数
| 超参数 | 典型值 | 范围 | 说明 |
|---|---|---|---|
| $G$ (组大小) | 8-16 | 4-32 | 更大的组更稳定但计算成本高 |
| $\epsilon$ (裁剪范围) | 0.2 | 0.1-0.3 | 限制重要性采样比率的范围 |
| $\beta$ (KL 权重) | 0.05 | 0.01-0.2 | 平衡奖励追求和分布约束 |
| $\gamma$ (折扣因子) | 0.99 | 0.95-1.0 | 控制到末端 token 的权重衰减 |
| 学习率 | 5e-7 | 1e-7-1e-6 | 较小的学习率,通常比 SFT 小 100 倍 |
| 批大小 | $B=8, G=16$ | - | 总共 $B \times G$ 个序列 |
调优建议
$G$ 的选择:
- 显存充足:使用 $G = 16$ 或更大
- 显存紧张:使用 $G = 4$ 或 $G = 8$
- 避免 $G$ 过小($< 4$),否则相对优势不可靠
$\beta$ 的调优:
- 若 KL 散度过大:增大 $\beta$
- 若训练不动(模型变化太慢):减小 $\beta$
- 推荐从 $0.05$ 开始,根据 KL 散度监测值调整
学习率的选择:
- GRPO 的学习率通常比 SFT 小 100-1000 倍
- 从 5e-7 开始,根据梯度范数调整
- 避免学习率过大,否则训练不稳定
折扣因子 $\gamma$:
- $\gamma = 0.99$:末端 token 权重约为前端的 $0.37$ 倍
- $\gamma = 1.0$:均等分配(最简单)
- 推荐从 $\gamma = 1.0$ 开始,必要时调整
GRPO 的完整训练流程
算法伪代码
1 | 算法:GRPO 训练 |
训练流程图
1 | ┌─────────────────────────────────────────────────────┐ |
GRPO 完整数值示例
让我们用一个具体例子演示整个计算过程。
假设条件
- 批大小:$B = 1$(1 个 prompt)
- 组大小:$G = 2$(2 个序列)
- 序列长度:$T_1 = 3, T_2 = 4$(两个序列长度不同)
- 奖励:$r_1 = 0.8, r_2 = 0.6$(第一个序列更好)
- 折扣因子:$\gamma = 0.99$
- 裁剪范围:$\epsilon = 0.2$
- KL 权重:$\beta = 0.05$
计算过程
步骤 1: 计算序列优势
1 | 序列 1: r_1 = 0.8, T_1 = 3 |
解释:序列 1 相对于平均水平好一点,序列 2 相对于平均水平差一点。
步骤 2: 分配到 Token 级(使用折扣分配)
折扣分配公式:
其中分母是折扣权重的和。
序列 1 计算($T_1 = 3$):1
2
3
4
5
6折扣权重: γ^(3-1)=0.9801, γ^(3-2)=0.99, γ^(3-3)=1.0
权重和: 0.9801 + 0.99 + 1.0 = 2.9701
Token 1: A_1^(1) = (0.9801 * 0.1) / 2.9701 = 0.0330
Token 2: A_2^(1) = (0.99 * 0.1) / 2.9701 = 0.0333
Token 3: A_3^(1) = (1.0 * 0.1) / 2.9701 = 0.0337
序列 2 计算($T_2 = 4$):1
2
3
4
5
6
7折扣权重: γ^(4-1)=0.9703, γ^(4-2)=0.9801, γ^(4-3)=0.99, γ^(4-4)=1.0
权重和: 0.9703 + 0.9801 + 0.99 + 1.0 = 3.9404
Token 1: A_1^(2) = (0.9703 * (-0.1)) / 3.9404 = -0.0246
Token 2: A_2^(2) = (0.9801 * (-0.1)) / 3.9404 = -0.0249
Token 3: A_3^(2) = (0.99 * (-0.1)) / 3.9404 = -0.0251
Token 4: A_4^(2) = (1.0 * (-0.1)) / 3.9404 = -0.0254
观察:
- 序列 1 的最后 token (0.0337) 权重高于最前 token (0.0330)
- 序列 2 的所有优势都是负的(因为序列质量较差)
步骤 3: 全局归一化
所有 token 的优势值:1
2
3
4
5
6
7
8
9序列 1: [0.0330, 0.0333, 0.0337]
序列 2: [-0.0246, -0.0249, -0.0251, -0.0254]
合并: [0.0330, 0.0333, 0.0337, -0.0246, -0.0249, -0.0251, -0.0254]
均值: μ_A = (0.0330 + 0.0333 + 0.0337 - 0.0246 - 0.0249 - 0.0251 - 0.0254) / 7
= 0 / 7 = 0 (近似)
方差: σ_A ≈ 0.0291
归一化后(减去均值、除以标准差):1
2序列 1: [0.1134, 0.1145, 0.1159] (正值,鼓励)
序列 2: [-0.0846, -0.0856, -0.0863, -0.0873] (负值,惩罚)
步骤 4: 计算 PPO 损失
假设 Actor 和 Reference 模型在序列 1 的第 1 个 token 处:
- Actor log_prob: -1.5
- Reference log_prob: -1.6
- 生成的 token ID
计算过程:1
2
3
4
5
6
7
8
9
10log_ratio = -1.5 - (-1.6) = 0.1
ratio = exp(0.1) ≈ 1.105
优势: A_hat_1^(1) = 0.1134
无裁剪: ratio * A_hat = 1.105 * 0.1134 ≈ 0.1253
有裁剪: clip(ratio, 0.8, 1.2) = 1.105
clipped * A_hat = 1.105 * 0.1134 ≈ 0.1253
PPO loss: min(0.1253, 0.1253) = 0.1253
步骤 5: KL 散度
假设 KL 散度计算(简化):1
2
3
4
5KL_1^(1) = log_ratio = 0.1
总 KL 损失 (简化,仅示意):
L_KL = β * log_ratio_sum / num_tokens
= 0.05 * (所有 log_ratio 之和) / 7
最终损失
1 | 序列 1 损失: L_1 = (L_policy_1 + β * L_KL_1) / 3 |
关键观察:
- 序列 1 的优势为正,鼓励增加这些 token 的概率
- 序列 2 的优势为负,抑制这些 token 的概率
- Token 级别的优势差异(末端 > 前端)反映了对最终质量的贡献
GRPO 的收敛性与稳定性
方差分析
GRPO 相比 PPO 的方差优势来自于:
组内相对比较:
- PPO 使用单个序列的价值函数差分 $\delta_t$,仅与该序列相关
- GRPO 使用组内所有序列的平均,$E[\text{Var}(A_t)]$ 更小
不依赖模型准确性:
- PPO 的 GAE 依赖 Critic 的准确性
- GRPO 直接使用真实奖励,无模型误差
折扣分配的效果:
- 给予末端更高权重,减少信号的不确定性
收敛性证明
GRPO 的收敛性可以通过以下论证:
- 策略改进:每次更新时,$\mathbb{E}[r_t A_t] \geq 0$ 当 $A_t > 0$
- KL 约束限制:防止策略离开信任域(trust region)
- 优势无偏估计:组内比较提供无偏的相对信号
定理(简化版):在合理的假设下,GRPO 的策略序列收敛到满足 KL 约束的最优策略。
GRPO 在实践中的表现
DeepSeek 的实验结果
根据 DeepSeek 的研究报告,GRPO 在以下指标上表现出色:
数学推理任务(GSM8K/MATH)
- 收敛速度:更快(通常 10-50% 的步数)
- 最终效果:相当或优于 PPO(特别是在数学问题上)
- 训练稳定性:更稳定,奖励波动更小
通用能力(基准测试)
- 不会显著退化:通过 KL 约束保持基础能力
- 任务特定性强:在目标任务上显著改进,日常闲聊改进不大
- 内存节省:相比 PPO 节省 20-30% 的显存(无需 Critic)
什么情况下 GRPO 更好
- 有明确的 RM 评分:任务有定量的奖励信号(数学、代码、写作评分等)
- 大规模模型:模型越大,Critic 的省省成本越显著
- 单轮生成:适合生成单个长序列的场景(如数学推导、代码)
GRPO 可能不如 PPO 的情况
- 奖励信号不清晰:RM 评分方差大、不稳定
- 组大小受限:显存不足,无法采样足够大的组
- 多步交互任务:需要按步骤获得反馈的任务
常见问题与解答
Q1: GRPO 是否需要参考模型?
A: 是的。GRPO 需要参考模型来计算 KL 约束,防止策略漂移。虽然 GRPO 不需要 Critic,但仍需要 Reference 模型(通常是 SFT 模型的冻结副本)。
Q2: GRPO 的组大小 G 应该怎么选?
A:
- 最小值:$G \geq 4$(否则相对优势不可靠)
- 推荐值:$G = 8 \sim 16$(平衡准确性和效率)
- 最大值:受显存限制,通常 $G \leq 32$
根据经验,$G$ 增加一倍通常能稍微改进效果但计算成本翻倍。
Q3: GRPO 会过度拟合组内序列吗?
A: 有可能。如果组大小 $G$ 太小,相对优势的估计可能不稳定。解决方案:
- 增加 $G$ 的大小
- 跨 batch 计算优势(不仅限于单个 batch 内的序列)
- 加入额外的正则化
Q4: GRPO 的 KL 散度约束怎么调?
A: 观察 KL 散度的值:
- 若 KL > 0.1:$\beta$ 太小,增大 $\beta$
- 若 KL < 0.01:$\beta$ 太大,减小 $\beta$
- 目标范围:0.01-0.05
Q5: GRPO vs PPO,我应该选哪个?
A: 根据以下决策树:
1 | 计算资源充足? |
总结
GRPO 代表了 LLM RLHF 训练的一个重要方向,其核心贡献包括:
- 简化优势计算:从复杂的 GAE 到简单的组内相对比较
- 减少计算负担:不需要额外的 Critic 模型
- 提高稳定性:组内比较天然降低方差
- 实用高效:在大规模模型上表现更好
关键理解:
- GRPO 仍然是 token 级别的重要性采样和裁剪(与 PPO 相同)
- GRPO 的创新在于优势的计算方式(组内相对而非 GAE)
- GRPO 和 PPO 是互补的方法,根据具体场景选择
推荐阅读: