第 16 讲:后训练 II —— 可验证奖励的强化学习(RLVR)

Language Modeling from Scratch · Lecture 16。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应:Stanford CS336 Spring 2026 Lecture 16(“Post-training 2: Reinforcement Learning from Verifiable Rewards”,Tatsunori Hashimoto 的幻灯片)。Spring 2025 的第 16、17 讲内容相近,有公开录像。 配套代码:code/lecture16/ 预计阅读时间:3 小时 硬件说明:全部在 CPU 上运行。模型只有约 7 万个参数,一次 200 步的强化学习只要十几秒。


0. 本讲导航

0.1 学完本讲,你应该能够

  1. 解释为什么 RLHF 难以”放开手脚”优化,而可验证的奖励可以。
  2. 从策略梯度出发,说清基线、TRPO、PPO 的裁剪目标各自解决什么问题;说出语言模型版 PPO 的实现要点(奖励塑形、KL 截断、GAE、价值模型)。
  3. 解释 GRPO 为什么能去掉价值模型,并亲手实现它。
  4. 说出 GRPO 的两个偏差(除以标准差、按回答长度平均),以及 Dr. GRPO 的修正。
  5. 描述 DeepSeek-R1、Kimi k1.5、Qwen3 的训练配方,以及它们各自的关键细节。
  6. 用 pass@k 讨论”强化学习到底教会了模型什么”。

0.2 先修知识

知识点用在哪里最低要求
第 15 讲全讲SFT、奖励模型、DPO、KL 约束、过度优化
第 10 讲第 5 节KV 缓存与批量生成(强化学习要大量采样)
期望与方差第 2、4 节E[X - c] = E[X] - c;方差衡量估计值的波动
log 求导第 2 节∇ log f = ∇f / f

0.3 本讲地图

第1节 目标:把强化学习用在"能精确衡量我们想要什么"的地方
第2节 从策略梯度到 PPO                                ← 01、02 号文件
第3节 为什么是 GRPO                                   ← 03、04 号文件
第4节 仔细看 GRPO 的目标:两个偏差                    ← 01、05 号文件
第5节 动手:一个会自己学会"先想后答"的小模型          ← 03 号文件
第6节 案例:DeepSeek-R1、Kimi k1.5、Qwen3、智能体强化学习
第7节 小结

1. 目标:扩大强化学习的范围和威力

预训练 + RLHF 能带我们到 GPT-3.5 的水平。这一讲要一路走到 o1 / R1 这样的推理模型。

第 15 讲的结论是:RLHF 没法干净地”放大”,因为过度优化——奖励模型是学出来的,优化得越狠,它越不可信。那么,能不能在强化学习擅长的领域里工作——在那里,我们优化的恰好就是我们想要的?

答案是可验证的奖励:数学题有标准答案,代码有测试用例,格式可以用规则检查。奖励就是”对 / 错”,没有”讨好奖励模型”的空间(至少少得多)。这就是 RLVR(Reinforcement Learning from Verifiable Rewards)。

本讲分两部分:核心算法(PPO → GRPO → GRPO 的变体)和案例(R1、Kimi k1.5、Qwen3),中间穿插两个现象:长思维链、SFT 还是 RL。


2. 从策略梯度到 PPO

2.1 策略梯度

我们想最大化期望奖励 Ez∼pθ[R(z)]\mathbb{E}_{z \sim p_\theta}[R(z)](z 是模型写的整段回答)。对 θ 求导:

∇θEpθ[R(z)]=Epθ[R(z) ∇θlog⁡pθ(z)]\nabla_\theta \mathbb{E}_{p_\theta}[R(z)] = \mathbb{E}_{p_\theta}\big[R(z)\, \nabla_\theta \log p_\theta(z)\big]

(推导:∇p=p∇log⁡p\nabla p = p \nabla \log p。)直觉:采样一个回答,奖励高就提高它的概率,奖励低就降低。问题是方差太大:只用几个样本估计这个期望,估计值忽大忽小。

基线(Sutton & Barto):可以从奖励里减去任何一个不依赖于具体回答的量 b,梯度的期望不变:

E[(R(z)−b) ∇log⁡p(z)]=E[R(z) ∇log⁡p(z)]\mathbb{E}\big[(R(z) - b)\, \nabla \log p(z)\big] = \mathbb{E}\big[R(z)\, \nabla \log p(z)\big]

因为 E[∇log⁡p(z)]=∑z∇p(z)=∇1=0\mathbb{E}[\nabla \log p(z)] = \sum_z \nabla p(z) = \nabla 1 = 0。选一个好的 b(例如”这道题的平均奖励”),方差可以小得多。

01_policy_gradient.py 在一个”只有 5 种回答的题目”上把几种估计量和精确的梯度比较(每组 8 个样本,重复 2 万次):

方法平均值与精确梯度总方差
不减基线相等(无偏)0.024
减组内平均(GRPO 的分子)精确梯度的 7/8 倍(方向不变)0.014
减留一平均(RLOO)相等(无偏)0.018
再除以组内标准差(GRPO)方向不变,尺度放大约 2 倍0.066

基线的作用在”奖励有公共部分”时特别明显:给所有奖励加 5 分(比如”格式正确就先给 5 分”),期望的梯度一点没变,但不减基线的方法 150 步后平均正确率只有 0.84,最差的一次被推到一个错误回答上再也回不来(正确率 0.001);减了基线的方法完全不受影响(0.99 左右)。

2.2 TRPO 与 PPO

  • TRPO:在当前策略附近把问题线性化,加一个”新旧策略的 KL 不超过 δ”的约束——每一步都不走太远;
  • PPO(Schulman et al. 2017):用一个简单得多的办法达到类似的效果——裁剪概率比值:

L=Et[min⁡(rtAt, clip(rt,1−ϵ,1+ϵ)At)],rt=πθ(at)π旧(at)L = \mathbb{E}_t\Big[\min\big(r_t A_t,\ \mathrm{clip}(r_t, 1-\epsilon, 1+\epsilon) A_t\big)\Big], \quad r_t = \frac{\pi_\theta(a_t)}{\pi_{\text{旧}}(a_t)}

02_ppo_components.py 演示 1:优势为正时,比值超过 1.2 以后梯度为 0(这个 token 的概率已经提高得够多了,这一轮不再推);优势为负时,比值低于 0.8 以后梯度为 0。为什么需要它:PPO 用同一批采样数据做好几步梯度更新(采样很贵),几步之后策略变了,比值不再是 1;裁剪保证策略不会因为这批数据偏离太远。如果每批只更新一步,比值恒为 1,PPO 就退化成普通的策略梯度。

PPO 最早用于真正的强化学习任务(OpenAI Five 打 Dota 2)。课件的吐槽:“如果有人专门写了一篇博客讲 PPO 的实现细节(“PPO 的 37 个实现细节”),你就知道日子不好过了。”

2.3 语言模型版的 PPO

在语言模型里:每个 token 是一个”动作”,整段回答写完之后才有一个大的奖励(Zheng et al. 2023 的形式化)。AlpacaFarm 的 PPO 实现(被好几个项目成功使用)的结构:

  • 外层循环:用当前策略采样(rollout)一批回答,计算奖励;
  • 内层循环:在这批数据上做几轮小批量的 PPO 更新(裁剪范围 0.2);
  • 奖励塑形:每个 token 的奖励 = -β·KL_t,最后一个 token 再加上奖励模型的分数; 实践细节:把每个 token 的 KL 截断到 ≥ 0——否则策略可以靠”让某些 token 的概率比参考模型还低”来赚 KL 奖励,训练可能发散;
  • 优势:用广义优势估计(GAE)。有趣的是,这是一个”老虎机”问题(回答写完才有奖励),γ = λ = 1 就行,此时优势 = “从这里到结尾的奖励之和” - 价值;
  • 预期的训练曲线:总奖励上升(其中奖励模型的分数上升,负的 KL 奖励越来越负)。

02_ppo_components.py 演示 2、3 把这些零件单独算了一遍,其中有一个值得注意的结果——KL 的三种估计量(从策略自己的样本估计 KL(π‖π_ref),log r = log π_ref - log π):

估计量公式性质
k1-log r无偏,但单个样本可能为负,方差大
k2(log r)²/2有偏(KL 大时明显),恒 ≥ 0
k3(r - 1) - log r无偏,恒 ≥ 0;KL 小时方差远小于 k1(GRPO 用它)

但 KL 大的时候(真实 KL 1.36),k3 的标准差(8.1)反而比 k1(1.0)大——它含有 elog⁡re^{\log r},有长尾。没有”永远最好”的估计量。

2.4 为什么说 PPO 很贵

PPO 要同时放 4 个模型:策略(训练)、参考模型(冻结)、奖励模型(冻结)、价值模型(训练)。价值模型和策略一样大、一样要训练。以 70 亿参数为例(第 2 讲的核算方法,不算激活值):PPO 约 252 GB,去掉价值模型约 140 GB,如果奖励来自规则验证器、连奖励模型也不要,约 126 GB。价值模型还带来一堆额外的超参数。


3. 为什么是 GRPO

为什么不用 PPO? 实现复杂;价值模型吃显存,还要额外调参。 为什么不用 DPO? 可验证的奖励天然是”一个个回答的对错”,不是成对比较;DPO 是离线的(虽然可以迭代着变成在线的)。

GRPO(Group Relative Policy Optimization,DeepSeekMath,Shao et al. 2024):

  • 从 PPO 出发(很多部分一样);
  • 去掉价值函数和它的优势估计;
  • 优势 = 组内 z 分数:对同一道题采样 G 个回答,Ai=ri−mean(r)std(r)A_i = \dfrac{r_i - \text{mean}(r)}{\text{std}(r)}。

在”在线”的情况下(采样完立刻更新一次),GRPO 就是带组内标准化奖励的策略梯度。它简单到可以写成很短的程序(例如 nano-aha-moment):给每个回答算奖励 → 组内减均值除标准差(标准差上加一个 1e-4 防止除以 0)→ 算 KL 项 → 梯度更新。

DeepSeekMath 的结果:GRPO 胜过 RFT(只在正确答案上微调),过程监督(给推理的每一步打分)还有一些额外收益。

04_ppo_vs_grpo.py 在第 5 节的心算任务上并排比较(每一步 256 个回答,200 步):

做法第 25 步正确率第 200 步正确率用时
PPO(每批 2 轮 × 4 个小批量 = 8 次更新)88%100%53 秒
GRPO(每批 1 次更新)51%93%18 秒
GRPO(每批 8 次更新,靠裁剪约束)90%99%60 秒

乍一看 PPO 快得多,但它在每批数据上更新了 8 次;让 GRPO 也更新 8 次,差距就消失了。比较算法时要控制住”每批数据用了几次”。在这个小任务上,两者的区别主要在复杂度:PPO 多一个要训练的价值模型(训练初期它的预测是 0,基线形同虚设,要等价值损失降下来才有用)。


4. 仔细看 GRPO 的目标

4.1 除以标准差不是一个”合法的基线”

减去组内平均是合法的基线(只差一个常数倍,接近”留一法”的 RLOO)。但除以组内标准差不是:标准差依赖于样本本身,而且它把不同的题目按不同的权重加起来。Liu et al. 2025(Dr. GRPO,“Understanding R1-Zero-Like Training”)提出的无偏版本去掉了它,非常接近 RLOO。

它对不同难度的题目意味着什么?(01_policy_gradient.py 演示 3)设一道题的正确率是 p,奖励 0/1。策略梯度沿”这道题答对的概率的 logit”方向的期望步长 ∝ p(1-p)(奖励的方差);除以标准差后 ∝ √(p(1-p))。于是:

p全对或全错的概率(G = 8)标准化使步长放大
0.0285%7.1 倍
0.143%3.3 倍
0.51%2.0 倍
0.943%3.3 倍
0.9885%7.1 倍

标准化放大了太难和太简单的题目的相对权重(相对于 p = 0.5 的题,放大了 3.5 倍)。另外,全对或全错的组优势全是 0,这一步完全没有学习信号——所以 Kimi k1.5、Qwen3 都按难度筛选题目,DAPO 等工作在训练中动态丢弃这样的组。

4.2 按回答长度平均的长度偏差

GRPO 的损失对每个回答先在自己的 |o_i| 个 token 上求平均:

L=−1G∑i1∣oi∣∑tAilog⁡π(oi,t)\mathcal{L} = -\frac{1}{G}\sum_i \frac{1}{|o_i|}\sum_t A_i \log \pi(o_{i,t})

每个回答的”总推动力”是 AiA_i,与长度无关,于是(05_length_bias.py 演示 1):

  • 答对的回答(A > 0):越短,每个 token 分到的奖励越多——倾向于”短的正确回答”;
  • 答错的回答(A < 0):越长,每个 token 分到的惩罚越少——倾向于”长的错误回答”。

Dr. GRPO 的修正:把 1/|o_i| 换成一个固定常数(例如最大长度),并去掉除以标准差。

演示 2 构造了一个”长度完全不影响对错”的玩具模型(答对的概率固定为 0.3;模型在”走对路”和”走错路”时,各自控制自己写多少个思考 token)。正确的梯度应该让两个长度都原地不动:

步数GRPO:对的长度GRPO:错的长度Dr. GRPO:对的长度Dr. GRPO:错的长度
04.004.004.004.00
1000.2224.364.004.00
3000.0534.804.004.01

GRPO 把错误回答推向了长度上限、把正确回答推向了 0——纯粹是损失函数造成的。所以看到”训练中回答变长”时,要分开看对的和错的回答各自的长度,问一句:是长思考真的有用,还是损失函数的偏差?


5. 动手:一个会自己学会”先想后答”的小模型

5.1 任务

arith_task.py:把 10 个数字加起来,只说出和的个位数。例如 “9458073021=” 的答案是 9(和是 39)。两种回答格式:

  • 直接回答:“#9$”
  • 先想后答:“[9386636689]#9$“——方括号里是逐个累加时和的个位数(9,9+4=13→3,3+5=8……)

直接回答要”一眼”看出 10 个数字之和的个位数——信息分散在 10 个位置上,小 Transformer 很难一步算出来(和”奇偶校验”难学是同一个道理),准确率接近瞎猜的 10%。逐步累加时,每一步只需要”上一步的结果 + 下一个数字”。

SFT 预热:两种格式各占一半,而且思维链由一个每步有 10% 概率算错的老师写出(10 步全对的概率只有 0.9^10 ≈ 35%)——真实的 SFT 数据(人写的、或较弱的模型生成的)总有错误。预热后的模型(温度 1 采样):正确率 19%,一半时间用思维链,思维链的正确率 32%(和老师差不多——SFT 连老师的错误一起学会了),直接回答的正确率 6%。

一个有意思的现象:贪心解码时,思维链的正确率变成了 100%——老师的错误是随机的、分散在 9 个错误数字上,每一步”最可能的数字”仍然是对的。但贪心解码下第一步选哪种格式也是固定的,35% 的题目选了直接回答,总正确率只有 70%。强化学习和推理模型的使用都靠采样,下面看的都是采样时的表现。

5.2 GRPO 训练

03_grpo.py:每步 32 道题 × 每题 8 个回答,学习率 1e-4,200 步(奖励:格式合法且最终答案正确得 1 分,否则 0 分):

步数正确率用思维链回答长度思维链正确率全对/全错组KL
019%50%9.132%—0.00
2551%85%13.359%2%0.52
5071%96%14.674%5%0.87
10084%98%14.986%24%1.34
20093%98%14.994%55%1.47
  • 模型自己发现了”先想后答”更好:从没有人告诉它要思考,它只知道”对 / 错”,使用思维链的比例却从 50% 升到 98%,回答平均长度从 9.1 变成 14.9——DeepSeek-R1-Zero”训练中回答越来越长”的玩具版(在这里,变长是因为思考真的有用,而不是损失函数的偏差:思考的回答几乎都对);
  • 超过了老师:思维链本身越算越准,从 32% 升到 94%,远超教它的老师(35%)。SFT 只能模仿,强化学习看的是结果;
  • 训练后期,“全对/全错组”越来越多(55%),能学习的信号越来越少——这就是要按难度筛选训练题目的原因。

对比(同样 200 步):Dr. GRPO 最终 94%,RFT(只在答对的样本上做 SFT、“只有正梯度”)96%。在这个简单任务上差别不大,RFT 甚至略快——但 Kimi k1.5 的消融实验在真实推理任务上发现,利用错误样本的”负梯度”更好。玩具任务说明不了哪个算法在大模型上更好。

5.3 pass@k:强化学习教会了什么?

每道题采样 k 次,只要有一次答对就算”通过”:

pass@1pass@4pass@16
SFT 预热后25%62%98%
GRPO 之后94%100%100%

SFT 模型的 pass@16 已经是 98%——它”有能力”答对,只是每次答对的把握不大。GRPO 把 pass@1 提高到接近 pass@16 的水平,pass@16 本身几乎没变。Yue et al. 2025 在真实的推理模型上观察到类似的现象:RLVR 主要是把基座模型已经能采样到的正确推理变得更可靠(“锐化”分布),k 很大时基座模型的 pass@k 甚至可能更高。这也和下面 R1 的”顿悟时刻”争论有关。


6. 案例

6.1 DeepSeek-R1(2025)

这篇论文引发了一场社会现象。它的特别之处:性能超过 OpenAI o1;公开了一个相当简单的强化学习配方;终结了”推理模型必须用 MCTS / 过程奖励模型(PRM)“的猜测;以及关于 SFT 的洞见(R1-Zero 和蒸馏)。

算法:GRPO(沿用 DeepSeekMath),但不用过程监督。

R1-Zero(受控实验):直接在基座模型 DeepSeek-V3 上做强化学习,不做 SFT。

  • 奖励:准确率奖励(答案对不对)+ 格式奖励(思考过程放在指定的标签里);
  • 数据不公开;结果比 o1 略差;
  • 有趣的现象:训练中思维链越来越长;出现了”顿悟时刻”(模型在推理中写出”等等,我再检查一下……”)。

但可能被夸大了(Dr. GRPO 的后续分析):长度增长可能部分来自有偏的目标(4.2 节);而且基座模型本来就会”顿悟”——这种自我反思的语句在强化学习之前就能采样到(呼应 5.3 节的 pass@k)。

R1 vs R1-Zero 的关键区别:

  1. SFT 初始化:先用一些长思维链数据做 SFT(再做一些验证,细节模糊)。声称的好处是可读性;数据的来源不太清楚;
  2. 语言一致性奖励:强化学习会自然地导致思维链里中英文混杂,于是加了一个”思维链中目标语言的比例”的奖励;
  3. 第二阶段加入不可验证的奖励。

整个流程:DeepSeek-V3 → 推理 SFT → 强化学习(GRPO)→ SFT / RLHF。

用于推理的 SFT:少量样本就能有效地”引导”出推理能力——例如 s1(Muennighoff et al. 2025)只用 1000 道数学和科学题 + Gemini / R1 写的长思维链做 SFT。

强化学习之后的常规后训练:SFT 两轮——推理数据约 60 万条(不可验证的任务,例如”证明 X”,用 V3 当评委筛选),非推理数据约 20 万条(V3 的 SFT 数据);然后 RLHF——推理部分沿用 R1-Zero 式的强化学习,不可验证的任务沿用 V3 的 RLHF 流程,同样用 GRPO。

蒸馏:让 R1 生成 80 万条思维链,用它们对 Qwen2.5 等较小的模型做 SFT——非推理模型也能学会推理。

不成功的尝试:论文专门有一节写”失败的尝试”:过程奖励模型(PRM800k、DeepSeekMath 的做法)和 MCTS。

6.2 Kimi k1.5(2025)

和 R1 同时发布,同样用强化学习超过了 o1,提供了与 R1 互补的细节。

数据整理:平衡各个数学类领域;排除选择题和判断题(容易蒙对,产生假阳性的奖励);只选模型 best-of-8 都做不对的题(按难度筛选)。SFT 描述很少(“提示工程”,可能是蒸馏)。

强化学习算法:用”参考答案 + 奖励模型”的方式判断对错。优化问题的推导和 DPO 类似(非参数假设 + 解出 r),再用平方损失作为替代目标,结果相当于”带基线的策略梯度 + 正则项”。

长度控制:Kimi 的目标没有 GRPO 那样的长度偏差,但他们还想进一步压缩思维链。对每一组回答加一个长度奖励(05_length_bias.py 演示 3):

λi=0.5−leni−min_lenmax_len−min_len\lambda_i = 0.5 - \frac{\text{len}_i - \text{min\_len}}{\text{max\_len} - \text{min\_len}}

答对的回答得 λ_i(越短越好,在 [-0.5, 0.5] 之间);答错的回答得 min(0, λ_i)(不奖励”错得短”,但惩罚比中间长度更长的)。而且训练后期才打开,因为太早打开会损害效果。

其他细节:

  • 课程学习:给数据标难度,从易到难;按 (1 - 成功率) 的比例采样题目,避免反复做已经会的题;
  • 奖励:代码题——拿有标准解答的题,生成新的测试用例;数学题——用 80 万个样本训练一个”思维链奖励模型”来判断答案是否等价(例如 1/2 和 0.5)。

强化学习的基础设施:系统和利用率非常重要。为什么强化学习难以高效?

  • 在线策略(on-policy)意味着要采样,也就是(慢的)推理;
  • 训练和采样往往用不同的框架(训练用 Megatron / FSDP,推理用 vLLM),来回切换要同步权重;
  • 长思维链让一批回答的长度参差不齐(最长的那个决定了整批的时间)。

消融:能不能不用强化学习的”负梯度”、只从正确的样本学(专家迭代)?Kimi 发现强化学习更好。

6.3 Qwen3(2025)

比 o1 和 R1 更好(当然更晚),有一些有趣的规模与数据结果。

整体流程:推理强化学习之后是 RLHF(和 R1 一样),再之后是蒸馏(给小模型)。

SFT + 推理强化学习:大家已经熟悉的配方——

  • 按难度筛选(用 best-of-n,和 Kimi 一样);
  • 去掉”不用思维链也能答对”的题;
  • 去掉和验证集太相似的题;
  • 人工检查思维链的质量(区分”猜对的”和”真正推出来的”);
  • 只用 3995 道题做 GRPO。

Qwen3 特有的新东西——思考模式融合:控制思维链的长度。

  1. 把”思考”和”不思考”两种数据混在一起训练,用标签区分;
  2. 提前终止:到了思考预算,插入一句固定的话(大意是”用户给的时间有限,我必须基于目前的思考直接给出答案”),让模型停止思考、直接作答。

于是有了测试时扩展:思考预算越大,数学等任务的成绩越高。另外,各阶段的组合显示:通用的 RLHF 之后,数学 / STEM 能力会略有下降。

6.4 智能体强化学习:Qwen3-Coder-Next

在 Qwen3-Next 上做智能体方向的后训练:

中期训练的代码数据:

  • GitHub:仓库级的长上下文数据(把整个仓库的文件拼起来)约 6000 亿 token;带检索上下文(仓库当时的状态)的 Pull Request;
  • Common Crawl:文字 + 代码混合的文档,用语言模型解析 HTML;
  • 合成数据:让语言模型为网页上的代码内容写问答;在各种环境里运行代码智能体得到的轨迹;
  • 指令跟随 / 填空(Fill-in-the-Middle)数据。

专家模型:从 Qwen3-Next 训练几个专家——网页开发、用户体验(UX)、单轮问答、软件工程(SWE),再蒸馏回一个模型。网页开发专家在”合法的网页代码”上做 SFT(用视觉语言模型和智能体操作来检查);UX 专家在很多种工具调用格式上训练;问答专家就是更多的单轮代码数据。

环境构建:自动化地构建 SWE-bench 式的环境(约 80 万个任务,第 14 讲的 SWE-smith、SWE-rebench 是同一类工作),然后做智能体强化学习。


7. 小结

  1. 过度优化是 RLHF 的一个根本问题;在可以验证的窄领域里做强化学习是一种解决办法;
  2. GRPO 很简单(去掉价值模型,用组内平均做基线),使 RLVR 容易实现;但它有缺陷(除以标准差、按长度平均),Dr. GRPO 等做了修正;
  3. 野外有很多成功的配方:R1(GRPO + 格式与准确率奖励 + 蒸馏)、Kimi k1.5(难度筛选、长度奖励、课程学习、基础设施)、Qwen3(极少量的题目、思考模式融合),以及正在兴起的智能体强化学习;
  4. 我们的玩具实验:强化学习只凭”对 / 错”就让模型学会了先想后答、并超过了教它的老师;但它主要是让已有的能力更可靠(pass@1 大涨,pass@16 几乎不变)。

8. 与作业 5 的关系

作业 5 的主体是在数学题(MATH 等)上用一个小的数学模型(例如 Qwen2.5-Math-1.5B)做 SFT、专家迭代和 GRPO(具体设置以当年的作业说明为准)。本讲的代码对应其中的:

作业中的组件本讲代码
组内标准化的优势(减均值、可选地除以标准差 + eps)03_grpo.compute_advantages
按 token 的策略梯度损失:不减基线 / 减基线 / GRPO-Clip03_grpo.policy_loss、01_policy_gradient.estimate
按回答平均 vs 按固定常数归一化(masked mean / masked normalize)policy_loss 的 length_norm 参数、05_length_bias.py
在同一批数据上做多轮更新(off-policy,需要裁剪)train_rl 的 inner_epochs 参数
答案解析与奖励函数(格式 + 正确性)arith_task.parse、reward
专家迭代compute_advantages(mode="rft")

9. 练习

练习 1(基线):证明 Ez∼pθ[∇θlog⁡pθ(z)]=0\mathbb{E}_{z \sim p_\theta}[\nabla_\theta \log p_\theta(z)] = 0,并说明为什么”减去组内平均”时,如果平均值里包含了样本自己,梯度会变成 (G-1)/G 倍。

参考答案

E[∇log⁡p(z)]=∑zp(z)∇p(z)p(z)=∇∑zp(z)=∇1=0\mathbb{E}[\nabla \log p(z)] = \sum_z p(z) \frac{\nabla p(z)}{p(z)} = \nabla \sum_z p(z) = \nabla 1 = 0。设 Ai=ri−1G∑jrjA_i = r_i - \frac{1}{G}\sum_j r_j。对 j ≠ i,E[rj∇log⁡p(zi)]=E[rj] E[∇log⁡p(zi)]=0\mathbb{E}[r_j \nabla \log p(z_i)] = \mathbb{E}[r_j]\,\mathbb{E}[\nabla \log p(z_i)] = 0(独立);j = i 那一项是 −1Gri∇log⁡p(zi)-\frac{1}{G} r_i \nabla \log p(z_i)。所以 E[Ai∇log⁡p(zi)]=(1−1G)E[r∇log⁡p(z)]\mathbb{E}[A_i \nabla \log p(z_i)] = (1 - \frac{1}{G})\mathbb{E}[r \nabla \log p(z)]。用”留一平均”(RLOO)就没有这个缩放。

练习 2(PPO 的裁剪):A = +2,ε = 0.2。比值 r 分别为 0.5、1.0、1.1、1.5 时,裁剪目标的值和对 r 的梯度是多少?如果每批数据只更新一次,裁剪还有用吗?

参考答案

min(r·2, clip(r, 0.8, 1.2)·2):r = 0.5 → min(1.0, 1.6) = 1.0,梯度 2;r = 1.0 → 2.0,梯度 2;r = 1.1 → 2.2,梯度 2;r = 1.5 → min(3.0, 2.4) = 2.4,梯度 0。只更新一次时,更新前 r 恒等于 1,裁剪不起作用;它只在同一批数据被重复使用、策略已经变化之后才起作用。

练习 3(GRPO 的优势):一组 8 个回答,奖励为 [1, 0, 0, 0, 0, 0, 0, 0]。分别用 GRPO(除以标准差,用总体标准差)和 Dr. GRPO 计算每个回答的优势。哪种方法给唯一答对的回答的”奖励”更大?这对难题意味着什么?

参考答案

平均 0.125,总体标准差 √(0.125 × 0.875) ≈ 0.331。Dr. GRPO:答对的 0.875,答错的 -0.125。GRPO:答对的 0.875 / 0.331 ≈ 2.65,答错的 -0.125 / 0.331 ≈ -0.38。GRPO 把难题(正确率低、标准差小)上的信号放大了约 3 倍——4.1 节说的”放大太难和太简单的题目的权重”。

练习 4(长度偏差):一组里有一个答对的回答(长 100 个 token,A = +1)和一个答错的回答(长 1000 个 token,A = -1)。在 GRPO(按回答长度平均)和 Dr. GRPO(除以最大长度 1000)下,每个 token 的权重分别是多少?

参考答案

GRPO:答对的每个 token +1/100 = +0.01,答错的每个 token -1/1000 = -0.001——长的错误回答里每个 token 几乎没有受罚。Dr. GRPO:答对的每个 token +0.001,答错的每个 token -0.001,一视同仁;答错的回答”合计”受罚 -1,答对的合计 +0.1。

练习 5(Kimi 的长度奖励):一组 4 个回答,长度 200、400、600、1000,前两个答对、后两个答错。算每个回答的长度奖励。

参考答案

λ = 0.5 - (len - 200)/800:200 → 0.5,400 → 0.25,600 → 0,1000 → -0.5。答对的得 λ:+0.5、+0.25;答错的得 min(0, λ):0、-0.5。

练习 6(pass@k):如果一个模型对某道题的单次正确率是 p,pass@k = 1 - (1-p)^k。p = 0.1 时 pass@16 是多少?强化学习把 p 提高到 0.9,pass@16 变成多少?这说明用 pass@k(k 很大)评估时,强化学习的收益为什么看起来很小?

参考答案

p = 0.1:1 - 0.9^16 ≈ 0.81;p = 0.9:1 - 0.1^16 ≈ 1.0。pass@1 从 10% 变成 90%,pass@16 只从 81% 变成 100%。k 越大,“只要有一次对就行”越宽松,基座模型已经能靠多试几次答对,强化学习的收益(让每一次都更可靠)就被掩盖了。

练习 7(动手): (a) 把 arith_task.TEACHER_ERROR_RATE 改成 0(完美的老师),删掉 checkpoints/ 的缓存,重新运行 03_grpo.py:强化学习还需要学什么?学得多快? (b) 在 train_rl 中加上 KL 惩罚(beta=0.04),看思维链的比例、KL、正确率怎样变化。 (c) 把组大小 G 从 8 改成 2 和 32,观察”全对/全错组”的比例和学习速度。 (d) 在 05_length_bias.py 演示 2 中把答对的概率改成 0.7,长度偏差的方向会变吗?为什么?


10. 延伸阅读

  • CS336 Spring 2026 Lecture 16 幻灯片(stanford-cs336/lectures 中的 lecture_16.pdf)。
  • 算法:Schulman et al.,Proximal Policy Optimization Algorithms(2017);Schulman et al.,High-Dimensional Continuous Control Using Generalized Advantage Estimation(2016);Schulman 的博客 Approximating KL Divergence(2020);Huang et al.,The 37 Implementation Details of PPO(博客);Dubois et al.(2023,AlpacaFarm 的 PPO 实现);Zheng et al.,Secrets of RLHF in Large Language Models Part I: PPO(2023)。
  • GRPO 及其变体:Shao et al.,DeepSeekMath(2024);Liu et al.,Understanding R1-Zero-Like Training: A Critical Perspective(2025,Dr. GRPO);Ahmadian et al.,Back to Basics: Revisiting REINFORCE Style Optimization(2024,RLOO);Yu et al.(2025,DAPO);nano-aha-moment(McGill-NLP 的迷你实现)。
  • 案例:DeepSeek-AI,DeepSeek-R1(2025);Kimi Team,Kimi k1.5(2025);Qwen Team,Qwen3 Technical Report(2025);Muennighoff et al.,s1: Simple Test-Time Scaling(2025)。
  • 强化学习到底教会了什么:Yue et al.,Does Reinforcement Learning Really Incentivize Reasoning Capacity in LLMs Beyond the Base Model?(2025)。

11. 下一讲预告

到目前为止,我们的模型只处理文字。但世界是多模态的。下一讲(多模态模型):

  • 怎样把图片变成 token:切块(ViT)、CLIP 的缩放裁剪、AnyRes、动态分辨率;
  • CLIP 与 SigLIP:用”图片 + 说明文字”做对比学习;
  • LLaVA 的模板(视觉编码器 + 投影层 + 语言模型)与 Qwen-VL 系列的演进(M-RoPE、DeepStack、平方根归一化的损失);
  • Chameleon:把图片也变成离散 token,一个模型既能看图也能画图。

下一讲之前,建议你:跑通 code/lecture16/ 下的 5 个脚本,完成练习 1、3、4、6。

← 返回课程目录