RL POST-TRAINING · GRPO 归一化偏差 · DR.GRPO

答错就写长一点

两个归一化项,两种偏差:1/|y| 摊薄惩罚,逐题 std 抬高极端题

R1-Zero 训练里最有名的一张图,是回答长度和训练奖励同步上涨——社区把它读成「模型学会了想更久」。Sea AI Lab 的 Dr.GRPO 论文(arXiv:2503.20783)问了一个更简单的问题:奖励已经停涨的平台期,长度为什么还在爬?答案写在 GRPO 目标函数的两个归一化项里:答错时,写得越长,每个 token 越不容易受到惩罚;极端难度的题,std 越小、advantage 被放得越大。另一半故事藏在代码里:trl/verl 的 masked_mean 把 PPO 公式里没有的长度平均悄悄加了回来。

本报告为博客正文配套的交互版 · 正文:njx-njx.github.io/posts/dr-grpo-length-and-difficulty-bias/ · 论文 arXiv:2503.20783
姊妹篇交互研报:DAPO Clip-Higher · GSPO 序列级重要性采样 · TIS 训练推理不一致
证据分级:论文一手 > 本地教材 > 推算/作者判断 [已标注] · 图内数字可点击下钻 · 点击画布切换 Â=+1 / −1

SCROLL

§0 · 关键结论

平台期还在上涨的长度,可能不是推理在涌现,而是优化器在推

R1-Zero 式训练的标志性曲线——回答长度与奖励同步上涨——被社区讲成了「长 CoT 通过 RL 不断形成」的故事。Dr.GRPO 论文逐一定位后给出更朴素的结论:在奖励已停止上涨的平台期,优化器仍在持续推动模型生成更长的回答,动机就写在 GRPO 目标函数的两个归一化项里。

两个归一化项、两种各自独立的偏差:1/|y| 让一条回答内部的所有 token 平分梯度——答错(Â=−1)时,1000 token 的回答每个 token 只被惩罚 0.001,是 100 token 回答(0.01)的十分之一,答错写长更安全;逐题 std 让每道题有自己的除数——8 条全对的题 std≈0.35、权重放大约 2.9 倍,四对四错的题 std≈0.52、放大 1.9 倍,越极端的题拿走越多更新预算。第三层偏差不在公式里:trl/verl 的 masked_mean 用 response 实际长度当除数,把 PPO 公式(2)里本不存在的平均加了进去。

修正方法简单到不像论文:把两项归一化都去掉,advantage 只减组内均值,目标函数恢复为 PPO 目标;实现上把 masked_mean 的除数换成全局常数 MAX_TOKENS——一行。效果同样直接:GRPO 在平台期后继续攀爬的长度曲线被压住,错误回答显著变短,7B 极简配方在 AIME 2024 拿到 43.3%。

报告按论证链展开:§1 拆 1/|y| 如何把惩罚摊稀(长度偏差),§2 拆逐题 std 如何把权重交给极端题(难度偏差),§3 看 masked_mean 里的实现层偏差,§4 是 Dr.GRPO 的修正、三点理论依据与三层实验,§5 是一次教材勘误和与 DAPO / GSPO / dynamic sampling 的分工,§6 给出三个判断与三条未决问题。

答对必须简洁,答错不妨冗长——这不是数学错误,而是目标函数写进每个更新步骤里的内容。

— 本报告 · 机制小结

语境每个 token 实际拿到的梯度权重是 Â/|y|:答对时短回答被器重,答错时长回答更安全。 为何重要奖励进入平台期后,上半部分(答对)的提升空间用尽,下半部分(答错写长)仍在推动长度——曲线因此继续爬。

§1 · 偏差一 · 1/|y|

按 token 平均,会把惩罚变稀

GRPO 目标函数(论文公式 3)里有一个不显眼的分母:一条回答内部,先对所有 token 的梯度项取平均,再把 G 条回答加起来。每个 token 实际拿到的梯度权重是 Â/|y|。点击公式的三个组成部件,逐个查看:

JGRPO = 𝔼 [ 1/G · Σi=1..G 1/|yi| · Σt=1..|yi| min( wi,t·Âi , clip(wi,t,1−ε,1+ε)·Âi ) ]

FORMULA ANATOMY · 论文公式(3)· GRPO 目标

点击公式上方的部件

四个部件对应「期望 / 组内回答如何汇总 / 一条回答内部如何平均 / PPO 的 min-clip 项」。高亮部件是长度偏差的唯一入口:1/|y_i| 让一条回答内部的所有 token 平分这条回答的 advantage。

算一笔具体的账:同一道题采出两条回答,一条 100 token、一条 1000 token,advantage 的绝对值都是 1、方向相反。答对(Â=+1)时,短回答每个 token 被强化 1/100=0.01,长回答只有 1/1000=0.001——正确回答里,越短越被器重;答错(Â=−1)时,短回答每个 token 被惩罚 0.01,长回答只被惩罚 0.001——错误回答里,越长越不受惩罚,相差十倍。下面这张图中,拖动滑杆改变回答长度,看每 token 权重如何沿 1/|y| 双曲线摊薄:

这不是数学错误造成的异常,而是目标函数写进每个更新步骤里的内容:答对必须简洁,答错不妨冗长。训练后期奖励进入平台期,模型在「答对」上的提升空间已经用尽,「答错写长」这一项仍在推动模型生成更长的回答——尤其是错误回答继续变长。论文 Fig.5 Plot 2 清楚地展示了这一阶段:GRPO 的长度曲线在奖励进入平台期后继续上升。

机制要点。1/|y| 的作用域是「一条回答内部」——它不改变两条回答之间的相对权重(每条回答的 advantage 仍是 Â),只改变同一条回答内部每个 token 分到多少。所以它的后果是长度分布的系统性偏移,而不是难度之间的权重错配;后者是 §2 的故事。两个偏差各自独立,整改选型依赖这个区分(§5 勘误)。

§2 · 偏差二 · 逐题 std

除以 std,极端难度的题拿走更多权重

第二个归一化项在 advantage 里。除以组内奖励标准差,本意是统一量纲——这是 RL 的常规 trick;但经典 RL 在整个 batch 上算 std(所有样本共享一个除数),GRPO 是每道题单独算——除数不同,权重就不同。

Âi = ( Ri − mean{ Rj }j=1..G ) / std{ Rj }j=1..G

再算一笔具体账:题 1 采 8 条全对,std≈0.35,advantage 按 z-score 的尺度放大约 2.9 倍;题 2 采 8 条四对四错,std≈0.52,放大约 1.9 倍。放大的倍数就是 1/std——越极端的题目(全对的送分题、全错的死题)std 越小,除完之后的权重越大。模型会把最多的更新预算花在已经全对的题和完全不会的题上,而「部分对部分错、正好处于学习价值区间」的题权重最小。这就是论文说的难度偏差(difficulty bias):

需要说明边界:std 归一化并不是只有坏处——它在小方差场景下放大信号的设计初衷,是让模型也能从全对的题里学到东西。论文的批评在于逐题归一化造成的权重不等,不是归一化本身。与之对照,batch 级归一化让所有题共享同一个除数:不同难度之间的相对权重保持为 1,不存在「极端题被放大」的通道——图中虚线即这条对照线。

全对的送分题和全错的死题 std 最小,除完权重最大;正好处于学习价值区间的题,权重最小。

— DR.GRPO 论文 · 难度偏差,arXiv:2503.20783

语境每道题有自己的除数:std≈0.35 → 放大 2.9 倍,std≈0.52 → 放大 1.9 倍。 为何重要更新预算被系统性地分配给「已经会的」和「完全不会的」,而不是「正要学会的」。

§3 · 偏差三 · 实现层

公式里没有长度偏差,实现却把它加上了

第三个发现对工程师更有冲击力。PPO 的目标公式(论文公式 2)是对 response 的 token 求和,没有除以长度的步骤。但论文检查主流开源实现后发现:trl、verl 等框架的 loss 里都有一句 masked_mean——用 response 的实际 token 数当除数算平均。

PPO · 论文公式(2)

L = Σ_t min(w_t·Â, clip(w_t,1−ε,1+ε)·Â)   # 对 token 求和:不除长度

无长度偏差 —— 公式本身不做平均

trl / verl · 实现

loss = (loss * mask).sum(dim) / mask.sum(dim)   # masked_mean:除数 = 每条回答的实际长度(变量)

实现层偏差 —— 公式没有的,实现加上了

Dr.GRPO · 修正(一行)

loss = (loss * mask).sum(dim) / MAX_TOKENS   # 除数换成全局常数

除数从变量换回常数 —— 与公式重新对齐

为什么会出现这种情况?论文的推测源于历史实践:预训练阶段所有数据打包成定长 context,loss.mean(-1) 按 context 长度平均既方便数值又稳定——那是常数除法,没有引入偏差;这套写法延伸到 RL 阶段后,除数悄悄从「定长 context」变成「每条回答的实际长度」——从常数变变量,效果也随之改变。

公式作者和框架作者可能做的是同一套测试,却得到两套梯度。这类「公式与实现不一致」的问题比论文层面的偏差更隐蔽:读十遍论文都发现不了,只有读代码才看见。下表把本报告涉及的全部除法做一次审计——共同模式一目了然:

§4 · Dr.GRPO 的修正与依据

把两个归一化项都去掉,目标函数恢复为 PPO

修正方法很简单:advantage 只减组内均值。论文 Appendix A 给出三点理论依据——点击卡片查看:

Ãi = Ri − mean{ Rj }j=1..G (去掉 1/|y| 与 std)

依据一

恢复 PPO 目标

去掉两项后,目标函数恢复为 PPO 目标(公式 2)。

advantage 就是无 baseline 的 Monte Carlo return 加无偏 baseline——GRPO 相对 PPO 多出来的两个变量除数被移除,公式与实现重新对齐。

Hover for the full story

依据二

减均值不引入偏差

baseline 对梯度的期望贡献恒等于零——策略梯度的标准结论。

E[b·∇logπ]=0 对任何不依赖当前动作的 baseline 成立:减组内均值只压方差,不改变梯度的期望。Dr.GRPO 的修正在这一点上是无偏的。

Hover for the full story

依据三

≈ RLOO 差一个常数

与 Leave-One-Out 只差常数因子 G/(G−1),可纳入学习率。

RLOO 的 baseline 把被评估的那条回答自己剔除;Dr.GRPO 的组内均值含己。两者方向一致,只差 G/(G−1) 的尺度——这个因子不影响训练动力学。

Hover for the full story

实验在 Oat 框架、Qwen2.5-1.5B 上做对照,结果分三层:训练动力学——GRPO 和 Dr.GRPO 前期都出现 R1-Zero 式的奖励、长度一起上涨,但 GRPO 在奖励平台期后长度继续攀爬,Dr.GRPO 的长度稳定下来(Fig.5 Plot 1&2);行为层面——Dr.GRPO 在 benchmark 上错误回答的长度显著缩短,同时缓解了过度思考(Fig.5 Plot 4);可复现性——Llama-3.2-3B 数学预训练后同样出现 double-increase,Dr.GRPO 同样抑制(Fig.7)。下图为按论文结论做的示意重建(非逐点实测):

最能说明「方法极其简单」的是最后一组数字:Qwen2.5-Math-7B 用 MATH level 3–5 的训练集、Qwen-Math 模板,在 8 张 A100 上训练 27 小时,AIME 2024 达到 43.3%——当年 7B 的 SOTA。

§5 · 一次教材勘误,以及分工

两个偏差各自独立——整改方案的选择依赖这个区分

本地教材 hands-on-modern-rl 的 16.4 节也讲到这组偏差,但表述值得修正:它把「std 趋近于零时优势被放大」标成了长度偏差,并把长度膨胀归因于「除以 std 鼓励模型增加组内方差」。

勘误两层错位。对照论文原文:std 造成的是难度偏差(不同题之间的权重不等),不是长度偏差;长度偏差的直接来源是 1/|y|,与 std 无关,作用在回答内部每个 token 的权重上。两项归一化、两种偏差各自独立存在——勘误的价值在于:去掉 std 解决不了长度问题,反之亦然。

本周已发的几篇文章,恰好分别从三个层面回应了这件事:DAPO 的 token-mean 把损失粒度改成 batch 级统一平均,形式上消除长度偏差——但 advantage 保留 z-score(含 std),只解决了一半;GSPO 在序列级使用一个比率,不存在「每个 token 除以 |y|」的平均操作,从结构上绕开;Dr.GRPO 不改目标函数结构,只从归一化项中去掉两个变量除数。逐格点击下钻:

还有一对分工容易被混成替代:Dr.GRPO 和 dynamic sampling 解决的是不同问题。去掉 std 归一化修正的是权重失真(不该被放大的样本得到了过大的权重);DAPO 的 dynamic sampling(std=0 的题直接丢弃重采)处理的是没有梯度信号(全对/全错时,减均值后 advantage 照样是 0,什么也没学到)。注意:去掉 std 后,零信号的题还是零信号——Dr.GRPO 没有为这类题带来任何梯度。一个保证样本内的相对权重正确,一个保证样本整体有可学习的信号,实际训练系统里需要同时配置。

§6 · 三个判断与未决问题

先排除优化器的虚假信号,再区分失真与零信号,审计从除数下手

三条判断是博客作者基于全部证据给出的操作结论;未决问题是证据本身留下的三个缺口。

判断一

RL 曲线先做排除法

「长度持续上涨」既被引为 RL 生效的证据,又被当成要干预的异常——先逐项排除优化器偏差与评估口径假象。

论文还观察到另一类要排除的因素:使用 template 的 Qwen2.5-Math 模型在 RL 前的能力会先被 template 破坏、再被 RL 重建(§3.3)——一部分「RL 增益」其实是原本就存在的能力。分析 RL 曲线前,先排除优化器引入的偏差和评估口径造成的假象。

Hover for the full story

判断二

失真 ≠ 零信号

Dr.GRPO 修权重失真,dynamic sampling 治零信号——不构成替代关系,需要同时配置。

去掉 std 后,全对/全错的题 advantage 照样是 0:Dr.GRPO 没有为零信号题带来任何梯度;dynamic sampling 也不修正非极端题之间的相对权重。两者一个保证样本内相对权重正确,一个保证样本整体有可学习信号。

Hover for the full story

判断三

除数审计

查归一化,先查「除的是变量还是常数」——成本最低的审美审计。

三项偏差的共同模式:表面是常规归一化,分母却不是常数——1/|y| 的除数是每条回答的长度,std 的除数是每道题的组内波动,masked_mean 的除数是当前 batch 的掩码和。查训练代码里的每个 mean/divide,问一句「这个除数会不会随样本变化」。

Hover for the full story

未决问题

  • 一 ·Dr.GRPO 去掉 std 后,「极端难度题目」的权重变化对超长训练(数万步)的影响——论文的 1.5B/7B 实验时间窗口较短。
  • 二 ·token-mean(DAPO)与去掉变量除数(Dr.GRPO)在同一训练栈叠加时的有效学习率换算,缺少公开的统一口径。
  • 三 ·对「预训练打包阶段的 loss.mean(-1) 习惯还有多少残留在 RL 框架」的系统性检查,目前只有论文对 trl/verl 的抽查。

右栏仪表盘随章节切换:两个归一化项状态、除数审计读数与本章关键数字;全部可点击下钻。