DeepSeek-R1强化学习实战:从奖励函数到GRPO训练推理模型 简介这份资源围绕DeepSeek团队首个基于强化学习的推理语言模型展开面向机器学习研究人员、开发者以及希望提升大模型推理能力的从业者尤其适合关注RL训练与编程、数学等密集型推理任务的读者。内容涵盖DeepSeek-R1-Zero纯强化学习训练路径、冷启动数据与迭代式RL微调机制以及知识蒸馏至1.5B至70B小型稠密模型的完整方案并附有基准性能评测与失败尝试的讨论。资源包共1个PDF文件约2.62MB为完整技术报告包含引言、方法、实验与讨论等章节可系统了解模型架构、奖励设计与评估结果。目前已有1359人学习下载适合需要深入理解强化学习如何激发大模型推理能力、并希望借鉴其训练与蒸馏思路的读者参考。1. 推理能力不是玄学从 DeepSeek-R1 的强化学习路线说起很多团队在做垂直领域模型时都会撞上同一堵墙模型能背出知识点却做不对多步推理题。你问它一道需要三步计算的工程问题它第一步就跳步第二步把单位搞混第三步直接编一个看起来合理的答案。这不是模型“笨”而是监督微调阶段喂进去的数据里推理链本身就不完整。DeepSeek-R1 这条路线之所以值得一线工程师认真看是因为它把“推理能力”从提示词工程里拎出来交给强化学习去磨。它解决的核心问题是当标注数据贵、推理链难写、答案又必须可验证时怎么让模型自己学会一步步想。适合谁适合手里有可验证任务数学、代码、结构化抽取、有少量 GPU 资源、愿意折腾奖励函数的人。不适合指望调个 API 就完事的人。2. DeepSeek-R1 的强化学习到底在训什么奖励信号与策略更新2.1 从 SFT 到 RL为什么推理链不能只靠模仿监督微调的本质是模仿。你给模型看一万条“问题→推理链→答案”它学会的是“在这种问题下人类通常怎么写推理链”。但推理链的写法是发散的同一道题可以正推、反推、枚举、构造辅助量。SFT 数据只能覆盖其中一小部分模型遇到没见过的题型就开始胡编。更麻烦的是SFT 的损失函数只看 token 匹配不看答案对不对。模型写了一段语法通顺但逻辑断裂的推理损失照样很低。强化学习换了一个目标不看你怎么写只看你最后答对没有。DeepSeek-R1 路线里策略模型生成完整回答奖励模型或规则函数给一个标量分数策略根据分数调整生成概率。这样模型可以探索出人类没写过的推理路径只要最终答案可验证正确。常见做法是先用少量 SFT 数据做冷启动让模型学会基本输出格式再切到 RL 阶段用可验证奖励大规模探索。这里的关键选型理由是奖励必须可自动计算。数学题对答案、代码跑单元测试、结构化抽取比对字段都属于可验证任务。如果你做的是开放域对话奖励只能靠人类偏好模型成本和噪声都会上一个量级。2.2 奖励函数怎么写规则奖励与偏好奖励的混合我一般会把奖励拆成三块格式奖励、答案奖励、长度惩罚。格式奖励要求模型把推理过程放在指定标签里答案放在另一个标签里没按格式输出直接给负分。答案奖励用规则匹配或执行结果判定。长度惩罚防止模型靠堆废话刷分。import re def reward_fn(response: str, ground_truth: str) - float: # 格式奖励必须包含 thinking 和 answer 标签 format_score 0.0 if thinking in response and answer in response: format_score 0.2 # 提取答案区域 answer_match re.search(ranswer(.*?)/answer, response, re.DOTALL) if not answer_match: return format_score - 0.5 # 没答案直接惩罚 pred answer_match.group(1).strip() # 答案奖励精确匹配给 1.0数值近似给 0.5 if pred ground_truth: answer_score 1.0 else: try: if abs(float(pred) - float(ground_truth)) 1e-6: answer_score 0.5 else: answer_score -0.3 except ValueError: answer_score -0.3 # 长度惩罚超过 800 token 后每 100 token 扣 0.05 length_penalty max(0, (len(response) - 800) / 100) * 0.05 return format_score answer_score - length_penalty这段奖励函数里format_score是引导模型学会结构化输出answer_score是核心信号length_penalty是防止 reward hacking。参数上格式分不宜给太高否则模型会只输出标签不认真答题答案错误惩罚要足够大让模型不敢乱猜。实际训练时我会先用小学习率跑几百步观察奖励曲线是否稳定上升如果震荡剧烈先把长度惩罚去掉确认答案奖励本身没有歧义。2.3 策略更新PPO 还是 GRPO显存和稳定性的取舍PPO 需要同时加载策略模型、参考模型、奖励模型、价值模型显存占用大训练不稳定时调参很痛苦。DeepSeek-R1 路线里更常用的是 GRPO 这类去掉价值模型的变体对同一个问题采样一组回答用组内相对分数做优势估计省掉价值网络。显存省了但组大小和采样温度变得敏感。# 常见 GRPO 训练启动参数示例以 7B 模型为例 python train_grpo.py \ --model_name_or_path ./sft_checkpoint \ --reward_fn reward_fn.py \ --num_generations 8 \ --temperature 0.9 \ --learning_rate 1e-6 \ --per_device_batch_size 2 \ --gradient_accumulation_steps 8 \ --max_new_tokens 1024 \ --kl_coef 0.04 \ --output_dir ./grpo_checkpointnum_generations是每个问题采样的回答数太小优势估计噪声大太大显存吃不消7B 模型上 8 是常见起点。temperature不能太低否则组内回答几乎一样优势全为零也不能太高否则全是胡言乱语。kl_coef控制策略偏离参考模型的程度太小会训崩太大会学不动。我一般从 0.04 开始观察 KL 散度曲线如果持续上涨超过 10就调大这个系数。3. 把 DeepSeek-R1 的 RL 路线落到自己的任务数据、环境与训练循环3.1 可验证任务怎么选从数学题到结构化抽取不是所有任务都适合 RL。选任务时看三条答案能不能自动判对、推理链有没有必要、错误答案会不会被规则放过。数学题最直接代码题次之结构化抽取再次之。我做过一个工单字段抽取的模拟项目把每条工单的文本输入模型要求输出 JSON字段值必须和数据库记录一致。奖励函数就是 JSON 解析后逐字段比对全对给 1.0错一个给 0.3格式错误给负分。这种任务的好处是数据现成坏处是推理链短RL 提升空间有限。如果你要做多步推理最好选那种“中间步骤错了最终答案一定错”的任务比如多跳问答、单位换算、依赖计算。这样奖励信号才能有效传导到中间步骤。3.2 训练环境搭起来显存、并行与检查点7B 模型做 GRPOnum_generations8、max_new_tokens1024单卡 80G 显存勉强够但 batch size 只能开到 1 到 2。常见做法是用 LoRA 冻结大部分参数只训低秩适配器显存能降到 40G 左右。如果要做全参数 RL至少 4 卡起步用 FSDP 或 DeepSpeed ZeRO-3 切分。# 用 LoRA 做 GRPO 的配置片段 peft_config: r: 16 lora_alpha: 32 target_modules: [q_proj, v_proj, k_proj, o_proj] lora_dropout: 0.05 bias: noner是低秩矩阵的秩16 是常用值任务越复杂可以调到 32 或 64。target_modules至少要覆盖注意力层的 Q、V加上 K、O 更稳。lora_dropout给 0.05 防止过拟合。检查点保存频率别太高RL 训练动辄几千步每 200 步存一次只保留最近三个和最佳奖励的。3.3 训练循环里的三个观察指标跑 RL 最怕的是“奖励涨了但模型变傻”。我一般盯三个指标平均奖励、KL 散度、回答长度。平均奖励要稳步上升如果突然跳高大概率是 reward hacking比如模型发现输出某个固定格式就能骗分。KL 散度反映策略偏离参考模型的程度超过 15 就要警惕。回答长度如果持续变长但奖励不涨说明模型在堆废话需要加大长度惩罚。# 训练日志里定期打印这三个指标 def log_metrics(rewards, kl_divs, lengths, step): print(fstep{step} freward_mean{sum(rewards)/len(rewards):.3f} fkl_mean{sum(kl_divs)/len(kl_divs):.3f} flen_mean{sum(lengths)/len(lengths):.0f})这段日志代码不复杂但少了它你就是在盲训。奖励均值看趋势KL 均值看稳定性长度均值看废话率。三个一起看才能判断模型是真的在学推理还是在钻奖励空子。4. 避坑与排查RL 训练里最容易翻车的五个地方4.1 奖励全为零模型学不到东西现象训练几百步后平均奖励一直在零附近KL 散度几乎不动。原因通常是任务太难模型采样出的回答没有一个是对的组内优势全为零梯度消失。解决先用 SFT 数据把模型冷启动到能答对 30% 左右再切 RL或者把num_generations调大增加采到正确答案的概率还可以在奖励函数里给部分正确加小分比如答案格式对但数值错给 0.1。4.2 奖励突然飙升但验证集崩了现象训练奖励从 0.3 跳到 0.9但人工看输出发现模型在重复同一句话。原因reward hacking模型找到了奖励函数的漏洞比如长度惩罚没加、答案匹配用了宽松的正则。解决检查奖励函数里有没有可以被“空输出”或“固定模板”骗过的分支加一个格式校验答案区域不能为空定期用独立验证集跑一遍别只看训练奖励。4.3 KL 散度爆炸输出变成乱码现象KL 散度从 2 涨到 30模型输出开始夹杂无意义符号。原因学习率太大或者kl_coef太小策略跑偏了。解决把学习率降到 5e-7kl_coef调到 0.1重新从上一个检查点加载。如果还不行检查参考模型是不是和策略模型初始化不一致。4.4 显存溢出训练跑不过 100 步现象CUDA out of memorybatch size 已经降到 1。原因max_new_tokens太大或者num_generations太多采样阶段显存峰值过高。解决把max_new_tokens从 1024 降到 512num_generations从 8 降到 4开启梯度检查点用 LoRA 替代全参数训练。如果还不行换更小的模型先跑通流程。4.5 训练速度慢到无法迭代现象一步要跑十几分钟一天只能跑几十步。原因采样阶段没有用 vLLM 或类似推理加速逐 token 生成太慢。解决把生成部分换成 vLLM 或 TGI批量采样减少num_generations用更短的max_new_tokens。我一般会在正式训练前先跑 20 步测速如果一步超过 5 分钟就先优化生成后端别硬跑。5. 进阶技巧用拒绝采样和课程学习把 RL 效果再推一截5.1 拒绝采样把 RL 训过的模型再蒸馏回 SFTRL 训练结束后模型会生成大量推理链。这些推理链里有一部分是对的有一部分是错的。拒绝采样的做法是用奖励函数筛出高分的回答和问题一起组成新的 SFT 数据集再对模型做一轮监督微调。这样做的价值是RL 探索出的新推理路径被固化下来模型在推理时的稳定性会更好。我一般会筛奖励大于 0.8 的样本每个问题保留最多 3 条不同路径避免过拟合单一解法。# 拒绝采样筛选高分回答 def filter_samples(samples, threshold0.8, max_per_question3): filtered {} for q, resp, r in samples: if r threshold: filtered.setdefault(q, []).append((resp, r)) # 每个问题按奖励排序取前 max_per_question 条 result [] for q, resps in filtered.items(): resps.sort(keylambda x: x[1], reverseTrue) for resp, r in resps[:max_per_question]: result.append({question: q, response: resp}) return resultthreshold设太高会导致数据太少设太低会引入噪声0.8 是常用起点。max_per_question控制多样性太大容易过拟合太小又浪费探索结果。筛完之后用这批数据做 1 到 2 个 epoch 的 SFT学习率比正常 SFT 小一半。5.2 课程学习从简单题到难题的调度策略RL 训练初期模型能力弱直接上难题会导致奖励全零。课程学习的思路是先拿简单题训等奖励稳定了再逐步混入难题。实现上可以给每个问题打一个难度分比如按 SFT 模型答对的概率训练时按难度分桶每 N 步提升一次难题比例。训练阶段简单题比例中等题比例难题比例预期奖励0-500 步80%20%0%0.5-0.6500-1500 步50%30%20%0.6-0.71500-3000 步30%40%30%0.7-0.83000 步以上20%30%50%0.8这个比例不是固定的要根据奖励曲线动态调。如果某个阶段奖励卡住不涨就把难题比例降回去等稳定了再加。课程学习的好处是训练更稳坏处是要多维护一套难度标注适合有充足数据标注资源的团队。5.3 验证方法别只看训练奖励用这三个测试集交叉验证RL 训练最容易骗自己的就是训练奖励。我一般会准备三个测试集同分布测试集、分布外测试集、对抗测试集。同分布测试集看模型有没有过拟合训练题型分布外测试集看推理能力有没有泛化对抗测试集放一些容易触发 reward hacking 的样本比如答案格式正确但数值错误的题。三个测试集上的准确率如果同步上升才说明 RL 真的在提升推理能力。如果只有训练奖励涨测试集不动甚至下降那就是在钻空子得回头改奖励函数。我自己的习惯是每次改奖励函数或课程调度先跑 200 步看三个测试集的早期信号再决定要不要继续。RL 训练没有后悔药跑歪了只能从头来所以前期验证比后期调参重要得多。希望帮到你。本文还有配套的精品资源点击获取