推理模型与 RLVR
第 12 课:推理模型与 RLVR
RLVR(即用程序直接判定答案对错来当奖励的强化学习)——上一课我们把模型调成了"会按偏好说话"。但偏好管的是好不好听,管不了算得对不对。这一课换一个目标:让模型在多步问题上想得更久、更准。讲清"写步骤"的能力从哪来、奖励怎么换成程序可判的对错、纯 RL 为什么能自己长出长思考、长度膨胀这笔账怎么算、推理预算该分配给哪些题,最后把大模型的长思考搬进小模型。
② 说清 RLVR 为什么能用"对错"当奖励,以及它的适用边界
③ 会算长度偏差与 test-time scaling 两笔账,并给出蒸馏与 RL 的选型判据
上一课我们把对齐那条线走完了:模型学会了"按人类偏好说话"。但那套偏好管的是好不好听,因为它只回答"人更喜欢哪个",所以管不了算得对不对——这一课换一个目标,让它在多步问题上想得更久、算得更准。
要让模型"一步步想",有两条供给路径:提示和训练。可以把这类比成教人做菜:一种是把菜谱贴在灶台边,每次做菜都得看着它;另一种是让人把菜谱背下来,以后不用带纸条。前者不动权重、随时可换,后者要把步骤真正写进脑子。
更自然的做法是直接问它要答案(标准提示)——但 PaLM 540B 这样问,在 GSM8K 上只能拿到 17.9%。原因是答题需要多步推导,而模型被训练的默认行为是「一次给一个 token」,中间步骤全被压进一步里、没有展开的空间;把 8 个带中间步骤的示范放进提示后,同一模型的同一批题就升到 56.9%——差的不是知识,而是「把中间步骤写出来」这件事本身。
| 对比项 | 提示(in-context) | 训练(写进权重) |
|---|---|---|
| 改了什么 | 只改本次输入 | 改模型参数 |
| 推理时要不要带示范 | 要,每次都要 | 不要 |
| 能力上限 | 受基座已有能力限制 | 可把外部/自产的推理过程写进去 |
| 代价形态 | 每次请求都付的"输入税" | 一次性数据与训练成本 |
| 项 | 数值 | 说明 |
|---|---|---|
| 示范条数(Wei 2022) | 8 条 | 论文用的 exemplars |
| 每条示范的 CoT 长度 | 约 120 token(示意) | 长题更长,此处按题意估值 |
| 每次请求的固定输入开销 | 8 × 120 = 960 token | 与题目本身无关 |
| 题目本身长度 | 约 50 token(示意) | 一道应用题 |
| 输入放大倍数 | 960 ÷ 50 ≈ 19 倍 | 示意 |
| 问题 | 读数 | 来源 |
|---|---|---|
| CoT 在什么规模上才有效 | 小模型上收益很小甚至更差,约 100B 参数以上才出现正收益 | Wei 2022 |
| 论文评测的模型规模区间 | 约 0.35B ~ 540B(含 LaMDA / GPT-3 / PaLM / UL2 / Codex 等多个家族,最小约 350M) | Wei 2022 |
| 540B 标准提示(GSM8K) | 17.9% | Wei 2022 |
| 540B + 8 个 CoT 示范 | 56.9%(Google 博客记 58.1%) | Wei 2022 / Google 官方博客 |
让模型写出中间步骤有两条路——提示(改输入、不动权重)和训练(改权重、推理时零开销)。提示法简单、随时可换,但有两条硬边界:① 每次请求都要付固定输入开销;② 只能激发基座已有的能力。"要足够大才会出现"这一点,正是它必须从"提示"走向"训练"的原因。
上一张卡片我们看到:要把更强的推理过程装进去,就得动权重。可一旦要"训",第一个绕不开的环节就是奖励从哪来。
对齐那一课用的是"人类比较",但对数学题,比较是弱信号——两个错误答案之间"谁更好"意义不大,人还得读完整段推理才判得出来。可以把这类比成判卷:主观题必须请人阅卷,客观题只要对答案就行——能把自动判的题,就别浪费人的时间。所以做法是让程序直接判对错,把 RLHF 里那个学出来的奖励模型整个换掉——这样一来策略的 gradient 就只剩"对 / 错"这一个方向可爬。
| 奖励来源 | 谁能给 | 信号形态 | 能自动规模化吗 | 主要风险 |
|---|---|---|---|---|
| 人类偏好 | 人工标注 | 成对比较(哪个更好) | 否(贵、慢) | 标注噪声、偏好被"冗长"挟持 |
| AI 偏好(RLAIF) | 强模型 | 成对比较 | 是 | 继承强模型的偏见 |
| 可验证规则(RLVR) | 程序 / 测试用例 | 对 = 1、错 = 0(二值) | 是 | 只覆盖"能自动判对错"的题 |
| 步骤 | 做什么 | 例子 |
|---|---|---|
| extract(抽取) | 从回答里抓出被检查的那部分 | 取出 <answer> 标签内、或 \boxed{} 里的内容 |
| canonicalize(规范化) | 把无害的表面差异抹平 | 「(2,3)」「{3,2}」「x=2, x=3」都归成集合 {2,3} |
| reward(给分) | 与标准答案比对 | 相等给 1,否则给 0 |
| 项 | 数值 | 说明 |
|---|---|---|
| 一道题一次采样给的信号 | 1 比特(对 / 错) | 二值奖励 |
| 一组采样(G = 8)给的信息 | 8 个 0/1 | 组内相对好坏由此算出 |
| GSM8K 题库规模 | 8,792 题(常引作 8.5K) | Cobbe et al., 2021(7,473 训练 / 1,319 测试) |
| MATH 题库规模 | 12,500 题 | Hendrycks et al., 2021(7,500 训练 / 5,000 测试) |
| 两库可训练题合计 | 7,473 + 7,500 = 14,973 题 | 算术 |
RLVR 换掉的不是算法,而是奖励的来源:把"学出来的偏好模型"换成"确定性的验证程序",奖励变成二值的 0/1。它的边界同样清楚——只在"能被程序判对错"的领域成立(数学、代码、形式化逻辑、结构化指令遵循);写作、开放问答这类没有唯一判据的任务,仍然得回到偏好奖励。奖励换成可验证的,才谈得上把 RL 的规模做大。
上一张卡片我们把奖励换成了可验证的对错。现在的问题是:只有对错,模型凭什么学会"想更久"?
先把"学"这件事讲清:组内相对优势只看"同一题里哪条回答更好",完全不关心它是怎么想出来的。可以把这类比成打靶训练:教练不点评姿势,只在命中时报一声"中"——练久了,你自己会摸索出更容易命中的姿势。于是策略的 gradient 只会沿着"更可能答对"的方向走;只要"想得更久"恰好与答对相关,它就会被反复强化。
更早、也更自然的做法是先做 SFT、把「怎么想」的示范喂进去——但那要有现成的高质量长链推理数据,而这类数据恰恰很贵、很难大规模获得。R1-Zero 反过来走:不加任何示范,只留「答案对不对」的 0/1 奖励,让基座自己从 15.6% 的起点摸索,最终把 AIME 2024 的 pass@1 推到 71.0%——自我检查、回溯都不是被教的,而是「更可能答对」被强化出来的副产品。
| 指标 | 起点 | 终点 | 备注 |
|---|---|---|---|
| AIME 2024 pass@1 | 15.6% | 71.0% | 单次采样答对率 |
| AIME 2024 多数投票 | — | 86.7% | 论文称与 o1-0912 相当 |
| pass@1 提升倍数 | — | 71.0 ÷ 15.6 ≈ 4.55 倍 | 算术 |
| 奖励项 | 类型 | 作用 |
|---|---|---|
| 正确性 | 规则校验(二值) | 数学比对最终答案、代码跑测试 |
| 格式 | 规则校验(二值) | 要求把思考包在 <think>、答案包在 <answer> |
| 神经奖励模型 | 不使用 | 论文明确排除,理由是长链推理下容易被钻空子 |
| 现象 | 说明 | 代价 |
|---|---|---|
| 平均响应 token 数上升 | 论文 Figure 3 记录训练全程平均响应长度持续增长 | 推理成本随长度上升 |
| 自我检查 / 回溯 | 出现"等一下,这里不对"式的回头重算 | 重复劳动、偶发绕圈 |
| 可读性差 / 语言混杂 | R1-Zero 的已知缺陷 | 难以直接上线,需后续阶段修 |
R1-Zero 说明的是当奖励够纯、够可验证时,RL 能在基座之上自己找到提升路径——自我检查、回溯都不是被教的,而是"有利于答对"被强化的结果。但同时要记住两件事:① 这些行为的代价是输出变长、变难读;② "同时发生"不等于"因果"。把长度直接当成"变强的原因"去追求,正是下一张卡片的坑。
上一张卡片我们发现"平均响应长度"一路在涨。长度本身不是坏事,问题是——它也会被优化器当成捷径。
关键在损失怎么算:GRPO 会把一条回答的总损失按 token 数做归一化(normalization),而每条回答的贡献又要在组内取平均。可以把这类比成按"每道题的平均分"给班级排名:一个学生交的题越少,他每道题占的权重就越大——于是"少做题"意外变成了一种策略。所以只要长度进了分母或求和,它就不再是中性的,而是一个可以被优化的维度。
更早的做法是只用最终对错、对长度不加任何约束——看上去最干净,但损失里的长度项会悄悄把「答错就多写」变成划算的选择:同组里答错的回答从 100 个 token 拉到 300 个,每个 token 分到的惩罚就从 0.01 摊薄到 0.0033——总惩罚不变,但长回答的逐 token 梯度被摊薄了。训练越久,错误回答被拉得越长。
| 回答 | 结果 | token 数 | 组内优势 A | 逐 token 权重 |
|---|---|---|---|---|
| ① | 对 | 100 | +1 | 1 ÷ 100 = 0.010 |
| ② | 错 | 300 | −1 | −1 ÷ 300 = −0.0033 |
| ③ | 对 | 300 | +1 | 1 ÷ 300 = 0.0033 |
| 口径 | 逐 token 权重 | 对长度的偏好 |
|---|---|---|
| 样本级(除以 |oi| 再组内平均) | 1 / |oi| × Ai | 答错时偏向长回答 |
| token 级(全批总 token 归一) | 1 / Σ|oj| × Ai | 长度不再进分母,偏差消除 |
| DAPO 的超长奖励塑形 | 超过软阈值后奖励线性下降 | 给"过长"一个连续代价 |
| 方案 | 基座 | AIME 2024 | 备注 |
|---|---|---|---|
| 朴素 GRPO 复现 | Qwen2.5-32B | 30 分 | DAPO 论文自述的起点 |
| DeepSeek-R1-Zero-Qwen-32B(Qwen 基座复现) | Qwen-32B | 47 分 | 非官方 V3-Base 版;官方 R1-Zero 的读数见 Card 3(71.0%) |
| DAPO | Qwen2.5-32B | 50 分 | 只用了一半训练步数 |
| Dr. GRPO | Qwen2.5-Math-7B | 43.3% | 7B 规模 |
长度膨胀不是"模型变啰嗦"的性格问题,而是目标函数里的结构性偏差:只要长度以分母或求和的形式进入损失,优化器就有动机去操纵它。处置方式有两条——把长度从归一化里拿掉(Dr. GRPO),或给它一个显式价格(DAPO 的超长惩罚)。两条路指向同一件事:凡是能被优化的量,都必须先想清楚给它定的价对不对。
上一张卡片我们算清了"想太久"的代价。既然长度既是成本、又能换来能力,那正确的问法就不是"要不要想久",而是这笔预算怎么分配。
三种花法摆在一起看:串行(一条回答想更久)、并行(多条独立回答,投票或挑最好的)、验证器搜索(让另一个模型逐步打分并剪枝)。可以把这类比成解题时间:你可以一道题死磕一小时,也可以十分钟做一份、做四份再对答案——哪种更划算,取决于这道题值不值得死磕。
| 策略 | 怎么花算力 | 需要的额外组件 | 典型适用 |
|---|---|---|---|
| 串行延长(budget forcing) | 把单条思考拉长(续写"Wait") | 无 | 难题、单次生成 |
| 并行采样 + 多数投票 | 同题采 N 条,取出现最多的答案 | 无 | 答案短、可投票 |
| best-of-N | 采 N 条,用打分器挑最好 | 打分器(奖励/验证模型) | 有可靠打分器 |
| 验证器搜索(PRM/ORM:PRM = 对每一步中间推理打分的奖励模型;ORM = 只看最终答案对错的奖励模型) | 逐步打分 + 剪枝 / 回溯 | 过程奖励模型 | 步骤可判的推理 |
| 项 | 数值 | 说明 |
|---|---|---|
| 基准思考长度 | 约 800 token(示意) | 单条回答的平均长度 |
| 延长后思考长度 | 约 3,200 token | 拉长 4 倍 |
| AIME24 pass@1 | 50% → 57% | s1 项目页报告的 budget forcing 外推读数(论文口径为 56.7%,arXiv:2501.19393) |
| AIME24 题量 | 15 题 / 年 | 官方赛制 |
| 换算成题 | 15 × (57% − 50%) = 1.05 题 | 算术 |
| 额外 token | 15 × (3,200 − 800) = 36,000 token | 按示意长度算 |
| 题目难度 | 加算力的收益 | 该怎么做 |
|---|---|---|
| 简单(模型本来就对) | 接近 0,甚至变差(绕圈) | 不要加预算 |
| 中等(有时对有时错) | 最高 | 加预算最划算 |
| 过难(几乎总错) | 很低 | 加预算也难救 |
test-time scaling 不是"想得越久越好",而是一笔要按题分配的预算。同一份算力,串行拉长、并行投票、验证器搜索各有适用面;而最关键的旋钮是"把预算给哪些题"——按难度自适应分配,效率能比均匀分配高数倍。这也给工程上留下空间:思考长度、context 占用与单位成本,其实是同一个旋钮的三个面。
上一张卡片我们把"想多久"算成了一笔预算。那还有一条更省的路:不让小模型自己想,而是让它学会大模型怎么想。
这里有两种"搬"的方式,容易混:经典的知识蒸馏让学生的 logits 去逼近教师的 logits 分布(学的是"每个位置上老师会怎么选");而 R1 蒸馏是小模型直接模仿教师写出来的思考轨迹(一条条 token 序列)。可以把这类比成学做菜:前者是站在旁边看师傅每一步的手感,后者是照着师傅写好的菜谱一句句练。因此后者的实现简单得多——它就是一次普通的 SFT。
更自然的做法是让 7B 也自己跑 RL(和训大模型一样的流程)——但那需要环境、验证器与持续的在线采样,成本随采样量线性增长,7B 靠自己探索的上限也更低。R1 蒸馏先用 671B 的 R1 生成约 80 万条轨迹,小模型只做一次 SFT 就拿到 AIME 2024 55.5%——用一次性、可预估的离线成本,换教师已经探明的那条路径。
| 项 | 数值 | 说明 |
|---|---|---|
| 总样本 | 约 80 万条 | R1 生成(论文口径) |
| 其中推理相关 | 约 60 万条 | 论文口径 |
| 其余(通用类) | 约 20 万条 | 由 80 − 60 推得,具体构成以论文原表为准 |
| 训练方式 | 只做 SFT,不做 RL | 关键差别 |
| 模型 | 规模 | AIME 2024 pass@1 | MATH-500 | 训练方式 |
|---|---|---|---|---|
| DeepSeek-R1 | 671B 总 / 37B 激活 | 79.8% | 97.3% | 多阶段 RL |
| R1-Distill-Qwen-7B | 7B 稠密 | 55.5% | 92.8% | 纯 SFT 蒸馏 |
| R1-Distill-Qwen-7B(cons@64) | 7B 稠密 | 83.3% | — | 推理时多数投票 |
| 维度 | 蒸馏(模仿轨迹) | RL(自己探索) |
|---|---|---|
| 需要什么 | 教师 + 一次 SFT | 环境 / 验证器 + 在线采样 |
| 成本形态 | 一次性、可预估 | 持续、随采样量增长 |
| 上限 | 受教师限制 | 可能超过教师(R1-Zero 从 15.6% 一路爬到 71.0%) |
| 风险 | 会把教师的坏习惯一起学走 | 长度膨胀、训练不稳 |
蒸馏和 RL 不是替代关系,而是两种不同的"思考从哪来":蒸馏把已有的推理模式高效复制到小模型(便宜、可预估、上限被教师封顶);RL 则让模型自己探索(贵、可能超车,但更容易踩长度膨胀这类坑)。工程上常见的组合是:先用 RL 把大模型的上限推上去,再蒸馏给小模型落地。