这里记录一下从零配置openr1的过程,需要注意的内容.openr1是huggingface上复现grpo训练大语言模型的成推理模型的一个开源方案,接下来从零实现一下改训练过程
首先把官方的说明先整体认识一下,如果想要直接看本地实现篇,链接:deepseek强化学习训练大模型复现-openr1——本地篇(2)
2025.3.17待校对.
csdn目录页-openr1
我的目录截至
Open R1
一个完全开源的 DeepSeek-R1 再现项目。这个仓库还在建设中,让我们一起完善它!
目录-openr1官方
概述
本仓库的目标是完善 R1 流程中缺失的部分,使任何人都能够复现并在此基础上进行开发。项目设计简洁,主要包含以下内容:
src/open_r1
:包含用于训练、评估模型以及生成合成数据的脚本:grpo.py
:在给定数据集上使用 GRPO 训练模型。sft.py
:对模型在数据集上进行简单的监督式微调。evaluate.py
:在 R1 基准测试上评估模型。generate.py
:使用 Distilabel 从模型生成合成数据。
Makefile
:包含利用上述脚本运行 R1 流程中每一步的便捷命令。
计划
我们将以 DeepSeek-R1 技术报告 为指导,大致分为以下三个主要步骤:
- 第一步:通过从 DeepSeek-R1 蒸馏高质量语料库来复现 R1-Distill 模型。
- 第二步:复现 DeepSeek 用于创建 R1-Zero 的纯强化学习 (RL) 流程。这可能需要为数学、推理和代码任务策划新的大规模数据集。
- 第三步:展示如何通过多阶段训练从基础模型过渡到经过 RL 调优的模型。
新闻 🗞️
- ⚡️ [2025/03/11] (更新 #3): 我们发布了 CodeForces-CoTs 数据集,包含 1 万个编程竞赛问题和 10 万个由 R1 蒸馏的解决方案。我们还发布了 IOI24:一个来自国际奥林匹克竞赛的非常困难的题目基准。一个在 CodeForces-CoTs 上训练的 7B Qwen 模型可以在 IOI24 上超越 Claude 3.7 Sonnet,而一个 32B 模型可以超越 R1 本身。
- ∞ [2025/02/10] (更新 #2): 我们发布了 OpenR1-Math-220k 数据集,包含 22 万个从 NuminaMath 新版本中蒸馏的 R1 推理轨迹。在此数据集上训练的模型与 DeepSeek 的蒸馏模型表现相当。
- 🔥 [2025/02/02] (更新 #1): 我们实现了 训练、推理 和 评估 流程的第一部分。出发!
安装
[!CAUTION]
本项目依赖 CUDA 12.4。如果遇到与段错误相关的错误,请使用nvcc --version
检查系统是否运行此版本。
要运行本项目中的代码,首先需要使用 uv
创建 Python 虚拟环境。安装 uv
的方法可以参考 UV 安装指南。
[!NOTE]
作为快捷方式,运行make install
可以设置开发所需的库(具体步骤见下文)。安装完成后,您可以尝试使用 Open-R1 模型。
uv venv openr1 --python 3.11 && source openr1/bin/activate && uv pip install --upgrade pip
[!TIP]
对于 Hugging Face 集群用户,将export UV_LINK_MODE=copy
添加到您的.bashrc
中,以抑制uv
的缓存警告。
接下来,安装 vLLM 和 FlashAttention:
uv pip install vllm==0.7.2
uv pip install setuptools && uv pip install flash-attn --no-build-isolation
这还将安装 PyTorch v2.5.1
,使用此版本非常重要,因为 vLLM 二进制文件是为此版本编译的。然后,您可以通过 pip install -e .[LIST OF MODES]
为您的特定用例安装其余依赖项。对于大多数贡献者,我们建议:
GIT_LFS_SKIP_SMUDGE=1 uv pip install -e ".[dev]"
接下来,按如下方式登录您的 Hugging Face 和 Weights and Biases 帐户:
huggingface-cli login
wandb login
最后,检查您的系统是否安装了 Git LFS,以便您可以加载模型/数据集并将其推送到 Hugging Face Hub:
git-lfs --version
如果未安装,请运行:
sudo apt-get install git-lfs
训练模型
我们支持使用 DDP 或 DeepSpeed(ZeRO-2 和 ZeRO-3)训练模型。例如,要在从 DeepSeek-R1 蒸馏的带有推理轨迹的数据集(例如 open-r1/OpenR1-Math-220k)上运行 SFT,请运行:
通过命令行训练
accelerate launch --config_file=recipes/accelerate_configs/zero3.yaml src/open_r1/sft.py \
--model_name_or_path Qwen/Qwen2.5-1.5B-Instruct \
--dataset_name open-r1/OpenR1-Math-220k \
--learning_rate 1.0e-5 \
--num_train_epochs 1 \
--packing \
--max_seq_length 16384 \
--per_device_train_batch_size 16 \
--gradient_checkpointing \
--bf16 \
--output_dir data/Qwen2.5-1.5B-Open-R1-Distill
通过 YAML 配置训练
accelerate launch --config_file recipes/accelerate_configs/zero3.yaml src/open_r1/sft.py \
--config recipes/Qwen2.5-1.5B-Instruct/sft/config_demo.yaml
目前,支持以下任务:
- 监督微调
sft
- 群组相对策略优化
grpo
[!TIP]
如果您放大/缩小 GPU 的数量,我们建议同时放大每个设备的批量大小或梯度累积步骤的数量,以保持全局批量大小不变。
默认情况下,这些脚本会将每个模型推送到您的 Hugging Face Hub 用户名,即 {username}/{model_name}-{task}
。您可以通过将参数附加到命令来覆盖每个 YAML 配置中的参数,如下所示:
更改批量大小、epoch 数等
accelerate launch --config_file recipes/accelerate_configs/zero3.yaml src/open_r1/sft.py \
--config recipes/Qwen2.5-1.5B-Instruct/sft/config_demo.yaml \
--per_device_train_batch_size=1 --num_train_epochs=5
如果您还想覆盖 Weights and Biases 默认设置,可以按如下方式操作:
accelerate launch --config_file recipes/accelerate_configs/zero3.yaml src/open_r1/sft.py \
--config recipes/Qwen2.5-1.5B-Instruct/sft/config_demo.yaml \
--wandb_entity huggingface --wandb_project open-r1 --run_name Qwen2.5-1.5B-GRPO
[!NOTE]
以下训练命令是为 8 x H100s (80GB) 的节点配置的。对于不同的硬件和拓扑,您可能需要调整批量大小和梯度累积步骤的数量。
SFT
要在从 DeepSeek-R1 蒸馏的带有推理轨迹的数据集(例如 open-r1/OpenR1-Math-220k)上运行 SFT,请运行:
ACCELERATE_LOG_LEVEL=info accelerate launch --config_file recipes/accelerate_configs/zero3.yaml \
src/open_r1/sft.py \
--config recipes/Qwen2.5-1.5B-Instruct/sft/config_demo.yaml
GRPO
要通过 GRPO 训练器进行训练,我们使用一个 GPU 运行 vLLM 以加快生成速度,其余 GPU 用于训练。例如,在具有 8 个 GPU 的节点上,设置 --num_processes
以覆盖 accelerate
配置中的默认值:
ACCELERATE_LOG_LEVEL=info accelerate launch --config_file recipes/accelerate_configs/zero2.yaml \
--num_processes=7 src/open_r1/grpo.py \
--config recipes/DeepSeek-R1-Distill-Qwen-1.5B/grpo/config_demo.yaml
[!WARNING]
蒸馏的 DeepSeek 模型中使用的聊天模板省略了<think>
和</think>
标签内推理块的内容。它还使用<think>
预填充了助手响应,这会干扰格式奖励函数。为了解决这个问题,必须覆盖聊天模板,如 recipes/DeepSeek-R1-Distill-Qwen-1.5B/grpo/config_demo.yaml 中所示。
我们提供了一个使用 GRPO 进行数学推理的最小可重现实验,参考了 SimpleRL-Reason 的方法,该方法使用在 8K 示例上训练的 7B 模型。在 8 个 H100 80G GPU 上运行此操作大约需要 3 小时:
ACCELERATE_LOG_LEVEL=info accelerate launch --config_file recipes/accelerate_configs/zero2.yaml \
--num_processes=7 src/open_r1/grpo.py \
--config recipes/Qwen2.5-Math-7B/grpo/config_simple_rl.yaml
我们最终的 模型,虽然使用了不同的学习率、损失函数和奖励结构,但在 MATH-500 上实现了 69.4% 的准确率,表明比基础模型提高了 17% 以上。
👨💻 使用代码解释器进行训练
我们提供了一个 code
奖励函数,用于执行训练期间策略生成的代码。目前,此奖励函数针对 Codeforces 等代码竞赛,其中解决方案针对一组测试用例执行,并将整体成功率作为最终奖励返回。为了确保安全执行,我们使用 E2B 沙箱,它们运行速度快且成本低廉。要使用此奖励函数,请首先安装必要的依赖项:
uv pip install -e '.[code]'
然后创建一个 .env
文件,并在其中放置来自 E2B 的 API 令牌:
E2B_API_KEY=“e2b_xxx”
然后确保您的数据集包含一个 verification_info
列,其架构如下(采用自 PrimeIntellect 出色的 数据集 的可验证问题):
在 Slurm 集群上启动作业
如果您有权访问 Slurm 集群,我们提供了一个 slurm/train.slurm
脚本,它将自动为您排队训练作业。以下是如何使用它:
sbatch --job-name=open_r1 --nodes=1 slurm/train.slurm {model_name} {task} {config_suffix} {accelerator}
这里 {model_name}
和 {task}
的定义如上所述,而 {config_suffix}
指的是特定配置,{accelerator}
指的是 recipes/accelerate_configs
中 🤗 Accelerate 配置的选择。如果您想覆盖默认配置参数,可以通过附加一个以空格分隔的字符串(如 '--arg1=value1 --arg2=value2'
)来提供它们。以下是在 1 个包含 8 个 GPU 的节点上运行 SFT 的具体示例:
在 Slurm 上启动并覆盖默认超参数
sbatch --job-name=open_r1 --nodes=1 slurm/train.slurm Qwen2.5-1.5B-Instruct sft demo zero3 '--per_device_train_batch_size=1 --num_train_epochs=5'
您可以通过增加 --nodes
标志来扩展节点数量。
[!NOTE]
slurm/train.slurm
中的配置针对 Hugging Face 计算集群进行了优化,可能需要进行调整才能适应您自己的计算节点。
评估模型
我们使用 lighteval
来评估模型,自定义任务在 src/open_r1/evaluate.py
中定义。对于适合单个 GPU 的模型,请运行:
MODEL=deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
MODEL_ARGS="pretrained=$MODEL,dtype=bfloat16,max_model_length=32768,gpu_memory_utilization=0.8,generation_parameters={max_new_tokens:32768,temperature:0.6,top_p:0.95}"
OUTPUT_DIR=data/evals/$MODEL
AIME 2024
TASK=aime24
lighteval vllm $MODEL_ARGS "custom|$TASK|0|0" \
--custom-tasks src/open_r1/evaluate.py \
--use-chat-template \
--output-dir $OUTPUT_DIR
MATH-500
TASK=math_500
lighteval vllm $MODEL_ARGS "custom|$TASK|0|0" \
--custom-tasks src/open_r1/evaluate.py \
--use-chat-template \
--output-dir $OUTPUT_DIR
GPQA Diamond
TASK=gpqa:diamond
lighteval vllm $MODEL_ARGS "custom|$TASK|0|0" \
--custom-tasks src/open_r1/evaluate.py \
--use-chat-template \
--output-dir $OUTPUT_DIR
LiveCodeBench
lighteval vllm $MODEL_ARGS "extended|lcb:codegeneration|0|0" \
--use-chat-template \
--output-dir $OUTPUT_DIR
[!IMPORTANT]
您必须在vllm
命令中设置max_model_length=32768
,以与我们为每次评估定义的max_new_tokens
对齐。否则,lighteval
将抛出错误。
要提高跨多个 GPU 的吞吐量,请使用数据并行,如下所示:
NUM_GPUS=8
MODEL=deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
MODEL_ARGS="pretrained=$MODEL,dtype=bfloat16,data_parallel_size=$NUM_GPUS,max_model_length=32768,gpu_memory_utilization=0.8,generation_parameters={max_new_tokens:32768,temperature:0.6,top_p:0.95}"
TASK=aime24
OUTPUT_DIR=data/evals/$MODEL
lighteval vllm $MODEL_ARGS "custom|$TASK|0|0" \
--custom-tasks src/open_r1/evaluate.py \
--use-chat-template \
--output-dir $OUTPUT_DIR
对于需要跨 GPU 分片的超大型模型,请使用张量并行并运行:
NUM_GPUS=8
MODEL=deepseek-ai/DeepSeek-R1-Distill-Qwen-32B
MODEL_ARGS="pretrained=$MODEL,dtype=bfloat16,tensor_parallel_size=$NUM_GPUS,max_model_length=32768,gpu_memory_utilization=0.8,generation_parameters={max_new_tokens:32768,temperature:0.6,top_p:0.95}"
TASK=aime24
OUTPUT_DIR=data/evals/$MODEL
export VLLM_WORKER_MULTIPROC_METHOD=spawn
lighteval vllm $MODEL_ARGS "custom|$TASK|0|0" \
--custom-tasks src/open_r1/evaluate.py \
--use-chat-template \
--output-dir $OUTPUT_DIR
您还可以使用 make evaluate
启动评估,指定模型、任务,以及可选的并行技术和 GPU 数量。
在单个 GPU 上进行评估:
make evaluate MODEL=deepseek-ai/DeepSeek-R1-Distill-Qwen-32B TASK=aime24
使用数据并行:
make evaluate MODEL=deepseek-ai/DeepSeek-R1-Distill-Qwen-32B TASK=aime24 PARALLEL=data NUM_GPUS=8
使用张量并行:
make evaluate MODEL=deepseek-ai/DeepSeek-R1-Distill-Qwen-32B TASK=aime24 PARALLEL=tensor NUM_GPUS=8
复制 Deepseek 的评估结果
[!NOTE]
DeepSeek-R1 论文使用每个查询 64 个响应的采样来估计pass@1
。下面,我们报告了每个查询采样 1 个响应的结果,这可能解释了我们的结果与他们的结果之间 1-3σ 的小差异。
AIME 2024
我们能够在 ~1-3 个标准差内重现 Deepseek 在 AIME 2024 基准测试中报告的结果:
模型 | AIME 2024 (🤗 LightEval) | AIME 2024 (DeepSeek Reported) |
---|---|---|
DeepSeek-R1-Distill-Qwen-1.5B | 26.7 | 28.9 |
DeepSeek-R1-Distill-Qwen-7B | 56.6 | 55.5 |
DeepSeek-R1-Distill-Qwen-14B | 60.0 | 69.7 |
DeepSeek-R1-Distill-Qwen-32B | 73.2 | 72.6 |
DeepSeek-R1-Distill-Llama-8B | 43.3 | 50.4 |
DeepSeek-R1-Distill-Llama-70B | 73.3 | 70.0 |
要重现这些结果,请使用以下命令:
NUM_GPUS=1 # 32B 和 70B 模型设置为 8
MODEL=deepseek-ai/{model_name}
MODEL_ARGS="pretrained=$MODEL,dtype=bfloat16,max_model_length=32768,gpu_memory_utilization=0.8,data_parallel_size=$NUM_GPUS,generation_parameters={max_new_tokens:32768,temperature:0.6,top_p:0.95}"
OUTPUT_DIR=data/evals/$MODEL
lighteval vllm $MODEL_ARGS "custom|aime24|0|0" \
--custom-tasks src/open_r1/evaluate.py \
--use-chat-template \
--output-dir $OUTPUT_DIR
或者,您可以按如下方式启动 Slurm 作业:
python scripts/run_benchmarks.py --model-id {model_id} --benchmarks aime24
MATH-500
我们能够在 ~1-3 个标准差内重现 Deepseek 在 MATH-500 基准测试中报告的结果:
我们能够在 ~1-3 个标准差内重现 Deepseek 在 MATH-500 基准测试中报告的结果:
模型 | MATH-500 (🤗 LightEval) | MATH-500 (DeepSeek Reported) |
---|---|---|
DeepSeek-R1-Distill-Qwen-1.5B | 84.6 | 83.9 |
DeepSeek-R1-Distill-Qwen-7B | 93.0 | 92.8 |
DeepSeek-R1-Distill-Qwen-14B | 95.0 | 93.9 |
DeepSeek-R1-Distill-Qwen-32B | 96.6 | 94.3 |
DeepSeek-R1-Distill-Llama-8B | 88.6 | 89.1 |
DeepSeek-R1-Distill-Llama-70B | 96.4 | 94.5 |
要重现这些结果,请使用以下命令:
NUM_GPUS=1 # 32B 和 70B 模型设置为 8
MODEL=deepseek-ai/{model_name}
MODEL_ARGS="pretrained=$MODEL,dtype=bfloat16,max_model_length=32768,gpu_memory_utilization=0.8,data_parallel_size=$NUM_GPUS,generation_parameters={max_new_tokens:32768,temperature:0.6,top_p:0.95}"
OUTPUT_DIR=data/evals/$MODEL
lighteval vllm $MODEL_ARGS "custom|math_500|0|0" \
--custom-tasks src/open_r1/evaluate.py \
--use-chat-template \
--output-dir $OUTPUT_DIR
或者,您可以按如下方式启动 Slurm 作业:
python scripts/run_benchmarks.py --model-id {model_id} --benchmarks math_500
GPQA Diamond
我们能够在 ~1-3 个标准差内重现 Deepseek 在 GPQA Diamond 基准测试中报告的结果:
模型 | GPQA Diamond (🤗 LightEval) | GPQA Diamond (DeepSeek Reported) |
---|---|---|
DeepSeek-R1-Distill-Qwen-1.5B | 34.3 | 33.8 |
DeepSeek-R1-Distill-Qwen-7B | 50.5 | 49.1 |
DeepSeek-R1-Distill-Qwen-14B | 59.6 | 59.1 |
DeepSeek-R1-Distill-Qwen-32B | 63.6 | 62.1 |
DeepSeek-R1-Distill-Llama-8B | 52.0 | 49.0 |
DeepSeek-R1-Distill-Llama-70B | 67.2 | 65.2 |
要重现这些结果,请使用以下命令:
NUM_GPUS=1 # 32B 和 70B 模型设置为 8
MODEL=deepseek-ai/{model_name}
MODEL_ARGS="pretrained=$MODEL,dtype=bfloat16,max_model_length=32768,gpu_memory_utilization=0.8,data_parallel_size=$NUM_GPUS,generation_parameters={max_new_tokens:32768,temperature:0.6,top_p:0.95}"
OUTPUT_DIR=data/evals/$MODEL
lighteval vllm $MODEL_ARGS "custom|gpqa:diamond|0|0" \
--custom-tasks src/open_r1/evaluate.py \
--use-chat-template \
--output-dir $OUTPUT_DIR
python scripts/run_benchmarks.py --model-id {model_id} --benchmarks gpqa
LiveCodeBench
我们能够在 ~1-3 个标准差内重现 Deepseek 在 LiveCodeBench 代码生成基准测试中报告的结果:
模型 | LiveCodeBench (🤗 LightEval) | GPQA Diamond (DeepSeek Reported) |
---|---|---|
DeepSeek-R1-Distill-Qwen-1.5B | 16.3 | 16.9 |
DeepSeek-R1-Distill-Qwen-7B | 36.6 | 37.6 |
DeepSeek-R1-Distill-Qwen-14B | 51.5 | 53.1 |
DeepSeek-R1-Distill-Qwen-32B | 56.6 | 57.2 |
DeepSeek-R1-Distill-Llama-8B | 37.0 | 39.6 |
DeepSeek-R1-Distill-Llama-70B | 54.5 | 57.5 |
要重现这些结果,请使用以下命令:
NUM_GPUS=1 # 32B 和 70B 模型设置为 8,或者使用 data_parallel_size=8 加速较小模型
MODEL=deepseek-ai/{model_name}
MODEL_ARGS="pretrained=$MODEL,dtype=bfloat16,max_model_length=32768,gpu_memory_utilization=0.8,data_parallel_size=$NUM_GPUS,generation_parameters={max_new_tokens:32768,temperature:0.6,top_p:0.95}"
OUTPUT_DIR=data/evals/$MODEL
lighteval vllm $MODEL_ARGS "extended|lcb:codegeneration|0|0" \
--use-chat-template \
--output-dir $OUTPUT_DIR
python scripts/run_benchmarks.py --model-id {model_id} --benchmarks lcb
数据生成
从小型蒸馏 R1 模型生成数据
以下示例可以在 1xH100 中运行。
首先安装以下依赖项:
uv pip install "distilabel[vllm]>=1.5.2"
现在将以下代码段保存到名为 pipeline.py
的文件中,并使用 python pipeline.py
运行它。它将为 10 个示例中的每一个生成 4 个输出(将存储库的用户名更改为您的组织/用户名):
from datasets import load_dataset
from distilabel.models import vLLM
from distilabel.pipeline import Pipeline
from distilabel.steps.tasks import TextGeneration
prompt_template = ///
"""
您将获得一个问题。请逐步推理,并将您的最终答案放在 \\boxed{}: 中:
{{ instruction }}
"""
dataset = load_dataset("AI-MO/NuminaMath-TIR", split="train").select(range(10))
model_id = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B" # 替换为另一个小型蒸馏 r1
with Pipeline(
name="distill-qwen-7b-r1",
description="一个从蒸馏 r1 模型生成数据的管道",
) as pipeline:
llm = vLLM(
model=model_id,
tokenizer=model_id,
extra_kwargs={
"tensor_parallel_size": 1,
"max_model_len": 8192,
},
generation_kwargs={
"temperature": 0.6,
"max_new_tokens": 8192,
},
)
prompt_column = "problem"
text_generation = TextGeneration(
llm=llm,
template=prompt_template,
num_generations=4,
input_mappings={"instruction": prompt_column} if prompt_column is not None else {}
)
if __name__ == "__main__":
distiset = pipeline.run(dataset=dataset)
distiset.push_to_hub(repo_id="username/numina-deepseek-r1-qwen-7b")
查看 HuggingFaceH4/numina-deepseek-r1-qwen-7b 的示例数据集。
从 DeepSeek-R1 生成数据
要运行更大的 DeepSeek-R1,我们使用了 2 个节点,每个节点有 8×H100 GPU,使用此存储库中 slurm/generate.slurm
的 slurm 文件。首先,安装依赖项:
(目前我们需要安装 vllm dev wheel,它修复了 R1 cuda 图捕获)
pip install https://wheels.vllm.ai/221d388cc5a836fa189305785ed7e887cea8b510/vllm-1.0.0.dev-cp38-abi3-manylinux1_x86_64.whl --extra-index-url https://download.pytorch.org/whl/cu121
uv pip install "distilabel[vllm,ray,openai]>=1.5.2"
然后运行以下命令:
sbatch slurm/generate.slurm \
--hf-dataset AI-MO/NuminaMath-TIR \
--temperature 0.6 \
--prompt-column problem \
--model deepseek-ai/DeepSeek-R1 \
--hf-output-dataset username/r1-dataset
[!NOTE]
作业运行时,您可以通过集群登录节点设置 SSH 隧道,从运行ssh -L 8265:ray_ip_head_node:8265 <login_node>
的计算机访问 Ray 仪表板,然后浏览http://localhost:8265
贡献
欢迎贡献。请参阅 https://github.com/huggingface/open-r1/issues/23。
致谢
该项目是开放 AI 社区中许多团体和个人共同努力的成果。我们特别感谢 vLLM 和 SGLang 团队创建了高性能工具来扩展 GRPO 的推出。我们还要感谢 OpenThoughts、Prime Intellect 和 General Reasoning 团队创建和共享高质量的推理数据集。
引用
如果您发现此项目在您的工作中很有用,请考虑如下引用:
@misc{openr1,
title = {Open R1: DeepSeek-R1 的完全开放复制},
url = {https://github.com/huggingface/open-r1},
author = {Hugging Face},
month = {January},
year = {2025}
}