论文地址:https://arxiv.org/pdf/2501.12948
第一阶段:不仅是 RL,更是"进化的本能"
通常我们训练 LLM 的范式流程是:Pretrain -> SFT (教会格式/指令) -> RLHF (对齐人类偏好)。
SFT(Supervised Fine-Tuning,监督式微调)
是指在大规模无监督或自监督预训练完成之后,使用人工标注的高质量"输入---输出"对,对模型进行进一步训练,使模型更符合人类期望的行为和输出格式。就是预训练是续写,SFT就是让模型学会基本的对话结构和根据用户不同输入生成不同类型的输出。
RLHF:在 SFT 之后,对"已经会对话的模型"进行偏好层面的精细对齐。
但 DeepSeek-R1-Zero 做了一个极其大胆的假设:如果我不教模型怎么推理(不给 SFT 数据),只给它一道题和一个验证器(对/错),把它扔进 RL 的炼丹炉里,它能自己学会推理吗?
答案是:能。而且它进化出了我们没教过的行为。
1. 算法:GRPO (Group Relative Policy Optimization)
不知道大家还记不记得PPO,不记得可以看下我之前的文章,PPO 需要一个与 Policy Model 同等大小的 Critic Model(Value Function)来评估当前状态的价值。
想象一下,PPO 就像是一个学生(Policy)在考试,旁边必须坐一个私教(Critic)时刻盯着他,告诉他"这步做得好,那步做得差"。这非常贵,因为私教和学生一样耗资源(显存、计算量)。
DeepSeek 用的是 GRPO 。 GRPO :给一个学生10次机会做题,然后告诉他10次里面最好的哪次。
原理: 对于同一个 Prompt ,采样一组输出
。
基线(Baseline): 不再需要 Critic 预测 Value,直接用这组输出的平均奖励作为 Baseline。
优势函数(Advantage):
为什么要这么做?除了省去 Critic 模型的巨大显存开销 ,这种 Group 比较的机制,是不是天然地降低了 Reward Model 的方差?(这一点我们在实现 RL 时非常痛苦,Variance Reduction 是核心)。
2. 奖励机制:返璞归真 (Rule-Based Rewards)
你在做 RLHF 时,最头疼的是什么?肯定是 Reward Hacking(模型钻空子)以及 Reward Model 本身的不准确。
DeepSeek-R1-Zero 居然完全放弃了神经网络 Reward Model 。 他们只用了两类最简单的规则奖励 :
Accuracy Rewards(准确率奖励): 比如数学题,答案在不在框里?LeetCode 通过测试用例没有?(这是一个确定性的信号)。
Format Rewards(格式奖励): 强行要求模型把思维过程写在 <think> 和 </think> 之间 。
这就像教小孩骑自行车。不需要告诉他每块肌肉怎么用力(Neural RM),只需要告诉他:"别摔倒(Accuracy),手扶好把手(Format)"。只要他不摔倒并一直往前骑,他自己会调整肌肉的用力方式。
3. 涌现时刻
这是整篇论文最让我起鸡皮疙瘩的地方。
在没有任何 SFT 数据教模型"如何思考"、没有任何人类告诉它"要反思"的情况下,DeepSeek-R1-Zero 在训练中期突然学会了自言自语式的反思。
请看论文里捕捉到的这个中间版本片段 :
模型在解一个方程突然它停下来了:
"Wait, wait. Wait. That's an aha moment I can flag here. Let's reevaluate this step-by-step..."
它自己意识到前面的路走不通,主动回退,重新规划。
这就是 RL 激励出来的 Chain-of-Thought(CoT)。 并没有人教它 CoT,它是为了获得那个最终的 Reward,被"逼"出来的生存策略。思考时间越长,准确率越高,这是一种自发的进化 。
第一阶段复盘:
冷启动的悖论: 论文提到 R1-Zero 虽然强,但初期很不稳定,且可读性差(中英夹杂、自我重复)。这说明纯 RL 虽然能探索出逻辑,但很难探索出"人类喜欢的表达规范"。
GRPO 的本质: 公式的核心目标函数里包含了 KL 散度项 。
这和你平时做 PPO 是一样的,为了防止模型在探索时偏离 Base Model 太远,导致语言能力崩塌。
Prompt Template 的极简主义: 你看他们的 Template ,极度简单。 User: prompt. Assistant: <think> process </think> <answer> result </answer> 他们特意避免在 Template 里通过 Prompt Engineering 引导模型(比如"请一步步思考"),就是为了验证纯 RL 能走多远 。
这是论文的第一部分,主要讲 R1-Zero(纯 RL 版本)。虽然它验证了原理,但它并不完美(可读性差、不收敛)。 接下来,DeepSeek 引入了 Cold Start(冷启动) 和 Pipeline 训练 打造了完全体的 DeepSeek-R1,这部分更接近工程落地了。
如果 R1-Zero 已经能自我进化出 CoT,为什么 DeepSeek 还要在后续的 R1 中引入 SFT(监督微调)作为冷启动?这是否违背了"纯 RL"的初衷?还是说,SFT 在这里扮演了另一种角色?
第二阶段:DeepSeek-R1 的完全体流水线
这一段非常精彩,它实际上是在回答一个核心问题:在 RL 的强力探索和 SFT 的人类先验之间,如何找到最佳平衡点?
DeepSeek 给出的答案是:"三明治"结构------SFT --> RL --> SFT -->RL。我们一步步拆解。
1. Cold Start(冷启动 SFT):注入先验
在 R1-Zero 中,模型是从零开始瞎猜。在 R1 中,DeepSeek 先收集了数千条高质量的思维链(CoT)数据,对 Base Model 进行微调。
数据来源: 用 少样本提示让模型生成长 CoT,或者人工后处理 R1-Zero 的输出(把乱七八糟的洗干净) 。
目的: 不是为了教模型"怎么解题"(RL 会教这个),而是为了教模型"怎么说话"。
格式规范: 强行定义了输出格式: | special_token | <reasoning_process> | special_token | <summary>
bash
Base Model
↓
Cold Start SFT(注入推理表达先验)
↓
R1(具备"会好好想、会好好说"的初始模型)
↓
大规模 RL(真正学会推理、优化解题策略)
问题背景:R1-Zero 的核心缺陷
R1-Zero 使用纯 RL:
-
会想,但不会说
-
推理轨迹混乱、语言不稳定
-
CoT 长度、结构、风格高度不可控
-
对 RL 来说:credit assignment 难度极高
所以需要一个"语言层面的启动器"。
数据来源:CoT 是怎么来的?
(1)Few-shot prompting 生成长 CoT
-
给基础模型喂少量示例
-
明确告诉它:
-
你要逐步思考
-
用自然语言写清楚中间推理
-
-
生成结构化、较长的 CoT
(2)清洗 / 人工后处理 R1-Zero 输出
-
从 R1-Zero 的 RL 轨迹中:
-
去噪
-
去重复
-
修正语法
-
统一结构
-
-
本质是:把"能用的推理痕迹"转成人类可读文本
SFT 本身:模型学的不是"解题",而是"表达"
| 教什么 | 不教什么 |
|---|---|
| 如何展开推理叙述 | 如何找到最优解 |
| 如何一步步写思考 | 具体数学 / 逻辑技巧 |
| 如何收尾总结 | 答案正确与否 |
bash
| special_token |
<reasoning_process>
| special_token |
<summary>
这是在人为制造一个"推理与结论解耦"的通道。
-
<reasoning_process>:给模型一个"允许啰嗦思考"的空间 -
<summary>:给模型一个"简洁、可监督、可评价"的空间
这是 为强化学习铺路:
-
奖励更稳定
-
reward 主要看
<summary> -
不被中间推理噪声干扰
-
-
推理可以自由探索
-
<reasoning_process>不直接被 reward 卡死 -
减少 reward hacking
-
-
推理轨迹可被解析
-
token 边界清晰
-
方便做 trajectory-level RL
-
2. Reasoning-oriented RL(面向推理的 RL):逻辑强化
这一步和 R1-Zero 的逻辑几乎一样,用 GRPO 刷题(数学、代码)。 但在 Reward 中加了一个小补丁:Language Consistency Reward(语言一致性奖励) 。
-
计算方式: 统计模型生成的思维链(Chain-of-Thought, CoT)中目标语言单词的比例。例如,如果目标语言是英语,则奖励模型在推理过程中使用更多英语词汇。
-
效果: 虽然论文承认加了这个约束会导致性能轻微下降(因为限制了模型的搜索空间),但为了在这个人类的世界里混,可读性必须排在第一位 。
3. Rejection Sampling & General SFT(拒绝采样与通用微调):能力泛化
这是整个 Pipeline 中最像"永动机"的一步。 当第二步的 RL 收敛后,模型已经是个推理大师了。这时候,DeepSeek 用这个模型生成了 60 万条 推理数据 。
拒绝采样(Rejection Sampling): 对于一道题,让模型生成多个答案,只保留正确的那些。如果是开放性问题(比如写代码),就用 DeepSeek-V3(Teacher)去当裁判(Generative Reward Model) 。
bash
输入问题 Q
↓
模型生成 N 个候选答案 {A₁, A₂, ..., Aₙ}
↓
质量筛选(判断正确性/质量)
↓
保留高质量答案 → 加入训练集
丢弃低质量答案
python
# 伪代码示例
def generative_reward_model(question, candidate_answer):
"""
DeepSeek-V3作为裁判评估答案质量
"""
prompt = f"""
问题:{question}
候选答案:{candidate_answer}
请从以下维度评分(1-10分):
1. 正确性
2. 逻辑连贯性
3. 步骤完整性
4. 可读性
总分:
"""
score = teacher_model.generate(prompt)
return score > threshold
混合通用数据: 这里还混入了 20 万条非推理数据(写作、问答、自我认知) 。
为什么? 因为之前的 RL 专注于数理逻辑,把模型的"文科"能力搞退化了。这时候必须把通用能力补回来,否则它就变成了一个只会做题的呆子。
注意到了吗?这一步的 SFT 数据,大部分是模型自己生成并筛选的 。这是一个典型的 Self-Training 循环。模型的"天花板"在这一步被通过大规模的高质量合成数据进一步撑开了。
bash
[初始模型]
│
↓
强化学习(推理专项训练)
│
↓
[成为推理专家]
│
↓
生成推理数据(60万条)
│
↓
拒绝采样筛选
│
↓
混合通用数据(20万条)
│
↓
监督微调(SFT)
│
↓
[更强的通用模型]
│
└─────┐
↓
下一轮迭代
突破"天花板"的原理
传统训练的瓶颈:人类标注数据有限
-
人类专家能标注的问题数量有限
-
标注质量受主观影响
-
难以覆盖所有难度级别
Self-Training的优势:
-
数据规模突破:模型可生成无限数据
-
难度自适应:模型自然生成合适难度的数据
-
多样性保证:不同生成策略产生多样化解法
4. RL for all Scenarios(全场景 RL):最后对齐
最后,再来一轮 RL。但这次不仅是为推理(Math/Code),还加入了对齐人类偏好(Helpfulness/Harmlessness)。
Helpfulness: 只看最后的 Summary 有没有用 。
Harmlessness: 检查整个 CoT 和 Summary 也就是所谓的安全性检查 。
第三阶段:蒸馏(Distillation)------ 颠覆性的发现
这部分在论文的 2.4 节和 4.1 节,非常短。
DeepSeek 尝试了一个实验:
-
方案 A: 把 DeepSeek-R1(大老师)生成的 80w 条数据,直接拿去 SFT 一个小模型(如 Qwen-7B)。
-
方案 B: 不用大老师教,直接拿 Qwen-7B 去跑大规模 RL(就像 R1-Zero 那样),让它自己顿悟。
结果: 方案 A 完胜。 DeepSeek-R1-Distill-Qwen-32B 的表现远超 DeepSeek-R1-Zero-Qwen-32B(纯 RL 训练的 32B 模型)。
这告诉我们一个略显残酷的真理:"顿悟"可能只是大参数模型的特权。 小模型(7B/14B)的容量可能不足以支撑在大规模搜索空间中进行高效的探索(Exploration)。它们很难像 671B 的大模型那样,通过 RL 突然"Aha!"一下找到复杂的逻辑路径。 但是,小模型模仿能力很强。如果大模型把路探好了,把思考过程(CoT)写出来,小模型只要照着背(SFT),也能达到惊人的效果。
这也解释了为什么他们开源了那么多 Distill 的小模型------因为这才是社区(也就是你我这样显卡有限的研究者)最实用的福利。
伪代码详解流程
接下来我用伪代码详细讲解一下全流程,以后我都尽量用伪代码了,因为已经没必要去死磕这种工程代码了,大家理解思路最重要,落地代码任务交给AI:
Part 1: GRPO Trainer
这是 R1 最底层的算法。请注意,这里没有 Value Model (Critic),这是它相比 PPO 最显著的简化
python
class GRPOTrainer:
def __init__(self, policy_model, ref_model, beta=0.04):
self.policy = policy_model # 当前训练的模型 (Actor)
self.ref_model = ref_model # 冻结的参考模型 (用于计算 KL 惩罚)
self.beta = beta # KL 惩罚系数 (对应公式中的 beta)
def compute_loss(self, prompts, generated_outputs, rewards):
"""
GRPO 的核心逻辑:Group Relative Policy Optimization
"""
# 1. 计算 Advantage (优势函数)
# 输入的 rewards 形状是 [Batch_Size, Group_Size]
# 不再通过 Critic 网络预测 Value,而是直接用 Group 内的统计数据
# 公式: A_i = (r_i - mean(R_group)) / std(R_group) [cite: 134]
mean_rewards = rewards.mean(dim=1, keepdim=True)
std_rewards = rewards.std(dim=1, keepdim=True)
advantages = (rewards - mean_rewards) / (std_rewards + 1e-8)
# 2. 计算重要性采样比率 (Importance Sampling Ratio)
# pi_theta(o|q) / pi_theta_old(o|q)
# 注意:在单次迭代中,policy 和 old_policy 开始是相同的
log_probs = self.policy.get_log_probs(prompts, generated_outputs)
old_log_probs = log_probs.detach() # 这里的 old_policy 在当前步是不变的
ratios = torch.exp(log_probs - old_log_probs)
# 3. 计算 KL 散度 (作为正则项)
# D_KL(pi || pi_ref) = pi_ref / pi - log(...) - 1
# DeepSeek 这里用了一个近似公式或者直接计算
ref_log_probs = self.ref_model.get_log_probs(prompts, generated_outputs)
kl_div = torch.exp(ref_log_probs - log_probs) - (ref_log_probs - log_probs) - 1
# 4. 构建 Surrogate Objective (PPO 风格的裁剪)
# Loss = min(ratio * A, clip(ratio, 1-eps, 1+eps) * A) - beta * KL [cite: 130]
surr1 = ratios * advantages
surr2 = torch.clamp(ratios, 1 - 0.2, 1 + 0.2) * advantages
loss = -torch.mean(torch.min(surr1, surr2) - self.beta * kl_div)
return loss
def train_step(self, batch_prompts):
# 1. 采样 (Sampling)
# 对于每个 Prompt,生成 G 个输出 (例如 G=64) [cite: 128]
outputs = self.policy.generate(
batch_prompts,
num_return_sequences=64, # Group Size
do_sample=True
)
# 2. 奖励评估 (Reward Calculation)
# 这里由外部环境给出,不需要梯度
rewards = self.get_rewards(batch_prompts, outputs)
# 3. 优化 (Optimization)
loss = self.compute_loss(batch_prompts, outputs, rewards)
loss.backward()
self.optimizer.step()
Part 2: DeepSeek-R1 Pipeline
有了 GRPO ,下面是怎样把模型从小白训练成大师的四阶段流水线。
Phase 1: DeepSeek-R1-Zero (验证纯 RL 可行性)
这是一个"野蛮生长"的阶段,不涉及 SFT 数据,直接开干。
python
def train_r1_zero(base_model):
"""
对应论文 Section 2.2: DeepSeek-R1-Zero
"""
trainer = GRPOTrainer(policy_model=base_model, ref_model=copy(base_model))
# 这里的 Reward 极其简单,完全基于规则
def rule_based_reward(prompt, output):
r_acc = check_correctness(output) # 答案对不对? (Accuracy Reward) [cite: 145]
r_fmt = check_format(output) # 是否包含 <think> 标签? (Format Reward) [cite: 148]
return r_acc + r_fmt
# 开始 RL 循环
for step in range(MAX_STEPS):
prompts = math_and_code_dataset.sample()
trainer.train_step(prompts, reward_fn=rule_based_reward)
# 现象:如果你盯着 Log 看,你会发现模型在某一刻突然开始自我反思
# 这就是 "Aha Moment"
Phase 2: DeepSeek-R1 (完全体流水线)
这是为了解决 Zero 版本"不说人话"的问题,引入了冷启动和多阶段迭代。
python
def train_deepseek_r1_pipeline(base_model_v3):
"""
对应论文 Section 2.3: DeepSeek-R1
"""
# --- Stage 1: Cold Start (冷启动) ---
# 目的:教会模型可读性和基本格式,减少 RL 初期的震荡
# 数据来源:Few-shot 生成或人工清洗 R1-Zero 的输出
cold_start_data = load_data("thousands_of_long_CoT_examples.json")
actor_model = SFT_Trainer(base_model_v3, cold_start_data).train()
# --- Stage 2: Reasoning-oriented RL (推理强化) ---
# 目的:提升数理逻辑能力
trainer = GRPOTrainer(actor_model)
def reasoning_reward(prompt, output):
# 增加语言一致性奖励,防止中英夹杂
r_lang = calculate_language_consistency(output)
r_acc = check_correctness(output)
return r_acc + r_lang
actor_model = trainer.train(dataset="math_code_logic", reward_fn=reasoning_reward)
# 此时模型已经是个推理高手,但可能是个"偏科生"
# --- Stage 3: Rejection Sampling & SFT (拒绝采样与通用微调) ---
# 目的:利用强模型生成大量数据,扩展能力并修复通用能力
# 3.1 生成推理数据 (Self-Evolution)
synthetic_data = []
for prompt in large_scale_prompts:
outputs = actor_model.generate(prompt, n=N)
# 只保留答案正确 且 格式清晰(无可读性问题) 的输出
correct_outputs = [o for o in outputs if is_correct(o) and is_readable(o)]
synthetic_data.extend(correct_outputs)
# 3.2 混合通用数据 (General Data)
# 加入写作、问答、自我认知数据,防止只会做题
general_data = load_data("general_capability_dataset.json")
combined_data = synthetic_data + general_data # 总量约 800k [cite: 282]
# 3.3 重新 SFT
# 注意:这里是拿最初的 Base Model 重新微调,继承 V3 的通用能力 + R1 的推理数据
finetuned_model = SFT_Trainer(base_model_v3, combined_data).train()
'''为什么? 因为base_model_v3本身已经具备强大的通用能力基础。在这个"全能底座"上,
注入高质量的推理数据和通用数据,可以让模型同时继承V3的通用性和R1的推理专长,
避免从"偏科模型"开始修正的困难。
这好比用一块质地优良的原料(V3)按照新配方(混合数据)重新塑造,
而不是去改造一个已经定型、但形状古怪的陶器(阶段2模型)。'''
# --- Stage 4: RL for all Scenarios (全场景 RL) ---
# 目的:对齐人类价值观 (Helpfulness, Harmlessness)
final_trainer = GRPOTrainer(finetuned_model)
def aligned_reward(prompt, output):
if is_reasoning_task(prompt):
return rule_based_reward(output) # 数理题看对错
else:
# 通用任务使用 Reward Model 评估人类偏好
# Helpfulness: 重点看 Summary
# Harmlessness: 检查全过程
return preference_reward_model(output)
deepseek_r1 = final_trainer.train(dataset="all_scenarios", reward_fn=aligned_reward)
return deepseek_r1
Part 3: 蒸馏 (Distillation) ------ 给小模型传功
这一步展示了如何把 R1 的能力转移给 Qwen-7B 这种小模型。
python
def distill_to_small_model(teacher_model_r1, student_model_7b):
"""
对应论文 Section 2.4: Distillation
"""
# 1. 老师生成数据
# 利用 DeepSeek-R1 生成 800k 条高质量 CoT 数据
distillation_data = generate_with_teacher(teacher_model_r1, corpus_800k)
# 2. 学生进行 SFT (Supervised Fine-Tuning)
# 直接监督微调,甚至不需要 RL
distilled_model = SFT_Trainer(student_model_7b, distillation_data).train()
# 结论:这样得到的 7B 模型,性能吊打直接用 RL 训练的 7B 模型
return distilled_model
到现在,我们精读完了核心逻辑。
-
R1-Zero 证明了: LLM 的推理能力可以通过纯 RL 激励涌现,不再强依赖人类标注的 CoT。
-
R1 证明了: 加上少量冷启动和多阶段 SFT/RL,可以把这种野蛮的推理能力驯化成强大且通用的助手。
-
蒸馏证明了: 大模型的思考过程是最高级别的知识,可以直接"传功"给小模型。