
最近翻了一圈大模型算法岗的面经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策略是70BCritic也是70B。这就意味着显存、计算量、工程复杂度全部翻倍。更要命的是Critic在LLM上还特别难训。语言生成的过程并不是传统强化学习那种严格的马尔可夫决策过程每一步的token状态价值非常难估计奖励又往往只在生成结束之后给出。结果就是Critic算出来的V(s)经常是个很糊的值误差一大量化到优势函数里策略更新方向都是抖的。很多团队训练LLM时发现Critic的loss收敛了但策略就是提不上去问题就出在价值函数压根教不准。1.2 GRPO的解题思路不学baseline了直接用样本组做baselineGRPO的全称是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 手算一个G4的例子感受归一化威力假设奖励模型对某个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_sequencesG, temperature1.0 ) # 2. 奖励模型打分 rewards reward_model.score(batch_prompts, outputs) # [B, G] # 3. 组内归一化 mean rewards.mean(dim-1, keepdimTrue) std rewards.std(dim-1, keepdimTrue) 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.2advantage epsilon防std为0导致的爆炸1e-6到1e-41e-4G的取舍要讲清楚。G越大baseline越准方差越低但成本是线性的采样G个response就要跑G次生成训练吞吐直接除以G。G8是很多开源实现里常见的起点效果和成本比较平衡。如果你的任务奖励噪声大比如偏好的RLHF打分建议G拉到16任务奖励明确比如数学题答案对错G8足够。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还是64G太小组内baseline噪声大正样本可能因为组内出现一个更强的样本而被迫变负这会让策略更新来回抖动。G太大成本太高G个response都要完整decode一遍训练时间线性增长。实际工程里我建议先在G8跑通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 G1时GRPO会怎样组内均值和标准差都退化到单样本自身0/0无量纲无法计算归一化优势。所以G必须至少为2实际至少要4才有统计意义。如果你是G1又想用类似思路那就退化成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不能照搬推理时的低温度。如果你用temperature0.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模型在四卡环境下能跑起来G8时的吞吐大概每秒几百条样本还过得去。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把这个洞察贯彻到了工程细节里这也是它能在大模型对齐里站稳脚跟的根本原因。如果你自己动手实现先找一个小到能单卡跑起来的模型配一个假奖励函数把整个闭环跑通亲眼看一下归一化前后优势值的分布很多理论上的困惑都会迎刃而解。