GRPO算法解析:去掉Critic的组相对策略优化,如何降低RLHF训练成本

发布时间:2026/9/28 1:35:18
GRPO算法解析:去掉Critic的组相对策略优化,如何降低RLHF训练成本 这次要拆的是 DeepSeekMath 里那个省掉 critic 的 GRPO。如果你关心 RLHF 为什么这么贵、PPO 的价值网络到底有没有必要、以及怎么在数学推理任务里用一套更省内存的策略优化目标这篇文章可以直接收藏。GRPO 全称 Group Relative Policy Optimization组相对策略优化核心思路是同一个 prompt 采样一组输出组内比较算分数拿 z-score 标准化后的奖励替代传统 PPO 的优势函数。整个算法不训练价值模型也不走 GAE 那套时序差分估计实现和显存占用都会友好不少。这篇 H17 会按“背景 - 数学推导 - 直觉 - PPO 对比 - 工程实现 - 排查清单”的顺序展开。文中会用公式推一遍组内相对优势和 clip 近端更新目标也会给一个基于 TRL 库的最小可运行思路和一组调参建议。适合已经了解策略梯度、看过 RLHF 流程、但没真正动手推过 GRPO 公式的读者。如果你只是想知道“GRPO 能不能用、值得不值得试”先看第 1 节和第 6 节其他部分按需跳着看。1. GRPO 算法核心能力速览先给一张速览表把 GRPO 最关键的属性放在前面。这张表里的信息是算法设计层面的结论具体数值和框架实现需要按实际环境确认。能力项说明算法全称Group Relative Policy Optimization组相对策略优化提出来源DeepSeek 团队在 DeepSeekMath 技术报告中提出后续在多个开源 RLHF 框架中得到支持核心作用在 RLHF / 奖励模型训练阶段优化 LLM 策略替代 PPO 中的 critic 价值和 GAE 时序差分关键操作同一prompt采样 G 条回复对奖励做组内均值/标准差标准化得到组内相对优势近端更新复用 PPO 的 ratio clip 机制限制策略更新步长防止单步更新过大内存特点不训练 critic 模型省掉了价值网络的前向/反向计算、梯度和优化器状态显存占用通常低于标准 PPO典型应用数学推理、代码生成、规则验证器可自动判分的任务不适合场景开放对话中只能靠人工偏好评分的场景以及需要细粒度时序价值估计的任务GRPO 不一定占优实现生态TRL 提供 GRPOTrainerOpenRLHF 等方案也有对应支持硬件门槛由基底模型规模决定一般按 LLM 训练集群配置评估不依赖特殊设备从表里能看到GRPO 并不是一个全新的策略优化范式它只是把策略梯度框架里的“优势估计”这一环换成了组内统计量。正因为这样它可以直接复述 PPO 已经验证过的 clip 机制同时在内存和工程复杂度和让出一大块优势。2. RLHF 训练里PPO 的 critic 问题到底出在哪要理解 GRPO必须回到 RLHF 的实际训练流程里看问题。标准的 RLHF 一般分三步SFT 微调一个基座模型训练一个奖励模型 RM再用强化学习优化策略。第三步里最常用的算法是 PPO它的损失函数可以写成这样最大化形式$$J_{\text{PPO}}(\theta)E_{q\sim P(Q), o\sim \pi_{\theta_{\text{old}}}(\cdot|q)}\left[ \min\left(R_i(\theta)A_i,\ \text{clip}(R_i(\theta),1-\epsilon,1\epsilon)A_i\right)\right]$$其中 $R_i(\theta)\frac{\pi_\theta(o_i|q)}{\pi_{\theta_{\text{old}}}(o_i|q)}$ 是重要性采样比率$A_i$ 是优势函数。PPO 里这个 $A_i$ 不是随随便便一个数值它通常由 GAEGeneralized Advantage Estimation算出公式是$$A_t\sum_{l0}^{T-t}(\gamma\lambda)^l\delta_{tl},\quad \delta_tr_t\gamma V(s_{t1})-V(s_t)$$GAE 里需要价值函数 $V(s)$这个价值函数来自一个和策略模型并行的 critic 网络。于是问题就来了actor 模型多大critic 往往也得是同一量级。训练时前向要过两个大模型反向传播要存两份梯度优化器状态、显存、通信开销全部翻倍。而且价值网络本身也很难训奖励噪声大的时候 critic 学不好误差会顺着优势传递到策略梯度里导致训练不稳定。GRPO 针对的场景更聚焦如果任务的奖励不是来自模糊的人类偏好而是来自可自动判分的规则验证器比如数学题的最终答案对不对、代码能不能通过编译和测试用例那么我们对一批输出打分时并不需要一个能逐 token 预测长期回报的价值函数。我们只需要在同一组输出里比较“谁更好、好多少”。这就是组内相对优势的出发点。从工程角度看GRPO 把 RLHF 的一步训练从“两个大模型 GAE”变成了“一个大模型 采样组 简单 reward 统计”实现难度和资源门槛同步下降。这也是它在数学推理这类任务上迅速被采用的原因之一。3. 策略梯度与优势函数GRPO 的数学前置知识GRPO 的推导需要先确认两个概念策略梯度和重要性采样比率。虽然 PPO 已经是常见知识但为了后面推公式顺畅这里还是把基底写清楚。强化学习里最大化期望奖励的策略梯度可以写作$$\nabla_\theta J(\theta)E_{o\sim \pi_\theta}\left[ \nabla_\theta \log \pi_\theta(o|q)\ A(q,o)\right]$$其中 $A(q,o)$ 表示在给定 prompt $q$ 下输出 $o$ 相比平均表现的优势。策略梯度是无偏的但方差通常很大所以才需要引入 baseline 或者 critic 来降方差。优势函数越准策略梯度更新方向就越稳。由于当前 rollout 是用旧策略 $\pi_{\theta_{\text{old}}}$ 采样的更新时要用重要性采样$$R_i(\theta)\frac{\pi_\theta(o_i|q)}{\pi_{\theta_{\text{old}}}(o_i|q)}$$PPO 对 $R_i(\theta)$ 做 clip是为了防止一步更新后新旧策略差异太大。GRPO 完整保留了这个机制所以它也被称为“近端更新”思路的延续。区别只在于 $A_i$ 怎么算PPO 用 critic 估计价值函数GRPO 用组内奖励的标准化结果。4. GRPO 原理与数学公式推导现在进入全文最核心的部分。GRPO 总共有三个关键步骤组采样、组内标准化优势、clip 近端更新加 KL 正则。下面逐步推。4.1 从同一个 prompt 采样一组输出对于每个训练样本中的 prompt $q$GRPO 先从旧策略 $\pi_{\theta_{\text{old}}}$ 中采样 $G$ 个输出$$o_1,o_2,\dots,o_G\sim \pi_{\theta_{\text{old}}}(\cdot|q)$$这里的 $G$ 就是组大小。$G$ 越大组内统计量越稳但采样成本和 rollout 占用的显存、时间也会同步上升。TRL 中对应的参数通常是num_generations实际训练里常见取值从 4 到 16 不等具体取决于模型规模和设备余量。这组输出交给奖励模型得到一组奖励$$r_1,r_2,\dots,r_G$$奖励来源可以是训练好的 RM也可以是规则验证器。GRPO 本身并不绑定奖励来源只是在数学推理任务里规则验证器非常匹配这种组内比较的设计。4.2 组内相对优势与标准化公式第 $i$ 个输出的组内相对优势定义为$$A_i\frac{r_i-\text{mean}(\mathbf{r})}{\text{std}(\mathbf{r})}$$其中$$\text{mean}(\mathbf{r})\frac{1}{G}\sum_{j1}^{G}r_j$$$$\text{std}(\mathbf{r})\sqrt{\frac{1}{G}\sum_{j1}^{G}\left(r_j-\text{mean}(\mathbf{r})\right)^2\varepsilon}$$这里的 $\varepsilon$ 是防止除零的小常数。从形式上看$A_i$ 就是 z-score它做了两件事减去组内均值相当于用组内平均奖励作为 baseline。策略梯度添加一个不依赖当前样本的 baseline 不会改变期望梯度方向但能降低方差。组内平均奖励恰恰提供了一个很自然的 baseline它衡量“这组输出里到底哪个相对更好”。除以组内标准差相当于把不同 prompt、不同奖励尺度拉到同一个相对量级。比如一个简单 prompt 所有输出都拿到 0.8 到 0.9 的奖励另一个困难 prompt 所有输出在 0.2 到 0.4 之间直接拿原始 reward 当优势会让困难任务在梯度里被错误放大。标准化之后每个组内部的“好与坏”就具有了可比性。需要注意样本方差的无偏估计通常除以 $G-1$但工程实现里除以 $G$ 的版本也很常见因为 $G$ 本身不大加一个 $\varepsilon$ 后对训练结果影响较小。具体实现要参考对应框架源码。4.3 clip 近端更新目标有了 $A_i$策略比率依旧是$$R_i(\theta)\frac{\pi_\theta(o_i|q)}{\pi_{\theta_{\text{old}}}(o_i|q)}$$GRPO 的目标函数写成$$J_{\text{GRPO}}(\theta)E_{q\sim P(Q),{o_i}{i1}^{G}\sim \pi{\theta_{\text{old}}}(\cdot|q)}\left[\frac{1}{G}\sum_{i1}^{G}\left(\min\left(R_i(\theta)A_i,\ \text{clip}(R_i(\theta),1-\epsilon,1\epsilon)A_i\right)\right)\right]$$当 $A_i0$ 时说明这条输出优于组内平均。优化器希望增大它的概率即让 $R_i(\theta)$ 变大。但 clip 会把 $R_i(\theta)$ 限制在 $1\epsilon$ 以内防止一步更新过猛。当 $A_i0$ 时说明这条输出差于组内平均优化器会降低它的概率但同样限制在 $1-\epsilon$ 以下避免因为负优势过大把策略破坏掉。所以 GRPO 的“近端更新”来自 clip 机制这跟 PPO 一模一样。区别只是优势从 critic 换成了组内标准化奖励。4.4 加入 KL 正则的完整目标GRPO 不会让策略和参考策略偏离太远否则模型会开始乱说、忘记基础能力。因此目标函数里要加一项 KL 惩罚$$J_{\text{GRPO}}^{full}(\theta)E\left[\frac{1}{G}\sum_{i1}^{G}\left(\min\left(R_i(\theta)A_i,\ \text{clip}(R_i(\theta),1-\epsilon,1\epsilon)A_i\right)-\beta D_{KL}\left[\pi_\theta(o_i|q)|\pi_{\text{ref}}(o_i|q)\right]\right)\right]$$其中 $\pi_{\text{ref}}$ 是 SFT 之后的参考策略$\beta$ 控制 KL 的强度。如果训练中 KL 系数太小模型容易在奖励信号里过拟合KL 系数太大则策略几乎不更新。实际使用中$\beta$ 是需要重点调的超参数。有些实现会把 KL 惩罚放在序列生成阶段用逐 token 的 logits 来计算近似 KL有些实现直接按照上面的形式在损失里加 KL 项。两种方式各有取舍关键是要保证 KL 的监控曲线稳定。5. 组内标准化优势为什么能替代 critic组内标准化表面上看只是对 reward 做了一次归一化本质上却是在做一个“组内排序信号”。在数学题这类可判分任务里模型需要学会的是“提高正确输出概率、降低错误输出概率”并不需要精确模拟“每个 token 未来能带来多少奖励”。critic 的价值函数本来是用来逼近长期回报的但如果奖励是最终答案正确与否这种稀疏、离散的信号反而更适合用整条序列的组内相对优劣来驱动更新。换个角度说GRPO 把 PPO 里的“价值估计误差”问题转移成了“组内采样稳定性”问题。critic 会学偏采样组也会因为 $G$ 太小而不稳定但组内标准化有一个好处它对奖励尺度和偏离不敏感。即使不同 batch 之间奖励整体升高或降低组内标准差也会把这种全局漂移滤掉。结果是训练损失曲线的尺度比较稳定初始超参数通常能比 PPO 更容易调通。同时不训练 critic 意味着少维护一个模型。标准 PPO 训练中actor 和 critic 需要同时保存、同时更新、同时做梯度裁剪任何一边出问题都会影响另一边。GRPO 把这个耦合拆掉了工程上更容易做 checkpoint、更省内存、也更方便做单模型多卡的数据并行。RISK 也要讲清楚如果同一组输出彼此差异很小比如某个 prompt 下所有采样结果质量都很接近标准化后优势会被放大到一个夸张的范围。这时依赖奖励分布的形态可能产生噪声梯度。所以组采样质量很重要一般建议用带 temperature 的采样保证组内多样性。6. GRPO 与 PPO 的对比分析对比维度PPOGRPO优势估计critic 价值网络 GAE组内奖励 z-score 标准化额外模型一个与 actor 同量级的 value model无内存占用actor critic 双模型开销无 critic相对更省实现复杂度两个模型训练、GAE、价值损失、策略损失采样组 奖励统计 clip 目标适用奖励类型人类偏好、稀疏奖励、复杂长期回报可自动判分 / 奖励尺度明确的场景更适合训练稳定性受价值网络误差影响较大受组内采样多样性和 $G$ 影响较大超参数敏感度需要调 value loss 权重、GAE 参数主要调 $G$、$\beta$、clip 范围工程落地基础设施要求高相对容易复现开源框架支持多从这张表能看到GRPO 不是在所有场景下都碾压 PPO它是把“价值学习”从训练流程中拿掉换成更轻的组内统计估计。对数学、代码、规则验证器这类任务这个取舍普遍划算。对开放式聊天、人类偏好复杂的场景价值函数的泛化能力仍然有价值PPO 未必该被直接替换。7. GRPO 工程实现从公式到可运行代码公式推完落到工程上。下面给出一段展示 GRPO 核心流程的伪代码它不是某个框架的精确实现但把组采样、标准化、clip 损失三个关键步骤都接了起来。# GRPO 核心流程演示伪代码 # 实际工程需要处理 mask、pad、logprobs 累积方式等细节 import torch import torch.nn.functional as F def grpo_loss(logprobs_new, logprobs_old, rewards, eps0.2): logprobs_new: (G, seq_len) 当前策略的对数概率 logprobs_old: (G, seq_len) 采样时旧策略的对数概率 rewards: (G,) # 序列级别对数概率简化方式为 sum实际需按 mask 加权 ratio torch.exp( logprobs_new.sum(dim-1) - logprobs_old.sum(dim-1) ) # (G,) # 组内相对优势 mean rewards.mean() std rewards.std() 1e-8 advantages (rewards - mean) / std # (G,) # clip 近端更新 unclipped ratio * advantages clipped torch.clamp(ratio, 1.0 - eps, 1.0 eps) * advantages loss -torch.min(unclipped, clipped).mean() return loss注意这里的std()是样本标准差工程实现中要确定是除以 $G$ 还是 $G-1$同时关注数值稳定性。如果你不想手推这个 loss而是想直接在一个现成框架里体验 GRPO可以看 TRL 的 GRPOTrainer。TRL 官方仓库中给出了对应实现它的基本用法和 PPO Trainer 很接近。下面是一个参考形态的调用方式from transformers import AutoModelForCausalLM, AutoTokenizer from trl import GRPOTrainer, GRPOConfig model AutoModelForCausalLM.from_pretrained(your-base-model) tokenizer AutoTokenizer.from_pretrained(your-base-model) config GRPOConfig( output_dir./grpo_math_output, learning_rate1e-6, num_generations8, # 对应 G 8 max_completion_length512, beta0.04, # KL 惩罚系数 per_device_train_batch_size1, gradient_accumulation_steps4, ) trainer GRPOTrainer( modelmodel, argsconfig, train_datasettrain_dataset, tokenizertokenizer, reward_funcs[my_math_reward_func], # 规则验证器或奖励模型 ) trainer.train()这种配置的优点是你不需要自己写损失函数。训练时 GRPOTrainer 会为每个 prompt 采样num_generations条回复计算奖励组内标准化再调用 clip loss 做更新。一个最小实验流程可以是这样的先用一个 1B 左右的小模型准备 5000 条数学题 prompt每条 prompt 配一个规则验证器例如“最终答案是否等于标准答案”设置 $G8$先跑几十步观察 KL 曲线和 reward 变化。稳定之后再放大模型、加大数据量。先小规模跑通的意义是快速验证奖励分布是否合理如果验证器给出错误标注后面模型再强也没用。8. 资源占用与性能观察方法GRPO 相对 PPO 的显存优势主要来自不训练 critic。PPO 训练时actor 和 critic 都要做前向、反向、更新三组操作GRPO 只有 actor 一组。对于十几B甚至几十B的模型减少一个同量级模型意味着显存占用、通信量、优化器状态都成比例下降。不过具体能省多少需要看模型规模、batch size、序列长度、采样组大小。实际训练时建议把 GPU 利用率、显存占用、KL 均值、reward 均值这三类指标一起监控。GRPO 训练中最值得观察的曲线有三条组内奖励标准差如果一直很小说明采样输出过于同质化需要提高 temperature 或增大 $G$。KL 散度KL 快速上升说明策略正在偏离参考模型通常需要增大 $\beta$。整体 reward 均值只盯这一个指标不够因为它会随任务难度波动组内标准化已经过滤了尺度所以更多要看趋势。显存观察方法也很直接。训练时用nvidia-smi看每个进程占用或者用torch.cuda.max_memory_allocated()记录峰值。如果显存不足优先减少num_generations然后减小max_completion_length再考虑减小 batch size。采样长度对显存的影响通常比 prompt 长度更明显因为每条 prompt 会同时生成 $G$ 条完整输出。推理速度和训练吞吐也有关系。相同 batch 下$G$ 越大逆传播的样本数越多训练吞吐会下降。因此 GRPO 对 rollout 的效率要求更高工程上通常用 vLLM 这类高速推理引擎提前生成组内样本再用训练引擎更新策略。这也是为什么 GRPO 的成功复现往往不只是调参问题而是一个采样系统的性能问题。9. GRPO 训练常见问题与排查方法问题现象可能原因排查方式解决方案KL 快速爆涨$\beta$ 太小策略偏离参考模型过快查看 KL 曲线和 $\pi_\theta$ 与 $\pi_{\text{ref}}$ 的概率差调大 $\beta$降低学习率奖励曲线不涨奖励验证器本身有噪声或奖励信号和任务不对齐抽样检查 reward 标注正确率修正验证器或改用更可靠的 RM训练 loss 波动大$G$ 太小组内统计量不稳定观察组内 reward 标准差增大num_generations提高采样 temperature效果提升后快速遗忘基础能力KL 约束过弱策略过度对齐训练分布检查通用 benchmark 分数增大 $\beta$或加入参考策略混入训练显存溢出采样组 长序列导致 rollout 缓存过大用nvidia-smi查看峰值显存降低num_generations或max_completion_length所有组内优势都很接近 0采样退化成贪心解码组内输出几乎相同检查 generation 的 temperature、top_p 设置提高采样随机性打开冻结采样参数这些坑在 GRPO 复现过程中非常典型。相比 PPO 的价值网络误差GRPO 更容易出问题的地方是采样阶段组内不够多样标准化优势就失去意义。如果深度调优后仍然不稳定建议做一个消融对比固定同一份训练数据把 GRPO 和 PPO 分别跑同样的步数记录 KL、reward、评测分数三个维度。不要只看最终分数要看训练过程的稳定性。10. 最佳实践与后续扩展从实际训练角度给几条建议。第一次跑 GRPO 不要一上来就用大模型、大 batch先用小模型、小数据、几十步训练把流程跑通确认奖励函数、采样参数、KL 控制都没有问题再放大规模。模型小不代表算法验证不充分很多 reward 噪音和采样问题在小模型上反而暴露得更快。组大小 $G$ 的选择要结合奖励函数形态。如果奖励是二值的0 或 1组内输出很容易大部分落在同一个值上标准化后的优势可能会被放大得很夸张。此时可以把优势计算改成带平滑的形式或者考虑将奖励函数换成连续的打分。如果奖励来自 RM连续分布更稳。数据管理上建议把 prompt 数据集、reward 验证器、采样输出、checkpoint、日志分开目录存放每次实验记录一份参数记录。GRPO 的复现难点往往不在 loss 公式而在采样参数、数据切分、奖励函数版本这些看起来不重要的小事。训练前把 prompt 分 train/val不要让验证 prompt 泄漏到训练集。合规上也要提一句用公开模型和数据集做数学推理实验前确认数据集的授权范围如果奖励函数里包含人工偏好或用户内容需要做匿名化和授权处理。开源模型权重也遵循各自的许可证训练后的模型如果再发布需要检查模型 license。后续扩展可以从几个方向走把规则验证器换成更复杂的自动判分系统把 GRPO 和在线采样引擎 vLLM 结合提升 rollout 吞吐在代码生成任务上测试测试用例通过率奖励或者研究 $G$ 的退火策略训练初期用大 $G$ 稳定信号后期减小 $G$ 提高效率。另一个值得做的实验是把 KL 惩罚从固定系数改成自适应控制比如参考目标 KL 动态调节 $\beta$。最后说一句最实在的GRPO 使 RLHF 中“策略优化”这一步的门槛降了不少但它并不是魔法。第一次跑的时候重点盯组内 reward 分布、KL 曲线、pass1 趋势记录一次完整的成本和收益数据。这一套验证清楚后GRPO 就能真正成为你 RLHF 流程里可复用的组件。公式在这篇文章里已经推完代码框架给了参考剩下就是拿真实数据跑一轮验证它在你自己的场景里能不能稳定提分。