最近好几个朋友都在准备大模型方向的面试,其中被问到次数最多的一个点就是 GRPO 强化学习。有些候选人能说出“Group Relative Policy Optimization”的全称,但再往深问一层——它和 PPO 到底差在哪、组内相对奖励的数学直觉是什么、训练时 KL 项怎么处理——就卡住了。
这篇文章我想把 GRPO 这条线彻底讲透。不管你是马上要上战场,还是看了不少相关资料但总隔着一层,这篇内容都会帮你把关键环节串起来。我会从面试官视角拆解考点,再回到工程落地讲实操细节,最后附上我实际训练中踩过的一些坑。内容偏硬核,但我会尽量用大白话把原理说清楚。
1. 先搞清楚面试官到底想考什么
1.1 GRPO 是什么,为什么会被频繁问到
GRPO 全称 Group Relative Policy Optimization,是一种针对大规模语言模型设计的强化学习训练方法。它解决的问题本质上是:如何用强化学习让模型在推理任务(数学、代码、逻辑题等)上自我进化,同时不会跑偏成奖励黑客。
面试官爱问这个问题,很重要的一个背景是:某开源推理模型上线后,在数学和代码任务上表现惊艳,技术报告里明确写了用 GRPO 做强化学习微调。这个信号让整个行业都意识到,传统 PPO 在大模型场景下遇到了瓶颈,而 GRPO 提供了一种更轻量、更高效的替代方案。所以面试官不是单纯考你一个算法名词,而是在确认你是否跟进过这波推理模型的训练范式转变。
1.2 面试考察的三个层次
根据我了解到的面试反馈,GRPO 相关问题的考察通常分三个层次:
第一层是概念层。你能不能一句话说清楚 GRPO 的核心机制——不训练价值网络,用一组采样输出的相对优劣来计算优势。这一层大多数候选人能过关。
第二层是原理层。这一层要理解为什么可以去掉 critic,组内标准化的直觉是什么,KL 约束为什么不能省。能讲清楚这一层的大概只有三成候选人。
第三层是工程层。训练时组大小设多少、奖励需要归一化吗、策略更新时为什么参考模型 logprob 是固定的、遇到训练崩溃怎么排查。能答到这一层的,基本就是这个领域的资深从业者了。
这篇文章的结构就按照这三个层次展开,你可以对照自己的掌握程度查漏补缺。
2. GRPO 核心原理逐层拆解
2.1 组相对奖励的数学逻辑
理解 GRPO,最关键的是理解它的优势函数是怎么算的。我们先回忆一下 PPO 的优势函数:A = r + γV(s') - V(s),需要训练一个 critic 网络来预测状态价值。这个 critic 在语言模型场景下是个巨大的开销,因为它要处理的是整个 token 序列的隐状态。
GRPO 换了一条路。对于同一个提示(prompt),策略模型采样一组输出(比如 4 个或 8 个),每个输出算出一个奖励 r_i。然后对这组奖励做标准化:
A_i = (r_i - mean(r_1,...,r_G)) / std(r_1,...,r_G)这里 G 是组大小。这么做的直觉是:不需要一个绝对的价值函数来告诉模型“这个回答有多好”,只需要在一组样本中比较“哪个回答相对更好”。平均值相当于这个任务在当前策略下的基准表现,标准差衡量了这组样本的波动幅度。标准化之后,高于平均水平的样本优势为正,会被强化;低于平均水平的样本优势为负,会被抑制。
这种做法的好处非常直接——省掉了一个参数量以亿计的 critic 模型。训练内存开销大幅下降,数据采样和训练 pipeline 也简化了。在大模型场景下,省掉 critic 不光是省显存,还省掉了大量训练不稳定因素。critic 训练不收敛、价值估计偏差大这些问题在大模型场景下极其常见,GRPO 一刀切掉。
2.2 KL 散度约束为什么不省
有人可能会想,既然有了组内相对比较,模型不就能自己学会“好”的行为吗,为什么还需要对参考模型做 KL 约束?这个问题我在面试中听到过,答案其实很实际。
强化学习训练容易出现的状态是:模型发现某种格式能有更高奖励,就开始疯狂输出这种格式,甚至编造答案来迎合奖励信号。比如在数学任务中,模型可能学会输出一大段看似合理的推理,但最终答案是错的——如果奖励只看结果格式给分,模型就会钻这个空子。
KL 约束在这里起的是“安全带”作用。具体实现方式:策略模型之外冻结一个参考模型(通常是 SFT 之后的模型),每一步更新时计算策略输出 token 分布与参考模型分布的 KL 散度,作为惩罚项加进损失里。
GRPO 的损失函数大致是这样的:
L_GRPO = -1/G * Σ [1/(G-1) * Σ (min(ratio_i * A_i, clip(ratio_i, 1-ε, 1+ε) * A_i))] - β * KL(π_θ || π_ref)其中 ratio_i = π_θ(o_i|x) / π_old(o_i|x),是重要性采样比率。KL 惩罚系数 β 控制模型偏离参考模型的自由度。β 太大,模型学不动;β 太小,模型容易放飞自我。我自己的经验是从 β = 0.01 起步,观察 KL 曲线走向再调整,这个我们后面细说。
2.3 和 PPO 的四个关键差异
把 GRPO 和 PPO 放在一起对比,会让你对两者本质理解更深。我整理过四个核心差异,面试时从这个角度答通常能让面试官眼前一亮。
| 对比维度 | PPO | GRPO |
|---|---|---|
| 价值网络 | 需要 critic 网络估计状态价值 | 不需要,用组内奖励标准化替代 |
| 优势计算 | A = r + γV(s') - V(s),依赖时序差分 | A = 组内标准化后的奖励,不跨时间步 |
| 内存占用 | 高,需同时加载 actor、critic、reference | 较低,无 critic 模型 |
| 样本效率 | 单样本逐条评估 | 按组评估,组内比较天然有对比性 |
这里要注意,GRPO 并不是简单粗暴地删掉了 critic,它是用“组内相对比较”这个操作替代了 critic 的价值估计功能。这种替代的隐含假设是:同一提示下的多个采样结果,它们的难度差异可以忽略,直接比较奖励是公平的。在数学题、代码题这类有确定标准答案的任务中,这个假设成立;但在对话生成这类开放性任务中,这个假设就不那么稳了。
2.4 为什么 GRPO 在推理任务上特别契合
当前 GRPO 最成功的应用场景几乎都是可验证奖励(verifiable rewards)的推理任务——数学题答案比对、代码用例通过率、选择题答案正误。这类任务的共同点是:奖励信号稀疏但绝对可靠。
GRPO 的处理方式天然适合这种场景。采样一组候选答案,哪些对了哪些错了,奖励一清二楚,组内标准化后,正确的方案即使没有完整推理过程,也能获得正向优势。模型通过反复试错,逐渐学会更可靠的推理路径。
另一个关键点是,推理任务通常要求模型生成较长的思维链,PPO 在这种长序列场景下 critic 的价值预测非常不准——一个 5000 token 的推理过程,每一步的即时奖励基本都是 0,critic 很难从最终结果反推中间状态的价值。GRPO 完全绕开了这个难题,只在整段输出结束时算一次奖励,然后组内比较。
3. 从零到一训练 GRPO 的实操要点
3.1 训练框架和基础组件选型
如果在实际项目中要训一个 GRPO,我的建议是先别急着写算法代码。先把几个基础组件准备好。
第一是基础模型。GRPO 不是从零预训练,它是在一个已经具备基本推理能力的 SFT 模型上做强化学习。模型本身需要会生成完整的推理过程,即使答案经常错,但格式要能对——这样强化学习才有优化的起点。
第二是参考模型。实践中发现,参考模型直接复用 SFT 模型的后几轮 checkpoint 效果最好,不要用更早的基座模型。原因很好理解:如果参考模型和策略模型初始分布差距太大,KL 惩罚项一开始就会很大,训练前端不稳定。选一个靠后的 SFT checkpoint 作为 reference,KL 起点低,训练更顺畅。
第三是奖励函数。这一步非常关键。浮点数格式要统一,输出解析成最终答案时要把多余内容剥离干净。我在工程里看到太多奖励函数第一步就挂掉的例子——模型明明答对了,但因为输出格式里多了个冒号,解析失败被判零分,这种信号对训练是灾难。
第四是分布式训练配置。策略模型、参考模型至少各占一份显存,如果开启 offload 还要考虑 CPU 内存带宽。一般场景下单机多卡或者多机多卡并行是标配,用 Trainer API 或者加速库做张量并行,参考模型可以走半精度或者更低精度。GRPO 的优势之一就是显存门槛比 PPO 低不少——不用加载 critic 模型,省下来的空间可以增大 batch size 和组大小。
3.2 训练循环的完整流程
完整跑通一层 GRPO 训练循环,大致分为六步:
第一步,从训练数据集中采样一个 batch 的提示(prompt)。这里注意提示的多样性要足够,不要反复用同一批问题,否则模型容易对特定题型过拟合。
第二步,对每个提示让策略模型采样 G 个回答。采样温度一般设置为 0.7 到 1.0。温度太低,组内样本差异性不够,标准化之后优势波动小,梯度信号弱;温度太高,样本质量太差,甚至输出格式都会崩溃。小组大小 G 从 4 到 8 比较常见,更大的组(如 32、64)一般只在并行资源充足的实验室里使用。
第三步,对每个回答计算奖励并保存。这里注意整个回答序列只产生一个奖励分数,不需要每一步都算。可验证任务(带标准答案、可执行代码)直接用规则函数算分,不可验证任务才需要额外训练一个奖励模型。
第四步,计算每个回答在“当前策略模型下”和“参考模型下”的平均对数概率。这一步是核心性能优化点——如果对每个 token 都实时生成 logprob,速度会非常慢。优化思路是一次性将策略输出拼成 batch 送入模型,并行计算所有 token 的 logprob,而不是逐条循环。
第五步,组装损失并更新梯度。计算组内均值、标准差做标准化;计算重要性比率;应用 clip 限制;叠加 KL 惩罚项。这里有个注意事项:要将条数转换变为维度配对,确保每条回答的各自 logprob 与全局库中比对时能对得上,不会张冠李戴。
第六步,固定周期清空缓存、重新采样。每一轮迭代采集新的提示和回答,持续循环。
3.3 损失计算与参数更新的细节
损失计算的细节往往决定训练成败。我项目里踩得最深的一个坑是重要性比率的数值稳定性。
GRPO 的比率定义为策略新旧的概率比,去掉 log 后再求指数。但语言模型的输出概率在序列长度上千后,数值极小,概率比存入 float32 会出现下溢。更稳健的方式是用 log 域差值减去 log sum,再做一次 exp,确保数值稳定。
另一个细节是策略模型和参考模型的计算精度要一致。实际工程中最容易出现的隐患是:策略模型用 bf16 训练,参考模型用 fp16 推理,这会引入额外的分布偏移。建议两个模型用同一种精度和同版本分词器,否则 KL 值在训练前期就会开始震荡。
clip 参数选择上,我用过的默认值是 0.1 到 0.2。有团队报告过 GRPO 对这种大小不是太敏感,但我会倾向于用小一点,比如 0.1,保持更新步伐稳定。如果训练 reward 提升过慢,再放宽到 0.2 试试。
最后的梯度裁剪也很重要,全局梯度范数裁剪在 1.0 附近,可以有效预防偶发的巨大损失跳变。这点实际上是语言模型强化学习里的老经验,但在 GRPO 里更容易被忽略——毕竟没有了 critic 的干扰项,很多人会以为损失天然稳定,而实际并非如此。
3.4 训练过程中必须盯的关键指标
跑 GRPO 训练,不能只看 reward 曲线,那样滞后太多。我建议实时监控四类指标。
第一个指标是组内奖励的标准差。训练初期这个值应该较大,说明采样样本差异明显,模型还在探索;后期如果标准差趋近于 0,说明模型已经对同一任务收敛输出一致——这时候再训练意义不大,甚至可能出现某种模式坍塌。
第二个指标是 KL 散度曲线。KL 整体应该呈现缓慢上升趋势。如果 KL 增长过快,说明 β 值太小,模型正在偏离参考分布;如果 KL 几乎不动,同时 reward 也不涨,说明 β 太大,模型被锁住了,需要调低 β 值。
第三个指标是采样的回答格式规范率。每过一个训练周期,随机抽一组 step 的生成结果,人工观察格式是否保持统一。这个在自动化指标看起来一切正常的情况下,是最好的人工防线。
第四个指标是训练和参考 logprob 矩阵的“错位”情况。如果发现同一个回答,在窗口内的训练 logprob 比参考 logprob 高出一个异常大的倍数,大概率是采样样本和 logprob 记录之间的对齐出了问题——这个错位问题我曾排查过很久,最后发现是 token izer 的批次 padding 不同导致。
4. 面试高频问题与回答思路实录
4.1 基础问题怎么答出层次感
“可以介绍一下 GRPO 吗?”这类问题是最基础但也最容易答得平庸的。我的建议是:先一句话给定义,再用一个类比解释组内相对奖励,最后补一句与 PPO 差异带来的实际收益。
组内相对奖励的类比可以这样打:假设你是一个教练,手下一组运动员跑百米。你不知道绝对成绩多少算好,但你看这组人里谁跑得快、谁跑得慢,就知道该表扬谁、该改进谁。GRPO 就是这样一个依靠组内比较的教练,不依赖一个绝对评分标准。
之后可以补一句:实际训练中省掉 critic 模型,让显存占用降低了大概三分之一到二分之一,训练吞吐量得到明显提升——这样回答就有了信息增量。
4.2 进阶问题怎么展现出真的理解
面试官如果追问“为什么不用 critic 也能估计优势”,这时要答出数学直觉。
可以这样回答:在语言模型场景,状态价值在不同时间步之间的差异主要体现在语义信息的累计上,而奖励其实在最终才揭晓。PPO 用 critic 做的是“提前预测未来奖励”,GRPO 用组内采样做的是“事后比较最终奖励”。后者不需要预测,只做统计归一化,在可验证奖励任务中,统计结果比预测结果更可靠。
还有一类进阶问题是关于 KL 惩罚系数 β 为什么不能用固定值。回答时可以说:理想状态的 KL 曲线是平缓上升的,说明模型在探索过程中逐步偏离参考分布;一旦 KL 出现突刺或骤降,就要检查是在哪个时间片段发生的,大概率是某个 batch 的提示质量异常导致了梯度激增。可以通过动态调整 β 来平滑这个曲线,比如在 KL 超过阈值时加倍惩罚强度。
4.3 追问细节时如何稳住不慌
面试官特别爱追问的一组细节是:KL 你算的是哪种?“训练时策略模型用自己的分布采样,再计算对参考模型的 KL”,还是“策略模型直接往参考模型方向推”。这一下能把没实际操作过的人问蒙。
正确思路是:GRPO 在计算 KL 时,把“当前策略分布”与“固定参考分布”之间的 KL 作为惩罚项加入损失。策略模型在采样时用的是自己的当前参数,loss 中要求策略模型 token 分布和参考分布不要差太远。参考模型参数保持冻结,不参与梯度更新。所以它和那种“反向 KL”或“前向 KL”的数学概念不是一个东西,但它主要由 KL 惩罚项完成,代码里用一个 masked select 在 token 级别抠出来累加。
另外还有个高频追问是“KL 应该加在哪个位置”。要能答出来:KL 对每个 token 计算后,需要在序列维度做平均或求和,再乘上系数 β,融入最终的策略损失。不同实现会略有差异,但一般不会影响大局。这个位置如果弄错,KL 惩罚就不会生效和约束到 token 选择上,训练很快就会崩溃。
4.4 程序设计/伪代码考点
面试中手写 GRPO 的风险点主要在“组内标准化”那一段。可以提前准备一个干净版的伪代码:
# 伪代码:GRPO 组内标准化与损失计算 # logprobs: (batch, G, seq_len) 当前策略的 logprobs # ref_logprobs: (batch, G, seq_len) 参考模型的 logprobs # rewards: (batch, G) 每条样本的奖励 # 1. 序列维度汇总 token 级别 logprob old_logps = old_logprobs.sum(-1) # 采样时的概率 ref_logps = ref_logprobs.sum(-1) new_logps = logprobs.sum(-1) # 最新一次 forward 的概率 # 2. 计算 KL 惩罚项(按 token 平均或汇总) kl = (new_logps.exp() * (new_logps - ref_logps)).sum(-1) # 3. 组内标准化奖励 mean = rewards.mean(-1, keepdim=True) std = rewards.std(-1, keepdim=True) advantages = (rewards - mean) / (std + 1e-4) # 4. 重要性比率与 loss ratio = (new_logps - old_logps).exp() pg_loss = -(ratio * advantages).clamp( min=1 - clip_eps, max=1 + clip_eps ).mean() loss = pg_loss + beta * kl.mean()注意 old_logprobs 是采样时保存下来的,不参与梯度计算,new_logprobs 是当前参数重新前向得到的。这两者在数值上如果完全一致,说明策略没有更新——意味着训练压根没跑起来。
5. 实战踩坑与排查经验
5.1 训练中期奖励数值爆炸
我遇到最多的问题是训练跑到几千步时,reward 曲线突然飙升,看起来像模型学会了某些极端的回答方式。人工查看生成结果后发现,模型学会了输出超长篇幅的无关内容,把真正的推理过程夹在中间,奖励函数因为解析到了正确字段就给高分。
这类问题的根因是奖励函数设计不够严格。排查思路是先随机采样五十组生成结果,人工标注格式违规率,确认是否出现奖励黑客。修复方式通常是收紧解析逻辑,限制输出格式模板,或者在奖励函数中统一加一个额外的小惩罚项,比如超过字数上限时按比例扣分。
另一个常见情况是组内奖励方差变为 0。这种情况通常发生在一组全部通过或全部失败的 batch。方差为 0 会导致(除以 0)后优化方向失效。解决方法是给标准差加一个极小的 epsilon(如 1e-4),同时在组内奖励全相同的时候,跳过这一组样本,不参与梯度更新。
5.2 训练进程崩溃与显存溢出
GRPO 理论显存占用低,但长序列下显存依旧吃紧。最容易溢出的位置是计算 token 级 logprob 的列表推导式,如果你对每个 token 分开做模型推理,显存会线性爆掉。
解决方式是做批量推理和 logprob 缓存。把整条回答序列组成一个 tensor,一次性前向得到全序列 logits,再在词表维度做 log_softmax,最后按 token id 索引取得 logprob。这也是所有开源实现的主流做法。内存不足时,可以把参考模型的 logprob 预计算好存到磁盘,或者用 offload 策略把参考模型挪到 CPU 推理——这样虽然会降低采样吞吐,但至少不炸显存。
还有一类情况是训练中途进程直接掉线。排查第一优先级永远是数据集质量,而不是模型代码。如果你训练数据里混入了超长答案,或者提示没有正确划分上下文长度,序列长度超出模型最大长度,GPU 计算图就会异常退出。稳妥做法是提前做长度截断,并在数据管道里加异常批次捕获逻辑。
5.3 采样吞吐低导致训练推进太慢
采样阶段如果采集速度明显跟不上训练速度,整个流程会陷入长时间等待。优化优先改造策略模型推理的 batch size。单条推理比 batch 推理慢几十倍,所以务必把采样时的 batch 打到最大,一次性采样 G 组。
如果显存充裕,还可以尝试多进程并行采样输出,或者把参考模型和策略模型放在不同加速卡上分布推理。一般情况下先将 batch size 拉满就能解决大部分问题,再考虑更复杂的流水线。
5.4 复现实验时效果不一致
很多团队在复现时出现同一套配置、不同机器效果差别很大的问题,这类复现问题一半来自随机种子,另一半来自算子和计算精度。
GRPO 对随机种子的敏感性比普通 SFT 高得多,因为采样本身有随机性,组内标准化的效果会直接受到采样分布影响。建议在实验代码里设置全链路随机种子,包括 PyTorch、NumPy、tokenizer 和采样器。如果无法做到完全一致,至少保留足够的采样量来降低方差。
另一个隐蔽因素是 tokenizer 版本的差异。参考模型与策略模型如果用的是两个不同版本的 tokenizer(哪怕只是新增了几个特殊 token),会直接导致 token 序列完全错开,KL 数值和组内 logprob 比较全部出错。工程上统一模型和 tokenizer 是一个不可踩的底线。
6. 面试之后,动手实操的准备清单
如果你看完这些内容,准备在真实项目里试 GRPO,我建议按这个顺序准备:
第一,准备一份高质量的训练数据集。数据必须是单一域且有确定正确答案的——数学题解是最合适的入门选择。数据量初期 1 万条上下即可,不需要一上来就上百万。
第二,选一个中等规模的 SFT 模型作为起点。项目早期的探索阶段用参数量小一些的模型会更省时间,比如几十亿参数级别。先把完整的训练链路跑通,再扩展规模。
第三,搭建一个可追踪的日志体系。reward、KL、group std、格式违规率逐项记录,并每五百步导出一次生成样本存档。这个动作会让你训练出问题时排查清理的时间缩短一半以上,属于投入产出比极高的一项。
第四,准备好奖励函数的回归测试集。选两三百条固定样本,每次改奖励函数后都跑一遍回归,保证历史样本上的解析行为不倒退。因为模型往往会针对奖励函数的新规则快速适应,回归集是一个可靠的行为基准。
我在实际使用中的一个体会是:GRPO 看起来比 PPO 简洁很多,但它的门槛藏在别处——没有 critic 给你兜底,策略模型在采样空间里“乱撞”时,奖励函数和 KL 约束就是唯一的护栏。护栏没立好,训练崩起来比 PPO 快得多。所以练熟 GRPO 的价值不只是在面试里对答如流,更是让你真正理解强化学习在语言模型上落地时的取舍逻辑。面试过了之后,自己动手训一把,把这些原理变成肌肉记忆,才算真正把这个问题内化成了你的能力。