GRPO 奖励信号
Day 111 讲了奖励从哪来(RLVR:确定性 grader),Day 112 讲了奖励会被怎么作弊(reward hacking 谱系)。今天补上中间那块:拿到奖励后怎么把它变成策略更新信号——GRPO 的组内归一化优势。这是 B1→B18 曲线上「奖励设计」的收口:能把 grpo.ts 的纯函数读懂、并把具体任务映射成「该用 exactMatch 还是该用 judge」的奖励设计表,就具备了
阶段: B12 · RLVR + 模型策略 memo(Day 111-120) 标签: #grpo #no-critic #reward-design #deepseek
今日导引(由浅入深)
Day 111 讲了奖励从哪来(RLVR:确定性 grader),Day 112 讲了奖励会被怎么作弊(reward hacking 谱系)。今天补上中间那块:拿到奖励后怎么把它变成策略更新信号——GRPO 的组内归一化优势。这是 B1→B18 曲线上「奖励设计」的收口:能把 grpo.ts 的纯函数读懂、并把具体任务映射成「该用 exactMatch 还是该用 judge」的奖励设计表,就具备了为一次真实 GRPO 训练写奖励 spec 的能力。注意诚信边界——今天只产出奖励设计映射,真实 GRPO 训练(在线 grpoScore 更新)需要 GPU,不声称已训练。最小可判定产出:一份 grpo-reward-design.md + 5 个 P1 任务的得分表 + 每条标注「exactMatch 可用 / 需 judge」。
1. 机理精读
核心思想。 GRPO(Group Relative Policy Optimization,arXiv:2402.03300)解决的是 PPO 的一个具体痛点:PPO 需要一个 value 网络(critic) 来估计 baseline,用于把绝对奖励转成优势 A = r - V(s)。critic 是一个与 policy 同量级的网络,要额外训练、额外占显存。GRPO 的洞见是:对同一个 prompt 采样一组(group)输出,用组内统计量当 baseline,就不再需要 critic。
优势的计算。 对一个 prompt 采样 G 个输出,拿到奖励 r_1..r_G,GRPO 的组内归一化优势为:
A_i = (r_i − mean(r)) / std(r)
其中 mean(r)、std(r) 是这一组奖励的均值与标准差。直觉拆解:
mean(r)充当了 critic 估计的 baseline——「这个 prompt 一般能拿多少分」,但它是经验估计(拿当场采样的 G 个样算)而非函数逼近(PPO 的 critic 网络)。这就是省 critic 的关键:用采样的经验分布替代一个要训练的网络。std(r)做归一化,让不同 prompt(难易不同、奖励尺度不同)的优势可比,稳定梯度尺度。A_i > 0表示「这个输出比组内平均好」→ 强化它(提高其生成概率);A_i < 0→ 抑制它。- 奖励
r_i可由 verifiable grader 直接给(RLVR 侧),无需任何 RM——这就是 GRPO + RLVR 的天作之合:优化器不要 critic,奖励不要 RM,整条链上没有需要额外训练的网络。
为什么这样设计能省。 PPO 的 critic 要单独前向 + 反向 + 存梯度,显存与算力都接近翻倍;critic 还要单独调参、单独防过拟合。GRPO 用组内 G 个采样的经验分布替代 critic 的函数逼近——代价是每个 prompt 要多采几个样(G 通常 8-64),但采样是推理(无反向),比训一个 critic 便宜得多,且天然支持 verifiable reward。这正是 B11 Day 110 TCO 对比里「小团队选 GRPO」的根因。
关键权衡。
- 组大小 G:太小(如 G=2)则 mean/std 估计噪声大、优势不稳;太大则采样成本上升(G 个输出都要前向)。R1 用的是相对较大的组(典型 8-64)。G 是 GRPO 最重要的超参之一——它替代了 PPO 里 critic 的「方差缩减」职能,G 越大 baseline 估计越稳,但每步算力线性上升。
- 奖励稀疏性:若组内所有输出奖励都一样(全 0 或全 1),
std(r)≈0,优势趋于 0(实现里加eps防除零),这组就没有学习信号——这是 verifiable 奖励太「全有全无」时的失效模式,需要 partial credit / composeRewards 来制造组内方差。实战表现为「训练初期 reward 卡在 0 不动」(所有采样都答错,组内无差异),或「后期 reward 顶到 1 不再升」(都答对,无差异)。 - 与 reward hacking 的关系:GRPO 只负责「怎么用奖励更新」,奖励本身的可信度(Day 112)是另一回事——组内归一化不会修复一个有 hack 漏洞的 grader,只会更高效地把策略推向 hack。所以「奖励设计(111-112)」必须先于「优化器(113)」,顺序不能反。
- KL 约束:GRPO 实际更新里还会加一个对参考策略的 KL 惩罚,防止策略偏离初始模型太远(崩坏语言能力)。本仓
grpo.ts是教学最小核(只演示组内优势),未实现 KL 项——这是与生产 GRPO 的诚实差距。
GRPO vs PPO 速查:
| 维度 | PPO | GRPO |
|---|---|---|
| baseline 来源 | value 网络(critic)函数逼近 | 组内 mean(r) 经验估计 |
| 额外网络 | 需 critic(约翻倍显存/算力) | 无 critic |
| 优势计算 | A = r − V(s)(GAE) | A_i = (r_i − mean)/std |
| 额外成本 | critic 训练 + 调参 + 防过拟合 | 每 prompt 多采 G 个样 |
| 适配 verifiable reward | 可,但要训 RM 或接 grader | 天然契合(直接给 r_i) |
与相邻概念的边界。 GRPO(优化器)⊥ RLVR(奖励来源)。DAPO 等是 GRPO 的变体(改进采样/裁剪/长度处理)。PPO+独立 RM 是被取代的「省显存」叙事——注意 GRPO 的卖点恰恰是去掉 critic,所以不能再拿「PPO 也能省显存」来对比,那是混淆。
2. 推导 / 手算 / 代码走读
src/agent/train/grpo.ts 走读(纯函数,已 built+tested,no GPU/no key):
groupRelativeAdvantage(rewards, eps=1e-8)(第 7-14 行):算mean→variance→std,返回rewards.map(r => (r - mean) / (std + eps))。这就是上面公式A_i = (r_i − mean(r))/std(r)的直接实现,eps防 std=0 除零。exactMatchReward(output, target)(第 17-19 行):output.trim() === target.trim() ? 1 : 0——RLVR 的 exactMatch verifier,给「有唯一答案」的任务。formatReward(output, pattern)(第 21-23 行):pattern.test(output) ? 1 : 0——格式 verifier,给「格式即正确性」的任务。composeRewards(parts)(第 26-30 行):权重归一化的加权平均,如[{weight:0.7, reward:correctness}, {weight:0.3, reward:format}]——制造组内方差、避免全有全无。grpoScore(group: GrpoSample[])(第 38-41 行):一步 GRPO 打分——调groupRelativeAdvantage给每个样本附advantage,reinforce = advantage > 0。这是「在线更新」的核——真实训练里 group 是模型当场采样的,需 GPU;本日不跑它。
最小手算示例(验证 groupRelativeAdvantage):
一组 4 个输出,verifiable 奖励 r = [1, 0, 1, 0](两个答对、两个答错):
mean = (1+0+1+0)/4 = 0.5variance = ((0.5)²+(0.5)²+(0.5)²+(0.5)²)/4 = 0.25,std = 0.5A = [(1-0.5)/0.5, (0-0.5)/0.5, (1-0.5)/0.5, (0-0.5)/0.5] = [+1, -1, +1, -1]grpoScore→ 两个答对的reinforce=true,两个答错的reinforce=false。✅ 符合直觉:组内对的被强化、错的被抑制,无需任何 critic。 反例(全对):r=[1,1,1,1]→std=0→A≈[0,0,0,0](eps 兜底)→ 无学习信号。这就是「奖励太满」的失效,说明需要 partial credit。
部分信用救场示例: 同一组若用 composeRewards(correctness 0.7 + format 0.3)给出连续奖励 r=[1.0, 0.3, 0.7, 0.0](一个全对、一个只对格式、一个只对内容、一个全错):
mean = 0.5,variance = (0.25+0.04+0.04+0.25)/4 = 0.145,std ≈ 0.381A ≈ [+1.31, -0.52, +0.52, -1.31]grpoScore→ 第 1、3 个reinforce=true,第 2、4 个false,且优势幅度区分了「全对」与「半对」。 对比纯 0/1 奖励,连续奖励让组内方差非零,训练信号更密——这就是为什么 RLVR 实战几乎都用composeRewards而非单一 verifier。
5 任务奖励设计映射(从 tasks.ts 选 5 个 P1 任务,标 exactMatch vs judge + 建议权重):
| task_id | 奖励类型 | verifier | 建议 composeRewards |
|---|---|---|---|
reasoning-numeric-sum($29,000) | exactMatch 可用 | exactMatchReward 直接 1/0 | correctness 1.0 |
aml-ctr-threshold($10,000) | exactMatch/format 可用 | formatReward(/10[,.]?000/) | correctness 0.8 + format 0.2 |
format-json-strict(bare JSON) | format 可用 | formatReward 验结构 | correctness 0.7 + format 0.3 |
aml-structuring-classic(识别 structuring) | 需 judge | LLM-judge pass/fail | judge 1.0(半可验证) |
aml-sar-5w1h(开放 SAR 叙事) | 需 judge | 覆盖度启发式 + judge | judge 0.7 + format 0.3 |
关键观察:format-json-strict 不能只用 formatReward——合法 JSON 但字段错照样满分(Day 112 格式套利),所以必须用 composeRewards 让 correctness 权重压过 format。而 aml-structuring-classic 的 has(/structur/i) 只能当便宜首过启发式(codeCheck),真正的奖励信号必须走 judge——这正是 Day 111 把它归「半可验证」的延续。
3. 今日实战
- 阅读
src/agent/train/grpo.ts,确认groupRelativeAdvantage(no-critic)、exactMatch/format/composeRewards、grpoScore均已实现且纯函数可测。 - 用 provider-agnostic runner(默认 deepseek,模型 id
deepseek-v4-pro)跑 5 个 P1 任务,记录原始得分分布。 - 对每个任务标注奖励类型:
exactMatch 可用(有唯一答案)vs需 judge(开放/半可验证),并给出建议的composeRewards权重(如 correctness 0.7 + format 0.3)。 - 用
grpoScore在一组手造样本上跑一次(纯函数,无 GPU),验证advantage/reinforce行为符合预期,作为「优化核已可测」的证据,但明确这不是训练。 - 写
grpo-reward-design.md+ 5 任务得分表,明确「本日产出奖励设计映射,不声称已训练」。
4. 今日实测 / 产出
- 产出:
grpo-reward-design.md+ 5 任务得分表。 grpo.ts逻辑已 built+tested(纯函数:groupRelativeAdvantage/exactMatchReward/formatReward/composeRewards/grpoScore)。- 真实 GRPO 训练运行 = 待 GPU(
grpoScore在线更新需 GPU 跑)。 - 本日只产出奖励设计映射,不声称已训练。
- runner 默认 deepseek,模型 id
deepseek-v4-pro(5 任务原始得分的真实跑批需 key,本日聚焦设计映射)。
5. 常见误区 / 陷阱
- 以为 GRPO 修复了奖励质量。GRPO 只管「怎么用奖励更新」,不管「奖励对不对」。grader 有 hack 漏洞,GRPO 只会更高效地把策略推向作弊。
- 组内奖励无方差却以为在学。
r=[1,1,1,1]→ std=0 → 优势≈0 → 无信号。verifiable 奖励太「全有全无」时必须靠 partial credit(composeRewards)制造组内方差。 - 把关键词命中当成 exactMatch。
aml-structuring-classic命中/structur/i不代表判断对,属半可验证、需 judge,不能用 exactMatchReward 直接给奖励。 - 拿 PPO 当「省显存」对比对象。GRPO 的卖点是去掉 critic;用「PPO+独立 RM 也能省」来对比是混淆,那是被取代的叙事。
- 以为本仓 grpo.ts 就是完整 GRPO。它是教学最小核(组内优势 + 纯函数 verifier),未含 KL 约束、未含在线策略更新与采样循环——真实训练需 GPU + 完整 RL loop。把它当「已能训练」是越界声称。
- 把组大小 G 当无关紧要的细节。G 替代了 critic 的方差缩减职能,G 太小会让 baseline 估计噪声大、训练不稳——它是 GRPO 的核心超参,不是随手设的。
6. 学习资源(每条带 YYYY-MM)
- DeepSeekMath GRPO 原始论文 — arXiv:2402.03300(2024-02,group-relative advantage、no value network)
- DeepSeek-R1 — arXiv:2501.12948(2025-01,GRPO + verifiable reward 驱动推理,组大小/KL 的实践参数来源)
- RLVR / reward-hacking 综述 — arXiv:2604.15149(2026-,奖励设计与作弊谱系)
- 本仓实现:
src/agent/train/grpo.ts(GRPO 优化核 + RLVR verifier,纯函数已测)、src/agent/eval/tasks.ts(5 个 P1 任务来源)
SOTA检查 (2026-06 更新)
- 当前主流:GRPO 仍是 2026 现役无 critic 主线(arXiv:2402.03300),是低成本 RL 后训练的默认优化器,配 verifiable reward(RLVR)用于推理/代码/数学类任务。
- 是否仍 SOTA:是。组内归一化优势替代 critic baseline 的范式仍是当前低显存 RL 训练的标准做法,被 R1/DeepSeekMath 系列与大量开源复现采用。
- 过时黑名单:
- 不要引用「PPO + 独立 reward-model」作为「省显存」叙事——GRPO 的卖点正是去掉 critic,拿 PPO 对比是错位;
- 不要把格式分当语义分(格式套利);
- 不要在无组内方差时声称有学习信号(std=0 失效);
- 不要把教学最小核 grpo.ts 说成「已能训练」(缺 KL/在线 loop,需 GPU)。
- 下次复查点:复查 DAPO 等 GRPO 变体是否在 verifiable 任务上超 GRPO(采样/裁剪/长度处理的改进);复查 deepseek
deepseek-v4-pro当周可用性(legacydeepseek-chat/deepseek-reasoner2026-07-24 退役,禁用)。
衔接
- 昨天:Day 112 — Reward hacking 谱系(五类 hack + evalBaseline.ts 自评循环审计)
- 今天:组内归一化优势
A_i=(r_i−mean)/std省掉 critic,走读 grpo.ts 纯函数,把 5 任务映射成 exactMatch vs judge 奖励设计;本日只产出奖励设计映射,真实训练待 GPU。 - 明天:Day 114 — 实验设计基础(base-vs-tuned 是因果实验,定 H0/H1、唯一变量、最小样本量 n≈70,序贯 vs 固定检验)
本批次三天(111-113)合起来构成「RLVR 奖励设计三件套」:奖励从哪来(111)→ 奖励怎么被作弊(112)→ 拿到奖励怎么更新(113)。接下来 114-117 转入「评测能下结论的统计纪律」,把这套奖励设计的成效真正测出来。