单卡复现DeepSeek R1 Zero技术全解析:性价比与性能的完美融合方案
核心内容:
1. 单卡环境下复现DeepSeek R1 Zero的可行性深度剖析
2. Unsloth+LoRA技术详解:如何优化性能并降低资源消耗
3. 环境搭建与分步复现指南:轻松上手实践操作
此前有读者向我们反馈:团队复现的R1 Zero效果确实出色,但算力门槛太高,至少需要3张A800显卡,有没有更经济、更便捷的学习复现途径?答案是肯定的。今天为大家介绍一种创新方法,让你仅用单卡就能复现DeepSeek R1 Zero,甚至只需一张GeForce RTX 4090显卡即可轻松实现!
为何单卡就能实现复现?
你可能会疑惑:“原本需要3张A800,现在单卡就能搞定,背后的黑科技是什么?”答案在于引入了Unsloth与LoRA技术。Unsloth的核心优势体现在:
- 强化学习算法优化:集成了多种强化学习(RL)算法,并通过底层代码优化(如优化计算图、减少冗余操作),显著提升大模型在推理和微调阶段的性能表现。
- 最新量化技术:大幅降低显存占用,使得原本需要多卡运行的大模型也能在单卡上流畅运行。
- 完整的LoRA与QLoRA微调支持:即便显存有限,也能通过少量资源成功复现R1 Zero。
这提供了一种成本更低、实现更简单的方案。据Unsloth官方博客介绍,仅需7GB的显存,即可训练Qwen2.5-1.5B模型。
Unsloth GitHub仓库:https://github.com/unslothai/unsloth
环境搭建
安装Unsloth
环境搭建部分在之前的公众号文章中已有详细说明,这里只需在原有基础上补充安装Unsloth及指定版本的trl库即可。
DeepSeek R1 Zero中文复现教程正式发布!
补充说明:在之前公众号发布的多卡训练代码中,错误地引入了“思考长度奖励函数”,且未在代码中使用flash-attn。Unlock-DeepSeek团队已修复该问题,请使用仓库中的最新代码,同时我们更新了一版训练示意图。
本文仅展示与前文有差异的代码部分,同时提供完整的训练代码,请于文末获取。
注意:为兼容Unsloth,需要安装特定版本的trl。具体命令如下:
# 安装 unsloth 和 vllm
pip install unsloth vllm
# 安装指定版本的 trl(兼容 unsloth)
pip install trl==0.15.0
参考来源:https://docs.unsloth.ai/get-started/unsloth-notebooks
配置文件修改
绝大部分配置与之前的Datawhale-R1.yaml文件保持一致。为支持单卡复现R1 Zero,进行了以下调整:
- LoRA参数设置:启用LoRA微调,将LoRA秩数(lora_r)调整为64(常用可选值有8、16、32、64、128等),并设置lora_alpha为32。
- 限制回答长度:将max_completion_length设置为1024,以控制输出长度。
- 优化器调整:优化器设置为adamw_8bit,以加速训练过程。
注意:为节省显存,此处max_completion_length设为1024,但这可能影响模型性能。若资源充足,可设置更高值(如4096、8196),以获得更佳效果,但也会增加资源消耗。若显存不足,可适当降低vllm_gpu_memory_utilization。此外,如果有更多资源,建议将优化器optim调整为adamw_torch,这有助于更好地复现模型效果。
# LoRA 参数调整
lora_r: 64 # LoRA 秩数,选择任意大于0的数字!建议使用8, 16, 32, 64, 128
lora_alpha: 32 # LoRA alpha 值
# 训练参数
learning_rate: 1.0e-5 # 学习率,调整为1e-5
# GRPO 算法参数
beta: 0.001 # KL 惩罚因子
optim: adamw_8bit # 使用8bit优化器以加速训练
max_prompt_length: 256 # 输入 prompt 的最大长度
max_completion_length: 1024 # 输出回答长度,包含推理思维链
num_generations: 4
use_vllm: true # 启用 vLLM 加速推理
vllm_gpu_memory_utilization: 0.4 # vLLM 的 GPU 内存利用率(内存紧张时可适当降低)
LoRA微调参考:https://zhuanlan.zhihu.com/p/663557294
启动训练
启动训练的代码十分简洁,由于仅需单卡,无需配置复杂的Accelerate库,直接运行以下命令即可。
python train_Datawhale-R1_unsloth.py --config Datawhale-R1_unsloth.yaml
训练代码优化解读
基于Unsloth框架,对原始代码进行了简化和优化。核心思路主要有两点:
打补丁提升训练速度
在执行强化学习训练的代码之前,添加了两行代码,利用PatchFastRL函数对某些RL算法(如GRPO)进行“打补丁”。该操作实际上在底层优化了计算图、减少了冗余计算,从而加速训练过程。
from unsloth import FastLanguageModel, PatchFastRL
PatchFastRL("GRPO", FastLanguageModel) # 对 GRPO 算法打补丁
GRPO 训练函数的改进
此外,还改进了grpo_function函数,在其中进行了优化,具体体现在代码的第14~34行。主要加入了以下两个方式:
- 模型加载:通过FastLanguageModel.from_pretrained方法加载预训练模型,并启用vLLM快速推理,同时支持4位加载(或LoRA 16位)。
- PEFT微调:利用get_peft_model方法对模型应用LoRA微调,指定了目标模块、LoRA参数以及梯度检查点,确保在有限显存条件下仍能有效训练。
# 定义 GRPO 训练函数
def grpo_function(
model_args: ModelConfig,
dataset_args: DatasetArguments,
training_args: GRPOConfig,
callbacks: List,
):
# 记录模型参数
logger.info(f"Model parameters {model_args}")
# 记录训练/评估参数
logger.info(f"Training/evaluation parameters {training_args}")
# 从预训练模型加载模型和分词器
model, tokenizer = FastLanguageModel.from_pretrained(
model_name=model_args.model_name_or_path, # 模型名称或路径
fast_inference=True, # 启用 vLLM 快速推理
load_in_4bit=True, # 是否以4位加载模型,False表示使用LoRA 16位
max_lora_rank=model_args.lora_r, # 设置LoRA的最大秩
max_seq_length=training_args.max_completion_length, # 设置最大序列长度
gpu_memory_utilization=training_args.vllm_gpu_memory_utilization, # GPU内存利用率,若内存不足可减少
attn_implementation=model_args.attn_implementation, # 设置注意力实现方式 flash attention
)
# PEFT 模型
model = FastLanguageModel.get_peft_model(
model,
r = model_args.lora_r,
target_modules = [
"q_proj", "k_proj", "v_proj", "o_proj", # 如果OOM内存不足,可以移除QKVO
"gate_proj", "up_proj", "down_proj",
],
lora_alpha = model_args.lora_alpha, # 设置LoRA的alpha值
use_gradient_checkpointing = "unsloth", # 启用 unsloth 的梯度检查
random_state = training_args.seed, # 设置随机种子
)
若遇到显存不足(Out of Memory)问题,可移除target_modules中的"q_proj", "k_proj", "v_proj", "o_proj"。
参考来源:https://unsloth.ai/blog/r1-reasoning
模型量化参考:LLM量化综合指南(8bits/4bits)https://zhuanlan.zhihu.com/p/671007819
训练结果与一些思考
以下是训练结果的部分截图,大致与Tiny Zero和Mini R1的复现结果类似,这里不再做详细分析。
接下来分享一些学习R1 Zero过程中的思考(非严谨学术研究,个人观点,仅供参考)。
Aha moment 是 RL 训练的结果吗?
在开始研究之前,对Aha moment(顿悟时刻)这个概念充满好奇,仿佛这是DeepSeek经过RL训练后突然获得的超能力。但深入学习oat的文章后,发现Aha moment并非凭空出现,它可能在base模型和SFT阶段就已经埋下了种子。RL训练所做的事情,更像是一个“放大器”——通过设计的奖励机制,最大化了模型产生顿悟时刻的概率。换句话说,RL训练将模型原本浅层的自我反思能力,转化为更有深度和效果的思考过程。
参考OAT文章:There May Not be Aha Moment in R1-Zero-like Training — A Pilot Study:https://oatllm.notion.site/oat-zero
思考长度越长越有效吗?
在社区中有一种普遍看法:RL训练让模型的输出变得更长,从而提升效果。这个观点确实有一定道理,因为RL强化了模型的思考过程,生成更多的token是自然的结果。然而,问题是:更长的思考真的意味着更好的结果吗?
在复现Tiny Zero的过程中,观察到一个有趣的现象:token数量呈现先降后升的趋势。这个现象可以这样解释:最初,由于存在格式奖励(format reward),模型必须保证格式正确,然而长度过长的输出较难学习到答案的格式,并且会包含很多对解决任务无用的token,因此token数量自然会先下降——模型先学习简单的格式,保留有利于正确计算的token,再去学习复杂的计算,先简后繁;随着训练的进行,模型开始进行更多的尝试和反思以得出正确答案,输出长度逐渐增加并趋于稳定。这一观察也印证了OAT的结论:输出长度与自我反思的质量并不一定存在线性关联。
S1 文章的一些结论和思考
最近也关注了李飞飞团队的S1文章,详细分析了其方法与R1 Zero的不同之处。总的来说,S1通过少量高质量数据(约1k + SFT + 设计Prompt)进行训练,而R1 Zero则是通过基础训练(Base)加RL强化训练完成的。在S1中,他们采用了budget forcing方法,在测试时强制设定最大和最小的思考token数量。具体而言:
- 通过添加"end-of-thinking token分隔符"和"Final Answer"来控制思考上限;
- 通过禁止生成分隔符并添加"wait"提示词来控制思考下限。
实验结果表明,适度增加思考token数量确实能够提升模型在AIME24基准测试上的表现。然而,他们也发现,过度抑制思考结束反而会导致模型陷入无效循环。这个发现非常符合直觉:就像人类的思考一样,简单问题(比如数一个单词中的字母数量)并不需要过度思考,而真正需要延长思考时间的,往往是那些较为复杂的问题。
s1参考阅读:16张H100训26分钟,超越o1-preview!李飞飞等用1K样本,揭秘测试时Scaling
总结与展望
再次感谢Unsloth的优化以及社区小伙伴的努力,这不仅使得大模型的训练和推理更加高效,还大幅降低了显存消耗,使得即便是仅有一块显卡,也能轻松完成R1 Zero的复现。这也提供了一个更经济、更简便的复现方案,为低资源环境下的大模型应用开辟了新的可能。
