reasoning-from-scratch 进阶 GRPO 训练脚本全解析:从指标追踪到 DAPO / DeepSeek-V3.2 / GDPO 改进

发布时间:2026/10/13 2:41:26
reasoning-from-scratch 进阶 GRPO 训练脚本全解析:从指标追踪到 DAPO / DeepSeek-V3.2 / GDPO 改进 示例工程【免费下载链接】reasoning-from-scratchImplement a reasoning LLM in PyTorch from scratch, step by step项目地址https://gitcode.com/gh_mirrors/re/reasoning-from-scratch点击查看免费下载本篇技术指南以 ch07/03_rlvr_grpo_scripts_advanced 目录为核心系统讲解 reason-from-scratch 项目中用于改进第 6 章基础 GRPO 算法的一整套进阶脚本从优势统计与熵的指标追踪、裁剪策略比率、KL 正则项、显式格式奖励到汇聚 DAPO、Dr. GRPO、DeepSeek-V3.2、GDPO 等文献思想的 7 个可运行脚本。读完本文你将理解每个脚本在 7_5_plus_kl.py 等实现中的具体代码逻辑、命令行参数含义并能在自己的机器上复现这些训练实验。脚本总览一条逐步加固 GRPO 的演进路径该目录下的脚本是一组层叠式改进后一个脚本通常在前一个脚本的基础上叠加一个新的稳定化机制全部以第 6 章rlvr_grpo_original_no_kl.py的 RLVR可验证奖励强化学习GRPO 训练框架为起点。主脚本一览脚本对应章节核心改进7_3_plus_tracking.py7.3额外追踪优势统计量与序列熵7_4_plus_clip_ratio.py7.4用裁剪策略比率clipped policy ratios稳定序列级 GRPO7_5_plus_kl.py7.5叠加 KL 损失项控制模型偏离程度7_6_plus_format_reward.py7.6为thinktoken 增加显式格式奖励进阶改进脚本7_7_improvements子目录则在7_5/7_6的基础上批量落地文献中的改进建议脚本实现的改进olmo3_style.py改进 1–7零梯度过滤、主动采样、token 级损失、无 KL、高位裁剪、截断重要性采样、无标准差归一化deepseek_v32_style.py改进 8–12领域化 KL、重加权 KL、off-policy 序列掩码、保留采样掩码、保留原始优势归一化gdpo.pyGDPO聚合前先对每个奖励分量做组内归一化所有脚本均从reasoning_from_scratch包复用核心函数如render_prompt、extract_final_candidate、grade_answer、evaluate_math500_stream、top_p_filter等避免重复代码同时又把compute_grpo_loss等关键函数在本文件内重新实现便于读者直接查看和修改。脚本都通过 tests/test_ch07_scripts.py 的--help冒烟测试验证可正常导入运行。运行方式与通用参数README 特别提示如果你不是uv用户把示例中的uv run ...py替换为python ...py即可。所有脚本共用一套命令行参数默认值见下表与第 6 章脚本保持一致参数类型默认值说明--stepsintNone训练集大小训练步数--num_rolloutsint8每步采样次数rollout 数--max_new_tokensint512每次 rollout 最多生成 token 数--temperaturefloat0.8采样温度--top_pfloat0.9top-p 采样截断--seedstr42随机种子None 可禁用--checkpoint_pathstrNone恢复训练的 .pth 检查点路径--eval_on_checkpointint0检查点时评估的 MATH-500 样本数0 禁用--skip-zero-advantage-updatesflag—当 rollout 优势全为零时跳过反向传播与优化器更新--show_etaflag—在步进日志中追加 ETA7_4及以后脚本额外增加--clip_eps默认 10.0注释明确指出 DeepSeek 使用 10、--inner_epochs默认 27_6中默认 17_5增加--kl_coeff默认 0.0017_6增加--format_reward_weight默认 1.0与--conditional_reward开关olmo3_style增加--clip_eps_low0.2与--clip_eps_high10.0deepseek_v32_style增加--top_k0与--off_policy_delta0.1gdpo增加--format_coeff0.1。一个典型的 100 步训练命令uv run ch07/03_rlvr_grpo_scripts_advanced/7_5_plus_kl.py \ --num_rollouts 8 \ --steps 100 \ --max_new_tokens 512 \ --kl_coeff 0.001训练产物统一输出到脚本同级的logs/*_outputs.txt、*_metrics.txt、*_metrics.csv与checkpoints/SCRIPT_NAME/目录。参考运行日志见 ch07/02_logs。7.3 进阶指标追踪优势统计量与熵7_3_plus_tracking.py 把原先只有 loss / reward / tokens-per-sec 的训练循环升级为完整的学习信号监控器。核心新增是sequence_logprob_and_entropy函数7_3_plus_tracking.py序列 log 概率对生成 token 的 log-softmax 概率做gather取出实际 token 的 logp再从prompt_len - 1位置开始求和得到整个答案序列的 log 概率熵对每个答案步的完整词表分布计算-sum(p * log p)再对所有答案步取平均作为模型不确定性的度量。若模型立刻输出 EOS 导致答案段为空则安全地返回 0。在训练循环中7_3_plus_tracking.py每步还会计算adv_avg/adv_std优势均值与标准差并连同entropy_avg、avg_response_len、tokens_per_sec一起写入三份日志*_outputs.txt每 10 步记录至多 3 条采样文本换行转义为\n*_metrics.txt人类可读的逐步指标*_metrics.csv机器可读的 CSV首行含表头step,total_steps,loss,reward_avg,tokens_per_sec,avg_response_len,adv_avg,adv_std,entropy_avg,eval_acc。主章节ch07_main.ipynb对这些指标的解读要点是优势均值在 GRPO 归一化下恒为 0这是代码正确性的 sanity check优势标准差才是更有信息量的信号——若它保持非零且稳定说明 rollout 之间仍有质量差异、学习信号没有消失熵过低接近 0说明某个 token 支配分布、模型近乎确定性输出可能是坍缩信号训练后期熵明显上升表示 next-token 分布变宽、探索更充分而高熵 非零优势标准差 合理奖励均值组合通常意味着健康的探索而非坍缩。7.4 用裁剪策略比率稳定序列级 GRPO原始 GRPO 的 loss 是-(advantages.detach() * logps).mean()即直接用当前策略的序列 log 概率乘优势。当策略更新过快时该目标会剧烈波动。7.4 引入 PPO 风格的策略比率裁剪先把当前策略new_logps与上一步策略old_logps的比值取对数差再指数化得到ratio然后 clamp 到[1 - clip_eps, 1 clip_eps]最后取min(ratio * adv, clipped_ratio * adv)的负均值作为 loss7_4_plus_clip_ratio.py。实现要点old_model copy.deepcopy(model)在每步开始时冻结一份上一步策略requires_grad False用于 rollout 采样与旧 logp 计算inner_epochs2表示在同一份 rollout 数据上做多次内部更新配合裁剪限制单次更新幅度clip_eps10.0是 DeepSeek-R1 训练中的取值——这是一个非常宽的裁剪区间近乎弱裁剪其他 RL 管线常见取0.1量级。脚本默认沿用 DeepSeek 的 10.0若想收紧策略更新可自行调低policy_ratio均值被额外记录进日志文本与 CSV用于观察新旧策略的平均偏离程度。主章节 7.4 的原理说明ch07_main.ipynb强调裁剪比率度量当前策略相对旧策略的变化量通过强制限制每个 rollout 对更新的影响力来提升训练稳定性clip_eps越小约束越强。7.5 用 KL 项控制模型改变程度7_5_plus_kl.py 在裁剪目标之上叠加 KL 惩罚。其核心思想是保留一份参考模型ref_model训练开始时对模型深拷贝并冻结计算当前策略与参考策略之间的 KL 散度防止策略偏离初始模型过远、丢失原有能力。关键代码路径7_5_plus_kl.pyif kl_coeff and ref_model is None: raise ValueError(ref_model must be provided when kl_coeff is non-zero.) ... if kl_coeff: ref_logp sequence_logprob_and_entropy(ref_model, token_ids, prompt_len) ... pg_loss -obj.mean() if kl_coeff: ref_logps torch.stack(roll_ref_logps).detach() kl_loss kl_coeff * torch.mean(new_logps - ref_logps) else: kl_loss torch.tensor(0.0, devicenew_logps.device) loss pg_loss kl_loss要点解读kl_loss kl_coeff * mean(new_logps - ref_logps)即序列级 KL 散度的蒙特卡洛近似log 概率之差的和再取平均kl_coeff越大偏离惩罚越强脚本默认0.001主章节实验中也尝试过0.02当kl_coeff0.0时ref_model保持NoneKL 项为零张量脚本退化为 7.4 行为同时日志中的kl列始终为 0训练主循环中ref_model只在脚本启动时创建一次并全程冻结7_5_plus_kl.py因此不会随训练更新。值得注意的权衡README 与主章节均强调KL 项能防止模型漂移但对数学任务可能反而损害性能——这正是第 6 章no_kl版本及 DAPO / Dr. GRPO / Olmo 3 建议数学场景不设 KL 的原因主章节 7.5 也记载了加大 KL 系数反而导致训练不稳定、reward 下滑的实验观察。7.6 显式格式奖励引导think标签7_6_plus_format_reward.py 引入第二个奖励信号——格式奖励用以激励模型按...think.../think...\boxed{ANSWER}的格式输出类似 DeepSeek-R1 的做法。这是四个主脚本中唯一一个基于 reasoning 模型which_modelreasoning而非 base 模型训练的脚本README 明确指出由于 reasoning 模型已熟悉thinktoken格式奖励作用于 reasoning 模型而非 base 模型。核心实现7_6_plus_format_reward.pyTHINK_TOKEN_ID 151667 END_THINK_TOKEN_ID 151668 def reward_format(token_ids, prompt_len): try: gen token_ids[prompt_len:].tolist() return float(gen.index(THINK_TOKEN_ID) gen.index(END_THINK_TOKEN_ID)) except ValueError: return 0.0若生成序列中thinktoken 出现在/think之前则得 1.0否则 0.0任一 token 缺失则抛ValueError返回 0.0综合奖励reward rlvr_reward format_reward_weight * format_rewardformat_reward_weight默认 1.0条件奖励开关--conditional_reward开启后format_reward * rlvr_reward即只有答案正确时才给格式奖励避免模型投机取巧——只输出正确格式却答错题目也能拿到奖励主章节练习 7.2 也专门验证了该条件逻辑并在 ch07_exercise-solutions.ipynb 中给出实现脚本内注释了一段表现更差的备选提示模板render_prompt_with_think_tokens提示我们不要轻易改动render_prompt模板日志额外记录format_reward_avg列CSV 表头含format_reward_avg用于观察格式奖励占比。主章节对7_6_plus_format_reward_metrics.csvch07/02_logs/7_6_plus_format_reward_metrics.csv的分析还提示若格式奖励过强可将--format_reward_weight从 1.0 降到 0.1实验中可见平均格式奖励曲线几乎与平均奖励曲线重合说明训练好的 reasoning 模型本来就会正确使用think标签格式奖励主要起防止优势坍缩到零的作用。GRPO 文献改进清单Tips TricksREADME 梳理了自 GRPO 2024 年 4 月随 DeepSeekMath 提出、2025 年 1 月随 DeepSeek-R1 流行以来文献中涌现的 15 项改进建议作者注明后续会展开详细论述此处仅作索引零梯度信号过滤DAPO全部奖励相同时跳过更新避免无效梯度主动采样DAPO过滤掉零梯度样本后重新采样保证每步都有学习信号token 级损失DAPO按 token 而非序列计算策略损失保留细粒度梯度不设 KL 损失DAPO、Dr. GRPO数学任务上 KL 惩罚常适得其反Clip higherDAPO提高裁剪上界允许正向奖励对应的策略更快提升截断重要性采样Yao et al.对重要性采样权重做截断以稳定 off-policy 更新不做标准差归一化Dr. GRPO直接用rewards - mean作为优势领域化 KL 强度数学为零DeepSeek-V3.2不同领域用不同 KL 系数重加权 KLDeepSeek-V3.2用新旧策略重要性比率加权 KLoff-policy 序列掩码DeepSeek-V3.2负优势且 KL 过大的序列被掩码top-p / top-k 保留采样掩码DeepSeek-V3.2训练时强制 log-prob 计算与采样同子空间保留原始 GRPO 优势归一化DeepSeek-V3.2聚合前逐奖励组内归一化GDPO多奖励场景先分别归一化再聚合序列级重要性采样与裁剪GSPO裁剪重要性采样权重而非 token 更新CISPOMiniMax。7_7_improvements中的三个脚本正是其中 1–12 及 13 的代码级实现下面逐一剖析。Olmo 3 风格脚本DAPO / Dr. GRPO 改进 1–7 的落地olmo3_style.py 以7_5_plus_kl.py为基底实现改进 1–7源码中每一处改动都标注了对应编号改进 1零梯度过滤 改进 7无标准差归一化olmo3_style.pyrewards torch.tensor(roll_rewards, devicedevice) advantages rewards - rewards.mean() # (7) No standard deviation normalization (Dr. GRPO) zero_grad rewards.max().item() rewards.min().item() # (1) Zero gradient signal filtering (DAPO)当组内所有奖励相等时zero_gradTrue直接返回零 loss、跳过反向传播。改进 3token 级损失answer_token_logprobs返回逐 token 的 log 概率向量olmo3_style.pyloss 计算时按 token 拼接后取平均torch.cat(obj_terms).mean()每个 token 的梯度独立生效改进 5 6Clip higher 截断重要性采样olmo3_style.pyratio torch.exp(log_ratio) ratio torch.clamp(ratio, max1.0 clip_eps_high) # (6) Truncated importance sampling (Yao et al., 2025) clipped_ratio torch.clamp(ratio, 1.0 - clip_eps_low, 1.0 clip_eps_high) # (5) Clip higher (DAPO)低端clip_eps_low0.2、高端clip_eps_high10.0上界放宽、下界收紧改进 2主动采样olmo3_style.py训练循环内for attempt in range(max_active_sampling_tries)依次尝试不同训练样本直到某次 rollouts 产生非零梯度信号才 breakmax_active_sampling_tries8为上限改进 4无 KLkl_coeff0.0为默认值ref_model缺省不创建。DeepSeek-V3.2 风格脚本改进 8–12 的落地deepseek_v32_style.py 同样以7_5_plus_kl.py为基底实现改进 8–12改进 12保留原始优势归一化deepseek_v32_style.py仍使用(rewards - mean) / (std 1e-4)与 Olmo 3 风格脚本形成对照改进 10off-policy 序列掩码deepseek_v32_style.pyseq_kl (old_logps - new_logps) / gen_lens off_policy_mask torch.ones_like(adv) off_policy_mask[(adv 0) (seq_kl off_policy_delta)] 0 adv adv * off_policy_mask对负优势且每 token 平均 KL 超过off_policy_delta0.1的序列直接清零其优势——这类样本偏离旧策略过远off-policy 更新不可靠改进 9重加权 KLdeepseek_v32_style.pykl_ratio torch.exp(new_logps - old_logps) kl_loss kl_coeff * torch.mean(kl_ratio * (new_logps - ref_logps))KL 项乘以新旧策略重要性比率缓解序列级 KL 的低估/高估偏差主章节 7.5 末尾也提出过同样的改进方向改进 11保留采样掩码sample_response在采样时记录每步 top-p / top-k 过滤后的掩码keep_masksdeepseek_v32_style.pyapply_keep_sampling_mask在计算新旧策略与参考策略 log 概率时把掩码之外的 logits 置为-infdeepseek_v32_style.py保证训练目标与采样空间严格一致改进 8领域化 KL数学默认零--kl_coeff默认 0.0且仅在非零时才创建ref_modeldeepseek_v32_style.py对应数学领域 KL 强度为零的设定。GDPO 脚本逐奖励组内归一化gdpo.py 在7_6_plus_format_reward.py之上实现 GDPOGroup-DPO 式改进因为 GDPO 本质上是针对多奖励场景的调整。其奖励设计gdpo.py把格式奖励从7_6的 token 顺序检查改为更宽松的\boxed{}存在性检查并拆出三个分量def reward_with_format_bonus(answer_text, ground_truth, format_coeff0.1): boxed extract_final_candidate(answer_text, fallbackNone) format_reward 1.0 if boxed else 0.0 ... correctness_reward float(correct) reward correctness_reward format_coeff * format_reward return reward, format_reward, correctness_reward关键区别在优势计算gdpo.py不再直接对混合奖励做归一化而是先把正确性奖励与格式奖励分别在 rollout 组内各自归一化加权求和后再对整个组做一次归一化adv_correct (rewards_correct - rewards_correct.mean()) / (rewards_correct.std() 1e-4) adv_format (rewards_format - rewards_format.mean()) / (rewards_format.std() 1e-4) adv_sum adv_correct format_coeff * adv_format advantages (adv_sum - adv_sum.mean()) / (adv_sum.std() 1e-4)这样能避免不同奖励分量尺度差异导致的优势被单一信号主导--format_coeff默认 0.1。与7_6相同gdpo 脚本默认从 reasoning 模型启动训练。训练产物、评估与检查点检查点每checkpoint_every默认 50步保存qwen3-0.6B-rlvr-grpo-stepXXXXX.pthKeyboardInterrupt时也会以-interrupt后缀保存最后一步四个主脚本与三个改进脚本均实现了该逻辑周期评估设置--eval_on_checkpoint N后每个检查点会用evaluate_math500_stream在 MATH-500 前 N 个样本上评估追加math500_acc到日志并把 JSONL 结果写入检查点目录预训练检查点下载7.3–7.6 对应的官方检查点可通过 ch07/04_download_trainining_checkpoints/README.md 中介绍的download_qwen3_grpo_checkpoints(...)下载其中7_6_plus_format_reward须配合reasoning tokenizertokenizer-reasoning.jsonapply_chat_template/add_thinking其余三个脚本使用base tokenizer参考日志ch07/02_logs 目录存放了7_3_plus_tracking_metrics.csv、7_4_plus_clip_ratio_metrics.csv、7_5_plus_kl_metrics.csv、7_6_plus_format_reward_metrics.csv等真实运行记录可直接用 ch06/02_rlvr_grpo_scripts_intro/plot_metrics.py 绘制例如uv run plot_metrics.py --csv ch07/02_logs/7_5_plus_kl_metrics.csv --moving_average 20资源提示第 6 章 README 给出的实测参考显示num_rollouts8 / max_new_tokens512约需 20.31 GB 内存4 / 512约需 14.60 GB内存紧张时优先降 rollouts 或响应长度会影响效果也可把--accum_steps提到 2–4 提升稳定性。从 ch06 README 的对照实验看基础 GRPO 在 100 步后准确率会大幅下滑50 步 33.4% → 100 步 0.4%而本文所述的无 KL / Olmo 3 风格 / DeepSeek-V3.2 风格变体在 100 步时仍能保持在 44%–47% 附近——这正是 7.3–7.7 这一系列脚本存在的意义在不牺牲 MATH-500 性能的前提下把 GRPO 训练延长到数百乃至数千步为更充分的推理能力强化腾出空间。赞分享示例工程【免费下载链接】reasoning-from-scratchImplement a reasoning LLM in PyTorch from scratch, step by step项目地址https://gitcode.com/gh_mirrors/re/reasoning-from-scratch点击查看免费下载相关推荐reasoning-from-scratch 第七章进阶 GRPO 策略优化实践指南指标追踪、Clipped Ratio、KL 约束与格式奖励reasoning from scratch 第七章进阶 GRPO 策略优化实践指南指标追踪、Clipped Ratio、KL 约束与格式奖励 导读 本文示例工程OpenLayers 格式模块开发指南从 ol/format/Feature 抽象接口到 ol/xml 解析框架OpenLayers 格式模块开发指南从 ol/format/Feature 抽象接口到 ol/xml 解析框架 本文是 OpenLayers 开源仓库中 s示例工程reasoning-from-scratch 第 6 章实战用 RLVR GRPO无 KL 项从零训练推理模型reasoning from scratch 第 6 章实战用 RLVR GRPO无 KL 项从零训练推理模型 本章是 reasoning from示例工程上一篇OneNote迁移终极指南使用onenote-md-exporter实现笔记无损转换到Markdown格式下一篇NoFences用开源桌面分区工具重塑你的数字工作空间创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询