时长 7 小时:§1 推理模型(1h)· §2 可验证奖励(1h)· §3 GRPO(1.5h)· §4 GRPO 的偏置与改进(1h)· §5 RL 到底教会了什么(1h)· §A–§C(1.5h)
对应正课 Lecture 6 的前半部分:推理模型、用于推理的强化学习、GRPO。学习计划点名要会的:推理模型与普通模型的区别;RLVR 为什么能在数学和代码上大幅提升;GRPO 相比 PPO 去掉了什么、为什么省显存、为什么在可验证任务上够用。
配套代码
w3day5_checks.py(纯 numpy):组内优势与”没有信号的组”、除以标准差带来的难度加权、按长度归一化带来的长度偏置、k3 放进损失时的梯度、pass@k 的无偏估计、“磨尖还是拓展”的机制模拟§B 参考实现(
code/目录):w3d5_grpo.py(GRPO 的优势、损失与各种变体开关;三位数加法玩具上的 SFT → GRPO;Qwen2.5-0.5B-Instruct + LoRA 在 GSM8K 上的 GRPO)。今天的目标:能说清推理模型是什么、为什么需要 RL;能写出 GRPO 的目标,解释组内优势、为什么不需要价值模型;能指出 GRPO 的两个归一化带来的偏置,以及 Dr. GRPO、DAPO 怎么改;能用 pass@k 讨论”RL 教会了模型新东西,还是只是让它更稳定”。
§0 今天的主线
Day 2–4 的偏好优化,奖励来自”人更喜欢哪个”,要靠奖励模型去近似,于是有了过度优化和 reward hacking(Day 2 §3.2)。今天换一类任务:数学题的答案对不对、代码能不能通过测试,可以由程序直接判定。 奖励不再是一个会被钻空子的近似,而是真值。
这一变化带来了 2024–2025 年最重要的进展之一:推理模型(OpenAI o1、DeepSeek-R1 等)。它们在回答前先生成很长的思维链,能自我检查、回溯、换一种方法再试。这种行为主要不是靠示范教出来的,而是用强化学习在可验证的任务上练出来的。
今天的路线:推理模型是什么(§1);可验证奖励为什么这么好用、边界在哪(§2);为这类任务设计的 GRPO 算法(§3);它的几个偏置和社区的修正(§4);最后一个开放的问题:RL 到底让模型学会了新的推理能力,还是只是把已有的能力磨得更稳定(§5)。
今天要用到的旧结论:思维链为什么有效、为什么小模型上失效(Week 2 Day 3 §5.1–5.2);自洽性投票(Week 2 Day 3 §5.3);策略梯度与基线(Day 3 §1.3);GAE 与价值网络的难处(Day 3 §2.3);PPO 的裁剪(Day 3 §3.2);KL 估计量(Day 3 §3.4);四个模型的显存(Day 3 §4.3);什么时候选 RL 而不是 DPO(Day 4 §5.2)。
§1 推理模型
1.1 和普通模型有什么不同
| 普通的对话模型 | 推理模型 | |
|---|---|---|
| 回答前 | 直接回答,或按提示写一段简短的思维链 | 先生成一段很长的”思考”(常见几千到上万 token),再给出答案 |
| 思考的内容 | 线性地一步步推 | 会自我检查(“等等,这里好像不对”)、回溯、换一种方法、验证结果 |
| 怎么来的 | SFT + 偏好优化 | 在可验证任务上大规模 RL(加上少量 SFT 做冷启动) |
| 推理算力 | 固定 | 可以调:想得越久通常越准(“思考预算”) |
思考预算:推理模型把”推理时花多少算力”变成了一个可调的旋钮。OpenAI 在发布 o1 时展示了两条曲线:准确率随训练时的 RL 算力和测试时的思考长度都呈对数线性增长。第二条就是 Day 6 的”测试时缩放”。
1.2 为什么长思维链有用
Week 2 Day 3 §5.2 给过一个论证:Transformer 一次前向的计算深度是固定的,每生成一个 token 就多做一次完整的前向。思维链把”串行计算”外包给了生成过程:需要的推理步数越多,就需要越多的 token 来承载中间结果。推理模型把这一点推到极致:让模型自己决定要想多久。
长思维链里最有价值的往往不是”更多步骤”,而是纠错能力:一条线性的推理只要错一步就全错(每步 0.9 的正确率,10 步后只剩 35%,Week 2 Day 3 §5.1),能检查并回溯的推理不受这个指数衰减的约束。
1.3 两个里程碑
- OpenAI o1(2024 年 9 月):第一个广为人知的推理模型。技术细节没有公开,但明确了”大规模 RL + 长思维链 + 测试时算力可扩展”这条路线。
- DeepSeek-R1(2025 年 1 月):公开了方法和权重。它的两个版本讲了一个很清楚的故事:
- R1-Zero:直接在基座模型(DeepSeek-V3-Base)上做 GRPO,不做任何 SFT,奖励只有两个规则:答案对不对、格式对不对(思考写在
<think>标签里)。训练中,回答长度自发地越来越长,模型自己学会了反思和验证(论文称之为”aha moment”)。AIME 2024 的 pass@1 从 15.6% 升到 71.0%,多数投票后到 86.7%。缺点是可读性差、中英文混杂。 - R1:用几千条高质量的长思维链做冷启动 SFT → 推理任务上的 RL(外加语言一致性奖励)→ 用 RL 后的模型做拒绝采样,得到约 80 万条数据(推理和非推理)再做 SFT → 覆盖所有场景的第二轮 RL。
- 蒸馏:用 R1 生成的这 80 万条数据直接 SFT 小模型(Qwen、Llama 的 1.5B 到 70B),效果超过在同样小模型上直接做大规模 RL。§5.3 会讨论这意味着什么。
- R1-Zero:直接在基座模型(DeepSeek-V3-Base)上做 GRPO,不做任何 SFT,奖励只有两个规则:答案对不对、格式对不对(思考写在
§2 可验证奖励的强化学习(RLVR)
2.1 什么是可验证奖励
奖励由程序判定,而不是由模型打分:
- 数学:从回答里抽取最终答案,和标准答案比对(数值相等、表达式等价)。
- 代码:运行单元测试,全部通过得 1 分。
- 格式:思考和答案是否写在规定的标签里、是否用规定的语言。
- 其他可自动检查的:逻辑谜题、结构化输出是否符合 schema、指令里的硬约束(“不超过 100 字”)是否满足。
2.2 为什么它这么好用
- 不会被钻空子(大体上)。奖励是真值,不存在 Day 2 §3.2 那种”奖励模型的误差被放大”的过度优化。可以放心地做很多步 RL。
- 便宜、无限。不需要人标注,任何有标准答案的题库都能用,想采多少样本就采多少。
- 信号清楚。对就是对,错就是错。
学习计划的问题:“数学和代码之所以能用 RL 大幅提升,是因为答案可以自动验证”:自动验证让 RL 能在策略自己的分布上、以任意规模持续采样和改进(在线 RL 的优势,Day 4 §5.2),又不必担心奖励模型被钻空子(偏好 RL 的最大隐患)。这两点同时成立,所以可以把 RL 规模化到以前不敢想的程度。
2.3 奖励设计与适用边界
奖励设计的经验(R1 等的报告):
- 用规则,不用神经网络奖励模型。R1 的报告明确说,训练 R1-Zero 时没有用神经网络奖励模型(无论是结果奖励还是过程奖励),因为在大规模 RL 中它可能被钻空子,重新训练它又要额外的资源、让整个流程更复杂。
- 格式奖励要小:它只是为了让答案能被抽取出来。参考代码给格式 0.1 分、答案 1 分。
- 警惕”可验证”里的漏洞:答案抽取规则太宽松(比如”最后一个数”),模型可能学会列出很多个数;代码测试太弱,模型可能学会针对测试用例硬编码。
适用边界:
- 开放式写作、对话、价值判断没有可验证的奖励,仍然要靠偏好数据(Day 2–4)。
- 奖励稀疏:题太难时一组全错,没有任何学习信号(§3.2)。RL 只能改进”模型偶尔能做对”的题。
- 只验证最终答案,不验证过程:推理过程可能是错的,答案碰巧对了,也会被奖励。
§3 GRPO
3.1 动机:价值网络在这里既难训、又占地方
PPO 用价值网络做基线(Day 3 §2)。在 LLM 推理任务上它有两个问题:
- 难训:奖励只在最后一个 token 出现(对 / 错),价值网络要从半截的思维链预测最终能否做对,这几乎和解题本身一样难。价值估计不准,GAE 的偏差就大(Day 3 §2.3)。
- 占地方:价值网络通常和策略一样大,训练它要再加 16 字节/参数(Day 3 §4.3:PPO 36 字节/参数,去掉它是 20)。
GRPO(Group Relative Policy Optimization,Shao et al. 2024,DeepSeekMath)的想法很朴素:同一道题采一组回答,用组内的平均得分当基线。它和 Day 3 §1.3 的”同批其他样本的均值”只差一个常数倍(§3.4),不需要任何额外的模型。
3.2 组内相对优势
对一道题 采 个回答 ,得到奖励 。每个回答的优势(回答内的所有 token 共用)是
直觉:比同组平均好的回答被推高,差的被压低。“同一道题”的比较天然控制了题目难度,这正是好的基线该做的事。
一个重要的后果:全对或全错的组没有信号。 这时 std = 0,所有优势都是 0。w3day5_checks.py 第 1 组:一组没有信号的概率是 :
| 单题正确率 | |||
|---|---|---|---|
| 0.02 | 92.2% | 85.1% | 72.4% |
| 0.1 | 65.6% | 43.0% | 18.5% |
| 0.5 | 12.5% | 0.8% | 0.0% |
| 0.9 | 65.6% | 43.0% | 18.5% |
题库的正确率两头多、中间少(Beta(0.5, 0.5))时, 有 39.4% 的组白白生成了、没有贡献任何梯度。题太难学不到东西,题被学会了也学不到东西,这决定了题库要按难度筛选、训练中要持续更新(§4.2 的动态采样)。
3.3 目标函数
GRPO 的损失(DeepSeekMath 的形式):
其中 和 PPO 一样(Day 3 §3.2), 是 估计(Day 3 §3.4):
和 PPO 的三个区别:优势来自组内比较,没有价值网络;KL 作为损失里单独的一项,而不是放进奖励(Day 3 §3.3 的第二种放法);按回答长度平均()。
一个微妙之处: 放进损失,梯度指向的是另一个 KL。 作为 KL(π‖π_ref) 的数值估计是无偏的,但把它写进损失、对采到的 token 直接求导时,期望梯度是正向 KL KL(π_ref‖π) 的梯度。第 4 组在一个 12 类的 softmax 上精确地算了: 与 的最大差是 ,与 差 0.30。 直接当损失更糟:期望梯度恒为 0()。两个 KL 在 π 接近 π_ref 时差不多,所以实践中问题不大;但它不是”精确的反向 KL 惩罚”。
3.4 一轮 GRPO
1. 取一批题 x(DeepSeekMath 每题采 64 个回答;小规模实验常用 8–16 个)
2. 用 π_old 对每道题采 G 个回答(纯温度采样,Day 3 §A.3)
3. 用规则算奖励 r_i;组内算 Â_i;(可选)扔掉全对 / 全错的组
4. 算 log π_old、log π_ref(参考模型只在 β > 0 时需要)
5. 在这批数据上做若干次梯度更新(常常只做 1 次,这时 ρ ≡ 1,裁剪不起作用)
回答学习计划的自测题:“GRPO 为什么省显存、为什么在可验证任务上够用?”
- 省显存:去掉了价值网络(和策略一样大、要训练,16 字节/参数);可验证任务又不需要奖励模型;若 ,连参考模型都可以不要。显存从 PPO 的 4 个模型降到 1–2 个。
- 够用:(1) 奖励只在最后出现,价值网络本来就估不准,GAE 的逐 token 信用分配优势有限;(2) 同一道题的一组回答天然提供了一个控制了难度的基线:组均值包含 自己,,只是 Day 3 §1.3 第 1 组那个无偏的”留一法”基线乘了一个常数(除以组内标准差会再引入一点偏差,§4.1);(3) 可验证奖励是真值,不需要 KL 和价值网络来防止被钻空子,组内比较提供的方差缩减就足够了。代价是每道题要采 G 个回答,生成的算力更多;但推理可以用 vLLM 高效地批量完成,而且这些回答本身就是需要的样本。
§4 GRPO 的偏置与改进
4.1 两个归一化带来的偏置(Dr. GRPO)
Liu et al. 2025(“Understanding R1-Zero-Like Training”,提出 Dr. GRPO)指出 GRPO 目标里的两个归一化会引入偏置:
除以组内标准差 → 难度偏置。 二值奖励、组内正确率为 时,每组的梯度总量 ;不除标准差是 。第 2 组:
| 答对的优势 | 答错的优势 | 相对 的放大倍数 | |
|---|---|---|---|
| 0.05 | +4.36 | −0.23 | 2.29 |
| 0.25 | +1.73 | −0.58 | 1.15 |
| 0.5 | +1.00 | −1.00 | 1.00 |
| 0.95 | +0.23 | −4.36 | 2.29 |
几乎全错的题里那一个正确回答、几乎全对的题里那一个错误回答,被赋予了很大的权重。
除以回答长度 → 长度偏置。 第 3 组:一组 4 个回答,1 个对(长 200),3 个错(长 200、400、800),组内优势 +1.73 与 −0.58。每个 token 得到的权重:
| 回答 | 优势 | GRPO: | DAPO: | Dr. GRPO:/常数 | |---|---|---|---|---| | 对,长 200 | +1.73 | +2.17e−3 | +1.08e−3 | +1.73e−3 | | 错,长 200 | −0.58 | −7.22e−4 | −3.61e−4 | −5.77e−4 | | 错,长 400 | −0.58 | −3.61e−4 | −3.61e−4 | −5.77e−4 | | 错,长 800 | −0.58 | −1.80e−4 | −3.61e−4 | −5.77e−4 |
长 800 的错误回答,每个 token 被压低的力度只有长 200 的 1/4。 模型学到的是:错的时候写长一点,惩罚就被摊薄了;对的时候写短一点,奖励更集中。R1 类训练里回答越来越长,一部分可能来自这里,而不全是”学会了想得更多”。
Dr. GRPO 的修正:不除标准差;不除 ,改为除以一个固定常数(比如最大生成长度)。
4.2 DAPO
DAPO(Yu et al. 2025)在大规模训练里总结了四个改动:
- Clip-Higher:裁剪区间不对称,、。对称的裁剪让低概率 token 的概率很难被大幅提高( 最多到 1.2),模型很快失去探索能力,熵迅速坍缩;放宽上界让”好的低概率 token”能被更快地提上来。参考代码的自检里有一项专门检查这一点。
- 动态采样:扔掉全对 / 全错的组(§3.2),继续采样直到凑满一个有信号的 batch。
- token 级的损失:所有 token 一起平均,而不是先在回答内平均(§4.1 的长度偏置)。
- 过长回答的奖励整形:超过最大长度被截断的回答,给一个随超长程度递增的惩罚,而不是直接当成错误。
很多近期的配方还去掉了 KL 项():在可验证任务上,我们本来就希望模型离初始策略足够远,而奖励又不会被钻空子。参考代码默认 ,可以用 --beta 0.04(DeepSeekMath 的取值)对比。
4.3 熵坍缩
RL 的一个普遍现象:策略的熵迅速下降,采样出来的回答越来越像,组内没有差异,优势全为 0,训练停滞。第 6 组的玩具里,300 步后”思路分布”的熵从 1.97 降到 0.03。对策:clip-higher、熵奖励、提高采样温度、控制学习率、定期重置参考策略等。熵坍缩和 §5.2 的”磨尖”是同一个现象的两面。
§5 RL 到底教会了什么
5.1 pass@k 与它的无偏估计
pass@k:对一道题采 个回答,至少一个对的概率。 衡量”稳定地做对”, 很大时衡量”有没有能力做对”(覆盖率)。
估计:采 个、其中 个对,无偏估计是(Chen et al. 2021)
第 5 组(每题采 ,重复 20 万次):
| 真实 | 真实 pass@k | 无偏估计 | 朴素估计 | |
|---|---|---|---|---|
| 0.05 | 5 | 0.2262 | 0.2263 | 0.2068 |
| 0.05 | 10 | 0.4013 | 0.4014 | 0.3366 |
| 0.2 | 10 | 0.8926 | 0.8927 | 0.8287 |
朴素估计系统性地偏低( 是凹函数,由 Jensen 不等式), 越大偏得越多。
5.2 磨尖还是拓展
问题:RL 之后模型的 pass@1 大幅上升,这是因为它学会了新的推理能力,还是只是把它本来就偶尔能做对的题变成了稳定做对?
Yue et al. 2025(“Does Reinforcement Learning Really Incentivize Reasoning Capacity in LLMs Beyond the Base Model?”)的观察:在多个模型和基准上,RL 后的模型 pass@1 远高于基座模型;但 很大时(几百),基座模型的 pass@k 反超 RL 后的模型。也就是说,RL 后能解出的题,基座模型采样足够多次大多也能解出;而一些基座模型偶尔能解出的题,RL 后反而解不出了。
第 6 组用一个机制模拟说明这是怎么发生的:模型在 8 种”解题思路”之间选择(跨题共享),思路 能解出一道题的概率不同(最常用的一种能解 60% 的题,冷门的只能解 10%–30%)。用 GRPO 训练思路偏好:
| 训练步 | pass@1 | pass@8 | pass@64 | pass@256 | 思路分布的熵 |
|---|---|---|---|---|---|
| 0 | 0.317 | 0.816 | 0.901 | 0.901 | 1.966 |
| 25 | 0.500 | 0.745 | 0.884 | 0.901 | 1.085 |
| 100 | 0.599 | 0.614 | 0.668 | 0.776 | 0.096 |
| 300 | 0.603 | 0.607 | 0.623 | 0.671 | 0.030 |
pass@1 几乎翻倍,但 pass@256 从 0.901 降到 0.671:分布变尖之后,只有冷门思路才能解的题,采样 256 次也碰不到正确的思路了。RL 没有教会模型新思路,只是重新分配了已有思路的概率。另外,9.8% 的测试题任何思路都解不出,无论怎么 RL 都学不会:它们的每一组都是全错,没有梯度。
意义:
- RL 擅长”磨尖”:把模型已经具备、但不稳定的能力变得可靠,pass@1 的大幅提升是实实在在的收益。
- RL 很难”拓展”:它只能强化采样中出现过的行为,出现概率为 0 的行为得不到任何信号。模型能力的上限主要由预训练(和蒸馏)决定。
- 这也是一个正在争论的问题:也有工作报告在更长的训练、更多样的任务上 RL 能扩展边界。把结论当作”目前的证据”,而不是定论。
5.3 蒸馏 vs RL
R1 的报告(§1.3):用大模型 RL 后生成的推理数据去 SFT 小模型,效果超过在小模型上直接做 RL。结合 §5.2 就好理解:小模型自己采样时很少碰到正确的长推理,RL 没有信号可学;而蒸馏直接把大模型的推理行为作为示范喂给它,相当于”拓展”了它的分布。小模型的推理能力,最有效的来源往往是更强的老师,而不是自己的 RL。
§A GRPO:API 用法与边界
A.1 trl 的 GRPOTrainer
- 需要:一个提示数据集、一个或多个奖励函数(输入回答文本,返回分数)。每个提示采
num_generations个回答。 - 奖励函数就是普通的 Python 函数,可以组合多个(答案正确 + 格式)。
- 它的默认值(、损失的聚合方式、是否除以标准差)在不同版本里有过调整,部分版本已经把 Dr. GRPO、DAPO 的做法作为选项。训练前打印完整的配置,确认它用的是哪一种(§4.1–4.2)。
- 生成通常是瓶颈,可以接 vLLM。
A.2 答案验证
- 数学答案的比对远比”字符串相等”复杂:
0.5与1/2、\frac{1}{2},带单位、带逗号……可以用专门的库(如 math-verify)或者 sympy 做等价判断。GSM8K 的答案是整数,参考代码的extract_answer够用。 - 规定答案的位置(
####之后、\boxed{}里),不要取”最后一个数”:否则模型可能学会列出很多个数(§2.3)。参考代码为了兼容,在找不到####时退回到”最后一个数”,同时给####格式奖励。
A.3 生成设置
- rollout 用纯温度采样(温度 1),覆盖掉模型自带的
top_p、repetition_penalty(Qwen2.5 的 generation_config 里就有),理由同 Day 3 §A.3。参考代码在generate里显式传入了这些参数。 - 批量生成要左补齐,重新计算 log 概率时要用与生成时一致的位置编号(参考代码的
seq_logps从 attention mask 算position_ids)。 - 最大生成长度决定了”想多久”的上限,也决定了显存和时间;被截断的回答怎么算奖励要想清楚(§4.2 第 4 条)。
§B 实操
- 跑通
w3day5_checks.py,6 组结论都看懂。第 6 组改变 q 和训练步数,观察 pass@k 曲线的交叉点。 - 推导(1h):(a) 二值奖励下组内优势的公式,以及每组梯度总量 ;(b) (提示:);(c) pass@k 无偏估计为什么无偏(提示:它是”从 个里无放回抽 个,至少一个对”的概率)。
- 加法玩具上的 GRPO(1.5h,CPU 可跑):
python code/w3d5_grpo.py --toy,然后分别试--adv drgrpo、--dynamic、--eps-high 0.28、--beta 0.04,记录 pass@1 与 pass@16 的变化。 - GSM8K 上的 GRPO(2h,需要 GPU):
--gsm8k,记录准确率、平均奖励和回答长度随训练的变化。这是学习计划”GRPO 玩具实验跑通”的正式版本。 - 读论文:DeepSeekMath 的第 4 节(GRPO);DeepSeek-R1 的第 2 节(R1-Zero 与 R1 的流程);挑读 Dr. GRPO 与 DAPO 的方法部分。
参考实现:code/w3d5_grpo.py。
§C 自测
动机与直觉层
- 推理模型和普通模型的区别是什么?“思考预算”指什么?
- 为什么数学和代码能用 RL 大幅提升?RLVR 的适用边界在哪?
- GRPO 去掉了什么?为什么在可验证任务上够用?代价是什么?
- 为什么全对和全错的组没有学习信号?这对题库设计意味着什么?
- R1-Zero 和 R1 的区别是什么?为什么 R1 需要冷启动?
推导与计算层
- 写出 GRPO 的目标函数,指出它和 PPO 的三个区别。
- 二值奖励、组内正确率 时,写出答对和答错的优势。除以标准差对不同难度的题意味着什么?
- 为什么按回答长度平均会让错误的回答变长?Dr. GRPO 和 DAPO 分别怎么改?
- 写出 pass@k 的无偏估计,说明朴素估计为什么偏低。
工程层
- DAPO 的四个改动各解决什么问题?
- 为什么很多推理 RL 的配方把 KL 项去掉了?
- RL 后的模型 pass@1 高了很多,但 pass@256 比基座模型低,你怎么解释?这对”RL 能不能教会模型新能力”意味着什么?
出关标准
- 能说清推理模型、思考预算、R1-Zero 与 R1 的流程
- 能解释 RLVR 为什么有效、边界在哪、奖励怎么设计
- 能写出 GRPO 的目标,回答”为什么省显存、为什么够用”
- 能说出 GRPO 的两个偏置和 Dr. GRPO、DAPO 的修正
- 能用 pass@k 讨论”磨尖还是拓展”
- 跑通
--toy,至少比较两种设置