推理模型的训练流程通常分为两个阶段:先用监督微调(SFT)让模型学会基本的思维链格式,再用强化学习(RL)让模型在真实任务中探索更优的推理路径。第二阶段直接决定了模型推理能力的上限。目前可选的算法不少,其中PPO是最经典的策略梯度方法,而GRPO(Group Relative Policy Optimization)则是DeepSeekMath提出、被DeepSeek-R1验证有效的轻量方案。两者在核心思想上有继承关系,但在工程开销和训练效果上差异明显,选错算法可能让训练成本翻倍,甚至导致训练崩溃。本文从原理入手,把这两种算法讲清楚。

PPO的核心原理与在推理训练中的局限
PPO(Proximal Policy Optimization)的核心思想是限制每次策略更新的幅度,避免一次大步更新把模型带偏。它引入了一个裁剪的代理目标函数,把新旧策略的概率比值限制在一个小区间内,比如常见的0.8到1.2。这样即使某个样本的梯度很大,实际更新量也会被截断,训练过程相对稳定。
但PPO有一个绕不开的组件:价值网络(critic)。为了估计优势函数,PPO需要训练一个与策略模型规模相当的价值模型,用它来预测每个状态的价值,再结合奖励计算优势。这个设计在普通对话任务中问题不大,但在推理训练中会遇到麻烦。推理任务的一条完整轨迹动辄几千甚至上万token,如果对每个token都做信用分配,价值网络必须逐token学习价值估计,这在长序列上非常困难,也容易带来偏差。
更现实的问题是显存。训练一个7B的推理模型,PPO需要同时在GPU上放置策略模型、参考模型、奖励模型和价值模型四份模型,其中价值模型和策略模型都要参与梯度计算。显存占用接近GRPO方案的两倍,在长上下文场景下这个问题会被进一步放大。这也是为什么很多团队在做推理训练时,第一反应就是找PPO的替代品。
GRPO的核心思想:用组内基线替代价值网络
GRPO的关键洞察是:优势估计不一定要靠价值网络,可以用同一个问题的多次采样结果做相对比较。具体做法是,对每个问题采样一组回答(比如8个或16个),计算每个回答的奖励,然后用组内平均奖励作为基线,每个回答的优势就是它自己的奖励减去组内平均值。奖励高于平均的回答获得正优势,低于平均的获得负优势。
这个设计的数学基础可以追溯到RLOO(REINFORCE Leave-One-Out)一类的无偏基线估计方法。由于组内奖励的期望与策略相关,直接用组均值做基线存在轻微偏差,但实践证明这点偏差对训练影响很小,换来的是省掉整个价值网络的巨大收益。下面是一个简化的GRPO优势计算伪代码:
import torch
def compute_grpo_advantage(rewards):
# rewards: shape为[group_size],同一问题的多个回答的奖励
# 组内标准化,减去均值除以标准差
mean = rewards.mean()
std = rewards.std()
advantages = (rewards - mean) / (std + 1e-8)
return advantages
rewards = torch.tensor([1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0])
advantages = compute_grpo_advantage(rewards)
print(advantages)
# 正确答案获得正优势,错误答案获得负优势去掉价值网络之后,GRPO只需要策略模型、参考模型和奖励函数三部分,显存占用直接减半。而且策略梯度的估计直接建立在完整回答的奖励之上,不再依赖逐token的价值学习,对长链推理这种奖励稀疏、轨迹漫长的任务反而更契合。这就是GRPO成为推理训练主流算法的原因。
损失函数设计:裁剪、KL惩罚与长度归一
GRPO完整保留了PPO的裁剪机制,同时把KL散度惩罚从奖励中拿出来,直接加到损失函数里。早期DeepSeekMath的版本把KL惩罚算进每个token的奖励里,后来DeepSeek-R1等实现改为在损失上直接加KL项,用一种无偏的低方差估计器(k3估计器)来计算,两种做法效果上有差异,后者更常见也更稳定。一个典型的GRPO损失如下:
def grpo_loss(log_probs_new, log_probs_old, log_probs_ref,
advantages, clip_eps=0.2, beta=0.04):
# 概率比值
ratio = torch.exp(log_probs_new - log_probs_old)
# 裁剪的代理目标
surr1 = ratio * advantages
surr2 = torch.clamp(ratio, 1 - clip_eps, 1 + clip_eps) * advantages
policy_loss = -torch.min(surr1, surr2).mean()
# KL惩罚项(k3无偏估计,恒为非负)
kl = (log_probs_ref - log_probs_new).mean()
kl_loss = beta * (torch.exp(kl) - kl - 1).mean()
return policy_loss + kl_lossKL惩罚的作用是防止模型偏离参考模型太远。推理训练中如果完全放开,模型很容易找到奖励模型的漏洞,输出一些格式正确但逻辑错误的回答刷分,出现严重的reward hacking。KL项像一根缰绳,把探索限制在参考模型附近的可信区域内。系数beta的取值需要平衡探索与约束,常见取值在0.001到0.04之间,任务越依赖探索可以取越小。
另外还有一个容易被忽视的细节:token级别的损失归一。GRPO会把同一个回答内所有token的优势设为相同值(因为奖励只在回答结束才给出),然后在计算损失时对总token数做平均。这种做法会让长回答的每个token权重被稀释,有实验表明改成对回答条数归一、或者干脆不做长度归一,能缓解模型输出越来越长的退化倾向。
实践中的调参要点与选型建议
组采样数量是GRPO最重要的超参数。组太小(比如4以下)基线估计噪声大,优势信号不准;组太大(比如64以上)计算成本线性上涨但收益递减。一般取8到16比较合适,如果任务奖励区分度高可以适当减小。还有一个关键前提:组内必须存在奖励差异。如果一组回答全对或全错,所有优势都是零,这批数据就没有梯度信号。实践中通常会过滤掉这类全对全错的组,或者调整采样温度保证多样性。
奖励设计直接决定训练走向。数学类任务可以用答案正确性做二值奖励,非常干净;代码类任务靠单元测试通过率;通用推理任务往往需要奖励模型打分,但奖励模型引入后reward hacking的风险也随之上升。一个常用技巧是混合规则奖励与格式奖励,比如答案正确给1分,思维链格式规范给0.1分,让模型在学会推理的同时保持输出格式稳定。
选型上,两者的界限其实比较清晰。如果你的任务有客观可验证的奖励(数学、代码),显存预算有限,长链推理是主要目标,GRPO几乎是默认选择,主流训练框架如TRL、veRL、OpenRLHF对它的支持也都比较成熟。如果你需要处理无法批量采样的场景,或者任务对逐步信用分配有明确需求,PPO配合GRPO化的价值估计也是一种混合思路。实际上不少团队的实践是把GRPO当作起点,遇到训练不稳定时再回头调整裁剪范围、KL系数和采样温度,而不是直接换回PPO。把算法选对只是第一步,奖励函数的质量和数据的干净程度,往往比算法本身更影响最终效果。
GRPOPPO推理模型强化学习微调修改时间:2026-09-04 22:50:52