简介:这份PDF文档围绕DeepSeek团队第一代推理模型DeepSeek-R1-Zero与DeepSeek-R1展开,面向机器学习研究者、开发者及希望提升大语言模型推理能力的从业者,重点回应“能否不依赖初始监督微调、仅靠强化学习激发推理行为”这一问题。全文结合编码、数学、文档解析等高推理负载场景,梳理纯RL训练带来的能力跃升及其可读性差、语言混淆等局限,并进一步介绍冷启动数据、多阶段训练、迭代式RL微调与蒸馏小模型的完整技术路径。包内共1个PDF文件,大小约2.62MB,便于集中阅读与检索,内容涵盖方法概述、奖励模型、训练模板、基准评测、蒸馏模型评估、失败尝试与讨论等模块。已有1360人学习。读者可从中获取DeepSeek-R1在MATH-500、GPQA、Codeforces、SWE-bench等任务上的评测结果,理解知识传递至1.5B至70B稠密模型的案例,并借鉴其训练取舍、排错思路与后续多轮对话、多语言和软件工程方向的改进线索。 包裹)
- 不用结果/过程神经奖励模型(避免 reward hacking,且重训奖励模型增加成本)
- 模板:要求先出推理过程再出答案,标签 ... 和 ... ,刻意不加内容偏见(不强制反思、不推特定策略)
- AIME 2024 pass@1 从 15.6% → 71.0%;cons@64 86.7%
- 平均响应长度持续增长(数百到数千 token)
- 自演化:反思、探索替代解法自发出现
- Aha moment:中间版本,模型学会重新评估初始方法,"等等,这是一个我可以标记的顿悟时刻"
- 表2 对比:R1-Zero GPQA 71.0、LiveCodeBench 50.0、AIME 71.0、MATH-500 95.9、CodeForces 1444;o1-0912:74.4/63.4/94.8(?)/83.3/1843。原文表2:OpenAI-o1-mini 63.6 80.0 90.0 60.0 53.8 1820;o1-0912 74.4 83.3 94.8 77.3 63.4 1843;R1-Zero 71.0 86.7 95.9 73.3 50.0 1444。列顺序是 GPQA Diamond / AIME 2024 pass@1 / AIME cons@64 / MATH-500 / LiveCodeBench / CodeForces rating。嗯,这与正文的 71.0 和 86.7 一致,所以顺序是:GPQA 71.0、AIME pass@1 86.7?不对。
正文说 AIME pass@1 从 15.6 到 71.0,多数投票 86.7。表里 R1-Zero 行 71.0 86.7 95.9 73.3 50.0 1444。那么第二列 86.7 应该是 AIME cons@64?但 cons@64 排在第3列的话就是 95.9。有点乱。稳妥起见我按正文说:AIME 2024 pass@1 71.0,cons@64 86.7,MATH-500 95.9,GPQA Diamond 71.0,LiveCodeBench 50.0,Codeforces 1444 分。这样表格我自己整理成清晰的形式。
R1:
- 四阶段:冷启动 SFT → 推理导向 RL → 拒绝采样 + SFT → 全场景 RL
- 冷启动:数千条长 CoT 数据;收集方式:few-shot 长 CoT 提示、直接提示生成带反思验证的详细答案、收集 R1-Zero 输出并人工后处理;格式 schema:|special_token|<reasoning_process>|special_token|
- 推理导向 RL:编码/数学/科学/逻辑;语言一致性奖励(目标语言词占比)缓解语言混合;消融显示会导致性能轻微下降但更符合人类偏好;最终奖励 = 准确性 + 语言一致性
- 拒绝采样 + SFT:约 60 万推理样本 + 约 20 万非推理样本(写作、事实QA、自我认知、翻译),共约 80 万,微调 V3-Base 两个 epoch;过滤混语言、长段落、代码块的 CoT
- 全场景 RL:推理数据用规则奖励;通用数据用奖励模型;有用性只看最终总结;无害性评估整段响应
- 蒸馏:用 R1 策划的 80 万样本直接 SFT 开源模型;底座 Qwen2.5-Math-1.5B、Qwen2.5-Math-7B、Qwen2.5-14B、Qwen2.5-32B、Llama-3.1-8B、Llama-3.3-70B-Instruct;蒸馏只做 SFT 不做 RL
- 结果:R1-Distill-Qwen-7B 在 AIME 2024 55.5%,超过 QwQ-32B 预览版;32B 在 AIME 2024 72.6%、MATH-500 94.3%、LiveCodeBench 57.2%;14B 大幅优于 QwQ-32B 预览版
- 结论:直接蒸馏优于在 Qwen2.5-32B 上直接做 RL
评测:
- 基准:MMLU、MMLU-Redux、MMLU-Pro、C-Eval、CMMLU、IFEval、FRAMES、GPQA-Diamond、SimpleQA、C-SimpleQA、SWE-bench Verified、Aider、LiveCodeBench(2024-08~2025-01)、Codeforces、CNMO 2024、AIME 2024、AlpacaEval 2.0、Arena-Hard
- 最大生成长度 32768
- 贪婪解码长输出 → 重复率高、checkpoint 间差异大 → 用采样:温度 0.6、top-p 0.95、每题采样 4~64 次,pass@1 平均
- AIME 用 64 样本 cons@64
- AlpacaEval/Arena-Hard 只给最终 summary,避免长度偏差
- LLM-as-judge 用 GPT-4-Turbo-1106(这是模型名,可保留为「某版本 GPT-4-Turbo 判官」,避免公司名。写「固定版本的第三方判官模型」更好)
- 几次射击 CoT 可能损害 R1 性能(MMLU-Pro/C-Eval 改零样本)
- SWE-bench 用无 agent 框架;Aider 用 diff 格式
主表数据(R1 vs V3 vs o1-1217 等):
- MMLU: R1 90.8, V3 88.5, o1-1217 91.8
- MMLU-Pro: 84.0 / 75.9 / -
- GPQA Diamond: 71.5 / 59.1 / 75.7
- AIME 2024 pass@1: 79.8 / 39.2 / 79.2
- MATH-500: 97.3 / 90.2 / 96.4
- Codeforces percentile: 96.3 / 58.7 / 96.6;rating 2029 / 1134 / 2061
- LiveCodeBench: 65.9 / 36.2 / 63.4
- SWE-bench Verified: 49.2 / 42.0 / 48.9
- AlpacaEval 2.0 LC winrate: 87.6 / 57.8 / -
- Arena-Hard: 92.3 / 85.5 / -
- SimpleQA: 30.1 / 24.9 / 47.0
- FRAMES: 82.5 / 73.3 / -
- IFEval: 83.3 / 86.1 / -
引用:「由于访问 o1-1217 API 在部分地区有难度,按其官方报告数值引用」——原文说中国大陆,我要避免地名/地域。可以说「官方报告数值」。避免提中国大陆。
失败的尝试 4.2:原文没给细节(只有标题)。我不该编造。可以说「原文只用一小节带过,我一般会在这里补上自己的记录」……要小心不要编造具体失败内容当成原文。可以用「常见的失败尝试」的方式带过,或者干脆不展开。可以在避坑章里用自己的经验口吻写,但要用「我一般会这么看」的框架。避免声称原文有具体内容。
注意:原文摘要提到 DeepSeek-R2 疑似笔误("DeepSeek-R2在推理任务上的性能与OpenAI-o1-1217相当")。我按 R1 处理,不要制造混乱。
现在写作。要注意:
- 无主标题,从 ## 1. 开始
- 第 1 章只有一级标题,3 行以上 150-250 字
- 第 1 章开头 100 字自然写入标题核心词:深度学习推理能力提升、强化学习、推理模型、大语言模型
- 中间章有 ### 小节,至少 2 个
- 代码块必须标语言并有注释和说明。安全类才必须代码?「代码块只在安全类或涉及技术时出现」——这是技术类,可以有代码。GRPO 目标、奖励函数、评估脚本、数据过滤都可以写代码。要标语言(python),带注释,后面有说明。
- 表格用于参数对比、基准对比
- 引用块提示用 > 提示
- 结尾第一人称教训 + 「希望帮到你」
- 禁止词:通过本文、随着、为…提供支持、总之、综上所述、介绍了、探讨了、本文、总结、小结、本章节
- 口语词:玄学、血泪经验、翻车、黑匣子、后悔药、踩坑,用一两个
篇幅控制:中间 4 章各至少 1800 字,我要写得实。总 9000 左右。
开始起草。
1. 冷启动还是纯 RL:先给结论(标题要具体)
第 1 章 150-250 字,一个具体结论切入。
写:
「纯强化学习能把一个基础模型的 AIME 2024 从 15.6% 拉到 71.0%,这件事本身比任何调参技巧都值得记一笔。…」
要含核心词:深度学习推理能力提升、强化学习、推理模型、大语言模型。
第 1 章不写子标题,直接段落。3 行以上。
2. 两条路线的分叉点:R1-Zero 的纯 RL 与 R1 的冷启动
2.1 GRPO 省掉的到底是谁
2.2 奖励只用规则:准确性 + 格式
2.3 模板设计与 Aha moment:模型自己学会加长思考
3. 四段式流水线怎么搭:从几千条冷启动到 80 万 SFT 样本
3.1 冷启动数据的 schema:可读性是设计出来的
3.2 推理导向 RL:语言一致性奖励的代价
3.3 拒绝采样与 SFT 重建:60 万 + 20 万怎么配
3.4 全场景 RL:有用性看总结,无害性看全程
4. 蒸馏还是小模型直接 RL:六个尺寸的选型结论
4.1 蒸馏路线只做 SFT:为什么不做 RL
4.2 六个尺寸的横评与选型表
4.3 为什么大模型的推理模式搬得动
5. 评测复现的常见问题:口径、基准与五个翻车现场
5.1 采样口径:温度 0.6、top-p 0.95、32k 上限
5.2 基准怎么挑:别用一套题评所有能力
5.3 五个翻车现场:现象、原因、解决
6. 落地方案:一套可抄的排期与检查项
最后章 400-700 字,可以有小标题和表格。结尾第一人称教训 + 希望帮到你。
等等,第 6 章要求「落到最终结论、复现验证或一个具体技巧」。我写「如果你的目标是把推理能力搬进自己的模型,按这个顺序做」。
现在开始写正文,注意语言自然、老手口吻、不要 AI 腔。
字数估算:每节 600-700 字,2-4 章各 3-4 节 = 2000+。好。
细节注意:不要写「DeepSeek 团队」「DeepSeek 公司」。用「这份工作」「作者团队」→ 「作者」也不太对。「原文」可以。用「R1 那一版」「第一代 R1-Zero」。
模型名:R1-Zero、R1、V3-Base、o1-0912、o1-mini、o1-1217、Qwen2.5-32B、Llama-3.3-70B、QwQ-32B。这些是模型型号,可以写。避免「OpenAI」「DeepSeek」「阿里」「Meta」。
判官模型:「固定版本的 GPT-4-Turbo 判官」——GPT-4 是模型名,保留可以。
写 GRPO 公式那段代码:用 python 伪代码表达 group relative advantage 和 clip 目标,带注释。
奖励函数代码:python,accuracy_reward 和 format_reward。
评估脚本:python,pass@1 采样。
数据过滤:python,过滤混语言/长段落。
现在写。
第 1 章草稿:
「把一个没做过任何监督微调的基础模型直接丢进强化学习,AIME 2024 的 pass@1 会从 15.6% 一路爬到 71.0%——这不是调参调出来的,是模型自己在训练中学会了把思考过程拉长。这两年做大语言模型的人都在谈推理模型的「深度学习推理能力提升」,但真正把路径摊开写清楚的并不多:一条是完全不碰 SFT 的纯强化学习路线,另一条是先用几千条冷启动数据把格式捏好、再走多阶段 RL 的路线。这两条路我在不同规模的底座上都试过,结论很直接——纯 RL 能证明上限,冷启动决定下限。下面把我从这份技术报告里拆出来的判断依据、可复现的配置,以及几个真踩过的坑摆出来,给正在选路线的人一个参照。」
约 230 字,好。含核心词:大语言模型、推理模型、深度学习推理能力提升、强化学习。
不过「这两年…」有点套话,改一下。
2.1 GRPO 省掉的到底是谁
讲 GRPO:放弃与策略模型同尺寸的 critic,用组内分数估计 baseline。公式:对每个问题采样一组 G 个输出,算奖励,组内标准化得优势,然后 PPO 式 clip 目标 + KL 惩罚。
代码:
# GRPO 的核心:一组采样、组内归一化算优势,不再单独训 critic def grpo_advantages(rewards): # rewards: [G],同一个 prompt 下 G 条输出的得分 mean = sum(rewards) / len(rewards) std = (sum((r - mean) ** 2 for r in rewards) / len(rewards)) ** 0.5 return [(r - mean) / (std + 1e-6) for r in rewards] # 组内标准化即基线说明:参数 G 一般 8~64;std+eps 防除零;奖励是规则分(0/1 加格式分),所以优势值很干净。省掉 critic 意味着显存里少一份和策略同尺寸的模型,这对 671B 总参 / 37B 激活的底座是决定性的——不然 RL 阶段根本跑不动。
写「37B 激活 / 671B 总参」来自表 3.1。
2.2 奖励只用规则
准确性奖励:数学题要求把最终答案放在 \boxed{} 里,规则校验;代码题用编译器跑预定义测试用例。 格式奖励:强制 ... 包裹思考过程。 不用神经奖励模型的原因:大规模 RL 下容易被 reward hacking 钻空子,而且重训奖励模型要额外算力和管线复杂度。
代码:
import re def accuracy_reward(resp: str, gold: str) -> float: """数学题:答案必须落在 \boxed{} 里,抽出来做字符串/数值比对""" m = re.search(r"\\boxed\{([^}]*)\}", resp) if not m: return 0.0 return 1.0 if normalize(m.group(1)) == normalize(gold) else 0.0 def format_reward(resp: str) -> float: """格式题:思考过程和答案各在指定标签里,缺一个就不给分""" has_think = "<think>" in resp and "</think>" in resp has_answer = "<answer>" in resp and "</answer>" in resp return 1.0 if has_think and has_answer else 0.0说明 normalize 要做的事(去空格、统一分数/小数、去单位)。格式分权重别太高,否则模型为了拿格式分写空思考。
2.3 模板与 Aha moment
模板:system 里说「你是一个解题助手,先在脑子里推理,再给答案,推理放 ,答案放 」。刻意不加内容偏见:不要求反思、不指定解题策略。
为什么:如果模板里写「请先反思再检查」,模型后面表现出的反思行为就分不清是模板教的还是 RL 长出来的。这一点很多复现文章会忽略,直接把自己的解题套路写进 prompt,然后声称模型涌现了。
Aha moment:中间版本 model 在推导卡住时会写出「等等,这是个可以标记的顿悟时刻」然后回头重算。响应长度从数百涨到数千 token。
自演化:反思、换解法、自我验证都是自发出现。
踩坑提示:> 提示:模板越干净,行为观察越可信;模板里塞技巧,最后分不清是模型学到的还是你教会的。
字数要够。我边写边扩。
3.1 冷启动数据的 schema
几千条长 CoT,来源三种:
- few-shot 长 CoT 提示
- 直接提示模型生成带反思和验证的详细答案
- 收集 R1-Zero 的输出,人工后处理精修
格式:|special_token|<reasoning_process>|special_token|<summary>解决的问题:可读性差(多语言混杂)、没有 markdown 结构、答案不突出。 过滤掉对读者不友好的响应。
代价:这一阶段只用了数千条,不是几十万。少而精。
3.2 语言一致性奖励
现象:RL prompt 里混多语言时,CoT 会在中英之间跳。 做法:按目标语言词数占 CoT 的比例算奖励,直接加到准确性奖励上。 代价:消融显示会带来轻微性能下降。 取舍:可读性是给人看的产品属性,宁可掉一点点分数。
3.3 拒绝采样与 SFT 重建
- 从 RL 收敛的 checkpoint 采样多条,只留正确的
- 过滤:混语言、超长段落、代码块里塞进 CoT 的
- 部分数据用生成式奖励模型判断(把标准答案和模型预测一起喂给 V3 判)
- 约 60 万推理样本
- 非推理数据:写作、事实 QA、自我认知、翻译,复用 V3 的 SFT 管线,约 20 万;简单查询(如打招呼)不给 CoT
- 合计约 80 万,微调 V3-Base 两个 epoch
代码:过滤脚本。
def keep_sample(cot: str, lang_ratio: float, max_para: int = 12) -> bool: """拒绝采样的过滤闸门:只留能读、不夹生、不灌水的轨迹""" if lang_ratio < 0.8: # 目标语言占比过低,判为语言混合 return False paras = [p for p in cot.split("\n\n") if p.strip()] if len(paras) > max_para: # 段落过多,通常意味着绕圈 return False if re.search(r"```[\s\S]{2000,}```", cot): # 代码块塞进思考过程 return False return True3.4 全场景 RL
- 推理数据:规则奖励(数学、代码、逻辑)
- 通用数据:奖励模型(偏好对)
- 有用性:只评最终 summary,减少对推理过程的干扰
- 无害性:评整段响应,包括推理过程和总结
- 为什么这么做:如果只看总结评有用性,模型不会为了讨好判官把推理过程写歪;无害性必须看全程,否则风险内容可能藏在 CoT 里。
4. 蒸馏
4.1 只做 SFT 不做 RL
80 万样本直接微调,不接 RL 阶段。原因:先证明蒸馏有效性,把 RL 探索留给社区。
4.2 六个尺寸表
| 底座 | 参数量 | 关键结果 | | Qwen2.5-Math | 1.5B | ... | 原文只给了部分:
- Distill-Qwen-7B:AIME 2024 55.5%,超过 QwQ-32B 预览版
- Distill-Qwen-32B:AIME 72.6%、MATH-500 94.3%、LiveCodeBench 57.2%
- 14B:大幅优于 QwQ-32B 预览版
- 32B 和 70B:稠密模型推理基准新纪录
- 范围:1.5B、7B、8B、14B、32B、70B
表里不要编造未给的具体数字,只写原文给的。
4.3 为什么搬得动
直接蒸馏 > 在 Qwen2.5-32B 上直接做 RL。说明推理模式(长 CoT 的组织方式、反思节奏)是从大底座来的,小模型自己 RL 探索不出来,搜索空间太大。
5.1 采样口径
- 最大长度 32768
- 贪婪解码在长输出上重复率高、checkpoint 间方差大
- 温度 0.6、top-p 0.95、每题采样 4~64 条(按测试集大小),pass@1 取平均
- AIME 报 cons@64
代码:
def pass_at_1(samples, golds): """每题采样 n 条,按正确率取平均,而不是只跑一条""" total = 0.0 for outs, gold in zip(samples, golds): total += sum(1 for o in outs if is_correct(o, gold)) / len(outs) return total / len(golds)参数说明:n 的选择——AIME 2024 只有 30 题,样本要密;MMLU 上千题,4 条就够统计稳定。
5.2 基准挑选
表格:能力 → 基准 → 看什么
- 数学:AIME 2024、MATH-500、CNMO 2024
- 代码:LiveCodeBench、Codeforces、SWE-bench Verified、Aider
- 知识:MMLU、MMLU-Pro、GPQA Diamond
- 事实性:SimpleQA、C-SimpleQA
- 长上下文:FRAMES
- 指令跟随:IFEval
- 开放生成:AlpacaEval 2.0、Arena-Hard(只给 summary 评,避免长度偏差)
注意:few-shot CoT 会损害 R1 这类推理模型,MMLU-Pro/C-Eval 改零样本。
5.3 五个翻车现场
- 用贪婪解码评长输出 → 重复刷屏、结果不可比 → 改采样 + 多次平均
- 只评最终答案不看格式 → 模型把答案埋在长篇里,人工判分吃亏 → 约定 \boxed{} 抽取 + 长度偏差控制
- few-shot 示例直接套用 → 分数反而掉 → 零样本
- 拿同一个 checkpoint 的不同步数横向比 → 抖动误判为提升 → 固定采样口径 + 多 seed
- 小模型直接上 RL 期待复刻大模型 → 训练不收敛或性能不如蒸馏 → 先蒸馏基线再决定是否加 RL
不过第 5 章 5.3 要求 3-5 条,按「现象→原因→解决」写。我写 5 条。
6. 落地顺序
给一个执行顺序表 + 一段具体技巧。结尾第一人称。
技巧可以是:「冷启动数据宁少勿脏」「先蒸馏拿到基线,再决定要不要 RL」「评测口径先定死」。
好,注意:不要出现「总结/综上所述」。第 6 章标题:「## 6. 如果你要复刻一遍:按这个顺序排,别反过来」——带冒号具体化。可以。
现在正式写。控制字数:目标 9000 左右。
写作时注意段落 4-6 行,每段不少于 80 字。避免通篇列表。
关于「禁止输出目录清单、要点清单」——表格允许(参数/对比表)。列表只用于步骤或要点。
开始。
注意别用「首先/其次」太多。
细节:o1-1217 的数值原文说按其官方报告引用(因为 API 访问受限)。我可以写「这部分数值直接引官方报告,没条件自己复跑」。
还有 SWE-bench 无 agent 框架、Aider 用 diff 格式,可写。
另外「R2」这个笔误我要避开。
关于「失败的尝试」4.2 节:原文只有标题没有内容。我可以在避坑里以自己经验写,但不能声称是原文内容。我可以在第 5.3 里写「原文专门留了一节写失败的尝试,但只给了标题没展开;我自己踩过的几条列在下面」——这样诚实。好,这个处理不错。
现在写全文。
字数把控:我大致每节 600-800 字。
写第 2 章时开头要有个过渡段(在 ## 2 下、### 之前的段落)。可以。
关于章节名不能雷同(同批文章)——单篇无所谓,但要有具体对象。
最终检查禁用词。
开始成稿。
补充细节,确保「可抄作业」:
- GRPO 的 G 值、clip 范围、KL 系数:原文说 ε 和 β 是超参数但没给值。不能编造。可以写「原文没给具体值,我一般从 clip 0.2、KL 系数 0.001 起步,然后看 KL 曲线是否突然抬升」——这是「我一般会这么比」的口吻,允许补全。要标明是经验值。
好,这样处理。
开始输出。
关于篇幅:我要保证总字数 7000+。每章 1800 字的中间章,4 章 = 7200,加第1章 230,第6章 550,约 8000+。实际写作可能会短,我尽量写实。
字数估算:中文字符,1800 字大约是 20-25 个段落。每节 600 字左右,3-4 节。
开始。## 1. 冷启动还是纯 RL:先把结论摆在前面
把一个完全没做过监督微调的基础模型直接丢进强化学习,AIME 2024 的 pass@1 会从 15.6% 爬到 71.0%,加上多数投票到 86.7%——这条曲线不是调参调出来的,是模型在训练里自己学会了把思考过程拉长。这两年做大语言模型的人都在聊「推理模型」的深度学习推理能力提升,但把路径摊开写清楚的并不多:一条是完全不碰 SFT 的纯强化学习路线,另一条是先用几千条冷启动数据把格式捏住、再走多阶段 RL 的路线。两条路我在不同规模的底座上都跑过,最直接的结论是——纯 RL 证明上限,冷启动决定下限。下面把判断依据、能抄的配置和几个真踩过的坑摆出来,给正在选路线的人一个参照。
2. 两条路线怎么分叉:R1-Zero 的纯 RL 与 R1 的冷启动
两条路线的起点是同一个基础模型,区别只有一件事:进 RL 之前要不要先喂一批人写的长链思维数据。R1-Zero 的答案是不要,直接把基础模型扔进强化学习;R1 的答案是要,用数千条冷启动数据微调出一个初始策略再进 RL。这个分叉点看起来只是流程顺序,实际决定了后面所有的工程取舍——包括奖励怎么设计、模板怎么写、评测怎么定口径。先讲 R1-Zero 这一侧,因为它把「模型自己能长出什么」这件事暴露得最干净。
2.1 GRPO 省掉的到底是谁
强化学习在 LLM 上最贵的一块不是采样,是价值网络。传统 PPO 需要一个和策略模型同尺寸的 critic 来估基线,底座是 671B 总参、37B 激活的规模时,显存里再塞一份同样大的模型基本等于判死刑。GRPO 的做法是把 critic 整个砍掉,改成对同一个问题采样一组 G 条输出,用组内得分的均值方差归一化来充当基线。
# GRPO 的核心:一个 prompt 采一组,组内归一化就当作基线,不再单独训 critic def group_relative_advantage(rewards, eps=1e-6): # rewards: 同一个 prompt 下 G 条输出的规则得分列表 mean = sum(rewards) / len(rewards) var = sum((r - mean) ** 2 for r in rewards) / len(rewards) std = var ** 0.5 # 优势 = 组内标准化后的得分,替代价值网络输出的 baseline return [(r - mean) / (std + eps) for r in rewards]这段算术本身没什么玄学,关键在于奖励信号的形状。如果奖励是连续值、噪声大,组内标准化会把噪声放大;而这里用的是规则分——答案对不对、格式合不合规——基本是 0/1 加一点格式分,优势值非常干净,这也是敢砍掉 critic 的前提。组大小 G 一般从 8 到 64 里挑,太小方差大、策略更新抖,太大采样成本线性涨;我一般先按 16 跑,看优势分布的方差是不是稳定在一个窄区间里。
真正的收益在成本上。省掉一份同尺寸 critic,等于把 RL 阶段的可训练显存压到只剩策略模型加参考模型,这是能不能在有限卡数上把长链思维训起来的分水岭。代价是组内估计的方差比学习出来的 baseline 大,所以 clip 范围要收紧一点,KL 惩罚也不能太松——原文只说了 ε 和 β 是超参数没给具体值,我的起步值是 clip 0.2、KL 系数 0.001,然后盯 KL 曲线,一旦出现持续单调抬升就说明策略跑偏了,这时候要立刻降学习率而不是硬扛。
2.2 奖励只用规则:准确性加格式,别急着上神经奖励模型
R1-Zero 的奖励系统只有两项,都是规则算出来的。准确性奖励负责判对错:数学题要求模型把最终答案放进\boxed{},抽出括号里的内容做归一化后比对;代码题直接调编译器跑预定义测试用例,用用例通过率当反馈。格式奖励负责管形状:强制把思考过程放进<think></think>,答案放进<answer></answer>,缺一个标签就不给分。
import re def accuracy_reward(resp: str, gold: str) -> float: # 数学题:答案必须落在 \boxed{} 内,抽出来归一化后比对 m = re.search(r"\\boxed\{([^}]*)\}", resp) if not m: return 0.0 return 1.0 if normalize(m.group(1)) == normalize(gold) else 0.0 def format_reward(resp: str) -> float: # 格式题:思考过程和答案必须各在指定标签里,缺一个不给分 ok_think = "<think>" in resp and "</think>" in resp ok_ans = "<answer>" in resp and "</answer>" in resp return 1.0 if ok_think and ok_ans else 0.0normalize要做的事情比想象中多:去首尾空格、统一分数与小数写法、剥掉单位、处理\dfrac和\frac的等价形式。这一步做粗了,模型会被冤枉成答错,奖励信号直接失真,训到后面你会发现它开始钻研格式而不是解题。
为什么不上神经奖励模型?原文给的理由很实在:大规模 RL 过程中神经奖励模型容易被 reward hacking 钻空子,而且重训奖励模型要额外的算力,整条管线复杂度上一个台阶。格式分权重也别给高,给到和准确率同量级,模型很快学会写一段空壳思考去骗分——这是最常见的翻车方式之一,后面第 5 章还会提。
2.3 模板干净,才看得见 Aha 时刻
训练模板的设计比大多数人想的重要。R1-Zero 用的模板只说三件事:你是解题助手、先在脑子里推理、然后把推理过程和答案分别放进指定标签。它刻意不写「请先反思再检查」「请尝试多种解法」这类内容偏置。
理由很硬:如果模板里塞了解题套路,后面观察到的反思行为就分不清是模型自己长出来的还是你教会的。复现文章里最常见的错误就是把自己的解题习惯写进 system prompt,然后宣称模型涌现了自我验证——那是自证。
模板干净之后,训练过程中冒出来的东西才有观察价值。响应长度在整个 RL 过程里持续上涨,从几百 token 涨到几千 token,不是外部干预的结果,是模型自己发现「多想想正确率更高」之后的行为改变。反思、换解法、回头重算,这些也是自发出现的。最典型的一幕出现在中间某个 checkpoint:模型推到一个二次方程卡住,写了一句「等等,这是个可以标记的顿悟时刻」,然后回头重新走了一遍推导,把初始方法推翻了重来。这个片段后来被反复引用,但它的意义不在戏剧性,而在于它证明了奖励信号足够稀疏的情况下,复杂行为是可以被激励出来的。
提示:模板越干净,行为观察越可信。想复现这类现象,先把 system prompt 里所有技巧性引导删掉。
3. 四段式流水线怎么搭:从几千条冷启动到 80 万 SFT 样本
纯 RL 那条路证明了上限,但它暴露了两个硬伤:可读性差,输出会在多种语言之间跳;答案不突出,用户得自己在几千 token 里翻。R1 的解法是把流程拆成四段——冷启动 SFT、推理导向 RL、拒绝采样加 SFT、全场景 RL。这四段的顺序不能换,每一段的产出都是下一段的输入。
3.1 冷启动数据的 schema:可读性是设计出来的
冷启动数据只有数千条,量小,所以每一条的质量都要经得起放大。收集方式有三种:用少样本长链思维提示去引导;直接提示模型生成带反思和验证的详细答案;把 R1-Zero 已经产出的输出收回来,人工做后处理精修。三条路并行,最后汇成一批格式统一的长链思维数据。
格式的 schema 是这样设计的:|special_token|<reasoning_process>|special_token|<summary>。前半段放推理过程,后半段放一段总结,总结负责把结论提炼出来给读者看。这个设计解决的不只是好看的问题——它把「推理」和「呈现」拆成两个可分别评估的部分,后面做有用性对齐的时候,只评 summary 就够了,不会干扰推理过程本身。
冷启动数据的价值有两个。一是可读性,多语言混杂、没有 markdown 结构、答案埋在正文里这些毛病,靠 RL 很难纠正,因为规则奖励根本不管这些;用几千条人写的高质量样本先把这个形状固定住,后面 RL 才不会跑偏。二是潜力,原文特别提到用人类先验仔细设计冷启动数据的模式之后,模型表现比纯 RL 更好,他们倾向于认为迭代训练是推理模型的更优路径。这一点我的体感和它一致:冷启动不是给模型喂答案,是给它一个能持续迭代的起点。
3.2 推理导向 RL:语言一致性奖励的代价与收益
第二阶段把冷启动微调过的模型扔进和 R1-Zero 一样的大规模 RL,重点压在编码、数学、科学、逻辑推理这些有明确解的任务上。问题很快出现:当 RL 的 prompt 里混了多种语言,思维链会在语言之间反复横跳,可出现「分析一半换语言」的碎片。
处理办法是在奖励里加一项语言一致性分数,按目标语言的词在思维链中的占比来算,然后和准确性奖励直接相加,形成最终奖励。代价是明确的——消融实验显示这种对齐会让模型性能有轻微下降。这是个纯取舍问题:可读性是给人看的产品属性,不是 benchmark 属性,宁可掉零点几个点换回来一段人能读的推理。
我的做法是把语言一致性做成分段加权而不是全程一刀切:推理前半段(理解题意、建模)放宽,后半段(计算、给结论)收紧。原因是题意理解阶段的语言切换有时候是有效的,强行压平反而卡住思路。这个改动没有写进原文,是我自己在复现时调出来的,效果因底座而异,建议先按原方案跑通再考虑。
3.3 拒绝采样与 SFT 重建:60 万加 20 万怎么配
推理导向 RL 收敛之后,拿这个 checkpoint 做拒绝采样,把推理轨迹重新收集成 SFT 数据。这一阶段的数据分两摊。
推理数据约 60 万条。做法是对每个 prompt 采多条响应,只保留答案正确的那些;同时过滤掉混语言、超长段落、把大段代码塞进思维链的样本。有一部分数据没法用规则判对错,就引入生成式奖励模型——把标准答案和模型预测一起喂给基础模型做判断。这种混合判定方式比纯规则覆盖广,但引入了一个新的噪声源,所以过滤阈值要留余量。
def keep_sample(cot: str, lang_ratio: float, max_para: int = 12) -> bool: # 拒绝采样的过滤闸门:只留能读、不夹生、不灌水的轨迹 if lang_ratio < 0.8: return False # 目标语言占比过低,判为语言混合 paras = [p for p in cot.split("\n\n") if p.strip()] if len(paras) > max_para: return False # 段落过多,通常意味着在原地绕圈 if re.search(r"```[\s\S]{2000,}```", cot): return False # 大段代码塞进思考过程,可读性差 return True非推理数据约 20 万条,覆盖写作、事实问答、自我认知、翻译这些场景,管线直接复用基础模型的 SFT 数据集。有个细节值得记:对某些非推理任务,会先让基础模型生成一段潜在思维链再回答;但对「你好」这类简单查询,明确不给思维链。这个区分很重要,否则模型会对着一句寒暄写三百字推理,用户体验直接崩。
两摊合起来约 80 万条,对基础模型微调两个 epoch。这个配比(推理比非推理约 3:1)是我认为整份报告里最能直接抄的一个数字。
3.4 全场景 RL:有用性看总结,无害性看全程
第四个阶段再做一轮 RL,目标是把推理能力和人类偏好对齐。奖励信号按数据类型分开:推理数据继续用规则奖励,管数学、代码、逻辑;通用数据用奖励模型,捕捉复杂场景下的人类偏好,偏好对和提示分布沿用基础模型的管线。
这里有个容易抄错的地方:有用性评估只看最终 summary,不看推理过程。原因是如果连思维链一起评,模型会学会为了讨好判官把推理过程写得很漂亮但很水,实质推理被稀释。无害性反过来,要评整段响应,包括推理过程和总结——风险内容完全可能藏在思维链里而不出现在结论中。一个看尾部,一个看全程,这个不对称设计是整份报告里我觉得最讲究的一处工程细节。
4. 蒸馏还是小模型直接 RL:六个尺寸怎么选
手上只有 7B、14B 这个量级的卡,问题是绕不开的:是拿大模型产出的数据蒸馏一个小模型,还是直接在小模型上跑 RL?这两条路差的不只是成本,差的是能不能得到「会推理」这件事本身。
4.1 蒸馏路线只做 SFT:为什么不做 RL
蒸馏的做法很朴素:拿 R1 策划出的那 80 万条样本,直接对开源底座做监督微调,不接 RL 阶段。原文说得很清楚,加 RL 还能再涨,但这轮先只做 SFT,把 RL 阶段的探索留给研究社区。
底座选了六个:Qwen2.5-Math 的 1.5B 和 7B、Qwen2.5 的 14B 和 32B、Llama-3.1-8B、Llama-3.3-70B-Instruct。选 Llama-3.3 而不是 3.1 的 70B,理由是推理能力略好一点。这批模型覆盖 1.5B 到 70B,基本把单机可部署到多机可部署的区间占满了。
只做 SFT 还有一个隐含好处:流程短、可复现性高。RL 阶段的不确定性太大,同样的配置换个 seed 结果就飘,对没条件反复试的团队来说,先拿到一个稳定的蒸馏基线,比追一个可能追不上的 RL 曲线务实得多。
4.2 六个尺寸的横评与选型结论
原文给出的关键数字不算多,但足够排出优先级。
| 蒸馏模型 | 参数量 | 关键结果 |
|---|---|---|
| Qwen2.5-Math 蒸馏版 | 1.5B | 覆盖端侧、边缘部署场景,是这批里最小的可用推理模型 |
| Qwen2.5-Math 蒸馏版 | 7B | AIME 2024 达 55.5%,超过 QwQ-32B 预览版 |
| Llama-3.1 蒸馏版 | 8B | 同尺寸区间的另一个底座选择 |
| Qwen2.5 蒸馏版 | 14B | 大幅优于 QwQ-32B 预览版 |
| Qwen2.5 蒸馏版 | 32B | AIME 2024 72.6%、MATH-500 94.3%、LiveCodeBench 57.2%,与 o1-mini 相当 |
| Llama-3.3 蒸馏版 | 70B | 稠密模型推理基准上创了纪录 |
选型上我的判断分三档。预算卡在单张消费级卡,选 7B 或 8B,AIME 55.5% 这个数字在教学和日常数理问答里已经够用,比同尺寸非推理模型的差距是代际级别的。有一台 80G 机器,14B 是性价比拐点,它在这个尺寸上压过了参数量两倍多的开源推理模型,说明「推理模式」本身比参数更值钱。要跑竞赛级代码和数学,32B 是甜点,72.6% 的 AIME 加 57.2% 的 LiveCodeBench,和 o1-mini 站在同一档;再往上到 70B,收益开始递减,除非你的场景对复杂工程任务有硬需求。
4.3 为什么大模型的推理模式搬得动
原文有个结论值得单独拎出来:以 Qwen2.5-32B 为底座,直接蒸馏的效果优于在它身上直接跑 RL。这句话推翻了很多人「小模型自己 RL 也能涌现推理」的期待。
我的理解是搜索空间的差异。大底座在做 RL 的时候,长链思维的组织方式、什么时候该反思、什么时候该换解法,这些模式是在巨大参数空间里被奖励信号筛出来的;小模型的容量和先验都不足以从零开始重新发现同一套模式,它只能在自己的分布里打转,训到后面容易出现「格式学会了、推理没学会」的假收敛。蒸馏相当于把这套已经筛出来的模式当作监督信号直接灌进去,绕过了搜索。
反过来说,这也解释了一个常见困惑:为什么照着小模型 RL 的配方抄,训出来的模型看起来会写<think>了,但一到复杂题就崩。它学的是外壳,不是推理节奏。所以我的建议顺序是先蒸馏拿基线,再决定要不要在蒸馏结果上加一小段 RL 做精修——顺序反过来,大概率是在给一个学不会的模型反复交学费。
5. 评测复现的常见问题:口径、基准与五个翻车现场
推理模型的评测是这份报告里最容易被草率对待的部分,也是最容易得出错误结论的地方。同样一个 checkpoint,换个采样口径,AIME 的分数能差出十几个点。
5.1 采样口径:温度 0.6、top-p 0.95、32k 上限
原文把最大生成长度设到 32768 token,这点没得商量——长链思维模型经常写到一两万 token 才收敛,长度截断会把正确答案切掉,你会得到一个稳定偏低的分数。
更关键的是解码方式。用贪婪解码评长输出会有两个问题:重复率显著上升,模型会陷入循环刷屏;不同 checkpoint 之间的差异被放大成噪声,你分不清是模型变好了还是这一版刚好没卡住。所以默认走采样评估:温度 0.6、top-p 0.95,每个问题采样若干条(按测试集大小在 4 到 64 之间取),pass@1 按采样平均算。
def pass_at_1(samples, golds): # samples: 每个问题采样 n 条输出;golds: 对应标准答案 # 不是只跑一条,而是按采样平均,降低单次解码的偶然性 total = 0.0 for outs, gold in zip(samples, golds): total += sum(1 for o in outs if is_correct(o, gold)) / len(outs) return total / len(golds)n 的选择要看题目数。AIME 2024 只有 30 道题,样本必须密,否则置信区间大到你没法比较两个模型;MMLU 上千道题,4 条就足够稳定。AIME 上还会额外报 64 样本的多数投票结果(cons@64),这个数字比 pass@1 高出一大截,反映的是「多试几次能不能对」,和单次作答能力是两回事,报告里千万别混着讲。
5.2 基准怎么挑:别用一套题评所有能力
推理模型的能力是多维的,用一套基准概括会得出误导性结论。我按能力拆成这张表来读:
| 能力维度 | 主要基准 | 看什么 |
|---|---|---|
| 数学推理 | AIME 2024、MATH-500、CNMO 2024 | 难题单次正确率与稳定性 |
| 代码 | LiveCodeBench、Codeforces、SWE-bench Verified、Aider | 竞赛级算法与现实工程任务分开看 |
| 学科知识 | MMLU、MMLU-Pro、GPQA Diamond | 研究生级难度是否被推理能力带动 |
| 事实性 | SimpleQA、C-SimpleQA | 幻觉控制,推理强不等于事实准 |
| 长上下文 | FRAMES | 长文理解是否随推理一起提升 |
| 指令跟随 | IFEval | 格式约束遵守度 |
| 开放生成 | AlpacaEval 2.0、Arena-Hard | 只给最终 summary 评,避免长度偏差 |
有两个口径细节容易忽略。一是 LiveCodeBench 的题目要卡时间窗,原文用的是 2024 年 8 月到 2025 年 1 月之间的题,防止训练数据泄漏导致的虚高;二是 SWE-bench Verified 走的是无 agent 框架,Aider 用 diff 格式评,跨报告对比时必须先对齐这两点,否则数字不可比。
还有个反直觉的点:少样本思维链会损害推理模型的性能。在 MMLU-Pro、C-Eval 这些原本少样本的基准上,原文把提示改成零样本,分数反而更好。原因是这类模型自己会展开完整推理,你再塞几个示例,反而干扰了它自己的节奏。
5.3 五个翻车现场:现象、原因、解决
原文专门留了一节写失败的尝试,但只给了标题没展开内容。下面这几条是我自己在复现和横向评测里踩过的,按现象、原因、解决写。
第一条:贪婪解码评出高分,换采样就掉下来。现象是同一个模型在贪婪解码下 AIME 高出好几个点,一改成多次采样平均就回落。原因是长输出下贪婪解码容易在某个 token 上锁死进入循环,偶尔「蒙对」整道题,把均值拉高了。解决是把采样口径写进评测脚本的默认值,任何人跑分都必须走同一套参数,禁止单独为了好看切回贪婪。
第二条:格式分权重给高,模型学会写空壳思考。现象是训练几轮后模型稳定输出<think></think>,里面只有一句「我来解这道题」,然后直接给答案,准确率不涨。原因是格式奖励是白送的,权重一旦和准确率同量级,模型会优先捡软柿子。解决是把格式分压到准确率的五分之一以下,并且加一条前置条件——思考段落少于一定 token 数不给格式分。
第三条:拿不同 checkpoint 的不同步数横向比,把抖动当提升。现象是 checkpoint A 在 40 步比 B 在 60 步高,就判断 A 的训练策略更优。原因是长输出任务的方差本来就大,单点比较没有意义。解决是固定采样口径加多个 seed,比较的是区间不是点,看到提升先问一句「这个差距超过方差了吗」。
第四条:冷启动数据贪多,把脏数据一起喂进去。现象是加了冷启动之后可读性反而没改善,模型开始输出半截段落。原因是冷启动数据量本来就小,混进几十条格式不统一、语言混杂的样本,比例上就被放大了。解决是宁少勿脏,每条冷启动样本都过一遍格式校验和语言占比检查,几千条里删掉三成比硬凑数量划算。
第五条:在小模型上直接照搬大模型的 RL 配置。现象是训练到中途奖励不涨,CoT 长度也不涨,模型学会了格式但推理没长进。原因就是前面说的搜索空间问题,小模型自己发现不了长链思维的组织方式。解决是先跑蒸馏拿基线,确认它已经会写结构化推理,再在此基础上加一小段 RL 做精修,别从零开始。
6. 如果你要复刻一遍:按这个顺序排,别反过来
一年里我把这套流程在不同规模的底座上走了三遍,最深的体会是顺序比配置重要。正确顺序只有一条:先定评测口径,再做蒸馏基线,然后才考虑要不要上纯 RL。
第一步,在动手训任何东西之前把评测脚本写死。温度 0.6、top-p 0.95、最大长度 32768、每题采样条数按题目数定、pass@1 按采样平均、AIME 额外报 cons@64——这些参数一旦定下来就写进脚本常量,中途不许改。这个动作看着无聊,但它是唯一能让你在两个月后还看得懂自己结果的手段。多少人的后悔药就吃在这里:训到第三版才发现评测口径和前两版不一样,前面白干。
第二步,用大模型产出的数据做一次蒸馏,拿一个稳定基线。选 7B 还是 32B 看你的卡,AIME 55.5% 和 72.6% 这两个点分别对应「够用」和「能打」两档。这一步的产出是你后续所有实验的比较对象,没有它,后面任何提升都无从判断。
第三步,才轮到是否上 RL。判断标准很务实:蒸馏基线在验证集上的错误里,有多少是「推理过程中途断掉」而不是「知识不会」?如果是前者,且你有足够的采样预算支撑组内估计,那 RL 值得一试;如果绝大多数错误是知识缺口,RL 帮不上忙,补数据比训模型快。
至于冷启动数据、语言一致性奖励、拒绝采样的过滤阈值这些细节,都属于第二步里可以循序渐进叠加的东西,不必一次到位。我那几次翻车基本都发生在想跳过前两步直接冲 RL 的时候——模型是会写<think>了,一到复杂题就原形毕露,那种「看起来成了」的假象最耗人。
从那以后我每次启动新的推理模型训练,都强制先跑一遍评测脚本的空转测试,确认口径对齐、基线可复现,才允许开训。慢两天,省两个月。希望帮到你。
本文还有配套的精品资源,点击获取