news 2026/8/7 12:43:17

大模型强化学习:GRPO超级无敌深度剖析,看完即高手

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
大模型强化学习:GRPO超级无敌深度剖析,看完即高手

前言:GRPO 宏观视角

1. 为什么我们需要 GRPO?(Motivation)

在DeepSeek-Math和DeepSeek-R1等前沿工作中,GRPO被证明是一种极其高效的强化学习算法。要理解它,我们必须先看一眼它的前辈——PPO (Proximal Policy Optimization)

在标准的RLHF(Reinforcement Learning from Human Feedback)流程中,PPO是绝对的王者,但它有一个巨大的痛点:显存占用极大,计算资源昂贵

请看下面这个内存占用对比图:

+-------------------------------------------------------+ | 传统 PPO (Standard RLHF) | | ----------------------------------------------------- | | 1. Actor Model (策略模型,即我们要训练的LLM) | <--- 梯度更新 | 2. Critic Model (价值模型,估算状态价值 V(s)) | <--- 梯度更新 | 3. Reference Model (参考模型,用于计算 KL 散度) | <--- 冻结参数 | 4. Reward Model (奖励模型,用于给 Answer 打分) | <--- 冻结参数 +-------------------------------------------------------+ ↓↓↓ (演变为) ↓↓↓ +-------------------------------------------------------+ | GRPO | | ----------------------------------------------------- | | 1. Actor Model (策略模型) | <--- 梯度更新 | 2. Reference Model (参考模型) | <--- 冻结参数 | [Critic Model 被移除了!] | | [Reward Model 依然存在,但通常是轻量级或规则基] | +-------------------------------------------------------+

核心痛点:PPO 需要维护一个和 Actor 一样大的 Critic 模型(通常是同等规模的 Transformer)。如果你在训练一个 70B 的模型,PPO 意味着你需要加载 70B (Actor) + 70B (Critic) + 70B (Ref) + RM,这对显存是灾难性的。

GRPO 的核心洞察:我们真的需要一个单独的神经网络(Critic)来告诉 Actor “你做得好不好”吗?能不能直接通过“这一组生成结果的内部比较”来判断优劣?

2. GRPO 的核心机制:自顶向下的直觉

GRPO 全称Group Relative Policy Optimization。顾名思义,它由两个关键词组成:

  1. Group(组)

  2. Relative(相对)

想象一下考试评分:

  • PPO (Value-based):学生 A 回答了问题。老师(Reward Model)打分 80 分。但是,这个 80 分好不好?我们需要一个“预言家”(Critic Model)来预测:“这道题通常大家能拿 75 分”。

    • 优势(Advantage)= 80 - 75 = +5。

    • 结论:Critic 必不可少,用来提供 Baseline(基线)。

  • GRPO (Group-based):我就不请“预言家”了。我让学生 A 针对同一个问题,生成 8 个不同的答案(Group)。 这 8 个答案的得分分别是:[80, 70, 90, 60, 85, 75, 95, 65]。 算出这组的平均分:77.5 分。

    • 答案1 (80分) 的优势 = 80 - 77.5 = +2.5

    • 答案3 (90分) 的优势 = 90 - 77.5 = +12.5

    • 答案4 (60分) 的优势 = 60 - 77.5 = -17.5

结论:GRPO 通过采样一组输出,计算组内的平均值作为 Baseline。不需要额外的 Critic 模型参数

3. GRPO 的系统脉络图 (Architecture Flow)

为了让你建立最直观的印象,我绘制了 GRPO 的数据流转图。请仔细观察“Group Sampling”这一步。

User Prompt (Question) │ ▼ +---------------------+ | Actor Model | <-- 也就是我们要训练的 LLM +---------------------+ │ │ (生成 N 个不同的回答) ▼ +---------------------------------------------------------------+ | Group Sampling (N=4 示例) | | | | Output 1: "The answer is A..." ----> Reward Model --> r1 | | Output 2: "Calculated as B..." ----> Reward Model --> r2 | | Output 3: "Let x = y, so A..." ----> Reward Model --> r3 | | Output 4: "Based on logic C..." ----> Reward Model --> r4 | +---------------------------------------------------------------+ │ ▼ +---------------------------------------------------------------+ | Advantage Calculation (核心) | | | | 1. 计算均值 (Mean): μ = (r1+r2+r3+r4) / 4 | | 2. 计算标准差 (Std): σ | | 3. 计算相对优势 (Advantage): A_i = (r_i - μ) / σ | +---------------------------------------------------------------+ │ ▼ +---------------------+ | Policy Optimization| <-- 使用 PPO 的 Clip Loss 公式 | (Update) | 但在 Advantage 项上使用了上述 A_i +---------------------+

本讲核心 takeaway:

  1. 省资源:GRPO 去掉了 Critic 模型,极大地节省了显存和计算量,使得训练超大模型变得更加可行。

  2. 基线(Baseline)的转变:从“神经网络预测的基线”(Value Function)转变为“当前Batch内的统计基线”(Group Mean)。

  3. 原理:通过对同一个问题采样多条路径,用组内归一化(Group Normalization)的方式来确定哪个答案是好的,哪个是差的。

GRPO 深度剖析:PPO 昂贵且脆弱的 Critic

在经典的强化学习(RL)理论中,Actor-Critic 架构几乎被奉为圭臬。但在大语言模型(LLM)的场景下,这个架构显得愈发笨重且低效。我们要解决的问题是:为什么训练一个好的 Value Function (Critic) 如此困难且昂贵?

1. 回顾 PPO 的核心数学依赖

要理解痛点,先看公式。PPO 的核心在于最大化以下目标函数(简化版):

在标准 PPO 中,我们通常使用GAE (Generalized Advantage Estimation)来计算它,而 GAE 高度依赖于 TD Error ():

请注意这里出现的。这就是 Critic 网络,它的任务是预测状态的预期回报。

致命逻辑链条:

  1. Actor 的更新方向取决于

  2. 的准确性取决于的预测精度。

  3. 如果 Critic也是一个刚开始训练的神经网络,它的预测是充满了噪声和偏差的

2. 痛点一:计算与显存的“双倍惩罚” (The Computational Tax)

在传统的 RL(如玩 Atari 游戏或机器人控制)中,Actor 和 Critic 通常只是几层 MLP 或小型 CNN,参数量很少。

但在 LLM 中,情况发生了质变:

  • 状态空间(State Space)极度复杂:输入是 token 序列,语义极其丰富。

  • 理解“价值”需要“智能”:要判断一句话“好不好”,Critic 网络必须具备和 Actor 相当的理解能力。

这意味着,如果你的 Actor 是一个7B的 Llama-3,你的 Critic 通常也必须是一个7B的 Transformer(或者至少共享大部分主干参数)。

显存账单(Training a 7B model):

  • Actor (7B):权重 + 梯度 + 优化器状态 很大。

  • Critic (7B):权重 + 梯度 + 优化器状态同样大

这就是为什么在 RLHF 阶段,显存占用往往是 SFT 阶段的 2-4 倍。Critic 不仅占据了显存,还占据了大量的 FLOPs(前向传播和反向传播),使得训练吞吐量(Tokens/sec)直接减半。

3. 痛点二:价值函数的“训练困境” (The Optimization Difficulty)

这才是更深层的学术痛点。在 LLM 生成任务中,训练 Critic 往往比训练 Actor 更难。

3.1 奖励的稀疏性与主观性

在围棋中,输赢是客观的。但在对话中,Reward Model 给出的分数(比如 0.85 或 0.92)往往带有很强的主观噪声。Critic 试图去拟合这个充满噪声的 Reward Model,极易过拟合或欠拟合。

3.2 价值评估的难度

比如以下场景:

Prompt: "请证明黎曼猜想。"

Token 1: "黎"

Token 2: "曼"

Token 3: "猜"

...

Critic 需要在看到 "黎曼猜" 这几个字的时候,就预测出这句话最终能得多少分(Value)。这几乎是不可能的任务,因为后续生成的质量完全未定。

结果: 在 LLM 训练初期,Critic 的 Loss 通常非常高,且收敛极慢。

后果: 如果 Critic 预测不准(V(s) 瞎猜),那么计算出的优势就是错误的。Actor 会根据错误的信号进行更新,导致模型性能震荡甚至崩塌(Collapse)。

4. GRPO 的降维打击:用“统计”替代“预测”

既然训练一个神经网络(Critic)去预测 Baseline(V(s))既贵又难,GRPO 选择了一个统计学的方法。

我们不再问 Critic:“这一单大概能得多少分?”

而是直接做实验:“既然我不知道基线,那我就多跑几次,取平均值当基线。”

让我们对比一下Baseline的来源:

特性PPO (Standard)GRPO
Baseline 来源参数化模型(Critic)蒙特卡洛采样的组均值 (Group Mean)
计算成本高 (需前向/反向传播整个 Critic 网络)低 (仅需对 Reward 标量求平均)
准确性依赖依赖 Critic 训练得好不好依赖 Group Size (N) 是否足够大
无偏性Critic 可能有 Bias组内均值是当前策略的无偏估计
【PPO 的视角:预言家模式】 学生(Actor): "我写完了,看我这篇作文!" │ ▼ 预言家(Critic): (甚至还没看别人的) "基于我对你过往表现和题目难度的深奥计算, 我觉得这种题目的平均分应该是 75 分。" │ ▼ 老师(Reward): "这篇实际得分 80 分。" │ ▼ 结果: 优势 = 80 - 75 = +5 (你比预言的要好) ---------------------------------------------------- 【GRPO 的视角:赛马模式】 学生(Actor): 分身成 4 个人,写了 4 篇作文。 │ ▼ 作文A (80分) | 作文B (60分) | 作文C (85分) | 作文D (75分) │ ▼ 统计员(Math): "大家停一下,算个平均分。" 平均分 = (80+60+85+75)/4 = 75 分。 │ ▼ 结果(A): 优势 = 80 - 75 = +5 (你比这一组的平均水平好)

本质总结:GRPO 利用大数定律(虽然 N 通常只有 8-64,但在统计上已足够有效)来实时的、动态的构建 Baseline,从而彻底删除了那个笨拙的 Critic 网络。

本讲核心 Takeaway:

  1. PPO 的 Critic 在 LLM 时代不仅仅是增加了显存,更重要的是它引入了优化难题

  2. Value Function 在长文本生成任务中极难收敛,不准确的 Value 会误导 Actor。

  3. GRPO 通过Group Relative(组相对)的方式,用“采样均值”替代了“参数预测”,在数学上依然构成了有效的 Advantage 估计,同时将计算成本砍半。

GRPO 深度剖析:数学形式化—目标函数的重构

在强化学习中,所有都蕴含在那个我们需要最大化的之中。GRPO 的美妙之处在于,它在 PPO 的基础上做了一次手术,切除了,植入了一个基于组(Group)的归一化算子。

1. 符号定义 (Notation Setup)

为了保证严谨性,我们先定义这一讲的数学符合:

  • : 我们要训练的策略模型(Actor),即当前的 LLM。

  • : 参考模型(Reference Model),通常是 SFT 后的初始模型,用于防止模型跑偏。

  • : 用户的问题(Prompt),从数据集 P(Q) 中采样。

  • 一组输出(Outputs)。这里 G是组的大小(Group Size),比如 8 或 16。

  • : 第个输出对应的奖励值(Reward),由 Reward Model 给出。

2. 核心变革:组相对优势

在 PPO 中,优势依赖于 Critic。而在 GRPO 中,优势则依赖于同行衬托

对于同一个问题,模型生成了一组输出,对应的奖励为

个输出的优势函数定义为:

深度解读:

  • Mean (): 这一组输出的平均水平。如果,说明这个回答比你自己生成的平均水平好,应当鼓励()。

  • Std (): 标准差用于缩放。这非常关键!

    • 如果某次生成大家的差别很大(比如 [10, 90, 50]),标准差大,优势会被缩小,梯度的更新幅度会变稳。

    • 如果差别很小(比如 [80, 81, 79]),说明模型对这个问题的表现很一致,标准差小,微小的分数差异会被放大,模型能学到细微的区别。

  • : 一个极小的数(如),防止分母为 0。

[原始奖励空间 Reward Space] Group A (简单题): [0.9, 0.92, 0.88, 0.95] <-- 分数都很高 Group B (困难题): [0.1, 0.05, 0.20, 0.15] <-- 分数都很低 如果不做归一化,模型会拼命学习 Group A (Reward大,梯度大), 而忽略 Group B (Reward小,梯度小)。这显然不合理。 ------------------------------------------- [GRPO 归一化空间 Normalized Advantage] Group A: [-0.4, +0.3, -1.1, +1.2] Group B: [-0.4, -1.2, +1.2, +0.4] ↑↑↑ 你看!无论是简单题还是困难题, 都被拉到了同一个“相对起跑线” (均值为0,方差为1)。 模型现在只关注:在这个场景下,哪个答案相对更好?

3. 终极公式:GRPO 目标函数

有了上面的,我们可以写出 GRPO 需要最大化的完整目标函数:

3.1 期望与采样 (Expectation & Sampling)

这告诉我们训练的循环逻辑:

  1. 采样一个 Prompt

  2. 用旧策略采样个输出

  3. 接下来的计算都是基于这个样本的平均值。

3.2 代理损失 (Surrogate Loss with Clipping)

这是直接继承自 PPO 的部分,但在 $A_i$ 上用了 GRPO 的定义:

  • 比率 (Ratio):衡量当前策略和采样时的策略差了多少。

  • Clip: 限制更新幅度,防止一次更新步子迈太大把模型扯坏了。这是 PPO 家族稳定性的基石。

3.3 KL 散度惩罚 (KL Divergence Penalty)

为什么要减去它?

  • 这是一个正则化项 (Regularization)

  • 是我们的 SFT 模型(它是懂人话的)。

  • 是我们在训练的模型。

  • 如果为了拿高分(Reward Hacking),开始输出乱码或者极端的欺骗性文本,它和的分布差异会变大,KL 散度飙升。

  • 因为公式前面是负号,最大化目标函数就意味着要最小化KL 散度。

4. Token 级 vs 样本级 KL

在实际实现中(如 DeepSeekMath 的论文),KL 散度通常使用如下近似计算方式:

(注:具体实现有多种近似公式,Schulman 的近似最为常见)

关键点在于:GRPO 通常将 KL 散度作为一个 Loss 项直接加在目标函数里,而不是像某些 PPO 实现那样作为 Reward 的一部分(PPO-reward-shaping)。这使得训练更加直观,我们明确地知道模型在优化什么:“相对优势”减去“偏离代价”

本讲核心 Takeaway:

  1. 公式的核心:是 PPO Clip Loss 的变体,唯一的区别在于 Advantage 的来源。

  2. 归一化的魔力:使得模型在面对不同难度的 Prompt 时,梯度尺度保持稳定,这是 GRPO 训练稳定的关键。

  3. 正则化:KL 惩罚项是防止模型“走火入魔”的必选组件。

现在,公式已经摆在桌上了。但在实际把代码跑起来之前,我们面临一个极其具体且棘手的超参数选择问题:(Group Size) 到底取多少?

取 4?取 16?还是 64?

如果太小,统计均值不准确怎么办?如果太大,显存爆了怎么办?

在下一讲,我们将深入探讨Group 的奥秘,从统计学角度分析的大小如何决定了 GRPO 的成败,以及如何根据你的显存大小来权衡这个参数。

GRPO 深度剖析:组(Group)——统计方差与采样策略

1. 为什么不能太小?——基线估计的方差问题

我们知道,GRPO 用组内均值来近似真实的 State Value。从蒙特卡洛(Monte Carlo)的角度看,这是一个无偏估计,但方差(Variance)可能极大。

1.1 统计学直觉

假设真实的价值

如果(极端的例子),我们只采样两个样本:

  • Case 1:运气好,采到 [74, 76]。均值 75,估计完美。

  • Case 2:运气差,采到 [50, 60](模型发挥失常)。均值 55。

    • 在这个 Case 2 中,60 分的样本会被认为具有“巨大优势”(+5分 relative to 55),而在真实基准(75分)下,它其实是很差的。

结论:太小时,Baseline () 的波动极其剧烈。这会导致梯度的方差变大,训练过程像是在“走醉鬼步”(Random Walk),难以收敛。

1.2 文献中的经验值

DeepSeek-Math 和 DeepSeek-R1 的论文中,通常倾向于较大的

  • DeepSeek-Math:推荐

  • 经验法则:对于复杂的逻辑推理任务(如数学题),解空间的方差本身就大(对就是1,错就是0),需要更大的来稳定均值。

2. 为什么 $G$ 不能无限大?——边际递减与显存墙

你可能会问:“既然 G 越大估计越准,为什么不设成 1024?”

这里有两个制约因素:

  1. 显存墙(The VRAM Wall):

    GRPO 需要在一次 Forward Pass 中生成 G 个完整的长序列。

    • 如果你训练 70B 模型,Context Length 4096。

    • G=64 意味着你需要同时显存驻留 64 条 4096 长度的 KV Cache 和中间激活值。这对显存是毁灭性的打击。

  2. 边际效益递减(Diminishing Returns):

    根据中心极限定理,标准误(Standard Error)随下降。

    • 从 4 增加到 16,误差减半,收益巨大。

    • 从 64 增加到 256,误差只减半,但计算成本翻了 4 倍。

3. 致命陷阱:模式崩塌(Mode Collapse)与标准差

在 GRPO 公式中,分母是(标准差)。这引入了一个在 PPO 中不存在的风险。

如果会发生什么?

这意味着模型生成的个回答完全一样,或者得分完全一样。

  • 此时,分子也是 0。

  • 结果:

  • 梯度消失:模型学不到任何东西。对于这个 Batch,训练是无效的。

3.1 采样策略的重要性 (Temperature is Key)

在 SFT 中,我们有时会用 Greedy Search (Temp=0) 来追求最稳妥的回答。

但在 GRPO 中,Temperature 绝对不能为 0。

你需要强制引入多样性(Diversity)

  • Temperature:通常设为 0.6 - 1.0。

  • Top-P / Top-K:适当放宽。

我们必须迫使模型在一个Prompt下探索不同的路径。只有产生了差异(Contrast),GRPO 才能通过比较(Comparison)来学习。

【无效的组 (Low Variance)】 -> 训练停滞 Temperature = 0.1 Prompt: 1+1=? Output 1: 2 (Reward: 1.0) Output 2: 2 (Reward: 1.0) Output 3: 2 (Reward: 1.0) Output 4: 2 (Reward: 1.0) Stats: μ=1.0, σ=0.0 Advantage: [0, 0, 0, 0] <-- 没有任何信号告诉模型“保持这样”或“改变” --------------------------------------------- 【有效的组 (High Variance)】 -> 高效学习 Temperature = 1.0 Prompt: 1+1=? Output 1: 2 (Reward: 1.0) -> Adv: +0.8 Output 2: 3 (Reward: 0.0) -> Adv: -1.2 Output 3: 11 (Reward: 0.0) -> Adv: -1.2 Output 4: Two (Reward: 1.0) -> Adv: +0.8 Stats: μ=0.5, σ=0.5 Advantage: 产生了强烈的正负反馈信号!

4. 进阶技巧:Iterative GRPO (在线生成 vs 离线生成)

处理带来的显存压力,学术界和工业界有两种做法:

4.1 Online Generation (标准 GRPO)

在训练步中实时生成个样本。

  • 优点:数据是完全 On-Policy 的,完全符合数学推导。

  • 缺点:慢,显存占用大。

4.2 Offline / Hybrid Generation (变体)

先用当前模型跑 inference,把数据存到 Buffer 里(比如存 64 个),然后训练时从 Buffer 里拿数据计算 Loss。

  • 风险:变成了 Off-Policy。如果模型更新了,Buffer 里的数据就“过时”了(Stale)。

  • 修正:需要引入 Importance Sampling (IS) 或者限制 Buffer 的刷新频率。DeepSeek 的实现通常倾向于高效的 Online 生成,或者极短周期的 Buffer。

本讲核心 Takeaway:

  1. Group Size ()是权衡“估计方差”与“显存成本”的杠杆。一般推荐

  2. 多样性是生命线:GRPO 依赖组内差异来提取信号。必须使用非零的 Temperature 采样。如果模型坍缩到单一输出,GRPO 将失效。

  3. 标准差的意义:不仅仅是分母,它是一个“自适应的各种系数”。当大家都很烂时,微小的差异会被放大;当大家都很好时,差异会被缩小。

明白了的设定,我们其实只解决了一半的问题。公式里的算出来了,但不要忘了,我们并没有 Critic。这就引出了一个深刻的问题:没有 Value Function 的情况下,我们如何确保 Advantage 的计算真的是“优势”,而不是“噪声”?尤其是当 Reward 本身很稀疏的时候(比如做数学题,全错就是0,很难拿到1)。

下一讲,我们将深入优势函数(Advantage Function)的重构,探讨在 Reward 稀疏或密集场景下,GRPO 具体的数值表现和潜在的改进技巧(如 Outcome Reward vs Process Reward)。

在传统的 PPO 中,优势函数是极其复杂的,它通常利用 GAE(Generalized Advantage Estimation)进行时间步(Token)级别的细粒度指派。而在 GRPO 中,由于移除了 Critic,我们的评价体系发生了根本性的范式转移:从“基于价值预测的绝对评价”转向了“基于群体竞争的相对评价”。

GRPO 深度剖析:优势函数(Advantage Function)的重构——零和博弈与稀疏奖励

1. 零和博弈:归一化的深层含义

让我们再次审视那个看起来人畜无害的公式:

如果你对这一组求和,你会发现一个惊人的性质:

(注:在极小的情况下,加权后的均值严格为 0,标准差严格为 1)

1.1 物理意义:组内“内卷”

这意味着 GRPO 构建了一个局部的零和博弈(Zero-Sum Game)环境。

  • 在一个 Batch 中,无论大家的回答质量整体有多高(比如都是 99 分),或者整体有多烂(比如都是 1 分),总有一半的回答会被“惩罚”(Adv < 0),另一半会被“奖励”(Adv > 0)。

  • 绝对分数的“消逝”:模型不再关心“我是否考了 60 分及格”,模型只关心“我是否考得比隔壁的同学高”。

1.2 这种设计的利弊

  • 利(鲁棒性):Reward Model 有时候会发生 Drift(整体分数虚高或虚低),组内归一化直接消除了这种整体性的 Bias。

  • 弊(错误信号):如果一组回答全是垃圾(Reward 都是 0.0),但有一个稍微沾点边(Reward 0.01),那个 0.01 的回答会被赋予巨大的正优势,导致模型过度强化这个“矮子里拔将军”的行为。(这也是为什么我们需要上一讲提到的 KL 散度约束,防止模型跑偏)

2. 信号粒度的问题:轨迹级 vs Token 级

这是一个学术界非常关注的细节。

  • PPO (Critc-based):每一句话的每一个 Token,Critic 都会给出一个价值评估。因此 PPO 可以精确地说:“虽然你最后答错了,但你中间推理的第三步是很棒的。”(Temporal Credit Assignment)。

  • GRPO (Outcome-based):通常情况下,我们只有一个最终的 Reward(比如答案对不对)。这意味着,我们将把这个产生的优势广播(Broadcast)给这条回答中的每一个 Token。

这听起来很粗糙,对吧?如果我写了 1000 字的推理,只有最后一步错了,导致,难道这 1000 字都要被惩罚吗?

DeepSeek 的解决方案:过程奖励与格式奖励

为了缓解这个“一刀切”的问题,GRPO 极其依赖Reward Engineering。在 DeepSeek-R1 中,Reward不再是一个单一的标量,而是多个部分的组合:

  1. 结果奖励 ():最终答案对不对?(LeedCode 通过率,数学答案匹配)。

  2. 格式奖励 ():这就是“过程”的一种体现。比如强制模型必须输出<think>...</think>标签。如果模型写了标签,即便答案错,它也能拿到一部分格式分,避免全盘否定。

通过这种方式,GRPO 在没有 Critic 进行逐词评估的情况下,依然引导模型学习到了结构化的推理能力,还是挺逆天的。

【场景:做一道数学题,过程完美,但最后算错了】 Prompt: 2 * 3 + 4 = ? Model: "2*3得6, 6+4得... 9!" (错误答案) --------------------------------------------------- [PPO 的视角 - 精细化打击] Token序列: [2*3得6] -> [6+4得] -> [9!] Critic V(s): ↑高 ↑高 ↓骤降 Advantage: (+0.5) (+0.6) (-2.0) 更新结果: "2*3得6" 被鼓励 (保留正确逻辑) "9!" 被狠狠惩罚 (修正错误结果) --------------------------------------------------- [GRPO 的视角 - 连坐制度] Token序列: [2*3得6] -> [6+4得] -> [9!] Group Mean: 0.5 (假设别人做对了) 此样本 Reward: 0.0 (因为答案错了) Advantage: -1.0 (全序列统一惩罚) 更新结果: "2*3得6" 被惩罚 (无辜躺枪) "6+4得" 被惩罚 (无辜躺枪) "9!" 被惩罚 (罪有应得) [思考]: 为什么 GRPO 依然能工作? 因为在海量的采样中 (Big Data + Large Steps), "2*3得6" 这一步出现在"正确样本"中的概率远高于"错误样本"。 虽然单次更新有噪声,但期望值 (Expectation) 最终会收敛到正确方向。 这就是大数定律的暴力美学。

4 处理稀疏奖励 (The Sparse Reward Problem)

在数学或代码任务中,Reward 往往是二值的(0 或 1)。这在 GRPO 中会制造麻烦。

极端情况:个样本全错(全是 0)或全对(全是 1)。

此时,公式退化。虽然有保护不报错,但会变成 0。梯度消失,训练空转。

工程上的应对策略:

  1. 冷启动(Cold Start):在使用 GRPO 纯 RL 之前,必须有一个足够强的 SFT 模型,保证它至少有 10%-20% 的概率能答对题。如果模型一开始什么都不会,GRPO 是推不动的。

  2. 混合奖励:如前所述,加入 dense reward(如格式检查、长度惩罚、语言流畅度分),确保存活下来的样本之间即使答案都错了,分数也有高低之分(比如写了步骤的 0 分比啥都没写的 0 分要稍微好一点点)。

本讲核心 Takeaway:

  1. 相对评价:GRPO 构建了一个组内竞争机制,Advantage 均值为 0。这消除了绝对 Reward 的波动影响。

  2. 粗粒度信号:相比 PPO 的 Token 级评价,GRPO 默认是 Trajectory 级评价。它依赖海量数据的统计规律来区分哪些 Token 是真正导致错误的。

  3. 对初始能力的依赖:因为没有 Critic 指导“这一步走得好”,GRPO 要求模型自身必须具备一定的成功率,否则无法从全 0 的反馈中学习。

现在,我们有了目标函数,有了采样策略,也有了奖励计算方法。 但是,强化学习最怕的就是模型为了拿高分而“走火入魔”(Reward Hacking)。比如,为了让回答变长(如果Reward和长度正相关),模型开始疯狂重复废话。

虽然我们在公式里写了 KL 散度项,但在实际代码和训练中,如何精确计算和控制 KL 散度是一门极深的学问。

在 RLHF 的世界里,有一个著名的诅咒叫Goodhart's Law(古德哈特定律):“当一个指标变成目标,它就不再是一个好的指标。”

如果我们完全放任 GRPO 去最大化我们定义的 Reward(比如数学题做对得 1 分),而没有任何约束,模型很快就会发现一些人类意想不到的“捷径”(Reward Hacking)。为了防止模型变成一个“为了得分不择手段的疯子”,我们需要一个锚点。这个锚点就是KL 散度(Kullback-Leibler Divergence)

GRPO 深度剖析:KL 散度的处理

1. 为什么要加 KL?

想象我们在训练模型写诗。 Reward Model 倾向于给押韵的句子高分。

如果没有 KL 散度约束,GRPO 训练出来的模型可能会变成这样:

Prompt:写一首关于春天的诗。Model:"猫 猫 猫 猫 / 喵 喵 喵 喵" (押韵满分,语义崩坏)

这就是Reward Hacking。模型利用了 Reward Model 的漏洞(比如对某些特定 Token 的偏好),牺牲了语言的可读性和逻辑性来换取高分。

(Reference Model)的作用就是那个拿着教鞭的老师。它通常是 SFT 阶段得到的模型。它的潜台词是:“你可以去尝试拿高分,但你的说话方式(概率分布)不能离我太远。你首先得像个正常人说话,其次才是答对题。”

2. KL 散度的数学计算:Token 级别的微操

在 LLM 中,KL 散度不是算整个句子的,而是算每一个 Token的。

对于第个 Token,模型预测的概率分布是,参考模型预测的概率分布是。 理论上的 KL 公式是

但在 GRPO 的实际工程实现中(参考 DeepSeekMath 和常见的 PPO 实现),我们通常使用Schulman 近似或者简单的Log-Ratio

最常用的近似公式:

对于生成的某个特定 token

注意:

  • 如果高很多(模型过度自信地输出了这个词),差值为正,KL Loss 变大,惩罚模型。

  • 如果变小了(模型不敢说 SFT 原本会说的词),差值为负,但这通常由期望项平衡。

汇总到 Loss 中

在 GRPO 的目标函数中,我们将这个 KL 值作为一个惩罚项(Penalty)减去:

这里 T 是生成的序列长度。这意味着:每一个偏离 Reference 的 Token 都要付出代价。

3. 两种流派:KL in Reward vs KL in Loss

在代码实现层面,你会看到两种处理 KL 的方式,这点非常容易混淆,你需要特别注意:

流派 A:PPO 经典做法 (Reward Shaping)

直接把 KL 惩罚扣在 Reward 里。

  • 逻辑:这里的 Reward 变成了“综合得分”。

  • 在 GRPO 中的问题:如果我们把 KL 加到里,再进行 Group Normalization (),KL 的物理意义会被方差缩放扭曲。这通常不是 GRPO 的最佳实践。

流派 B:DeepSeek-Math 做法 (Direct Loss Term)

保持 Reward 纯净,把 KL 放在目标函数里作为正则项。

  • 逻辑:负责指引方向(哪个答案好),负责拉住缰绳(别走太远)。

  • 优势:这种分离让优化更可控。可以独立调节,不受 Reward 数值范围的影响。

我们可以把想象成地球,是风筝。

[ 崩坏区 / Collapse Zone ] (模型输出乱码,但可能偶然骗过 Reward Model) WARNING: KL >>> 1.0 / / <-- 巨大的 KL 惩罚 (强引力) / +-----------------------+ | 训练中的模型 | ---> 试图往高 Reward 方向飞 | Policy (Actor) | +-----------------------+ \ \ <-- Beta (β) 决定了引力绳的粗细 \ [ 安全区 / Trust Region ] (语言通顺,符合人类语法,由 SFT 模型定义) Reference Model
  • 如果太大 (Beta=1.0):引力太强,风筝飞不起来。模型会死死守着 SFT 的参数,不敢做任何探索。训练 Loss 下降,但 Reward 不升。

  • 如果太小 (Beta=0.0):绳子断了。风筝飞入太空(崩坏区)。模型为了优化 Reward 开始胡言乱语。

  • 黄金甜点 (Beta0.01 - 0.05):既允许模型探索新的解题路径,又强迫它用“人话”把答案写出来。

动态 Beta (Adaptive KL) —— 进阶技巧

在长时间的训练(如几万步)中,固定的往往不好用。

  • 训练初期,模型很容易偏离,需要强 KL 约束。

  • 训练后期,模型已经学乖了,可以适当放松让它冲击更高分。

或者反过来(PPO 中常用):设定一个目标 KL 值(比如)。

  • 如果当前 KL >:说明跑太远了,调大

  • 如果当前 KL <:说明太保守了,调小

虽然 GRPO 论文中较少强调这一点,但在工程实践中,监控 KL 曲线是判断训练是否健康的唯一标准。

  • 健康的曲线:KL 缓慢上升,然后稳定在一个小数值(如 0.01-0.05)。

  • 暴雷的曲线:KL 指数级爆炸,或者突然变成 0。

本讲核心 Takeaway:

  1. 安全锚点:KL 散度约束是 RLHF 区别于普通 Fine-tuning 的关键,它保证了生成的语言质量。

  2. 公式选择:在 GRPO 中,建议将 KL 作为 Loss 的独立正则项,而不是混入 Reward,以避免被 Normalization 干扰。

  3. 计算粒度:KL 是 Token-level 的。每一个“标新立异”的词都会累积罚分。

理论闭环已经完成。现在,我们需要把这些积木拼成一个完整的、会动的机器。 下一讲,我们将进入系统级的整合,我们将像拆解引擎一样,一步步拆解GRPO 的完整训练循环 (Training Loop)。我们将看到数据是如何在 GPU 之间流转,以及梯度是如何反向传播的。

GRPO 深度剖析·:训练循环详解

GRPO 的训练过程可以被切割为两个截然不同的阶段:

  1. Rollout Phase (采样阶段):只做推理,不传梯度,极度消耗显存带宽。

  2. Training Phase (学习阶段):反向传播,更新权重,极度消耗算力。

1. Step 1: 采样 (Rollout / Generation) —— 最昂贵的开销

一切始于一批 Prompts。假设我们的 Batch Size (of Prompts) =,Group Size =

我们需要生成条完整的回答。

  • 输入:个问题(例如:["1+1=?", "解释量子力学", ...])。

  • 动作:模型(当前的 Actor)进入eval()模式。

  • 操作:

    1. 复制每个 Prompt次。

    2. 并行生成个回答。

    3. 关键数据留存:在生成的过程中,我们要顺手把每个 Token 的Log Probability (LogProbs)存下来!

      • 为什么要存?因为计算 Loss 里的比率时,分母就是这个时候算出来的。如果不存,训练时就要多做一次前向传播,太亏了。

注意:这是 GRPO 训练中最慢的一步。对于 70B 模型,生成长文本(COT)可能占据整个训练时间的 70%-80%。所以这里通常会用到 vLLM 等加速推理框架。

2. Step 2: 评分与归一化 (Evaluation & Advantage)

生成结束后,GPU 显存里躺着条轨迹(Trajectories)。现在的任务是给它们打标签。

  • 动作:

    1. 打分:调用 Reward Function(可能是代码解释器,也可能是另一个 Reward Model),得到个标量奖励

    2. 分组归一化(核心):

      • 将数据切分为组,每组个轨迹。

      • 对每组计算均值和标准差

      • 计算优势

    3. 释放显存:此时,原始的 KV Cache 可以扔掉了(除非你用 PPO 的特殊实现),我们只需要 Input IDs, Masks, Old LogProbs 和 Advantages。

3. Step 3: 学习 (Optimization) —— 内层循环

数据准备好了,现在进入真正的“训练”环节。这通常是一个内层循环(Inner Epochs)。

也就是说,我们辛辛苦苦生成的这批数据,不会只用一次,通常会反复用它更新模型 1-4 次(Update Epochs)。

对于每一次更新迭代:

  1. Actor Forward (新策略前向传播):

    • 把刚才那条数据喂给当前正在更新的 Actor 模型。

    • 计算 New LogProbs

    • 注意:这一步需要梯度requires_grad=True

  2. Reference Forward (参考模型前向传播):

    • 把同样的数据喂给 Reference Model(冻结参数)。

    • 计算 Ref LogProbs

    • 用途:用于计算 KL 散度。

    • 优化技巧:如果显存不够,这一步可以预先算好存起来,牺牲磁盘/内存换显存。

  3. Loss Calculation (损失计算):

    • Ratio:

    • Surrogate Loss:用 Clip 公式结合 Advantage 计算策略梯度。

    • KL Loss:

    • Total Loss:Surrogate Loss + KL Loss。

  4. Backward & Step (反向传播与更新):

    • loss.backward()

    • optimizer.step()

实例

Prompt (输入): “2 + 2 = ?”

Group Size (): 4 (我们让模型生成 4 个回答)

模型生成了以下 4 条数据(为了方便理解,我把 Token 拆开了):

  • 回答 A:["是", "4", "<EOS>"](正确,简洁)

  • 回答 B:["等", "于", "5", "<EOS>"](错误)

  • 回答 C:["答", "案", "是", "4", "<EOS>"](正确,啰嗦)

  • 回答 D:["不", "知", "道", "<EOS>"](错误,拒绝回答)

第一步:打分 (Scoring) —— 此时与 Token 长短无关

GRPO 并不是看一个字打一次分,而是看完整个句子打一次分。

假设 Reward Model 只看结果对不对(对=1.0,错=0.0):

  • 回答 A 得分 ():1.0

  • 回答 B 得分 ():0.0

  • 回答 C 得分 ():1.0

  • 回答 D 得分 ():0.0

注意:此时我们手里的 Reward 只是 4 个简单的数字:[1.0, 0.0, 1.0, 0.0]完全不涉及 Token 的切分。

第二步:计算均值与标准差 (Group Statistics)

现在我们在组内(Group)计算统计量:

  1. 均值 ():

  2. 标准差 ():计算可得

  3. 计算优势 ():公式

    • 回答 A (Adv):

    • 回答 B (Adv):

    • 回答 C (Adv):

    • 回答 D (Adv):

关键点:到目前为止,我们只得到了4 个标量值

第三步:广播 (Broadcasting)

现在的难题是:回答 A 有 3 个 Token,回答 C 有 5 个 Token,长度不一样,怎么把这一个标量用到计算里?

这就叫广播。我们将这个优势值,像“淋雨”一样,均匀地淋在每一个 Token 头上。

看看【回答 C】的内部视角:

Token 序列:["答", "案", "是", "4", "<EOS>"]

优势值:+1.0

在计算 Loss 时,我们会展开成这样:

时间步 (t)Token (xt​)模型预测概率 (π)这一步的优势 (A^t​)解释
t=10.2+1.0既然结果对了,鼓励你说“答”
t=20.9+1.0既然结果对了,鼓励你说“案”
t=30.8+1.0既然结果对了,鼓励你说“是”
t=440.9+1.0既然结果对了,鼓励你说“4”
t=5EOS0.99+1.0既然结果对了,鼓励你结束

哪怕 "答" 和 "案" 这两个字本身和数学没关系,它们也会被同样地奖励。

再看看【回答 B】的内部视角:

Token 序列:["等", "于", "5", "<EOS>"]

优势值:-1.0

时间步 (t)Token (xt​)模型预测概率 (π)这一步的优势 (A^t​)解释
t=10.6-1.0既然结果错了,惩罚你说“等”
t=20.8-1.0既然结果错了,惩罚你说“于”
t=350.3-1.0既然结果错了,惩罚你说“5”
t=4EOS0.9-1.0既然结果错了,惩罚你结束

第四步:Masking (对齐与遮盖) —— 工程实现的最后一步

在 GPU 里,因为 tensor 必须是方方正正的,所以短的句子后面会补 0 (Padding)。同时,我们不能计算 Prompt 的 Loss

假设 Prompt 长度为 5。 回答 A 长度为 3。 回答 C 长度为 5。 最大长度为 5。

优势矩阵 (Advantage Tensor) 的形状是[Batch, Group, Max_Seq_Len]

Prompt 部分 (Mask掉,不算分) | Response 部分 (参与计算) ------------------------------------------------------------ [ 0, 0, 0, 0, 0, +1.0, +1.0, +1.0, 0, 0 ] <- 回答 A (补了2个0) [ 0, 0, 0, 0, 0, -1.0, -1.0, -1.0, -1.0, 0 ] <- 回答 B (补了1个0) [ 0, 0, 0, 0, 0, +1.0, +1.0, +1.0, +1.0, +1.0 ] <- 回答 C (填满) [ 0, 0, 0, 0, 0, -1.0, -1.0, -1.0, -1.0, 0 ] <- 回答 D (补了1个0)
[ Prompts (Batch=B) ] │ ▼ +-----------------------------+ | Generation Phase | <--- 🕰️ 耗时最长 | (No Grad, Temp > 0) | | Outputs: B * G trajectories | | Save: Old LogProbs | +-----------------------------+ │ ▼ +-----------------------------+ | Scoring Phase | | 1. Calculate Rewards (r) | | 2. Group Normalization | <--- GRPO 魔法发生地 | 3. Compute Advantage (A) | A = (r - μ) / σ +-----------------------------+ │ ▼ [ Training Buffer ] (包含: InputIDs, Old_LogProbs, Advantages) │ ▼ +-----------------------------+ <--循环 N 次 (Inner Epochs) | Optimization Phase | | | | Current Policy (Actor) --> New LogProbs (with Grad) | Reference Model --> Ref LogProbs (No Grad) | | | Loss = PPO_Clip(A) + β*KL | | Backprop | +-----------------------------+ │ ▼ [ Updated Actor Model ] --> 准备下一轮采样

工程细节:显存优化的关键点

GRPO 虽然去掉了 Critic,但倍的数据量依然庞大。

  1. Gradient Checkpointing (梯度检查点):必须开。用 30% 的额外计算时间换取 4-5 倍的显存空间。否则的长序列直接 OOM。

  2. Micro-Batching (微批次):

    • 虽然我们采样了个样本(比如),在 Optimization 阶段,我们不需要一次性把 64 个样本全塞进 GPU。

    • 我们可以把这 64 个样本拆成 Chunk(例如每次 2 个),累积梯度(Gradient Accumulation),最后更新一次。

    • 注意:Group Normalization 必须在切分 Micro-Batch之前完成!优势的计算是基于全组的,不能切碎了算。

本讲核心 Takeaway:

  1. 两段式结构:GRPO 严格区分“造数据(Rollout)”和“吃数据(Train)”。

  2. 数据复用:为了摊薄昂贵的采样成本,通常会对同一批数据进行多次梯度更新(Inner Epochs)。

  3. 计算瓶颈:与 SFT 不同,SFT 的瓶颈在反向传播,GRPO 的瓶颈通常在生成阶段(因为是自回归的逐词生成)。

现在,我们已经彻底搞懂了 GRPO 内部是如何运转的。 但是,没有对比就没有伤害。学术界现在百家争鸣,DPO (Direct Preference Optimization)也是红极一时,号称“不需要强化学习的强化学习”。

GRPO 深度剖析:横向对比——GRPO vs DPO vs PPO,谁才是终局?

1. 三国鼎立:流派概览

首先,让我们用最简练的语言定义这三位选手:

1.PPO (Proximal Policy Optimization):

  • 哲学:“我要请个老师(Critic)时刻盯着你,你每走一步(Token),我就告诉你这步走得好不好。”

  • 状态:极其强大,但重得像坦克,显存杀手,调参火葬场。

2.DPO (Direct Preference Optimization):

  • 哲学:“我不需要老师。我只要看两份作业,一份是满分(Winner),一份是零分(Loser)。我只学满分的,远离零分的。”

  • 状态:轻量级,本质上是对比学习(Contrastive Learning),不是强化学习。训练极快,但容易过拟合。

3.GRPO (Group Relative Policy Optimization):

  • 哲学:“我不需要老师,但我让你们全班(Group)考试。谁考得比平均分高,谁就是好学生。”

  • 状态:结合了 PPO 的在线探索能力和 DPO 的轻量化优势。

2. DPO 的死穴:为什么推理模型(O1/R1)不爱用 DPO?

DPO 在聊天、写小说、排比句等主观偏好(Alignment)任务上是非常牛。但在数学、代码等客观推理(Reasoning)任务上,它有致命缺陷。

2.1 缺陷一:缺乏探索 (No Exploration)

  • DPO (Off-policy):数据集是静态的,通常由 GPT-4 蒸馏生成好和坏回答。

  • 训练时:模型看着 GPT-4 的答案说:“哦,我要模仿这个”。

  • 问题:如果 GPT-4 的解法不是最优的呢?或者模型自己能想出一种更“刁钻”的解法呢?DPO 不允许模型尝试新路径。它只是在做Behavior Cloning (行为克隆)的变体。

2.2 缺陷二:分布偏移 (Distribution Shift)

DPO 的数据往往是离线的。

  • 如果你的模型(Student)很弱,而数据(Teacher)太强,模型根本理解不了 Teacher 为什么这么做,只能死记硬背。

  • GRPO (On-policy):数据是模型自己刚刚生成的。

    • “这是我自己写出来的答案,虽然烂,但我知道我是怎么想的。”

    • 基于自己的能力边界进行改进,这种**自举(Bootstrapping)对于逻辑能力的提升至关重要。

【DPO 的路径:照猫画虎】 标准答案(y_w): A -> B -> C -> D (完美路径) 模型能力: 只能走到 B,后面看不懂。 结果: 强行背诵 C -> D。遇到新题直接懵逼。 ------------------------------------------- 【GRPO 的路径:自我进化】 尝试1: A -> X -> Y (错) -> Reward: 0 尝试2: A -> B -> E (错) -> Reward: 0 尝试3: A -> B -> C (对!) -> Reward: 1 <-- "Aha! 我找到路了!" 结果: 模型通过无数次试错,真的"理解"了从 B 到 C 的逻辑。

3. PPO vs GRPO:同门师兄弟的权衡

既然确定了要用 RL(强化学习),为什么不坚持用 PPO?

3.1 显存与计算效率

  • PPO:需要 Critic 模型。对于 70B 模型,这基本上意味着显存翻倍。

  • GRPO:只要 Actor。通过多次采样(Group Sampling)来代替 Critic。

    • 代价:GRPO 的采样阶段(Inference)很慢。

    • 收益:显存占用低,能训练更大的模型。

    • 结论:在推理算力(vLLM)越来越便宜,而训练显存(H100)依然昂贵的今天,GRPO 是更经济的选择。

3.2 信号的细腻程度

  • PPO:Token-level 信号。Critic 能告诉你:“第 5 步推导错了”。

  • GRPO:Trajectory-level 信号。只能告诉你:“这一整题做错了”。

    • 这看起来是 GRPO 的劣势。但在 DeepSeek-R1 等工作中,通过思维链(CoT)过程奖励(Process Reward)的结合,或者仅仅依靠大规模数据的统计规律,GRPO 证明了即使信号粗糙,只要样本量够大,依然能收敛出 SOTA 的效果。

维度DPOPPOGRPO
本质监督学习 (Contrastive)强化学习 (Actor-Critic)强化学习 (Policy Gradient)
核心机制拟合偏好数据 (Offline)价值函数指引 (Online)组内相对优势 (Online)
显存占用⭐ (极低)⭐⭐⭐ (极高)⭐⭐ (中等,含采样)
训练稳定性⭐⭐⭐ (需调参少)⭐ (极难调)⭐⭐ (较稳,看Group大小)
探索能力无 (模仿)强 (探索)强 (探索)
适用场景聊天、风格对齐、安全机器人控制、复杂博弈逻辑推理、数学、代码
Critic网络不需要需要不需要
BaselineValue ModelGroup Mean

为什么 GRPO 是“推理”的未来?

DeepSeek-Math 和 DeepSeek-R1 的成功揭示了一个趋势:

对于推理(Reasoning)任务,验证(Verification)比生成(Generation)容易。

  • 判断一道数学题做没做对(验证),只需要一个简单的 Python 脚本或 Rule。

  • 让 DPO 去模仿解题过程,很容易学到皮毛(格式)学不到神髓(逻辑)。

  • 让 GRPO 去猜答案,然后通过客观的验证器(Verifier/Compiler)给反馈,模型就能在不断的“猜-验证-修正”中涌现出真正的智能。

结论:如果你的目标是让模型像人一样说话,用 DPO。如果你的目标是让模型解出人类未解的数学题,必须用 RL (GRPO/PPO)。而 GRPO 是目前 RL 路线中性价比最高的工程解法。

本讲核心 Takeaway:

  1. DPO 缺乏探索:它是离线的,适合对齐人类偏好,但不适合探索未知解法(推理)。

  2. GRPO 是 PPO 的瘦身版:它用计算(采样)换显存(去 Critic),在算力成本结构变化的今天,这笔交易极其划算。

  3. 推理需要 On-policy:想要复现 O1/R1 的效果,必须让模型在环境中实时试错,GRPO 提供了这种环境。

现在,理论、公式、对比都讲完了。

你已经具备了手搓 GRPO 的所有知识储备。

在下一讲,我们将进入代码实战环节。我将为你构建一个PyTorch 风格的 GRPO 最小实现(Minimal Implementation)。我们将不再谈论抽象的,而是谈论具体的torch.gather,logits, 和loss.backward()

GRPO 深度剖析·:用 PyTorch 伪代码还原 GRPO

假设我们已经完成采样(Rollout),数据已经躺在显存里了。 现在的任务是:计算 Loss 并反向传播。

1. 核心输入数据结构 (The Inputs)

在进入计算之前,你必须极其清楚你的 Tensor 形状(Shape)。 假设:

  • Batch Size (B):2 (有多少个 Prompt)

  • Group Size (G):4 (每个 Prompt 生成了 4 个回答)

  • Sequence Length (L):1024 (Token 长度)

import torch import torch.nn.functional as F # 1. input_ids: 包含了 Prompt + Response 的完整 token 序列 # Shape: [B, G, L] -> [2, 4, 1024] # 在实际通过模型前,通常会 flatten 成 [B*G, L] -> [8, 1024] input_ids = ... # 2. attention_mask: 标记哪些是 Padding (0), 哪些是真实数据 (1) # Shape: [B*G, L] attention_mask = ... # 3. old_log_probs: 在采样阶段(Rollout)记录下来的 log 概率 # 这是为了计算 PPO 的 Ratio。 # Shape: [B*G, L] old_log_probs = ... # 4. rewards: 外部 Reward Model 给出的分数,每个回答一个分 # Shape: [B, G] -> [2, 4] # 注意:这是标量,还没广播到 Token 级别 rewards = torch.tensor([ [1.0, 0.0, 1.0, 0.5], # Group 1 [0.2, 0.2, 0.9, 0.1] # Group 2 ])

2. 核心函数一:计算优势 (Compute Advantages)

这是 GRPO 区别于 PPO 的灵魂代码。我们需要在 Group 维度上做归一化。

def compute_grpo_advantages(rewards, epsilon=1e-8): """ 输入 rewards: [B, G] 输出 advantages: [B, G] """ # 1. 计算组内均值 (Mean) # dim=1 表示沿着 Group 维度求平均 mean = rewards.mean(dim=1, keepdim=True) # Shape: [B, 1] # 2. 计算组内标准差 (Std) std = rewards.std(dim=1, keepdim=True) # Shape: [B, 1] # 3. 归一化 (Normalization) # 广播机制会自动把 [B, 1] 扩展成 [B, G] advantages = (rewards - mean) / (std + epsilon) # 返回 Shape: [B, G] return advantages

3. 核心函数二:获取 Token 概率 (Get LogProbs)

我们需要让模型再跑一次前向传播(Forward),拿到当前的 LogProbs。注意:这里有一个经典的gather操作,一定要看懂。

def get_per_token_logps(model, input_ids, attention_mask): """ 计算给定序列中每个 Token 的 Log Probability """ # 1. 模型前向传播 # outputs.logits Shape: [B*G, L, Vocab_Size] outputs = model(input_ids, attention_mask=attention_mask) logits = outputs.logits # 2. 对 Logits 取 LogSoftmax (转成 Log 概率) # Shape: [B*G, L, Vocab_Size] all_logprobs = F.log_softmax(logits, dim=-1) # 3. 提取特定 Token 的概率 (Gather) # input_ids 是我们需要模型预测的目标词。 # 我们通常把 input_ids 向左移一位作为 label (next token prediction),这里简化处理。 # 这一步是为了只把“模型实际生成的那个词”的概率拿出来。 # Shape: [B*G, L] token_logprobs = torch.gather( all_logprobs, dim=2, index=input_ids.unsqueeze(-1) ).squeeze(-1) return token_logprobs

4. 核心函数三:GRPO Loss 计算 (The Grand Assembly)

现在把所有东西拼起来。

def grpo_loss_step(model, ref_model, input_ids, mask, old_log_probs, rewards, beta=0.04): """ 单步训练逻辑 """ # --- Step 1: 准备优势 (Advantage) --- # Shape: [B, G] advantages = compute_grpo_advantages(rewards) # [关键] 广播机制 (Broadcasting) # 我们要把 [B, G] 的优势扩展到每个 Token 上 [B*G, L] # 先 flatten 成 [B*G] advantages = advantages.view(-1) # 再扩展到序列长度 (这里只是逻辑示意,实际代码通常在计算 loss 时利用 broadcasting) # 假设我们让 advantage 变成 [B*G, 1],后面乘以 [B*G, L] 的 loss 矩阵 advantages = advantages.unsqueeze(1) # --- Step 2: 当前模型前向传播 --- # Shape: [B*G, L] new_log_probs = get_per_token_logps(model, input_ids, mask) # --- Step 3: 参考模型前向传播 (用于 KL) --- with torch.no_grad(): ref_log_probs = get_per_token_logps(ref_model, input_ids, mask) # --- Step 4: 计算比率 (Ratio) --- # ratio = P_new / P_old = exp(log_P_new - log_P_old) # Shape: [B*G, L] ratio = torch.exp(new_log_probs - old_log_probs) # --- Step 5: PPO Clip Loss (Surrogate) --- # loss1 = ratio * A surr1 = ratio * advantages # loss2 = clip(ratio) * A surr2 = torch.clamp(ratio, 1 - 0.2, 1 + 0.2) * advantages # 取最小值 (PPO 核心),注意是负号因为要 maximize advantage policy_loss = -torch.min(surr1, surr2) # --- Step 6: KL Penalty --- # approx_kl = log_P_new - log_P_ref kl_div = new_log_probs - ref_log_probs # 这种写法是把 KL 当作 Loss 的一项 kl_loss = beta * kl_div # --- Step 7: 综合 Loss --- # Shape: [B*G, L] total_loss = policy_loss + kl_loss # --- Step 8: Masking (只计算 Response 部分) --- # 我们不能计算 Prompt 部分的 Loss,也不能计算 Padding 的 Loss。 # 假设我们要 mask 掉 Prompt 和 Padding,只保留 Response。 # completion_mask 是一个 0/1 矩阵,标记哪些是回答的 token。 completion_mask = ... (根据 prompt 长度生成) # 应用 Mask 并求平均 masked_loss = total_loss * completion_mask final_loss = masked_loss.sum() / completion_mask.sum() return final_loss

本讲核心 Takeaway:

  1. 代码即公式:GRPO 的代码实现就是对 PPO Loss 的一次简单修改,改动不超过 50 行。

  2. Group 处理:核心在于把[B, G]的 Reward 变成[B, G]的 Advantage,然后 Flatten 成[B*G]喂给 Loss 计算。

  3. 计算图:ref_model不需要梯度,old_log_probs是常数(detach),只有new_log_probs所在的计算图需要反向传播。

进阶与展望——R1 的变体与推理的未来

1. DeepSeek-R1 的实战变体:规则即奖励 (Rule-based Rewards)

DeepSeek-R1 最让人震撼的一点是:它在 R1-Zero 阶段,完全没有使用神经网络作为 Reward Model

这是一个极其反直觉的“退步”。我们花了几年时间研究怎么训练 Reward Model,结果 R1 告诉我们:对于推理任务,只要写个 Python 脚本就够了。

GRPO + Compiler/Verifier

在 R1 的 GRPO 训练中,Reward 的构成极其朴素:

  1. 准确性奖励 (Accuracy Reward):把模型生成的答案(Answer)塞进编译器运行,或者与标准答案字符串匹配。通过 = 1.0,失败 = 0.0。

  2. 格式奖励 (Format Reward):强制模型把思考过程写在<think></think>之间。这其实是一种“强约束引导”,防止模型在探索过程中把格式跑丢了。

洞察:这意味着 GRPO 将强化学习从“拟合人类偏好”(这是玄学)拉回了“通过客观检验”(这是科学)。只要你能写出一个验证脚本(Checker),你就能用 GRPO 训练出一个超越人类的模型。

2. 解决冷启动问题 (The Cold Start Problem)

在第五讲我们提到,如果模型一道题都做不对,GRPO 是无效的(全 0 奖励)。DeepSeek-R1 是如何解决这个问题的?

这里有两个阶段的 GRPO:

  1. R1-Zero (纯 RL):让模型盲搜。这需要极大的耐心和算力。初期模型会输出无数的乱码和错误,直到偶然间(Serendipity)它撞对了一次。一旦撞对,GRPO 的优势函数就会瞬间捕捉到这个信号,指数级地放大这条路径的概率。这是“顿悟时刻”(Aha Moment)的数学本质。

  2. R1 (SFT + RL):先用少量高质量的“思维链数据”做 SFT,把模型教会“怎么像人一样思考”。这相当于给 GRPO 一个很高的初始起点(Initial Policy)。这种做法收敛更快,效果更稳。

未来趋势:如何更高效地获取“第一口奶”(SFT Data)?使用小模型(Student)去蒸馏大模型(Teacher)的 GRPO 轨迹,可能是一条捷径。

3. 迈向多模态与 Agent (Multimodal & Agents)

GRPO 的逻辑可以完美迁移到 Text 以外的领域。

3.1 Visual GRPO

想象一个视觉推理任务:“图中这只猫在干什么?”

  • Prompt:图片 + 问题。

  • Group:生成 16 个不同的解释。

  • Verifier:这里很难用规则判断。但如果是“数图中有几个苹果”,这就是完美的 GRPO 场景。模型多数几次,如果答案是 5,且检测框对准了,Reward = 1。

3.2 Agent Tool Use

Agent 调用工具(如搜索、计算器)本质上也是一种推理路径。

  • Action:调用 API。

  • Outcome:API 返回结果是否解决了用户问题?

  • GRPO 的机会:我们可以采样一组 API 调用序列。有的序列调用了 10 次才解决,有的调用了 2 次就解决了。GRPO 会自然地奖励那些既快又准的工具使用策略。

4. 终极猜想:Process GRPO (Dense Reward)

目前的 GRPO 还是基于结果(Outcome)的。就像老师只看卷子最后的答案给分。

我个人猜想未来的 GRPO 可能会进化为 Dense GRPO。

我们不需要训练一个巨大的 Critic,但我们可以引入轻量级的Step-level Verifier

  • 每生成一行代码,就跑一次语法检查。

  • 每推导一步数学公式,就用符号计算引擎(SymPy)验算一步。

这样,Reward不再是一个标量,而是一个向量

优势函数将利用蒙特卡洛树搜索(MCTS)的思想,更精准地评估每一步的价值。这将是 System 2 思维的完全体。

【GRPO 知识图谱】 1. 核心动机 (Motivation) └── 抛弃 Critic -> 省显存 -> 赋能大模型训练 (Lecture 1-2) 2. 数学原理 (Math Foundation) ├── 目标函数: Clip Loss + KL Penalty (Lecture 3, 6) ├── 优势函数: Group Normalization (r - μ) / σ (Lecture 5) └── 采样策略: Group Size & Temperature (Lecture 4) 3. 工程实现 (Implementation) ├── 训练循环: Rollout -> Score -> Train (Lecture 7) ├── 代码实战: Gather, Broadcasting, Masking (Lecture 9) └── 算法对比: PPO vs DPO vs GRPO (Lecture 8) 4. 未来展望 (Future) └── Rule-based Reward, Self-Verification, Agents (Lecture 10)

你现在已经掌握了目前 LLM Post-training 领域最前沿的武器。

  • 当你看到显存不够时,你会想到 GRPO。

  • 当你看到模型推理能力弱时,你会想到 GRPO。

  • 当你看到 DPO 遇到瓶颈时,你会想到 GRPO。

能看到这里,说明你有及其惊人的毅力和学习渴望,希望本人小小的一点分享,能够帮助大家完全搞懂GRPO,在AGI的道路上出一份力,加油!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/7 22:52:06

如何快速分析C盘里到底是什么东西占用了最多空间?

如何快速分析C盘里到底是什么东西占用了最多空间&#xff1f;如果你的 c: 驱动器空间不足, 它会让电脑变慢, 阻止更新, 你不需要高深的技术技能来找出占用最多空间的项目, 使用几个简单的内置工具和一个免费的第三方实用程序, 你可以快速识别大文件和文件夹, 看看哪些文件类型占…

作者头像 李华
网站建设 2026/8/7 3:38:22

C盘如何清理?

C盘如何清理&#xff1f;your c: drive stores the windows system files, installed programs, and personal data, when it fills up, your computer can slow down, updates may fail, and programs might not run correctly, you do not need technical skills to free spa…

作者头像 李华
网站建设 2026/8/6 23:59:43

C盘清理?

C盘清理&#xff1f;your c: drive can fill up faster than you expect, when windows reports low disk space, programs can slow down, updates can fail, and backups might not work, you do not need to be a computer expert to free up space, with a few simple chec…

作者头像 李华
网站建设 2026/8/7 7:27:50

终极指南:5步轻松部署any-listen私有音乐播放器

终极指南&#xff1a;5步轻松部署any-listen私有音乐播放器 【免费下载链接】any-listen A cross-platform private song playback service. 项目地址: https://gitcode.com/gh_mirrors/an/any-listen 厌倦了商业音乐平台的限制和广告&#xff1f;想要拥有完全属于自己的…

作者头像 李华
网站建设 2026/8/7 11:51:29

从零到一:ArcObjects SDK实战开发完全指南

从零到一&#xff1a;ArcObjects SDK实战开发完全指南 【免费下载链接】arcobjects-sdk-community-samples This repo contains the source code samples (.Net c#, .Net vb, and C) that demonstrate the usage of the ArcObject SDK. 项目地址: https://gitcode.com/gh_mi…

作者头像 李华
网站建设 2026/8/6 23:59:42

sql server 事务日志备份异常恢复案例---惜分飞

有客户的sql server数据库运行在双机环境中,由于心跳网络异常导致双机频繁切换最终数据库损坏DBCC检查报大量错误 DBCC CHECKDB(OLTP) WITH NO_INFOMSGS, ALL_ERRORMSGS Msg 8909, Level 16, State 1, Line 1 Table error: Object ID 0, index ID -1, partition ID 0, alloc u…

作者头像 李华