Loading...
正在加载...
请稍候

PPO → DPO → GRPO 的完整技术演进路径

✨步子哥 (steper) 2026年03月12日 01:20

一、核心概念与演进脉络

这三种方法是 LLM 对齐(Alignment) 技术的三代范式演进:

维度 PPO (2017/2023) DPO (2023) GRPO (2024)
核心思想 在可信区域内小步更新策略,最大化奖励模型分数 将偏好数据直接转化为分类损失,绕过奖励建模 通过组内回答的相对好坏估计优势,无需价值模型
模型数量 4个(Actor + Critic + Reward Model + Ref) 2个(策略模型 + Ref) 3个(策略模型 + Reward + Ref)
计算成本 最高 最低 中等
数据需求 绝对分数奖励 成对偏好数据(chosen/rejected) 可验证奖励(对错/分数)
稳定性 中等(需调 GAE 参数) 高(自动归一化优势)

演进逻辑:PPO 是通用 RL 工具 → DPO 发现奖励模型与策略的对偶性,极简实现 → GRPO 针对 PPO 的 Critic 内存瓶颈,用组内相对排名替代绝对价值估计。


二、PPO:工业级 RLHF 基石

2.1 算法原理

PPO 是 On-policy 强化学习算法,核心约束是策略更新不能偏离旧策略太远(Trust Region)。

关键组件

  • Actor:生成回答的策略模型 \(\pi_\theta\)
  • Critic:价值模型 \(V(s)\),预估当前状态的期望回报
  • Reward Model:给完整回答打分 \(r_\theta\)
  • Reference Model:冻结的 SFT 模型,计算 KL 散度防止跑偏

损失函数(Clip 机制):

\[L^{CLIP}(\theta) = \mathbb{E}_t \left[ \min\left(r_t(\theta)A_t, \text{clip}(r_t(\theta), 1-\epsilon, 1+\epsilon)A_t\right) \right]\]

其中 \(r_t(\theta) = \frac{\pi_\theta(a_t|s_t)}{\pi_{old}(a_t|s_t)}\) 是新旧策略比率,\(A_t\) 是优势函数。

优势估计(GAE)

\[A_t^{GAE} = \sum_{k=0}^{\infty}(\gamma\lambda)^k\delta_{t+k}, \quad \delta_t = R_t + \gamma V(s_{t+1}) - V(s_t)\]

2.2 训练流程

# 伪代码:完整 PPO Step 
for epoch in range(ppo_epochs):
    # Step 1: Rollout 生成数据
    with torch.no_grad():
        seq = actor.generate(prompts)
        old_log_probs = actor(seq)           # 旧策略 log prob
        ref_log_probs = ref_model(seq)       # 参考模型 log prob
        values = critic(seq)                 # 价值估计
        reward_score = reward_model(seq)     # 奖励模型打分
    
    # Step 2: 计算 Reward(含 KL 惩罚)
    kl_div = old_log_probs - ref_log_probs
    rewards = reward_score - beta * kl_div   # Token-level KL 修正
    
    # Step 3: GAE 计算优势函数
    advantages, returns = compute_gae(rewards, values, gamma=0.99, lam=0.95)
    
    # Step 4: PPO 更新(多次 epoch)
    for batch in dataloader:
        new_log_probs = actor(batch.seq)
        ratio = torch.exp(new_log_probs - batch.old_log_probs)
        
        # PPO Clip Loss
        surr1 = ratio * batch.advantages
        surr2 = torch.clamp(ratio, 1-eps, 1+eps) * batch.advantages
        actor_loss = -torch.min(surr1, surr2).mean()
        
        # Critic Loss
        critic_loss = (critic(batch.seq) - batch.returns).pow(2).mean()
        
        loss = actor_loss + 0.5 * critic_loss
        loss.backward()
        optimizer.step()

2.3 实践要点

  • KL 散度系数 \(\beta\):通常 0.01-0.1,防止模型崩溃(Reward Hacking)
  • GAE 参数\(\gamma=0.99\), \(\lambda=0.95\) 是通用配置,\(\lambda\) 越小偏差越大方差越小
  • Critic 学习率:通常比 Actor 小一个数量级,稳定训练

三、DPO:极简对齐范式

3.1 核心洞察

DPO 发现:最优策略 \(\pi^*\) 与奖励函数 \(r\) 存在闭式解关系(Bradley-Terry 模型):

\[r(x,y) = \beta \log\frac{\pi^*(y|x)}{\pi_{ref}(y|x)} + \beta \log Z(x)\]

因此可以直接从偏好数据优化策略,无需训练奖励模型和 Critic

3.2 损失函数

对于偏好对 \((y_w, y_l)\)(win vs lose):

\[\mathcal{L}_{DPO} = -\mathbb{E}_{(x,y_w,y_l)\sim\mathcal{D}} \left[ \log\sigma\left(\beta\log\frac{\pi_\theta(y_w|x)}{\pi_{ref}(y_w|x)} - \beta\log\frac{\pi_\theta(y_l|x)}{\pi_{ref}(y_l|x)}\right) \right]\]

直观理解:最大化偏好回答与拒绝回答的对数似然比差距,同时用 \(\beta\) 控制与参考模型的偏离程度。

3.3 数据格式与代码

# DPO 数据格式 
{
  "prompt": "解释什么是机器学习",
  "chosen": "机器学习是让计算机从数据中自动学习规律...",
  "rejected": "机器学习就是让机器变聪明..."
}

# DPO 核心实现(简化)
def dpo_loss(policy_logps, ref_logps, labels, beta=0.1):
    """
    policy_logps: 策略模型对 chosen/rejected 的 log prob
    ref_logps: 参考模型的 log prob
    labels: 1 for chosen, 0 for rejected
    """
    # 计算 log ratios
    policy_ratio = policy_logps - ref_logps
    
    # 分离 chosen 和 rejected
    policy_chosen = policy_ratio[labels == 1]
    policy_rejected = policy_ratio[labels == 0]
    
    # DPO loss: 让 chosen 的 ratio 远大于 rejected
    logits = beta * (policy_chosen - policy_rejected)
    loss = -F.logsigmoid(logits).mean()
    return loss

3.4 变体与技巧

  • cDPO(保守 DPO):引入 label_smoothing 处理标注噪声
  • IPO(身份偏好优化):对长序列平均 log 似然,缓解长度偏见
  • ORPO:将 SFT 和 DPO 合并为单阶段训练,节省计算资源

四、GRPO:DeepSeek 的组相对优化

4.1 动机与核心思想

PPO 的痛点

  1. Critic 模型与 Actor 同量级,显存占用翻倍
  2. 价值函数估计误差会放大优势方差,导致训练不稳定
  3. 奖励模型通常基于对比数据训练,但 PPO 使用绝对分数,存在分布错位

GRPO 解决方案

  • 废弃 Critic:对同一问题采样 \(G\) 个回答,用组内相对奖励估计优势
  • 归一化优势\(A_{i,t} = \frac{R_i - \text{mean}(\{R_j\})}{\text{std}(\{R_j\})}\),自动零均值单位方差
  • 适合可验证奖励:数学题(对错)、代码(执行结果)、格式检查(规则匹配)

4.2 算法详解

对于每个问题 \(q\),采样 \(G\) 个输出 \(\{o_1, o_2, ..., o_G\}\)

优势计算

\[\hat{A}_{i,t} = \frac{R_i - \text{mean}(\{R_1, ..., R_G\})}{\text{std}(\{R_1, ..., R_G\})}\]

其中 \(R_i\) 可以是规则验证的 0/1 奖励,或奖励模型分数。

GRPO 目标函数

\[J_{GRPO}(\theta) = \mathbb{E}_{q\sim P(Q),\{o_i\}_{i=1}^G\sim\pi_{\theta_{old}}(O|q)} \left[ \frac{1}{G}\sum_{i=1}^G \frac{1}{|o_i|}\sum_{t=1}^{|o_i|} \left( \min\left(r_{i,t}(\theta)\hat{A}_{i,t}, \text{clip}(r_{i,t}(\theta), 1-\epsilon, 1+\epsilon)\hat{A}_{i,t}\right) - \beta D_{KL}(\pi_\theta||\pi_{ref}) \right) \right]\]

与 PPO 关键差异

  • PPO 优势:\(A_t = R_t + \gamma V(s_{t+1}) - V(s_t)\)(依赖 Critic)
  • GRPO 优势:\(A_i = R_i - \bar{R}\)(组内相对排名)

4.3 代码实现

# GRPO 训练步骤(基于 DeepSeek 实现)
def grpo_step(batch, actor, ref_model, reward_fn, G=4, beta=0.1, eps=0.2):
    """
    batch: 输入问题
    G: 每组采样数量
    """
    prompts = batch['prompt']
    
    # 1. 对每个 prompt 采样 G 个回答
    outputs = []
    for _ in range(G):
        out = actor.generate(prompts, max_length=512)
        outputs.append(out)
    
    # 2. 计算奖励(可验证奖励或模型打分)
    rewards = []
    for out in outputs:
        r = reward_fn(out)  # 例如:数学答案是否正确(0 或 1)
        rewards.append(r)
    rewards = torch.stack(rewards)  # (G, batch_size)
    
    # 3. 计算组内相对优势(关键!)
    mean_rewards = rewards.mean(dim=0, keepdim=True)
    std_rewards = rewards.std(dim=0, keepdim=True) + 1e-8
    advantages = (rewards - mean_rewards) / std_rewards  # 归一化
    
    # 4. 计算 GRPO loss(类似 PPO clip,但用相对优势)
    total_loss = 0
    for i in range(G):
        # 新策略 log prob
        new_log_probs = actor(outputs[i], return_log_probs=True)
        with torch.no_grad():
            old_log_probs = actor(outputs[i], return_log_probs=True)
            ref_log_probs = ref_model(outputs[i], return_log_probs=True)
        
        # 策略比率
        ratio = torch.exp(new_log_probs - old_log_probs)
        
        # Clip 损失
        surr1 = ratio * advantages[i]
        surr2 = torch.clamp(ratio, 1-eps, 1+eps) * advantages[i]
        policy_loss = -torch.min(surr1, surr2).mean()
        
        # KL 散度(在 loss 中直接加,而非 reward 中)
        kl_div = new_log_probs - ref_log_probs
        kl_loss = beta * kl_div.mean()
        
        total_loss += policy_loss + kl_loss
    
    return total_loss / G

4.4 最新进展(2024-2025)

Hybrid GRPO :结合 PPO 的价值函数和 GRPO 的组采样

  • 保留轻量级 Critic 作为基线,同时使用组内多样本估计
  • 优势函数:\(A_T = \frac{1}{N}\sum_{t=1}^N[\tilde{R}_T^{(t)} + \gamma V(s_{T+1}^{(t)}) - V(s_T)]\)
  • 在稀疏奖励环境下比原版 GRPO 更稳定

应用场景扩展

  • 多模态:VAR 视觉模型、扩散模型对齐(G²RPO)
  • 语音:ASR 错误率降低 18.4%,减少幻觉
  • 多智能体:GRPO-GCC 引入全局合作约束

五、方法选型决策树

选型建议

  • PPO:需要细粒度控制、复杂奖励函数、长期依赖任务(多轮对话)
  • DPO:快速原型、主观偏好对齐、计算资源受限
  • GRPO:数学/代码等可验证任务、显存瓶颈严重、需要高多样性探索

六、从入门到精通的学习路径

Level 1:理论理解(1-2 周)

  1. 强化学习基础:理解 Policy Gradient、Advantage Actor-Critic
  2. 读原始论文

Level 2:代码实践(2-3 周)

  1. 手撕 PPO:用 PyTorch 实现简化版 PPO,理解 GAE 计算
  2. DPO 微调:使用 trlllama-factory 对 7B 模型进行 DPO 训练
  3. GRPO 实验:在 GSM8K 数学数据集上复现 GRPO,对比 PPO 的显存占用

Level 3:进阶优化(持续)

  • 混合策略:先用 DPO 预热,再用 GRPO 强化(DeepSeek-R1 策略)
  • 长度归一化:解决 DPO/GRPO 的长度偏见(Length Bias)
  • 迭代训练:Online DPO / Iterative GRPO,使用模型自生成数据迭代优化

推荐资源


总结:PPO 是通用强大的"重武器",DPO 是简洁优雅的"轻量级方案",GRPO 则是针对可验证任务的"高效专精工具"。掌握三者的差异和联系,能根据任务特性灵活选择,是 LLM 对齐工程师的核心能力。

讨论回复

0 条回复

还没有人回复,快来发表你的看法吧!

推荐
智谱 GLM-5 已上线

我正在智谱大模型开放平台 BigModel.cn 上打造 AI 应用,智谱新一代旗舰模型 GLM-5 已上线,在推理、代码、智能体综合能力达到开源模型 SOTA 水平。

领取 2000万 Tokens 通过邀请链接注册即可获得大礼包,期待和你一起在 BigModel 上畅享卓越模型能力
登录