news 2026/4/12 17:02:07

大模型强化学习: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/4/12 13:20:50

cpu异常中断(2)

一、寄存器映射 内核里面的cpu主要通过D-Bus,I-Bus,S-Bus与外设沟通&#xff0c;其中S-Bus是主要用来访问外设的 当我们访问一个外设地址时&#xff0c;数据会从cpu然后通过S-Bus再到AHB总线矩阵&#xff0c;经过某些处理到达APB(挂载着外设) 但APB_BUS也不知道这个地址是什么…

作者头像 李华
网站建设 2026/4/10 10:55:43

5个Kronos高效使用技巧:从入门到精通的完整指南

5个Kronos高效使用技巧&#xff1a;从入门到精通的完整指南 【免费下载链接】Kronos Kronos: A Foundation Model for the Language of Financial Markets 项目地址: https://gitcode.com/GitHub_Trending/kronos14/Kronos Kronos作为金融市场的语言基础模型&#xff0c…

作者头像 李华
网站建设 2026/4/9 12:28:15

Qwen-Edit多角度插件完全攻略:12种视角变换让创意效率翻倍

Qwen-Edit多角度插件完全攻略&#xff1a;12种视角变换让创意效率翻倍 【免费下载链接】Qwen-Edit-2509-Multiple-angles 项目地址: https://ai.gitcode.com/hf_mirrors/dx8152/Qwen-Edit-2509-Multiple-angles 还在为单一视角的图像创作而烦恼&#xff1f;Qwen-Edit-2…

作者头像 李华
网站建设 2026/4/12 22:48:01

POML终极指南:5步构建企业级AI应用的完整方案

POML终极指南&#xff1a;5步构建企业级AI应用的完整方案 【免费下载链接】poml Prompt Orchestration Markup Language 项目地址: https://gitcode.com/GitHub_Trending/po/poml 还在为AI应用开发中复杂的提示工程和系统集成而头疼吗&#xff1f;POML&#xff08;Promp…

作者头像 李华
网站建设 2026/4/12 3:54:06

应该怎么开始学习大(型语言)模型?

想要学习LLM&#xff08;大型语言模型&#xff09;&#xff0c;首先要对LLM有一定的了解&#xff0c;知道LLM的基本概念和使用。因此&#xff0c;对于每一位初学者&#xff0c;首先都需要学习一些LLM的入门课程&#xff0c;包括基础的 Python 语法&#xff08;因为 LLM 目前基本…

作者头像 李华
网站建设 2026/4/11 6:33:37

【开题答辩全过程】以 高校教学质量监控平台为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人&#xff0c;语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

作者头像 李华