news 2026/10/20 11:54:03

GRPO强化学习:从PPO到群体相对策略优化的对齐新范式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
GRPO强化学习:从PPO到群体相对策略优化的对齐新范式

最近翻了一圈大模型算法岗的面经,"GRPO"这个词出现频率高得吓人。前两年大家还在问PPO怎么调参、GAE怎么算,现在面试官开口就是GRPO和PPO到底差在哪、为什么LLM对齐都开始往GRPO上转。这其实释放了一个信号:大模型强化学习的面试,已经从"背PPO公式"进化到"理解对齐训练的工程取舍"了。

这篇文章就围绕GRPO强化学习来写,从它要解决的问题、数学原理、训练流程,到面试里会被连环追问的细节,以及我自己在训练中踩过的坑,一次讲透。无论你是准备面试还是真要在项目里落地GRPO,按这个思路梳理一遍,基本能把大部分追问接住。

1. 从PPO到GRPO:大模型对齐里正在发生的范式切换

要理解GRPO为什么火,先得看它出现之前行业在用什么。大模型做强化学习对齐,标准路线是RLHF,核心算法用PPO。PPO在游戏机器人这类场景里很成熟,但搬到LLM上,暴露出一个特别尴尬的问题。

1.1 PPO在大模型场景的尴尬:一个仓库里塞四个大象

PPO训练一个LLM对齐策略,至少需要四个模型同时在线:策略模型负责生成、参考模型负责约束KL散度、奖励模型负责打分、还有Critic价值网络来估计状态价值。

问题就出在Critic上。PPO里面Critic学的是V(s),用来计算优势函数A = Q - V,本质上是一个baseline,用于降低策略梯度的方差。但在LLM场景里,这个Critic必须和策略模型同规模,策略是7B参数,Critic也得7B;策略是70B,Critic也是70B。这就意味着显存、计算量、工程复杂度全部翻倍。

更要命的是,Critic在LLM上还特别难训。语言生成的过程并不是传统强化学习那种严格的马尔可夫决策过程,每一步的token状态价值非常难估计,奖励又往往只在生成结束之后给出。结果就是Critic算出来的V(s)经常是个很糊的值,误差一大量化到优势函数里,策略更新方向都是抖的。很多团队训练LLM时发现,Critic的loss收敛了,但策略就是提不上去,问题就出在价值函数压根教不准。

1.2 GRPO的解题思路:不学baseline了,直接用样本组做baseline

GRPO的全称是Group Relative Policy Optimization,群体相对策略优化。它的核心观察很朴素:既然我不知道这个prompt在某种策略下到底值多少分,那我干脆让老策略一次采样多个输出,把这组输出互相比一比,不就有相对好坏了吗?

也就是说,对同一个prompt,用当前策略采样G个response,奖励模型逐个打分,然后做组内归一化,把每个样本的得分减去组均值再除以组标准差,得到的值直接作为优势函数。效果上等效于给每个样本算了一个"相对表现",高分样本获得正优势,低分样本获得负优势。

这一下就把Critic整个去掉了。训练时只有策略模型、参考模型、奖励模型三件套,内存压力直接降了一个级别。而且组内比较相比绝对打分更robust,就算奖励模型对大分和小分的刻度漂移了,只要组内相对排序是对的,归一化后照样稳定。

面试官问GRPO,其实想听的往往不是公式背得多熟,而是你能不能讲清楚这个"用采样组代替价值网络"的逻辑。背后的本质是:在LLM的奖励信号非常稀疏、价值函数难以估计的前提下,用Monte Carlo样本组的相对序来近似优势,比学一个困难的回归模型更可靠。

2. 拆掉critic之后:GRPO的优势函数到底怎么算

GRPO去掉Critic之后,最核心的计算点就落在组内归一化这一步。很多面试者知道公式,但被追问到"为什么除以std而不是只减均值"就卡住了,这里我拆开讲。

2.1 组内归一化:一个带有白化性质的baseline

给定一个prompt q,旧策略π_old采样出G个输出,记为o_1, o_2, ..., o_G。奖励模型对每个输出打分,得到r_i。GRPO对每个样本计算优势:

A_i = (r_i - mean(r)) / (std(r) + eps)

减去mean(r)就是减掉组内baseline,这是关键。因为同一个prompt在不同策略下可达到的奖励高度不同,一个本身就很简单的prompt,所有输出分数都高,一个极难的prompt,输出分数都低。如果不做组内比较,跨prompt直接对比绝对分数,那么在难样本上的正确行为会被错误压制。组内减去均值,就保证每个prompt组里总有一半正优势一半负优势,困难样本里相对不错的输出也能获得正向更新。

除以std(r)则是白化处理。reward model的分数尺度在不同任务、不同阶段会飘,早期可能集中在某小区间,后期可能分散开。除以标准差后,优势函数变成相对单位,这样不同prompt之间的更新步长可比,梯度不至于被个别离群组带偏。

2.2 策略梯度损失:PPO的骨架,GRPO的肉

有了优势A_i,剩下的更新目标跟PPO就同源了。令ρ_i = π_θ(o_i|q) / π_old(o_i|q),也就是新旧策略在生成序列上的概率比,GRPO的损失为:

J(θ) = E [ 1/G * Σ_i min(ρ_i * A_i, clip(ρ_i, 1-ε, 1+ε) * A_i) ] - β * KL(π_θ || π_ref)

前半部分是标准的PPO clip目标,后半部分是KL惩罚,约束策略不要偏离参考模型太远。注意优势A_i不是token级别的,而是整个response共享一个值,也就是说这个response里生成的所有token,都拿同一个优势去更新。

这里有个必须说清楚的细节:概率比ρ_i是序列级还是token级的。GRPO的实现中,通常要对每个token的log prob求差再累加,最终ρ = exp(Σ(log π_θ - log π_old))。也就是说,一个response整体被当作一条轨迹来处理,序列越长,这个乘积越小越容易出现数值下溢,所以工程上都用log-sum-exp技巧处理。

2.3 手算一个G=4的例子,感受归一化威力

假设奖励模型对某个prompt的四个输出打分是[1, 2, 4, 2]。组均值是2.25,组标准差约1.09。

  • 第一个样本:A = (1 - 2.25) / 1.09 ≈ -1.15,负优势,模型要降低这个response的概率

  • 第二个样本:A = (2 - 2.25) / 1.09 ≈ -0.23,轻微负优势,小幅降低

  • 第三个样本:A = (4 - 2.25) / 1.09 ≈ 1.61,正优势,重点提高

  • 第四个样本:A = -0.23,另一个中等样本,也小幅降低

可以看到,哪怕绝对分数都集中在2附近,归一化之后也有正负之分。这比直接用raw reward做策略梯度要稳定得多,因为raw reward的绝对值并没有"合格线"可以作为正负分界。

这里我多说一句实战中的选择:如果你奖励分数分布极度扁平,std会特别小,除出来的优势极大,容易梯度爆炸。工程上要么给std加一个epsilon,要么改成rank-normalize,也就是把分数先转成[0,1]的均匀排名,再做均值中心化。后者更稳定,我在实际使用中偏好rank-normalize。

3. GRPO训练流程与计算图:从采样到梯度更新

面试到了这一层,已经不只是考公式,而是考你有没有真正跑起来过训练。GRPO的训练迭代可以拆成六个明确步骤,每一步都有对应的时间、显存开销。

3.1 一次完整迭代的六个步骤

第一步是采样。从当前策略模型对每个prompt生成G个response。这里的temperature一般设到1.0左右甚至更高,因为组内比较需要样本有足够的多样性,如果temperature过低,G个输出长得差不多,归一化后没有区分度。

第二步是打分。把G个response交给奖励模型打分,得到一组标量。注意reward model的输入通常需要带上prompt,不然模型可能不记得上下文。

第三步是组内归一化,按上文公式计算出每个response的优势值。

第四步是回算log prob。分别用旧策略的快照和新策略的当前参数,计算这G个response的log prob。旧策略的log prob在采样时应该已经缓存下来,不需要重复前向。新策略的log prob需要当前参数下的完整前向计算,这一步是训练的主要计算开销。

第五步是组装loss。把概率比、优势、clip范围代入,算策略梯度损失,外加KL惩罚。KL惩罚通常也要用参考模型前向过一遍这G个response。所以一次迭代里,策略模型前向一次(求新logp)、参考模型前向一次(求KL)、奖励模型前向几次(打分),再加上逆向传播一次。

第六步是更新参数,然后清空缓存,进入下一个batch。整个过程完全是on-policy的,意味着每一个梯度步骤之后,policy变了,下一轮必须重新采样,这跟离线RL有本质区别。

3.2 一个最小可跑通的核心流程伪代码

为了便于理解,我给出一个高度简化的PyTorch风格伪代码,重点展示loss拼接逻辑,实际的分布式版本要处理的数据并行、G个response的packing这些细节这里略过。

# 假设已有 policy_model, ref_model, reward_model # batch: 一批prompt, G: 每组采样数量 for batch_prompts in dataloader: # 1. 采样G个response,并缓存log probs outputs, old_log_probs = policy_model.generate_with_logp( batch_prompts, num_return_sequences=G, temperature=1.0 ) # 2. 奖励模型打分 rewards = reward_model.score(batch_prompts, outputs) # [B, G] # 3. 组内归一化 mean = rewards.mean(dim=-1, keepdim=True) std = rewards.std(dim=-1, keepdim=True) + 1e-4 advantages = (rewards - mean) / std # [B, G] advantages = advantages.view(-1) # 4. 新策略log probs new_log_probs = policy_model.compute_log_prob(outputs) # [B, G] # 5. 序列级概率比 ratio = torch.exp(new_log_probs - old_log_probs) # 6. PPO式clip损失 eps = 0.2 clipped_ratio = torch.clamp(ratio, 1 - eps, 1 + eps) policy_loss = -torch.min( ratio * advantages, clipped_ratio * advantages ).mean() # 7. KL惩罚:这里用简化估计,实际可用无偏k3估计 ref_log_probs = ref_model.compute_log_prob(outputs) kl = torch.exp(ref_log_probs - new_log_probs) - (ref_log_probs - new_log_probs) - 1 kl_loss = kl.mean() beta = 0.01 total_loss = policy_loss + beta * kl_loss total_loss.backward() optimizer.step()

这个伪代码里有一点要解释:generate_with_logp这个函数在真实训练框架里是把采样和old log prob缓存合并在一起做的,因为采样过程中本来就要跑一次policy前向,顺手缓存可以省一次前向。如果不缓存而事后重算old log_probs,训练时间会白白增加三分之一以上,工程上是个明显优化点。

3.3 关键超参范围与调参经验

GRPO的核心超参我整理成一个表,方便对照:

超参作用常见范围我的经验值
G(组大小)组内样本数,决定baseline质量4到64小模型8,大模型16
ε(clip范围)限制单步更新幅度0.1到0.30.2,激进点0.1
β(KL系数)约束策略偏离参考模型的程度0.001到0.1从0.01起,观察KL曲线调
temperature采样多样性0.7到1.21.0,要探索就1.2
advantage epsilon防std为0导致的爆炸1e-6到1e-41e-4

G的取舍要讲清楚。G越大baseline越准,方差越低,但成本是线性的:采样G个response就要跑G次生成,训练吞吐直接除以G。G=8是很多开源实现里常见的起点,效果和成本比较平衡。如果你的任务奖励噪声大,比如偏好的RLHF打分,建议G拉到16;任务奖励明确,比如数学题答案对错,G=8足够。

KL系数β的调整有个经验:记录下来每个batch的平均KL值,理想状态是训练初期稍微上升,中后期平稳。如果KL持续爆炸,说明β太小或者更新步长过大,策略已经漂到参考模型很远的地方了。如果KL纹丝不动且reward也不涨,说明β太大,策略被焊死在参考模型附近,学不到新东西。

4. 面试高频追问Top 10:从原理到细节的连环炮

GRPO面试的经典套路是:先问GRPO和PPO的区别,然后顺着你的回答一直挖细节。下面十连问是我总结的、出现频率最高的追问,每个都给出我认为最稳的回答角度。

4.1 为什么GRPO能去掉Critic,不担心方差变大吗

去掉Critic当然会有代价,那就是优势估计的方差来源从"价值网络的回归误差"变成了"组内采样的蒙特卡洛误差"。但LLM场景本身就特殊:奖励稀疏、状态转移复杂,Critic的价值预测误差往往远大于采样组带来的方差。你可以直接说:CRITIC在这里并不work,所以用样本组替代它,本质上是把方差问题转化为G大小的选择问题——想要更低方差,就增大G。

这里最好提一下方差削减的思路。传统的PPO用Critic学习baseline来削减方差,GRPO用的是经验baseline:组内均值就是当前策略在这个prompt上的期望奖励的估计值。样本越多,估计越准,策略梯度的噪声越小。

4.2 为什么要除以组内标准差,而不是只做个均值差分

这是面试官最爱的细节追问。减均值已经给出了正负方向,除标准差的作用有两个:一是尺度归一化,让不同prompt的优势值处于同一尺度,避免那些本身奖励就分散的prompt主导更新;二是放大相对差异,尤其在G比较小的情况下,减去均值之后样本之间的差距可能很小,除以std后,正负优势的幅度拉开,有利于梯度信号鲜明。

顺便说一句,这也是GRPO和RLOO的一个关键区别:RLOO用的是leave-one-out baseline,只减均值不除std,对离群值的反应更温和;GRPO的标准化更激进,在挑出组内best sample时更果断。

4.3 KL惩罚里的β是干什么的,参考模型为什么必须冻结

没有KL惩罚,策略会迅速收敛到奖励模型的高分区域,但这类区域经常是"钻空子"的区域——语句重复、长度爆炸、利用reward model的偏见。KL惩罚项β * KL(π_θ || π_ref)把策略锚定在参考模型附近,确保每次更新都在合理言语空间内移动。

参考模型必须冻住,是因为KL要有一个固定锚点。如果参考模型一起训练,KL会退化成两个都在漂移的模型之间的距离,毫无约束意义。工程上,参考模型虽然冻结,但前向还是要跑,因此显存不能省。

4.4 G的大小对训练效果影响有多大,选8还是64

G太小组内baseline噪声大,正样本可能因为组内出现一个更强的样本而被迫变负,这会让策略更新来回抖动。G太大成本太高,G个response都要完整decode一遍,训练时间线性增长。

实际工程里,我建议先在G=8跑通pipeline,观察reward和KL曲线,如果不稳就加G。64的G通常只在奖励信号非常吵的场景下用,那就是拿钱换稳定性。

4.5 GRPO是on-policy吗,可以复用旧数据吗

标准GRPO是严格的on-policy:每个梯度步骤之后必须用最新策略重新采样。复用旧数据会导致概率比ρ=huge,因为策略已经更新到别处了,clip会大量触发,估算失真。如果非要复用,需要加重要性采样修正,但实践中收益有限,不如老老实实重新采样。

4.6 为什么GRPO在数学推理任务上效果特别好

因为数学题的奖励信号是明确的标量对错,组内排序有意义,好就是好、坏就是坏,归一化后正负样本区分得非常干净。而开放对话任务里,reward model打分本身就模糊,组内相对序也受噪声影响很大,GRPO的提升就没有那么显著。

4.7 和DPO这类离线方法比,优势在哪

DPO不需要在线采样和reward model,训练轻量,但它只能从静态数据中学习偏好,不能去探索那些在数据分布之外的高奖励行为。GRPO是active learning的思路:策略自己生成样本,反馈、修正、再生成,理论上限更高,代价就是训练成本高一大截。面试可以答:如果任务能承受在线采样的开销,GRPO这类在线方法能覆盖DPO够不着的高奖励区域。

4.8 reward model打分噪声大时,GRPO还稳吗

组内归一化对打分的单调变换是鲁棒的,整体平移和缩放不影响结果。但如果噪声让组内排序本身翻转,那归一化也无能为力,只能靠增大G和提升reward model质量。可以补充:把奖励改成pairwise对比的形式,比绝对分数更能抵抗噪声,这也是一个可行的优化。

4.9 G=1时GRPO会怎样

组内均值和标准差都退化到单样本自身,0/0无量纲,无法计算归一化优势。所以G必须至少为2,实际至少要4才有统计意义。如果你是G=1又想用类似思路,那就退化成ReMax——用一次greedy解码结果作为baseline,不过这是另一个故事了。

4.10 训练时GRPO的KL惩罚应该用有偏还是无偏估计

直接使用mean(logp_ref - logp_policy)作为KL是有偏的。GRPO论文里推荐使用无偏的k3估计器,形式是exp(logp_ref - logp_policy) - (logp_ref - logp_policy) - 1。我在伪代码中就是用的这个形式。面试时能主动提到"无偏k3"这个词,会有明显的加分。

5. 实战踩坑:训练GRPO时那些文档里不写的坑

理论说完了,真正动手跑GRPO,有几个坑几乎每个团队都会遇到。我把踩坑经历总结成4条,都很具体。

5.1 组内std趋近于零,归一化往异常方向跑

GRPO训练初期,策略刚从SFT权重初始化,采样出的G个response水平差不多,reward model打分可能都集中在0.1、0.2这种很小的区间。此时std一旦进入0.01级别,除以std后优势函数就能变成成百上千,梯度直接爆炸,一个step下来策略就崩了。

我的处理办法是:在std上加epsilon,同时优先使用rank-normalize。把分数排序后映射成均匀分布在[-0.5, 0.5]的排名,再减组均值。这么做的好处是优势的幅度被限制住了,不管reward model打分的绝对尺度如何,组内最好和最差的差距总是固定的。稳定之后,reward的方差会逐渐拉开,这时再换回标准归一化也会顺滑很多。

5.2 长度作弊:模型发现多说话就能得高分

GRPO训练到一半,模型会自己发现"规律":reward model偏爱长答案,那策略就把答案越写越长,回车空行、废话连篇。你去看组内reward,长答案确实高分,但验证集的人工评估里这些答案质量并没提升。

对策有三条。第一,在奖励函数里加length penalty,比如score = raw_score - α * max(0, len - target_len)。第二,把prompt按答案长度分桶,在各桶内分别做组内归一化,这样同一个长度桶内比较才公平。第三,在解码阶段限制max_new_tokens,别给它无限发挥空间。

5.3 采样温度太低,组内样本同质化

有个很容易被忽视的细节:训练时的temperature不能照搬推理时的低温度。如果你用temperature=0.3做GRPO采样,8个response可能只对应两三种说法,组内归一化区分度极低,优势函数几乎成了噪声。

我习惯把采样temperature设在1.0到1.2,必要时加top_p采样。多样性不足时,组的"相对比较"就名存实亡了。这里可以和面试官聊"exploration-exploitation tradeoff",能说出temperature对组内熵的影响,是个加分点。

5.4 三个模型的内存三角,7B起就是硬仗

policy、ref、reward三个模型同时在线,以7B为例FP16下光权重就42GB,再加梯度和优化器状态,单卡基本没戏。工程上比较省的做法是:把ref model的权重和policy合并存一份,前向时共享主干,只对输出层做KL计算;reward model可以用更小的模型,或者量化到8bit甚至4bit,因为打分对精度没有那么敏感。

我实践的配置是policy用全精度训练、ref半精度、reward量化加速。这一套下来,7B模型在四卡环境下能跑起来,G=8时的吞吐大概每秒几百条样本,还过得去。

6. 横向对比:GRPO、PPO、RLOO、DPO到底怎么选

面试聊到GRPO,基本跑不掉和邻近算法的比较。我直接给一张表,把关键维度摆出来,再逐条说明选择逻辑。

维度PPOGRPORLOODPO
价值模型需要Critic不需要不需要不需要
优势来源学出来的V(s) + GAE组内归一化留一法baseline静态偏好数据
在线采样是是是否
计算开销高(多一路Critic)中(多G路采样)中低
方差特性低但偏差大随G增大降低中等取决于数据质量
适用场景通用RL控制LLM推理/代码/结构化任务轻量级LLM对齐偏好数据充足的对齐

DPO是另一个维度的选择,它压根不跑在线采样,从静态偏对数据直接推导策略梯度,训练快、显存省,适合那种"我已经有几十万条人类偏好数据"的情况。它的上限受限于数据覆盖度,策略不太可能学到数据之外更好的行为。GRPO是主动探索,reward signal能持续引入新信息,适合任务本身有明确评估标准、可以自动打分的场景。

RLOO和GRPO最像,差别就在baseline的设计。RLOO对每个样本用"组内其他样本的平均"作为baseline,相当于每个样本都留一评价,不需要除以std。实际效果上GRPO因为做了标准化,对组内最优样本的放大作用更明显,在需要快速拉开差距的数学任务上更猛。

从面试角度,你最好能说出一个完整的选型逻辑:能拿到自动评估信号、成本能扛住在线采样的,选GRPO;只有静态偏好数据、没有交互环境,选DPO;传统机器人控制这类低维连续性动作空间,PPO依然是可靠选择。这种使用边界意识,比背十个公式都管用。

回到GRPO本身,我最想强调的还是那个朴素的道理:当一个组件(Critic)在特定场景下不work时,不要执着于修补它,而是回头想一想这个组件到底想解决什么——如果只是想获得一个baseline,那采样组的均值就是最简单直接的baseline。GRPO把这个洞察贯彻到了工程细节里,这也是它能在大模型对齐里站稳脚跟的根本原因。如果你自己动手实现,先找一个小到能单卡跑起来的模型,配一个假奖励函数把整个闭环跑通,亲眼看一下归一化前后优势值的分布,很多理论上的困惑都会迎刃而解。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 11:53:53

本体驱动开发:AI原生应用的语义契约基建

1. 为什么“本体驱动”不是又一个 buzzword,而是AI原生应用的底层基建逻辑“本体驱动的AI原生应用开发”——这个标题里藏着两个被严重低估的关键词:“本体”(Ontology)和“AI原生”(AI-Native)。很多人第一…

作者头像 李华
网站建设 2026/10/20 11:52:53

遥感图像目标检测实战:YOLOv8优化与切片推理指南

1. 项目背景:为什么普通目标检测思路在遥感图像上行不通做遥感图像目标检测之前,我默认会先把 YOLOv8 跑通一套通用流程——下数据集、配置类别、训练、验证、调参。这套流程在自然图像上非常顺滑,比如 COCO、VOC 这类常规目标检测数据集。但…

作者头像 李华
网站建设 2026/10/20 11:52:51

grblHAL 迁移实战:HAL 设计、编译配置与调试避坑指南

简介:grblHAL 是经典 grbl 1.1f 的 HAL 化移植分支,专为 32 位处理器设计,面向 CNC 铣削、运动控制与嵌入式固件开发的工程师和进阶玩家。资源覆盖 ESP32、STM32F103/F401/F411 系列、Arduino Due、MSP432、LPC17xx、TM4C123/129、SAMD21、Te…

作者头像 李华
网站建设 2026/10/20 11:52:15

hosa工具箱与3/2谱:用双谱分析揭示信号中的相位耦合关系

简介:一份高阶谱分析HOSA完整工具箱资源(兼容MATLAB R12),面向信号处理、机械故障诊断、生物医学与通信工程领域的研究者。该工具箱通过计算高阶累积量、矩函数及相关函数,支持一至四阶谱(含双谱、三谱&…

作者头像 李华
网站建设 2026/10/20 11:51:05

改进蚁群算法在栅格地图上的无人机路径规划与Matlab实现

简介:这份资源面向无人机路径规划方向的学习者与研究者,聚焦栅格地图环境下基于改进蚁群算法的最短路径求解问题,适合具备一定Matlab基础、希望深入理解智能优化算法实现细节的读者。压缩包内共1个html文件,大小约10KB&#xff0c…

作者头像 李华
网站建设 2026/10/20 11:50:35

SGDR热重启学习率策略:从原理到PyTorch实现与调参

SGDR学习率调整策略,这几年在目标检测、图像分类、语义分割这些任务上,几乎成了我默认的调参起手式。它不是那种需要你反复试错半天才能看到效果的花哨技巧,而是把“学习率怎么衰减”这件事,从玄学变成了一个有章可循的周期性过程…

作者头像 李华