跳到主要内容

数据截至 (上游 commit 1416fa0cf215)

Open R1 — 一份可运行的推理模型训练配方

30 秒导读: Open R1 是 Hugging Face 对 DeepSeek-R1 训练管线的完全开放复现。它不是框架——全部训练逻辑只有 sft.py(169 行)和 grpo.py(181 行)两个薄脚本,训练器直接借自 trl。这个仓库真正的价值在别处:一套写得明明白白、可以直接 sbatch 跑起来的 R1 级模型配方——每个模型一个 YAML、每个阶段一条命令、训练中途自动跑 benchmark、连 Slurm 集群脚本都给了。想知道「复现一个推理模型到底要做哪些事」,读这个仓库比读论文快。


1. 这是什么(零基础也能懂)

一句话定义

Open R1 是一套训练配方仓库:围绕「复现 DeepSeek-R1 推理能力」这个目标,把数据生成、监督微调(SFT)、强化学习(GRPO)、评测四件事各自做成一条可直接运行的命令,配上逐模型、逐阶段的完整配置文件。

它解决什么问题、给谁用

2025 年初 DeepSeek 发布 R1 论文:靠大规模 RL(GRPO 算法)让模型学会「先想再答」,数学/代码能力暴涨。但论文只给了路线和结果,没给代码和数据。

Open R1 补的就是这些缺失的零件(README.md:21-28)。它面向两类读者:

  • 想亲手复现的人——按 recipes/ 里的 YAML 逐条跑命令,就能从开源基座模型训出一个「小号 R1」。
  • 想搞懂配方长什么样的人——即使不跑,读配置就能学到:GRPO 一步采几个答案、奖励函数怎么组合、评测为什么要每题采样 64 次。

它能做什么

能力入口底层靠谁
SFT 蒸馏训练src/open_r1/sft.pytrl SFTTrainer
GRPO 强化学习src/open_r1/grpo.pytrl GRPOTrainer + vLLM 生成
可验证奖励(数学/格式/代码)src/open_r1/rewards.pymath-verify、E2B/Morph/Piston 沙箱
用 R1 批量生成推理数据src/open_r1/generate.pydistilabel + vLLM server + Ray
benchmark 评测src/open_r1/utils/evaluation.pylighteval
数据去污染scripts/decontaminate.py8-gram 重叠检测(s1 论文方法)
集群作业编排slurm/*.slurmSlurm + accelerate + DeepSpeed/FSDP

用起来什么样

整个仓库的使用模式就一种:accelerate launch + 一个训练脚本 + 一个 YAML 配置:

# 摘自 README.md:124-126:用现成配方复现 OpenR1-Distill-7B 的 SFT 蒸馏
accelerate launch --config_file recipes/accelerate_configs/zero3.yaml src/open_r1/sft.py \
--config recipes/OpenR1-Distill-7B/sft/config_distill.yaml

GRPO 同理,只是脚本换成 grpo.py、配置换成 recipes/<模型>/grpo/config_*.yaml。在 Slurm 集群上则连 accelerate 都不用敲,slurm/train.slurm 帮你拼好(README.md:399)。

一句话直觉

把这个仓库想成一份「米其林菜谱」,而不是一台「料理机」。 料理机(训练器、推理引擎、评测器)全是借来的——trl、vLLM、lighteval;菜谱本身才是作品:买什么菜(数据集)、火候多少(超参数)、什么时候尝味道(训练中途评测),全都写在 YAML 里,精确到能复现出论文级别的分数。


2. 顶层全景(它大概怎么转)

2.1 三条流水线一张图

仓库对应 DeepSeek-R1 技术报告的三步复现计划(README.md:33-36)。这张图从左到右读:数据从左边生成,模型在中间训练,分数从右边出来。

① 数据生成 ② 训练 ③ 评测
┌────────────────────┐ ┌──────────────────────────┐ ┌───────────────────┐
│ DeepSeek-R1 (671B) │ │ sft.py → trl SFTTrainer │ │ lighteval + vLLM │
│ vLLM server (2节点)│ │ 蒸馏: 学 R1 的推理轨迹 │ │ AIME/MATH/GPQA/ │
│ generate.py │ ├──────────────────────────┤ │ LCB │
│ (distilabel+Ray) │ │ grpo.py → trl GRPOTrainer│ │ evaluation.py │
└─────────┬──────────┘ │ RL: 可验证奖励驱动 │ │ 训练中途自动触发 │
│ │ + reward 函数注册表 │ └───────────────────┘
▼ │ + vLLM 采样(16答案/题) │
Mixture-of-Thoughts └────────────┬─────────────┘
OpenR1-Math-220k │
(Hub 数据集) ▼
recipes/*.yaml
(每模型每阶段一份配方)

怎么读这张图: 仓库自己不实现任何训练/推理/评测引擎,它的全部代码是「把三段流水线焊起来」的胶水;焊点的参数(温度、奖励权重、batch 计算)都集中在 recipes/ 的 YAML 里——那是阅读重点。

2.2 部件职责

部件干什么在哪个文件
SFT 入口加载数据/模型,套 trl SFTTrainer,训练+存盘+推 Hubsrc/open_r1/sft.py:55main
GRPO 入口同上,但多了 reward 注册和 prompt 拼装src/open_r1/grpo.py:35main
reward 注册表11 个可验证奖励函数,按名字从 YAML 选取src/open_r1/rewards.py:646get_reward_funcs
配置层在 trl 的 dataclass 上加 dataset_mixture、benchmarks、回调等字段src/open_r1/configs.py
数据混合按 weight 子采样多个数据集并拼成一个src/open_r1/utils/data.py:12get_dataset
数据生成distilabel 管线打 vLLM server,逐题采 N 条推理轨迹src/open_r1/generate.py:23build_distilabel_pipeline
评测编排把 lighteval 任务名翻译成命令、自动估算 GPU 数、sbatch 提交src/open_r1/utils/evaluation.py:69run_lighteval_job
训练中途评测回调每次 save 把 checkpoint 推 Hub 并排队 benchmarksrc/open_r1/utils/callbacks.py:43PushToHubRevisionCallback
代码沙箱E2B / Morph 云沙箱异步执行生成代码,返回通过率src/open_r1/utils/code_providers.py:46
集群脚本把「N 台训练节点 + 1 台 vLLM 节点」拼成 sbatch 作业slurm/train.slurm
配方本体逐模型逐阶段的完整超参数recipes/<模型>/<任务>/config_*.yaml

2.3 主线走一遍:GRPO 一步

以数学 GRPO 配方为例(recipes/DeepSeek-R1-Distill-Qwen-1.5B/grpo/config_demo.yaml),一步训练里发生的事:

YAML 配置加载
│ TrlParser 把 YAML + 命令行合进三个 dataclass(grpo.py:179)

数据集 → prompt 列表
│ 每题包成 [{"role":"system"...},{"role":"user"...}](grpo.py:91 make_conversation)

按 reward_funcs 名单取奖励函数
│ ["accuracy","format","tag_count"] → 三个函数(rewards.py:704)

GRPOTrainer 循环(trl 内部)
│ 每题经 vLLM 采 num_generations=16 个答案(config_demo.yaml:36)
│ → 三个奖励函数逐个打分 → 组内归一化算优势 → 策略更新

存盘 + 推 Hub +(可选)排队评测
│ PushToHubRevisionCallback 在每个 checkpoint 触发(callbacks.py:47 on_save)

记住一点: grpo.py 里没有任何 RL 算法代码——GRPO 的组内优势、PPO clip、KL 惩罚全在 trl 的 GRPOTrainer 里。这个仓库对训练循环的唯一「算法贡献」是 rewards.py 那 11 个奖励函数和它们的组合方式。想看算法实现本身,移步 verl 的 teardown。


3. 阅读地图(建议顺序)

三章由浅入深。只读一章的话读 02,reward 函数是这个仓库信息密度最高的文件。

顺序章节讲什么适合谁
101-reproduction-roadmap.md三步复现计划;R1 数据怎么生成、混配、去污染;蒸馏 SFT 配方逐项拆解想搞懂「R1 复现一共要做几件事」的人
202-grpo-rewards.mdGRPO 配方旋钮;11 个 reward 函数的原理与出处;代码奖励的沙箱架构想做 RLVR / 奖励工程的人
303-evaluation-decontamination.mdlighteval 集成、训练中途评测、pass@1 方差、8-gram 去污染、pass rate 过滤关心评测可信度和数据卫生的人

4. 巧妙之处(可借鉴的技术)

  1. 「配置即文档」的配方组织。 每个可复现的模型/阶段都落成一个 YAML,且配方里直接写注释解释为什么——例如 Codeforces 配方用四行注释把「8 GPU × 32 梯度累积 × 4 batch ÷ 16 代/题 = 每步 64 道唯一题 → 16k 数据约 250 步/epoch → 4 epoch 凑 1k 优化步」的账算给你看(recipes/Qwen2.5-Coder-7B-Instruct/grpo/config_codeforces.yaml:49-53)。复现性不是靠 README 承诺的,是靠配置里的算术保证的。

  2. 奖励函数的「None = 跳过」协议。 数学奖励在 gold 答案解析不出来时不罚模型,而是返回 None 让该样本退出这批(src/open_r1/rewards.py:70-79),代码奖励失败也返回 None 透传(src/open_r1/rewards.py:501-506)。脏数据因此不会污染梯度——一个容易被忽视但很关键的 RL 数据卫生设计。

  3. 训练中途自动评测闭环。 PushToHubRevisionCallback 在每次 save 时把 checkpoint 异步推上 Hub 分支({revision}-step-{N}src/open_r1/utils/hub.py:57-64run_as_future=True),推完回调里自动 sbatch 排队 lighteval 作业(src/open_r1/utils/callbacks.py:70-77)。训练跑着,榜单自己更新——不用等训完才知道配方行不行。

  4. train.slurm 的「最后一台节点给 vLLM」约定。 GRPO 多节点时,脚本自动把节点列表最后一台切出来跑 trl vllm-serve,其余训练,并透传 --vllm_server_hostslurm/train.slurm:128-136)。N+1 节点的拓扑全靠节点列表顺序表达,零配置。

  5. 用 safetensors 元数据 + 正则兜底猜参数量。 评测脚本要决定「这模型要不要 TP 切分」,它不是查表而是先读 Hub 的 safetensors 元数据,读不到就用正则从 repo id 里抠「7b」「8x7b」这种字样(src/open_r1/utils/hub.py:89-118)。土,但鲁棒。

5. 边界与局限

  • 是复现,不是原作。 README 明确记录了与 DeepSeek 报告值的差距:AIME 上 7B 差约 5 分(50.8 vs 55.5,README.md:545-551),多数 benchmark 落在报告的 1-3 个标准差内。配方能复现「R1 级」,不保证复现「R1 每一个数」。
  • 三步计划只完成了第一步。 截至本 commit,News 区(README.md:44)宣布完成的是 Step 1(蒸馏);R1-Zero 式纯 RL 从基座训起(Step 2/3)仍是进行中状态——仓库里 GRPO 配方都是从小模型/已蒸馏模型出发的。
  • 算力门槛是硬性的。 所有训练命令按「单机 8×H100 80GB」给(README.md:103-104);32B 模型 SFT 要 16 节点且被迫换 FSDP + paged AdamW 8-bit(recipes/README.md:19-23)。笔记本上没有「试一下」这个选项。
  • 集群脚本长在 HF 自家集群上。 slurm/train.slurm:27 写死 module load cuda/12.4、第 37 行刷新 Weka 文件系统、hopper-prod 分区——README 自己也提醒需要改造(README.md:416-417)。
  • 奖励函数是教学级实现。 例如 reasoning_steps_reward 只是数正则匹配个数除以 3(src/open_r1/rewards.py:124-129),len_reward 假设批内长度有差异否则全零(src/open_r1/rewards.py:187-189)。它们演示了「可以奖励什么」,不是各论文的最强实现。
  • 代码奖励依赖外部服务。 E2B/Morph 是付费云沙箱且有速率限制,免费档只配每进程 2 并发(src/open_r1/configs.py:286-291);Piston 要自架 worker 集群。代码 RL 的真实成本大头在沙箱,不在 GPU。

6. 横向对比

同书架上与它相邻的三个 teardown:

项目关系取舍差异
verl同为 RL 后训练,但 verl 是框架verl 造「训练引擎+推理引擎共置调度」的重型底座(单控制器、权重同步);Open R1 完全不碰这层,直接用 trl 现成的 colocate/server 两种 vLLM 模式,把精力全花在奖励与数据上
trlOpen R1 的训练器来源trl 提供通用 GRPOTrainer/SFTTrainer;Open R1 演示「在 trl 之上做一个具体项目」需要补什么:奖励注册表、数据混合、评测编排、集群脚本
lightevalOpen R1 的评测器来源lighteval 是通用 harness;Open R1 固定了 R1 复现专用的任务清单、采样参数(max_new_tokens:32768, temperature:0.6)和 pass@1 响应数约定

一句话定位:verl 回答「RL 训练的分布式系统怎么做」,trl 回答「算法循环怎么写」,Open R1 回答「一个具体的 R1 级模型,从头到尾怎么训出来」

7. 代码地图(入口级)

各章末尾有细粒度地图,这里列从零开始的五个入口:

主题文件路径符号名
GRPO 训练主线src/open_r1/grpo.pymainmake_conversation
SFT 蒸馏主线src/open_r1/sft.pymain
奖励函数全家桶src/open_r1/rewards.pyget_reward_funcsaccuracy_rewardcode_reward
配方样例(数学 GRPO)recipes/DeepSeek-R1-Distill-Qwen-1.5B/grpo/config_demo.yaml—(YAML)
集群编排slurm/train.slurm—(bash;vLLM 节点切分在 128-136 行)