强化学习动手实践:初探 DeepSeek R1 顿悟现象
在人工智能训练过程中,模型能力的跃迁往往并非线性提升,而是伴随着潜移默化的积累与突现的顿悟。本文以小模型为例,尝试通过强化学习探索 DeepSeek R1 中“顿悟现象”的再现与分析,揭示智能系统从量变到质变的过程。
一、实践目的
我们实践的目标包括:
- 探索语言模型在强化学习中表现出来的“顿悟”(Aha Moment)现象,即模型能力出现显著提升的瞬间。
- 理解模型训练过程中每个代码模块的作用,并 实际动手完成一次训练。
本教程基于 Philipp Schmid 在 GitHub 上公开的 Mini-R1: Reproduce Deepseek R1 „aha moment“ a RL tutorial 项目修改而来。代码和实验结果可以从 Github 或者 Gitee 下载。
二、强化学习任务介绍
强化学习的问题设定:
我们使用的数据集为 Jiayi-Pan/Countdown-Tasks-3to4,包含大量以数字运算为核心的数学问题。具体来说,每个题目都会提供:
- 一组数字(例如
80, 93, 62
) - 一个目标数字(例如
49
)
任务是:
使用给定的数字,每个数字且只能使用一次,通过基本的数学运算(加、减、乘、除)组合成一个算式,得到题目给出的目标数字。
举例说明:
给定数字:80, 93, 62
,目标:49
生成的 completion 样例如下:
<think>
We need to use the numbers 80, 93, and 62 exactly once with basic arithmetic operations to get 49. Let's try different combinations:
:
- 93 - 80 - 62 = -49(not 49)
- 80 + 62 - 93 = 49(this works)
</think>
<answer>80 + 62 - 93</answer>
模型需要先在 <think>
标签内展示思考推导过程,然后在 <answer>
标签内给出最终正确的算式。
三、实践框架概览
实践过程可分为以下几个主要阶段:
- 环境配置
- 数据准备与格式化(Prompt构建)
- 定义奖励函数用于评估生成结果
- 模型加载并运行 GRPO 训练
- 训练结果分析与顿悟现象识别
四、具体实践步骤
步骤 1:环境配置
本实践是在 Spader.AI 上的 8 卡 A100 上完成的。按照 Github 或者 Gitee 上的安装指南准备环境。
以下代码片段均来自 scripts/run_r1_grpo.py
。
步骤2:数据准备与 Prompt 格式化
从 Hugging Face 数据集Jiayi-Pan/Countdown-Tasks-3to4
中抽取数据后,使用如下代码格式化成 Prompt:
# 从 Hugging Face Hub 下载数据集
dataset = load_dataset(script_args.dataset_id_or_path, split=script_args.dataset_splits)
# 从中随机挑选 5 万个样本
dataset = dataset.shuffle(seed=42).select(range(50000))
#####################
# 准备并且格式化数据
#####################
# 转换成 DeepSeek R1 prompt 格式, 即带有 <think> 标签开头的 prompt
def generate_r1_prompt(numbers, target):
r1_prefix = [{
"role": "system",
"content": "You are a helpful assistant. You first thinks about the reasoning process in the mind and then provides the user with the answer."
},
{
"role": "user",
"content": f"Using the numbers {numbers}, create an equation that equals {target}. You can use basic arithmetic operations (+, -, *, /) one or multiple times but each number can only be used once. Show your work in <think> </think> tags. And return the final equation in <answer> </answer> tags, for example <answer> (1 + 2) / 3 </answer>. Think step by step inside <think> tags."
},
{
"role": "assistant",
"content": "Let me solve this step by step.\n<think>"
}]
return {"prompt": tokenizer.apply_chat_template(r1_prefix, tokenize=False, continue_final_message=True), "target": target, "nums": numbers}
# 把待训练的数据转换成 DeepSeek R1 格式的 prompt
dataset = dataset.map(lambda x: generate_r1_prompt(x["nums"], x["target"]))
# 切分 10% 的数据作为测试集
train_test_split = dataset.train_test_split(test_size=0.1)
train_dataset = train_test_split["train"]
test_dataset = train_test_split["test"]
格式化后的 Prompt 具体内容包含:
- 清晰的系统指令,要求模型先思考后作答。
- 用户问题明确要求模型用给定数字构造等于目标的算式,并明确要求在
<think>
标签 内展示推导过程、<answer>
标签内给出最终算式。 - Assistant 回复的开头固定为
Let me solve this step by step.<think>
以引导模型的推理流程。
步骤3:奖励函数定义(评估模型生成结果)
format_reward_func
用于检查输出是否满足<think>
和<answer>
格式要求。equation_reward_func
用于检查算式的数学正确性、数字是否用尽且仅使用一次,以及是否等于目标值。
奖励值为 1 表示成功,0 表示失败。奖励函数帮助模型学习生成满足要求的高质量答案。
步骤4:GRPO 模型训练
#########################
# 初始化 GRPO trainer
#########################
trainer = GRPOTrainer(
model=model_args.model_name_or_path,
reward_funcs=[format_reward_func, equation_reward_func],
args=training_args,
train_dataset=train_dataset,
eval_dataset=test_dataset,
peft_config=get_peft_config(model_args), # 此实践没有用到 Lora
)
###############
# Training loop
###############
train_result = trainer.train(resume_from_checkpoint=last_checkpoint)
步骤 5:启动训练
本实践采用 DeepSpeed Zero Stage 3 高效分布式训练框 架,使用 Qwen2.5-3B-Instruct 模型作为基础模型。配置信息通过如下命令装载并启动训练。因为采用的是 8 卡 A100 训练模型,利用了前 7 个 GPU 进行训练,最后一个 GPU 给 vLLM 对每个 prompt 生成答案使用,因此 num_processes 设置为 7。配置文件里的 vllm 配置改为最后一个 GPU,即 vllm_device: "cuda:7"
。
accelerate launch --num_processes 7 \
--config_file configs/accelerate_configs/deepspeed_zero3.yaml \
scripts/run_r1_grpo.py \
--config receipes/grpo-qwen-2.5-3b-deepseek-r1-countdown.yaml
训练启动后,观察到每个 step 耗时 3 分到 3 分半钟。同时通过日志(TensorBoard)跟踪:
- 奖励(reward)指标变化,查看是否存在明显跃升。
- 观察生成的
success_completion_samples.txt
样本文件,可直观看出模型生成的算式何时明显改善,以便定位顿悟时刻。
五、结果分析
上图是训练 450 steps 的结果,从训练过程看,模型整体表现良好。我们从训练有效性、奖励函数效果、稳定性分析、生成变化趋势和顿悟时刻探测五个方面进行系统分析。
1. 总体趋势:训练稳定,效果明显
指标 | 表现 | 分析结论 |
---|---|---|
train/reward | 平稳上升至 1.4+ | 模型持续学习,奖励稳定增长 |
equation_reward_func | 稳定在 0.5 左右 | 有约一半样本正确解答 |
format_reward_func | 达到 0.98+ | 几乎所有输出符合格式要求 |
train/loss | 基本收敛,偶有抖动 | 局部不稳定,但整体可控 |
train/kl & train/grad_norm | 出现短暂峰值后恢复 |