概述

Group Relative Policy Optimization (GRPO) 已成为训练推理模型(如DeepSeek-R1)的核心算法。本文介绍四种前沿扩展,分别针对特定场景优化:

方法核心关注关键创新效率提升
Latent-GRPO隐式空间RL流形感知优化质量提升
SPPO长程推理序列级 bandit5.9×
BPPO训练效率二值前缀选择6.08×
LamPO信用分配成对优势分解~1.5×

1. Latent-GRPO:隐式推理的GRPO

论文:arXiv:2604.27998

1.1 问题背景

隐式推理将中间推理步骤压缩到连续表示中,显著缩短推理链。但直接将GRPO应用于隐式空间会因概率密度和采样机制的差异而失败。

1.2 三个核心瓶颈

1. 内在隐式流形的缺失

无约束探索会推动rollouts离开有效流形,产生无法解码或正确评估的无效状态。

2. 探索-优化不对齐

轨迹级奖励(二值成功/失败)导致不正确的token级更新,模型无法区分哪些中间决策贡献了最终结果。

3. 隐式混合非闭合

当共同强化多条正确隐式路径时,对其平均化会产生无效的混合状态——与”正确路径的混合应该有效”的期望相矛盾。

1.3 关键创新

无效样本优势掩码

for each_sample in batch:
    if is_valid_latent(sample):  # 检查流形有效性
        compute_advantage(sample)
    else:
        mask_advantage(sample)  # 清零无效样本的优势

单侧噪声采样

只在保持流形有效性的方向添加噪声:

最优正确路径首token选择

当存在多条正确推理路径时,选择首token最优的路径:

correct_paths = [p for p in paths if p.reward == 1]
if correct_paths:
    optimal_path = min(correct_paths, key=lambda p: p.first_token_score)
    use_only(optimal_path)

1.4 实验结果

基准类别指标Latent-GRPO vs 隐式基线Latent-GRPO vs 显式GRPO
低难度 (GSM8K等)Pass@1+7.86分-
高难度 (AIME)Pass@1-+4.27分
链长度压缩率-3-4×更短

2. SPPO:序列级PPO

论文:arXiv:2604.08865,ACL 2026

2.1 问题背景

标准token级PPO在处理长链思维推理时存在:

  1. “尾部效应”:价值函数仅在序列末端附近区分正确/错误轨迹,中间步骤的优势信号噪声大或消失
  2. 内存成本:完整token级价值模型对大语言模型需要大量内存
  3. 多采样开销:GRPO通过每prompt采样N>1实现稳定,限制了吞吐量

2.2 核心洞察

GRPO的成功源于隐式地将推理视为序列级上下文 bandit。

整个推理链本质上是一个原子动作;prompt是上下文,最终的二值奖励对动作进行整体评估。

2.3 序列级上下文Bandit重构

标准PPO MDP:
    状态:s_t(位置t的token)
    动作:y_t(下一个token)
    奖励:仅终止时(r_T)
    
SPPO Bandit形式:
    上下文:s_p(仅prompt)
    动作:o(整个响应序列)
    奖励:仅终止时(r ∈ {0, 1})
    视野:1(概念上)

2.4 标量价值函数

SPPO使用单一标量critic而非token级价值:

通过二元交叉熵训练:

2.5 实验结果

模型:DeepSeek-R1-Distill-Qwen-7B

方法AIME24AIME25AMC23MATH500Minerva平均
Base45.2035.4285.3188.4827.8056.44
PPO45.2035.4285.3188.4827.8056.44
GRPO N=847.0835.0086.2590.1528.7457.44
SPPO50.8335.0086.2590.1328.3558.11
SPPO + 1.5B52.2934.5887.1989.8828.8658.56

训练效率:

  • SPPO在约22小时内达到峰值性能,而GRPO显著更长
  • 5.9×加速(相比N=8的GRPO)

3. BPPO:二值前缀策略优化

论文:arXiv:2605.28028

3.1 问题背景

GRPO更新每组采样的所有completion,产生:

  1. 大量计算成本 — 每prompt处理G个响应
  2. 冗长推理的强化 — 更长响应主导梯度更新
  3. 冗余学习信号 — 同类completion(全部正确或全部错误)产生相似梯度

3.2 关键观察:梯度相似性

在同一prompt组内:

  • 同类completion通常产生高度相似的更新方向
  • 正确-错误对提供更多不同的对比信号

3.3 关键创新

1. 二值前缀选择

不更新所有G个completion,而是选择两个代表性样本:

  • 最短正确completion ()
  • 最短错误completion ()
GRPO更新:    ∇θ Σ_{k=1}^{G} f(θ, o_k)
BPPO更新:    ∇θ [f(θ, o_c^{min}) + f(θ, o_i^{min})]

2. 自适应完成调度

if current_accuracy < threshold:
    sample_more_completions()  # 需要多样性信号
else:
    use_binary_prefix()  # 使用对比对微调

3. 前缀聚焦优化

不更新整个响应,而是聚焦于前缀:

# 只更新响应前缀(前T个token)
for response in [shortest_correct, shortest_incorrect]:
    prefix = response[:prefix_length]  # 通常30-50%的响应
    compute_gradient(prefix)

3.4 实验结果

基准:GSM8K, MATH, Geo3K

方法相对GRPO加速准确率响应长度
GRPO1× (基线)基线基线
BPPO6.08×持平缩短30-50%

4. LamPO:Lambda风格策略优化

论文:arXiv:2605.19416(已撤回,内容仍可获取)

4.1 问题背景

GRPO的标量基线(组均值)引入关系瓶颈

  1. 信息丢失:轨迹间丰富的关系拓扑被压缩为两个标量矩(μ, σ)
  2. 排列不变性:基线不区分哪些同伴表现更好或更差
  3. 高频抑制:细粒度排序和非对称性能差距被压制

4.2 核心洞察:LambdaRank启发

借鉴Learning-to-Rank文献(LambdaRank),LamPO将标量优势分解为成对比较

不说:“这个轨迹比均值高0.5个标准差”
LamPO计算:“这个轨迹比同伴A、B、C(不同地)好,但比D差”

4.3 关键创新

成对分解优势(PDA)

对于组内轨迹

其中:

  • :轨迹间的奖励差
  • :策略置信度差
  • :置信度加权
  • :温度超参数

4.4 实验结果

基准:AIME24, AIME25, MATH-500, GPQA-Diamond

方法AIME24MATH-500GPQA训练稳定性
GRPO基线基线基线中等
LamPO更高更高更高更稳定

5. 综合对比分析

5.1 方法对比矩阵

方面Latent-GRPOSPPOBPPOLamPO
主要目标隐式空间RL长程稳定性效率+简洁细粒度信用
核心创新流形感知优化序列级bandit二值前缀选择成对分解
理论基础隐式变量模型上下文bandit梯度相似性LambdaRank
样本效率取决于编码器N=1每组2个G个比较
内存效率类似GRPO减少12.8%减少50%+类似GRPO
输出长度缩短3-4×类似缩短30-50%类似
训练稳定性解决特定故障模式改善

5.2 与原始GRPO的关系

方法如何扩展GRPO
Latent-GRPO适配连续隐式空间的流形约束
SPPO使GRPO的隐式bandit结构显式化
BPPO通过智能采样减少GRPO的计算开销
LamPO将GRPO的标量基线丰富为关系结构

6. 代码实现

6.1 SPPO伪代码

#include <bits/stdc++.h>
using namespace std;
 
struct PolicyUpdate {
    vector<int> tokens;
    double log_prob;
    int reward;  // 0 or 1
};
 
double sppo_update(
    Policy& actor,
    Critic& critic,
    const vector<int>& prompt,
    const PolicyUpdate& response,
    double epsilon = 0.2
) {
    // 1. 序列级优势
    double value_estimate = critic.forward(prompt);  // V(s_p)
    double advantage = response.reward - value_estimate;
    
    // 2. 更新critic(使用BCE)
    double critic_loss = -(
        response.reward * log(value_estimate + 1e-8) +
        (1 - response.reward) * log(1 - value_estimate + 1e-8)
    );
    critic.backward(critic_loss);
    
    // 3. 更新actor(使用裁剪PPO,但优势是序列级的)
    double total_loss = 0.0;
    for (int i = 0; i < response.tokens.size(); i++) {
        double ratio = actor.log_prob(response.tokens[i]) / 
                       old_actor.log_prob(response.tokens[i]);
        double clipped = clamp(ratio, 1 - epsilon, 1 + epsilon);
        
        double token_loss = -min(
            ratio * advantage,  // 序列级优势应用于所有token
            clipped * advantage
        );
        total_loss += token_loss;
    }
    
    actor.backward(total_loss);
    return total_loss;
}

6.2 BPPO伪代码

struct BPPOConfig {
    int group_size = 16;
    double epsilon = 0.2;
    double prefix_ratio = 0.4;  // 使用前40%的token
};
 
double bppo_update(
    Policy& policy,
    RewardModel& reward_model,
    const vector<int>& prompt,
    const BPPOConfig& config
) {
    // 1. 采样完整组
    vector<PolicyUpdate> responses;
    vector<double> rewards;
    for (int i = 0; i < config.group_size; i++) {
        auto response = policy.sample(prompt);
        double reward = reward_model.check(response);
        responses.push_back(response);
        rewards.push_back(reward);
    }
    
    // 2. 计算组统计量(用于归一化)
    double mu = accumulate(rewards.begin(), rewards.end(), 0.0) / rewards.size();
    double sigma = 0.0;
    for (double r : rewards) sigma += (r - mu) * (r - mu);
    sigma = sqrt(sigma / rewards.size()) + 1e-8;
    
    // 3. 选择二值对
    vector<PolicyUpdate*> correct, incorrect;
    for (int i = 0; i < responses.size(); i++) {
        if (rewards[i] == 1.0) correct.push_back(&responses[i]);
        else incorrect.push_back(&responses[i]);
    }
    
    // 找最短的
    auto shortest = [](const vector<PolicyUpdate*>& v) {
        return *min_element(v.begin(), v.end(), 
            [](PolicyUpdate* a, PolicyUpdate* b) {
                return a->tokens.size() < b->tokens.size();
            });
    };
    
    PolicyUpdate* shortest_correct = correct.empty() ? nullptr : shortest(correct);
    PolicyUpdate* shortest_incorrect = incorrect.empty() ? nullptr : shortest(incorrect);
    
    // 4. 计算梯度
    double total_loss = 0.0;
    
    auto update_on_prefix = [&](PolicyUpdate* resp, bool is_correct) {
        if (!resp) return;
        
        // 计算前缀长度
        int prefix_len = int(resp->tokens.size() * config.prefix_ratio);
        
        // 计算优势
        double adv = is_correct ? (1.0 - mu) / sigma : (0.0 - mu) / sigma;
        
        // 计算前缀上的损失
        for (int i = 0; i < prefix_len; i++) {
            double ratio = policy.log_prob(resp->tokens[i]) / 
                          old_policy.log_prob(resp->tokens[i]);
            double clipped = clamp(ratio, 1 - config.epsilon, 1 + config.epsilon);
            
            double loss = -min(ratio * adv, clipped * adv);
            total_loss += loss;
        }
    };
    
    update_on_prefix(shortest_correct, true);
    update_on_prefix(shortest_incorrect, false);
    
    return total_loss;
}

7. 选择指南

使用决策树

你的模型使用隐式/连续表示吗?
├─ 是 → Latent-GRPO
└─ 否 ↓
训练效率是主要约束吗?
├─ 是 → BPPO(如果同时需要简洁性)
└─ 否 ↓
你有长推理链(>1000 token)吗?
├─ 是 → SPPO(稳定性和内存效率)
└─ 否 ↓
细粒度信用分配重要吗?
├─ 是 → LamPO
└─ 否 → GRPO(标准)

各方法最佳场景

方法最佳使用场景
Latent-GRPO隐式推理模型、推理链压缩、有限推理成本
SPPO长链思维推理、有限GPU内存、高吞吐量需求
BPPO训练效率至关重要、减少响应冗长、推理成本约束
LamPO排名敏感任务、细粒度信用分配、AIME等难题微调

8. 参考