mirror of
https://github.com/huggingface/open-r1.git
synced 2026-06-24 01:54:06 +00:00
Compare commits
11 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1416fa0cf2 |
||
|
|
0e06249d1c |
||
|
|
7e700c6218 |
||
|
|
b806e1092a |
||
|
|
a6b4f668fb |
||
|
|
01b4351c45 |
||
|
|
722f144d21 |
||
|
|
33f84def0d |
||
|
|
9eef995b4d |
||
|
|
5ac5971ea5 |
||
|
|
57e85b522f |
16 changed files with 155 additions and 241 deletions
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
|
|
@ -16,9 +16,9 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Setup Python environment
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
||||
with:
|
||||
python-version: 3.10.10
|
||||
- name: Install dependencies
|
||||
|
|
|
|||
9
Makefile
9
Makefile
|
|
@ -8,10 +8,11 @@ check_dirs := src tests
|
|||
|
||||
# dev dependencies
|
||||
install:
|
||||
uv venv openr1 --python 3.11 && . openr1/bin/activate && uv pip install --upgrade pip
|
||||
uv pip install vllm==0.8.4
|
||||
uv pip install setuptools
|
||||
uv pip install flash-attn --no-build-isolation
|
||||
uv venv openr1 --python 3.11
|
||||
. openr1/bin/activate && uv pip install --upgrade pip && \
|
||||
uv pip install vllm==0.8.5.post1 && \
|
||||
uv pip install setuptools && \
|
||||
uv pip install flash-attn --no-build-isolation && \
|
||||
GIT_LFS_SKIP_SMUDGE=1 uv pip install -e ".[dev]"
|
||||
|
||||
style:
|
||||
|
|
|
|||
105
README.md
105
README.md
|
|
@ -21,10 +21,9 @@
|
|||
The goal of this repo is to build the missing pieces of the R1 pipeline such that everybody can reproduce and build on top of it. The project is simple by design and mostly consists of:
|
||||
|
||||
|
||||
- `src/open_r1`: contains the scripts to train and evaluate models as well as generate synthetic data:
|
||||
- `src/open_r1`: contains the scripts to train models as well as generate synthetic data:
|
||||
- `grpo.py`: trains a model with GRPO on a given dataset.
|
||||
- `sft.py`: performs a simple SFT of a model on a dataset.
|
||||
- `evaluate.py`: evaluates a model on the R1 benchmarks.
|
||||
- `generate.py`: generates synthetic data from a model using [Distilabel](https://github.com/argilla-io/distilabel).
|
||||
- `Makefile`: contains easy-to-run commands for each step in the R1 pipeline leveraging the scripts above.
|
||||
|
||||
|
|
@ -42,6 +41,7 @@ We will use the DeepSeek-R1 [tech report](https://github.com/deepseek-ai/DeepSee
|
|||
|
||||
## News 🗞️
|
||||
|
||||
* **🧑🍳 [2025/05/26] (Step 1 completed!)** We release [**Mixture-of-Thoughts**](https://huggingface.co/datasets/open-r1/Mixture-of-Thoughts)--a curated reasoning dataset of 350k verified traces distilled from R1. The dataset spans tasks in mathematics, coding, and science, and is designed to teach language models to reason step-by-step. We also provide a recipe to train [OpenR1-Distill-7B](https://huggingface.co/open-r1/OpenR1-Distill-7B), which replicates the reasoning capabilities of [deepseek-ai/DeepSeek-R1-Distill-Qwen-7B](https://huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B) and marks the completion of step 1 in the Open R1 project.
|
||||
* **⚡️ [2025/03/11] [(update #3)](https://huggingface.co/blog/open-r1/update-3):** We release the [**CodeForces-CoTs**](https://huggingface.co/datasets/open-r1/codeforces-cots) dataset of 10k competitive programming problems and 100k solutions distilled from R1. We also release IOI24: a new benchmark of _very_ hard problems from international olympiads. A 7B Qwen model trained on CodeForces-CoTs can outperform Claude 3.7 Sonnet on IOI24, while a 32B model can outperform R1 itself.
|
||||
* **∞ [2025/02/10] [(update #2)](https://huggingface.co/blog/open-r1/update-2):** We release the [**OpenR1-Math-220k**](https://huggingface.co/datasets/open-r1/OpenR1-Math-220k) dataset of 220k traces distilled from R1 on a new version of NuminaMath. Models trained on this dataset match the performance of DeepSeek's distilled ones.
|
||||
* **🔥 [2025/02/02] [(update #1)](https://huggingface.co/blog/open-r1/update-1):** We implement the first parts of the [training](https://github.com/huggingface/open-r1?tab=readme-ov-file#training-models), [inference](https://github.com/huggingface/open-r1?tab=readme-ov-file#data-generation), and [evaluation](https://github.com/huggingface/open-r1?tab=readme-ov-file#reproducing-deepseeks-evaluation-results) pipelines. Let's go!
|
||||
|
|
@ -69,7 +69,7 @@ uv venv openr1 --python 3.11 && source openr1/bin/activate && uv pip install --u
|
|||
Next, install vLLM and FlashAttention:
|
||||
|
||||
```shell
|
||||
uv pip install vllm==0.8.4
|
||||
uv pip install vllm==0.8.5.post1
|
||||
uv pip install setuptools && uv pip install flash-attn --no-build-isolation
|
||||
```
|
||||
|
||||
|
|
@ -103,25 +103,27 @@ sudo apt-get install git-lfs
|
|||
> [!NOTE]
|
||||
> The training commands below are configured for a node of 8 x H100s (80GB). For different hardware and topologies, you may need to tune the batch size and number of gradient accumulation steps.
|
||||
|
||||
We support training models with either DDP or DeepSpeed (ZeRO-2 and ZeRO-3). For example, to run SFT on a dataset distilled from DeepSeek-R1 with reasoning traces such as [open-r1/OpenR1-Math-220k](https://huggingface.co/datasets/open-r1/OpenR1-Math-220k), run:
|
||||
We support training models with either DDP or DeepSpeed (ZeRO-2 and ZeRO-3). For example, to perform SFT on a dataset distilled from DeepSeek-R1 with reasoning traces such as [open-r1/Mixture-of-Thoughts](https://huggingface.co/datasets/open-r1/Mixture-of-Thoughts), run:
|
||||
|
||||
```shell
|
||||
# Train via command line
|
||||
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 5.0e-5 \
|
||||
--num_train_epochs 1 \
|
||||
--max_seq_length 16384 \
|
||||
--per_device_train_batch_size 16 \
|
||||
--model_name_or_path open-r1/Qwen2.5-Math-7B-RoPE-300k \
|
||||
--dataset_name open-r1/Mixture-of-Thoughts \
|
||||
--dataset_config all \
|
||||
--eos_token '<|im_end|>' \
|
||||
--learning_rate 4.0e-5 \
|
||||
--num_train_epochs 5 \
|
||||
--max_seq_length 32768 \
|
||||
--per_device_train_batch_size 2 \
|
||||
--gradient_checkpointing \
|
||||
--bf16 \
|
||||
--use_liger_kernel \
|
||||
--output_dir data/Qwen2.5-1.5B-Open-R1-Distill
|
||||
--output_dir data/OpenR1-Distill-7B
|
||||
|
||||
# Train via YAML config
|
||||
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
|
||||
--config recipes/OpenR1-Distill-7B/sft/config_distill.yaml
|
||||
```
|
||||
|
||||
Currently, the following tasks are supported:
|
||||
|
|
@ -135,17 +137,19 @@ Currently, the following tasks are supported:
|
|||
By default, these scripts will push each model to your Hugging Face Hub username, i.e. `{username}/{model_name}-{task}`. You can override the parameters in each YAML config by appending them to the command as follows:
|
||||
|
||||
```shell
|
||||
# Change batch size, number of epochs etc
|
||||
# Change the base model to a smaller variant
|
||||
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
|
||||
--config recipes/OpenR1-Distill-7B/sft/config_distill.yaml \
|
||||
--model_name_or_path Qwen/Qwen3-0.6B-Base \
|
||||
--hub_model_id OpenR1-Distill-0.6B \
|
||||
--output_dir data/OpenR1-Distill-0.6B
|
||||
```
|
||||
|
||||
If you also wish to override the Weights and Biases default settings, you can do so as follows:
|
||||
|
||||
```shell
|
||||
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
|
||||
--config recipes/OpenR1-Distill-7B/sft/config_distill.yaml
|
||||
--wandb_entity huggingface --wandb_project open-r1 --run_name Qwen2.5-1.5B-GRPO
|
||||
```
|
||||
|
||||
|
|
@ -158,10 +162,11 @@ Most base models like `meta-llama/Llama-3.2-1B` do not have a chat template, so
|
|||
accelerate launch --config_file=recipes/accelerate_configs/zero3.yaml src/open_r1/sft.py \
|
||||
--model_name_or_path Qwen/Qwen2.5-1.5B \
|
||||
+ --eos_token '<|im_end|>'
|
||||
--dataset_name open-r1/OpenR1-Math-220k \
|
||||
--learning_rate 5.0e-5 \
|
||||
--dataset_name open-r1/Mixture-of-Thoughts \
|
||||
--dataset_config all \
|
||||
--learning_rate 4.0e-5 \
|
||||
--num_train_epochs 1 \
|
||||
--max_seq_length 16384 \
|
||||
--max_seq_length 32768 \
|
||||
--per_device_train_batch_size 16 \
|
||||
--gradient_checkpointing \
|
||||
--bf16 \
|
||||
|
|
@ -177,10 +182,11 @@ accelerate launch --config_file=recipes/accelerate_configs/zero3.yaml src/open_r
|
|||
--model_name_or_path meta-llama/Llama-3.2-1B \
|
||||
+ --chat_template "$(cat llama_chat_template.jinja)" \
|
||||
+ --eos_token '<|eot_id|>' \
|
||||
--dataset_name open-r1/OpenR1-Math-220k \
|
||||
--learning_rate 5.0e-5 \
|
||||
--dataset_name open-r1/Mixture-of-Thoughts \
|
||||
--dataset_config all \
|
||||
--learning_rate 4.0e-5 \
|
||||
--num_train_epochs 1 \
|
||||
--max_seq_length 16384 \
|
||||
--max_seq_length 32768 \
|
||||
--per_device_train_batch_size 16 \
|
||||
--gradient_checkpointing \
|
||||
--bf16 \
|
||||
|
|
@ -188,55 +194,39 @@ accelerate launch --config_file=recipes/accelerate_configs/zero3.yaml src/open_r
|
|||
--output_dir data/Llama-3.2-1B-Open-R1-Distill
|
||||
```
|
||||
|
||||
### SFT
|
||||
### SFT distillation
|
||||
|
||||
To run SFT on a dataset distilled from DeepSeek-R1 with reasoning traces such as [open-r1/OpenR1-Math-220k](https://huggingface.co/datasets/open-r1/OpenR1-Math-220k), run:
|
||||
We provide a recipe to reproduce the reasoning capabilities of [deepseek-ai/DeepSeek-R1-Distill-Qwen-7B](https://huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B), starting from the same base model. To do so, run:
|
||||
|
||||
```shell
|
||||
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
|
||||
--config recipes/OpenR1-Distill-7B/sft/config_distill.yaml
|
||||
```
|
||||
|
||||
The result will be a model like [open-r1/OpenR1-Distill-7B](https://huggingface.co/open-r1/OpenR1-Distill-7B), with the following downstream performance:
|
||||
|
||||
| Model | AIME 2024 | MATH-500 | GPQA Diamond | LiveCodeBench v5 |
|
||||
|-----------------------------|-----------|----------|--------------|------------------|
|
||||
| OpenR1-Distill-7B | 52.7 | 89.0 | 52.8 | 39.4 |
|
||||
| DeepSeek-R1-Distill-Qwen-7B | 51.3 | 93.5 | 52.4 | 37.4 |
|
||||
|
||||
You can adjust the YAML config to train on a different base model or dataset.
|
||||
|
||||
### GRPO
|
||||
|
||||
We use TRL's [vLLM backend](https://huggingface.co/docs/trl/speeding_up_training?vllm+examples=GRPO#vllm-for-fast-generation-in-online-methods) to scale training to large models across multiple nodes. For single-node training of smol models across 8 GPUs, first spin up the vLLM server to run on e.g. 1 GPU as follows:
|
||||
We use TRL's [vLLM backend](https://huggingface.co/docs/trl/speeding_up_training?vllm+examples=GRPO#vllm-for-fast-generation-in-online-methods) to scale training to large models across multiple nodes. For single-node training of smol models across 8 GPUs, use `vllm_mode="colocate"` to run vLLM in the same process as the training script:
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0 trl vllm-serve --model deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
|
||||
```
|
||||
|
||||
Once the server is up, run training on the remaining GPUs as follows:
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=1,2,3,4,5,6,7 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
|
||||
ACCELERATE_LOG_LEVEL=info \
|
||||
accelerate launch --config_file recipes/accelerate_configs/zero3.yaml \
|
||||
src/open_r1/grpo.py --config recipes/DeepSeek-R1-Distill-Qwen-1.5B/grpo/config_demo.yaml \
|
||||
--vllm_mode colocate
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> The chat template used in the distilled DeepSeek models omits the contents of the reasoning block within the `<think>` and `</think>` tags. It also prefills the assistant response with `<think>` which interferes with the format reward function. To handle that, it is important to override the chat template as done in e.g. [recipes/DeepSeek-R1-Distill-Qwen-1.5B/grpo/config_demo.yaml](./recipes/DeepSeek-R1-Distill-Qwen-1.5B/grpo/config_demo.yaml).
|
||||
|
||||
To increase the throughput with data parallel on e.g. 2 GPUs, run:
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0,1 trl vllm-serve --model deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B --data_parallel_size 2
|
||||
```
|
||||
|
||||
Then run training on the remaining GPUs as follows:
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=2,3,4,5,6,7 ACCELERATE_LOG_LEVEL=info \
|
||||
accelerate launch --config_file recipes/accelerate_configs/zero2.yaml --num_processes 6 \
|
||||
src/open_r1/grpo.py --config recipes/DeepSeek-R1-Distill-Qwen-1.5B/grpo/config_demo.yaml
|
||||
```
|
||||
|
||||
For larger models, use tensor parallelism:
|
||||
|
||||
```shell
|
||||
CUDA_VISIBLE_DEVICES=0,1 trl vllm-serve --model deepseek-ai/DeepSeek-R1-Distill-Qwen-14B --tensor_parallel_size 2
|
||||
```
|
||||
|
||||
For multi-node training on N+1 nodes, with 1 node running the vLLM server and N nodes running training, we provide an example Slurm script. For example, to run the above example on 1+1 nodes with data parallelism, run:
|
||||
|
||||
```shell
|
||||
|
|
@ -309,6 +299,7 @@ Make sure your dataset contains a `verification_info` column with the following
|
|||
}
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
For example, to train a smol model on Python problems, start the vLLM server:
|
||||
|
||||
|
|
@ -411,7 +402,7 @@ sbatch --job-name=open_r1 --nodes=1 slurm/train.slurm --model {model_name} --tas
|
|||
Here `{model_name}` and `{task}` are defined as above, while `{config_suffix}` refers to the specific config and `{accelerator}` refers to the choice of 🤗 Accelerate config in `recipes/accelerate_configs`. If you wish to override the default config parameters, you can provide them by appending a space-separated string like `'--arg1=value1 --arg2=value2'`. Here's a concrete example to run SFT on 1 node of 8 GPUs:
|
||||
|
||||
```shell
|
||||
sbatch --job-name=open_r1 --nodes=1 slurm/train.slurm --model Qwen2.5-1.5B-Instruct --task sft --config demo --accelerator zero3
|
||||
sbatch --job-name=open_r1 --nodes=1 slurm/train.slurm --model OpenR1-Distill-7B --task sft --config distill --accelerator zero3
|
||||
```
|
||||
|
||||
You can scale the number of nodes by increasing the `--nodes` flag.
|
||||
|
|
@ -808,7 +799,7 @@ If you find this project is useful in your own work, please consider citing as f
|
|||
@misc{openr1,
|
||||
title = {Open R1: A fully open reproduction of DeepSeek-R1},
|
||||
url = {https://github.com/huggingface/open-r1},
|
||||
author = {Hugging Face},
|
||||
author = {{Hugging Face}},
|
||||
month = {January},
|
||||
year = {2025}
|
||||
}
|
||||
|
|
|
|||
48
recipes/OpenR1-Distill-7B/sft/config_distill.yaml
Normal file
48
recipes/OpenR1-Distill-7B/sft/config_distill.yaml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# Config for 1 node of 8 x H100s (80GB)
|
||||
# Model arguments
|
||||
model_name_or_path: open-r1/Qwen2.5-Math-7B-RoPE-300k
|
||||
model_revision: main
|
||||
torch_dtype: bfloat16
|
||||
attn_implementation: flash_attention_2
|
||||
|
||||
# Data training arguments
|
||||
chat_template: "{%- if tools %}\n {{- '<|im_start|>system\\n' }}\n {%- if messages[0]['role'] == 'system' %}\n {{- messages[0]['content'] }}\n {%- else %}\n {{- 'You are Open-R1, a language model trained by Hugging Face to help users. Your role as an assistant involves thoroughly exploring questions through a systematic thinking process before providing the final precise and accurate solutions. This requires engaging in a comprehensive cycle of analysis, summarizing, exploration, reassessment, reflection, backtracing, and iteration to develop well-considered thinking process. Please structure your response into two main sections: Thought and Solution using the specified format: <think> Thought section </think> Solution section. In the Thought section, detail your reasoning process in steps. Each step should include detailed considerations such as analysing questions, summarizing relevant findings, brainstorming new ideas, verifying the accuracy of the current steps, refining any errors, and revisiting previous steps. In the Solution section, based on various attempts, explorations, and reflections from the Thought section, systematically present the final solution that you deem correct. The Solution section should be logical, accurate, and concise and detail necessary steps needed to reach the conclusion. Now, try to solve the following question through the above guidelines.' }}\n {%- endif %}\n {{- \"\\n\\n# Tools\\n\\nYou may call one or more functions to assist with the user query.\\n\\nYou are provided with function signatures within <tools></tools> XML tags:\\n<tools>\" }}\n {%- for tool in tools %}\n {{- \"\\n\" }}\n {{- tool | tojson }}\n {%- endfor %}\n {{- \"\\n</tools>\\n\\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\\n<tool_call>\\n{\\\"name\\\": <function-name>, \\\"arguments\\\": <args-json-object>}\\n</tool_call><|im_end|>\\n\" }}\n{%- else %}\n {%- if messages[0]['role'] == 'system' %}\n {{- '<|im_start|>system\\n' + messages[0]['content'] + '<|im_end|>\\n' }}\n {%- else %}\n {{- '<|im_start|>system\\nYou are Open-R1, a language model trained by Hugging Face to help users. Your role as an assistant involves thoroughly exploring questions through a systematic thinking process before providing the final precise and accurate solutions. This requires engaging in a comprehensive cycle of analysis, summarizing, exploration, reassessment, reflection, backtracing, and iteration to develop well-considered thinking process. Please structure your response into two main sections: Thought and Solution using the specified format: <think> Thought section </think> Solution section. In the Thought section, detail your reasoning process in steps. Each step should include detailed considerations such as analysing questions, summarizing relevant findings, brainstorming new ideas, verifying the accuracy of the current steps, refining any errors, and revisiting previous steps. In the Solution section, based on various attempts, explorations, and reflections from the Thought section, systematically present the final solution that you deem correct. The Solution section should be logical, accurate, and concise and detail necessary steps needed to reach the conclusion. Now, try to solve the following question through the above guidelines.<|im_end|>\\n' }}\n {%- endif %}\n{%- endif %}\n{%- for message in messages %}\n {%- if (message.role == \"user\") or (message.role == \"system\" and not loop.first) or (message.role == \"assistant\" and not message.tool_calls) %}\n {{- '<|im_start|>' + message.role + '\\n' + message.content + '<|im_end|>' + '\\n' }}\n {%- elif message.role == \"assistant\" %}\n {{- '<|im_start|>' + message.role }}\n {%- if message.content %}\n {{- '\\n' + message.content }}\n {%- endif %}\n {%- for tool_call in message.tool_calls %}\n {%- if tool_call.function is defined %}\n {%- set tool_call = tool_call.function %}\n {%- endif %}\n {{- '\\n<tool_call>\\n{\"name\": \"' }}\n {{- tool_call.name }}\n {{- '\", \"arguments\": ' }}\n {{- tool_call.arguments | tojson }}\n {{- '}\\n</tool_call>' }}\n {%- endfor %}\n {{- '<|im_end|>\\n' }}\n {%- elif message.role == \"tool\" %}\n {%- if (loop.index0 == 0) or (messages[loop.index0 - 1].role != \"tool\") %}\n {{- '<|im_start|>user' }}\n {%- endif %}\n {{- '\\n<tool_response>\\n' }}\n {{- message.content }}\n {{- '\\n</tool_response>' }}\n {%- if loop.last or (messages[loop.index0 + 1].role != \"tool\") %}\n {{- '<|im_end|>\\n' }}\n {%- endif %}\n {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n {{- '<|im_start|>assistant\\n' }}\n{%- endif %}\n"
|
||||
dataset_name: open-r1/Mixture-of-Thoughts
|
||||
dataset_config: all
|
||||
dataset_num_proc: 12
|
||||
eos_token: <|im_end|>
|
||||
|
||||
# SFT trainer config
|
||||
bf16: true
|
||||
do_eval: false
|
||||
eval_strategy: 'no'
|
||||
gradient_accumulation_steps: 8
|
||||
gradient_checkpointing: true
|
||||
gradient_checkpointing_kwargs:
|
||||
use_reentrant: false
|
||||
hub_model_id: OpenR1-Distill-7B
|
||||
hub_strategy: every_save
|
||||
learning_rate: 4.0e-05
|
||||
log_level: info
|
||||
logging_steps: 1
|
||||
logging_strategy: steps
|
||||
lr_scheduler_type: cosine_with_min_lr
|
||||
lr_scheduler_kwargs:
|
||||
min_lr_rate: 0.1
|
||||
packing: false
|
||||
max_grad_norm: 0.2
|
||||
max_length: 32768
|
||||
max_steps: -1
|
||||
num_train_epochs: 5
|
||||
output_dir: data/OpenR1-Distill-7B
|
||||
overwrite_output_dir: true
|
||||
per_device_eval_batch_size: 1
|
||||
per_device_train_batch_size: 2
|
||||
push_to_hub: true
|
||||
report_to:
|
||||
- wandb
|
||||
save_strategy: epoch
|
||||
save_total_limit: 1
|
||||
seed: 42
|
||||
use_liger_kernel: true
|
||||
warmup_ratio: 0.03
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
# Model arguments
|
||||
# You need to download the model and manually change the rope to 300k and max_position_embeddings to 32768
|
||||
# the config file should match https://huggingface.co/open-r1/OpenR1-Qwen-7B/blob/main/config.json
|
||||
model_name_or_path: Qwen/Qwen2.5-Math-7B-Instruct
|
||||
model_revision: main
|
||||
torch_dtype: bfloat16
|
||||
attn_implementation: sdpa
|
||||
|
||||
# Data training arguments
|
||||
dataset_name: open-r1/OpenR1-Math-220k
|
||||
dataset_num_proc: 48
|
||||
|
||||
#SFT hyperparam
|
||||
max_length: 32768
|
||||
weight_decay: 0.0001
|
||||
optim: adamw_torch
|
||||
lr_scheduler_type: linear
|
||||
warmup_ratio: 0.1
|
||||
learning_rate: 5.0e-05
|
||||
gradient_accumulation_steps: 2
|
||||
per_device_eval_batch_size: 1
|
||||
per_device_train_batch_size: 1
|
||||
|
||||
# SFT trainer config
|
||||
max_steps: -1
|
||||
num_train_epochs: 3
|
||||
bf16: true
|
||||
do_eval: false
|
||||
use_liger_kernel: true
|
||||
eval_strategy: 'no'
|
||||
gradient_checkpointing: true
|
||||
gradient_checkpointing_kwargs:
|
||||
use_reentrant: false
|
||||
hub_model_id: OpenR1-Qwen-7B-SFT
|
||||
hub_strategy: every_save
|
||||
log_level: info
|
||||
logging_steps: 5
|
||||
logging_strategy: steps
|
||||
packing: false
|
||||
output_dir: data/OpenR1-Qwen-7B-SFT
|
||||
overwrite_output_dir: true
|
||||
push_to_hub: true
|
||||
report_to:
|
||||
- wandb
|
||||
save_strategy: "steps"
|
||||
save_steps: 500
|
||||
save_total_limit: 1
|
||||
seed: 42
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
# Model arguments
|
||||
model_name_or_path: Qwen/Qwen2.5-1.5B-Instruct
|
||||
model_revision: main
|
||||
torch_dtype: bfloat16
|
||||
attn_implementation: flash_attention_2
|
||||
|
||||
# Data training arguments
|
||||
dataset_name: open-r1/OpenR1-Math-220k
|
||||
dataset_num_proc: 48
|
||||
|
||||
# SFT trainer config
|
||||
bf16: true
|
||||
do_eval: false
|
||||
eval_strategy: 'no'
|
||||
gradient_accumulation_steps: 1
|
||||
gradient_checkpointing: true
|
||||
gradient_checkpointing_kwargs:
|
||||
use_reentrant: false
|
||||
hub_model_id: Qwen2.5-1.5B-Open-R1-Distill
|
||||
hub_strategy: every_save
|
||||
learning_rate: 5.0e-05
|
||||
log_level: info
|
||||
logging_steps: 5
|
||||
logging_strategy: steps
|
||||
lr_scheduler_type: cosine_with_min_lr
|
||||
lr_scheduler_kwargs:
|
||||
min_lr_rate: 0.1
|
||||
packing: false
|
||||
max_length: 16384
|
||||
max_steps: -1
|
||||
num_train_epochs: 1
|
||||
output_dir: data/Qwen2.5-1.5B-Open-R1-Distill
|
||||
overwrite_output_dir: true
|
||||
per_device_eval_batch_size: 16
|
||||
per_device_train_batch_size: 16
|
||||
push_to_hub: true
|
||||
report_to:
|
||||
- wandb
|
||||
save_strategy: "steps"
|
||||
save_steps: 100
|
||||
save_total_limit: 1
|
||||
seed: 42
|
||||
use_liger_kernel: true
|
||||
warmup_ratio: 0.05
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
# Model arguments
|
||||
model_name_or_path: Qwen/Qwen2.5-Math-7B
|
||||
model_revision: main
|
||||
torch_dtype: bfloat16
|
||||
attn_implementation: flash_attention_2
|
||||
|
||||
# Data training arguments
|
||||
dataset_name: DigitalLearningGmbH/MATH-lighteval
|
||||
dataset_config: default
|
||||
dataset_prompt_column: problem
|
||||
system_prompt: "You are a helpful AI Assistant, designed to provided well-reasoned and detailed responses. You FIRST think about the reasoning process as an internal monologue and then provide the user with the answer. The reasoning process MUST BE enclosed within <think> and </think> tags."
|
||||
|
||||
# GRPO trainer config
|
||||
bf16: true
|
||||
use_vllm: true
|
||||
do_eval: true
|
||||
eval_strategy: steps
|
||||
eval_steps: 100
|
||||
gradient_accumulation_steps: 8
|
||||
gradient_checkpointing: true
|
||||
gradient_checkpointing_kwargs:
|
||||
use_reentrant: false
|
||||
hub_model_id: Qwen-2.5-7B-Simple-RL
|
||||
hub_strategy: every_save
|
||||
learning_rate: 3.0e-06
|
||||
log_completions: true
|
||||
log_level: info
|
||||
logging_first_step: true
|
||||
logging_steps: 5
|
||||
logging_strategy: steps
|
||||
lr_scheduler_type: cosine
|
||||
max_prompt_length: 512
|
||||
max_completion_length: 1024
|
||||
max_steps: -1
|
||||
num_generations: 7
|
||||
num_train_epochs: 1
|
||||
output_dir: data/Qwen-2.5-7B-Simple-RL
|
||||
overwrite_output_dir: true
|
||||
per_device_eval_batch_size: 16
|
||||
per_device_train_batch_size: 16
|
||||
push_to_hub: true
|
||||
report_to:
|
||||
- wandb
|
||||
reward_funcs:
|
||||
- accuracy
|
||||
- format
|
||||
reward_weights:
|
||||
- 1.0
|
||||
- 1.0
|
||||
save_strategy: "no"
|
||||
seed: 42
|
||||
warmup_ratio: 0.1
|
||||
|
|
@ -1,5 +1,13 @@
|
|||
# Post-training recipes
|
||||
|
||||
## OpenR1 Distill 7B
|
||||
|
||||
To train the OpenR1 Distill 7B model, run:
|
||||
|
||||
```
|
||||
sbatch --nodes=1 slurm/train.slurm --model OpenR1-Distill-7B --task sft --config distill --accelerator zero3
|
||||
```
|
||||
|
||||
## OlympicCoder
|
||||
|
||||
To train the OlympicCoder models, run:
|
||||
|
|
|
|||
8
setup.py
8
setup.py
|
|
@ -55,7 +55,7 @@ _deps = [
|
|||
"jieba", # Needed for Chinese language support
|
||||
"langdetect", # Needed for LightEval's extended tasks
|
||||
"latex2sympy2_extended>=1.0.6",
|
||||
"liger-kernel>=0.5.9",
|
||||
"liger-kernel>=0.5.10",
|
||||
"lighteval @ git+https://github.com/huggingface/lighteval.git@d3da6b9bbf38104c8b5e1acc86f83541f9a502d1", # Critical bug fix for tokenizer revisions: https://github.com/huggingface/lighteval/pull/721
|
||||
"math-verify==0.5.2", # Used for math verification in grpo
|
||||
"morphcloud==0.1.67",
|
||||
|
|
@ -68,8 +68,8 @@ _deps = [
|
|||
"safetensors>=0.3.3",
|
||||
"sentencepiece>=0.1.99",
|
||||
"torch==2.6.0",
|
||||
"transformers @ git+https://github.com/huggingface/transformers.git@acdbe627e323dbc822f21499fead789b439cf45b", # Fix DeepSpeed x vLLM conflict: https://github.com/huggingface/transformers/pull/37755
|
||||
"trl[vllm] @ git+https://github.com/huggingface/trl.git@1bca49515ecd5b85d16e68c42c76670e252e19f1", # Fix DeepSpeed x vLLM conflict: https://github.com/huggingface/trl/pull/3351
|
||||
"transformers==4.52.3",
|
||||
"trl[vllm]==0.18.0",
|
||||
"wandb>=0.19.1",
|
||||
"async-lru>=2.0.5",
|
||||
"aiofiles>=24.1.0",
|
||||
|
|
@ -116,7 +116,7 @@ install_requires = [
|
|||
deps["transformers"],
|
||||
deps["trl"],
|
||||
deps["wandb"],
|
||||
deps["async-lru"]
|
||||
deps["async-lru"],
|
||||
]
|
||||
|
||||
setup(
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@
|
|||
# Be ye warned this may not work on other clusters!
|
||||
module load cuda/12.4
|
||||
|
||||
# Refresh Weka on h4 cache
|
||||
echo "Refreshing Weka filesystem..."
|
||||
find -L /fsx/h4/ -type f | xargs -d '\n' -r -n512 -P64 weka fs tier fetch
|
||||
|
||||
# Needed for vLLM
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ source openr1/bin/activate
|
|||
START_TIME=$(date +%s)
|
||||
echo "START TIME: $(date)"
|
||||
|
||||
# Refresh Weka on h4 cache
|
||||
echo "Refreshing Weka filesystem..."
|
||||
find -L /fsx/h4/ -type f | xargs -d '\n' -r -n512 -P64 weka fs tier fetch
|
||||
|
||||
# Default values
|
||||
MODEL=""
|
||||
TASK=""
|
||||
|
|
@ -175,4 +179,4 @@ ELAPSED_SECONDS=$((END_TIME - START_TIME))
|
|||
HOURS=$((ELAPSED_SECONDS / 3600))
|
||||
MINUTES=$(( (ELAPSED_SECONDS % 3600) / 60 ))
|
||||
SECONDS=$((ELAPSED_SECONDS % 60))
|
||||
echo "TOTAL JOB TIME: ${HOURS}h ${MINUTES}m ${SECONDS}s (${ELAPSED_SECONDS} seconds)"
|
||||
echo "TOTAL JOB TIME: ${HOURS}h ${MINUTES}m ${SECONDS}s (${ELAPSED_SECONDS} seconds)"
|
||||
|
|
|
|||
|
|
@ -136,15 +136,22 @@ class GRPOConfig(trl.GRPOConfig):
|
|||
metadata={"help": "The callbacks to run during training."},
|
||||
)
|
||||
chat_template: Optional[str] = field(default=None, metadata={"help": "The chat template to use."})
|
||||
hub_model_revision: Optional[str] = field(
|
||||
default="main", metadata={"help": "The Hub model branch to push the model to."}
|
||||
)
|
||||
num_completions_to_print: int = field(default=0, metadata={"help": "Number of completions to print."})
|
||||
overwrite_hub_revision: bool = field(default=False, metadata={"help": "Whether to overwrite the Hub revision."})
|
||||
push_to_hub_revision: bool = field(default=False, metadata={"help": "Whether to push to a Hub revision/branch."})
|
||||
system_prompt: Optional[str] = field(
|
||||
default=None,
|
||||
metadata={"help": "The optional system prompt to use."},
|
||||
)
|
||||
hub_model_revision: Optional[str] = field(
|
||||
default="main", metadata={"help": "The Hub model branch to push the model to."}
|
||||
wandb_log_unique_prompts: bool = field(
|
||||
default=True,
|
||||
metadata={
|
||||
"help": ("Whether to log the unique prompts to wandb. This will create a new run for each unique prompt.")
|
||||
},
|
||||
)
|
||||
overwrite_hub_revision: bool = field(default=False, metadata={"help": "Whether to overwrite the Hub revision."})
|
||||
push_to_hub_revision: bool = field(default=False, metadata={"help": "Whether to push to a Hub revision/branch."})
|
||||
wandb_entity: Optional[str] = field(
|
||||
default=None,
|
||||
metadata={"help": ("The entity to store runs under.")},
|
||||
|
|
|
|||
|
|
@ -140,6 +140,9 @@ def main(script_args, training_args, model_args):
|
|||
# Save model and create model card
|
||||
##################################
|
||||
logger.info("*** Save model ***")
|
||||
# Align the model's generation config with the tokenizer's eos token
|
||||
# to avoid unbounded generation in the transformers `pipeline()` function
|
||||
trainer.model.generation_config.eos_token_id = tokenizer.eos_token_id
|
||||
trainer.save_model(training_args.output_dir)
|
||||
logger.info(f"Model saved to {training_args.output_dir}")
|
||||
|
||||
|
|
|
|||
|
|
@ -19,20 +19,18 @@ Usage:
|
|||
|
||||
# One 1 node of 8 x H100s
|
||||
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 2.0e-5 \
|
||||
--num_train_epochs 1 \
|
||||
--packing \
|
||||
--max_seq_length 4096 \
|
||||
--model_name_or_path open-r1/Qwen2.5-Math-7B-RoPE-300k \
|
||||
--dataset_name open-r1/Mixture-of-Thoughts \
|
||||
--dataset_config all \
|
||||
--eos_token '<|im_end|>' \
|
||||
--learning_rate 4.0e-5 \
|
||||
--num_train_epochs 5 \
|
||||
--max_seq_length 32768 \
|
||||
--per_device_train_batch_size 2 \
|
||||
--gradient_accumulation_steps 8 \
|
||||
--gradient_checkpointing \
|
||||
--bf16 \
|
||||
--logging_steps 5 \
|
||||
--eval_strategy steps \
|
||||
--eval_steps 100 \
|
||||
--output_dir data/Qwen2.5-1.5B-Open-R1-Distill
|
||||
--use_liger_kernel \
|
||||
--output_dir data/OpenR1-Distill-7B
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
|
@ -55,7 +53,6 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
|
||||
def main(script_args, training_args, model_args):
|
||||
# Set seed for reproducibility
|
||||
set_seed(training_args.seed)
|
||||
|
||||
###############
|
||||
|
|
@ -87,24 +84,15 @@ def main(script_args, training_args, model_args):
|
|||
if "wandb" in training_args.report_to:
|
||||
init_wandb_training(training_args)
|
||||
|
||||
################
|
||||
# Load datasets
|
||||
################
|
||||
######################################
|
||||
# Load dataset, tokenizer, and model #
|
||||
######################################
|
||||
dataset = get_dataset(script_args)
|
||||
|
||||
################
|
||||
# Load tokenizer
|
||||
################
|
||||
tokenizer = get_tokenizer(model_args, training_args)
|
||||
|
||||
###################
|
||||
# Load model
|
||||
###################
|
||||
logger.info("*** Loading model ***")
|
||||
model = get_model(model_args, training_args)
|
||||
|
||||
if tokenizer.chat_template is None:
|
||||
logger.info("No chat template provided, using ChatML.")
|
||||
logger.info("No chat template provided, defaulting to ChatML.")
|
||||
model, tokenizer = setup_chat_format(model, tokenizer, format="chatml")
|
||||
|
||||
############################
|
||||
|
|
@ -140,6 +128,9 @@ def main(script_args, training_args, model_args):
|
|||
# Save model and create model card
|
||||
##################################
|
||||
logger.info("*** Save model ***")
|
||||
# Align the model's generation config with the tokenizer's eos token
|
||||
# to avoid unbounded generation in the transformers `pipeline()` function
|
||||
trainer.model.generation_config.eos_token_id = tokenizer.eos_token_id
|
||||
trainer.save_model(training_args.output_dir)
|
||||
logger.info(f"Model saved to {training_args.output_dir}")
|
||||
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ async def get_generated_contest_tests(contest_id: str) -> list[dict]:
|
|||
|
||||
import aiofiles
|
||||
import aiofiles.os
|
||||
|
||||
tests_folder = os.environ.get("CF_TESTS_FOLDER", None)
|
||||
if not tests_folder:
|
||||
raise ValueError(
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ def run_lighteval_job(
|
|||
if get_param_count_from_repo_id(model_name) >= 30_000_000_000:
|
||||
tensor_parallel = True
|
||||
else:
|
||||
num_gpus = 8
|
||||
num_gpus = 2 # Hack while cluster is full
|
||||
tensor_parallel = False
|
||||
|
||||
cmd = VLLM_SLURM_PREFIX.copy()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue