概述
Group Policy Gradient(GPG)是由阿里巴巴AMAP团队提出的简单强化学习方法,专为大语言模型(LLM)的推理优化设计。1与PPO和GRPO相比,GPG进一步简化:无需价值网络(critic)、无需KL惩罚、无需参考模型,仅依靠组内共享baseline实现方差缩减。
核心洞察:对于LLM推理任务,同一问题的多个采样响应天然构成一个”组”,利用组内相对奖励即可实现高效学习。
GPG引入
简单基线设计
传统RL算法对LLM的训练复杂度高:
| 方法 | Critic | 参考模型 | KL惩罚 | 实现复杂度 |
|---|---|---|---|---|
| PPO | 必须 | 必须 | 可选 | 高 |
| GRPO | 可选 | 可选 | 可选 | 中 |
| GPG | 无需 | 无需 | 无需 | 低 |
GPG的三大”无需”:
- 无需Critic:不使用价值函数估计未来奖励
- 无需KL惩罚:不约束与预训练模型的偏离
- 无需参考模型:训练更加稳定
核心思想
GPG的核心是组内样本共享baseline:
问题 q: "计算 23 × 47"
┌─────────────────────────────────────┐
│ 组内采样 (Group Size = 4) │
├─────────────────────────────────────┤
│ 响应1: "2601" 奖励: 0 ❌ │
│ 响应2: "1041" 奖励: 0 ❌ │
│ 响应3: "1081" 奖励: 1 ✓ │
│ 响应4: "1081" 奖励: 1 ✓ │
├─────────────────────────────────────┤
│ 组内均值 baseline = 0.5 │
│ 优势 = 奖励 - baseline │
└─────────────────────────────────────┘
数学框架
Group Policy Gradient估计器
给定一个问题 和组内采样 ,GPG的梯度估计为:
其中:
- 是第 组内采样序列的token索引集合
- 是第 个采样的奖励
- 是组内奖励均值(baseline)
优势函数推导
令 ,则:
因此 是一个无偏baseline:
这保证了梯度估计的无偏性。
与GRPO的关系
GRPO使用组内归一化优势:
GPG使用组内去均值优势:
关键区别:
- GRPO:保持优势方差为1,适合自适应学习率
- GPG:保留原始优势尺度,适合固定学习率
方差缩减分析
定理(方差缩减):设 ,组内相关系数为 ,则GPG梯度方差为:
其中 是组内奖励的相关系数。
直觉:同一问题下,奖励具有结构相关性(有的问题难,有的简单)。组内baseline消除了这种相关性带来的方差。
def gpg_gradient(policy, prompts, responses_group, rewards_group):
"""
计算GPG梯度
参数:
policy: 策略模型
prompts: 问题列表 [B]
responses_group: 组内响应 [B, G, T]
rewards_group: 组内奖励 [B, G]
"""
B, G = len(prompts), len(responses_group[0])
total_loss = 0.0
for b in range(B):
prompt = prompts[b]
rewards = rewards_group[b]
# 组内baseline
baseline = rewards.mean() # b_g
for g in range(G):
response = responses_group[b][g]
reward = rewards[g]
# 优势
advantage = reward - baseline
# 策略梯度
log_prob = policy.log_prob(response, prompt)
loss = -advantage * log_prob.mean() # 注意负号(梯度上升)
total_loss += loss
return total_loss / (B * G)与GRPO的理论联系
IBM Research的理论分析 (2025)
IBM Research对GRPO提供了严格的理论框架,与GPG密切相关。2
定理(GRPO作为On-policy PG):设 是参考策略,则GRPO等价于on-policy策略梯度加组baseline:
其中 是组归一化优势。
Mean+Variance Calibrated Reward
为处理奖励不确定性,引入均值-方差校准奖励:
其中 是组内奖励的标准差, 是不确定性惩罚系数。
理论性质:
| 性质 | GRPO | GPG + Calibrated |
|---|---|---|
| 无偏性 | ✓ | ✓ |
| 方差缩减 | ✓ | ✓✓ |
| 奖励不确定性处理 | ✗ | ✓ |
On-policy vs Off-policy GRPO变体
严格On-policy GRPO:
class OnPolicyGRPO:
"""严格On-policy GRPO(等价于GPG with normalization)"""
def __init__(self, model, reward_model, group_size=4, epsilon=0.2):
self.model = model
self.reward_model = reward_model
self.group_size = group_size
self.epsilon = epsilon
def step(self, prompts):
# 1. 组内采样(On-policy)
responses = []
log_probs_old = []
for prompt in prompts:
group = []
group_log_probs = []
for _ in range(self.group_size):
response, log_prob = self.model.sample(prompt)
group.append(response)
group_log_probs.append(log_prob)
responses.append(group)
log_probs_old.append(group_log_probs)
# 2. 奖励评估
rewards = [self.reward_model(prompt, group)
for prompt, group in zip(prompts, responses)]
# 3. 组归一化优势
advantages = []
for r in rewards:
mu, sigma = np.mean(r), np.std(r) + 1e-8
adv = [(ri - mu) / sigma for ri in r]
advantages.append(adv)
# 4. PPO更新
self.update(prompts, responses, log_probs_old, advantages)
def update(self, prompts, responses, old_log_probs, advantages):
# 计算新的log概率和损失
# ...
passOff-policy GRPO(带重要性采样):
泛化Policy Gradient定理
Transformer策略的PG定理
Mao等人将标准策略梯度定理推广到基于Transformer的策略。3
泛化PG定理:设 是由Transformer参数化的策略,则:
其中 是Transformer的隐状态, 是任一无偏优势估计。
KV-Cache存在下的梯度推导
LLM推理中,KV-Cache保存了已生成token的Key-Value对,这对梯度计算有重要影响。
问题:KV-Cache导致梯度计算复杂:
- 前向传播:(使用cache)
- 反向传播:需要保存所有中间激活
解决方案:分离策略梯度与KV-Cache更新:
class TransformerPG:
"""带KV-Cache的Transformer策略梯度"""
def compute_gradient(self, prompt, response, reward):
"""
计算带KV-Cache的策略梯度
关键点:
1. 前向:使用KV-Cache加速
2. 反向:需要recompute中间激活
"""
T = len(response)
# 1. KV-Cache前向传播
with torch.no_grad():
cache = self.model.init_cache()
for t in range(T):
logits, cache = self.model.forward(
response[t],
cache=cache,
use_cache=True
)
# 2. 计算log概率(需要recompute)
log_probs = []
cache = self.model.init_cache()
for t in range(T):
# Recompute以获取梯度
logits, cache = self.model.forward(
response[t],
cache=cache,
use_cache=False # 关闭cache以获取梯度
)
log_probs.append(torch.log_softmax(logits, dim=-1)[0, response[t]])
total_log_prob = sum(log_probs)
# 3. 策略梯度
loss = -reward * total_log_prob
loss.backward()
return self.model.parameters()与标准PG、GRPO的统一
┌─────────────────────────────────────────────────────────────┐
│ 策略梯度统一框架 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 标准PG: ∇J = E[∇log π(a|s) · G] │
│ │ │
│ ▼ │
│ 带Baseline: ∇J = E[∇log π(a|s) · (G - V(s))] │
│ │ │
│ ▼ │
│ GPG/GRPO: ∇J = E[∇log π(o|q) · (r(o) - μ_group)] │
│ │ │
│ ▼ │
│ PPO: ∇J = E[∇log π(a|s) · min(r̂·A, clip·A)] │
│ │
└─────────────────────────────────────────────────────────────┘
关键统一点:
- 基准线(baseline)是方差缩减的核心工具
- 组内baseline是问题级别(question-level)的自然选择
- 裁剪是对策略更新的稳定化手段
实验验证
MATH/AIME基准测试
GPG在数学推理任务上的表现:1
| 方法 | MATH (%) | AIME (%) | 参数量 | 训练时间 |
|---|---|---|---|---|
| SFT | 51.9 | 35.7 | 7B | 1× |
| PPO | 56.2 | 40.1 | 7B + 7B(Critic) | 3× |
| GRPO | 58.8 | 44.3 | 7B | 1.5× |
| GPG | 59.4 | 46.8 | 7B | 1.2× |
观察:
- GPG在减少计算的同时取得最优性能
- 无KL惩罚不会导致reward hacking
- 组内baseline有效控制了方差
与PPO/GRPO的对比
训练稳定性对比:
Reward
│
│ ╭── GPG (稳定上升)
│ ╱
│ ╱ ╭── GRPO (有波动)
│ ╱ ╱
│╱ ╱
├──────────────
│ PPO (收敛慢)
└─────────────────────────── Steps
方差对比:
| 方法 | 梯度方差 | 奖励方差 | 训练稳定性 |
|---|---|---|---|
| PPO | 中 | 中 | 高 |
| GRPO | 低 | 低 | 中 |
| GPG | 最低 | 低 | 最高 |
Ablation Studies
def ablation_group_size():
"""
组大小消融实验
"""
results = {}
for G in [2, 4, 8, 16, 32]:
agent = GPGAgent(group_size=G)
rewards = train(agent)
results[G] = {
'final_reward': rewards[-1],
'stability': np.std(rewards[-100:]),
'sample_efficiency': compute_efficiency(rewards)
}
# 结果可视化
# G=4-8 是最佳平衡点
return results发现:
- :退化为标准PG,方差大
- :方差显著降低
- :边际收益递减,计算成本增加
实践指南
超参数推荐
| 超参数 | 推荐值 | 说明 |
|---|---|---|
| 组大小 | 4-8 | 数学推理任务 |
| 学习率 | 预训练模型微调 | |
| Token长度 | 512-1024 | MATH任务 |
| Batch Size | 8-32 | 根据显存调整 |
代码模板
import torch
from typing import List, Tuple
class GPGTrainer:
"""Group Policy Gradient Trainer"""
def __init__(
self,
policy: torch.nn.Module,
reward_model,
group_size: int = 4,
lr: float = 1e-5,
max_grad_norm: float = 1.0
):
self.policy = policy
self.reward_model = reward_model
self.group_size = group_size
self.optimizer = torch.optim.AdamW(policy.parameters(), lr=lr)
self.max_grad_norm = max_grad_norm
def step(self, prompts: List[str]) -> dict:
"""
单步训练
1. 组内采样
2. 奖励评估
3. GPG梯度更新
"""
# 1. 组内采样
responses_group = []
log_probs_group = []
for prompt in prompts:
responses, log_probs = self._group_sample(prompt)
responses_group.append(responses)
log_probs_group.append(log_probs)
# 2. 奖励评估
rewards_group = []
for prompt, responses in zip(prompts, responses_group):
rewards = [self.reward_model(prompt, resp) for resp in responses]
rewards_group.append(rewards)
# 3. 计算GPG损失
loss = self._compute_gpg_loss(
prompts, responses_group, log_probs_group, rewards_group
)
# 4. 反向传播
self.optimizer.zero_grad()
loss.backward()
torch.nn.utils.clip_grad_norm_(self.policy.parameters(), self.max_grad_norm)
self.optimizer.step()
return {'loss': loss.item()}
def _group_sample(self, prompt: str) -> Tuple[List, List]:
"""组内采样"""
responses = []
log_probs = []
for _ in range(self.group_size):
response, lp = self.policy.generate(prompt)
responses.append(response)
log_probs.append(lp)
return responses, log_probs
def _compute_gpg_loss(
self,
prompts,
responses_group,
log_probs_group,
rewards_group
) -> torch.Tensor:
"""计算GPG损失"""
total_loss = 0.0
n_total = 0
for prompt, responses, log_probs, rewards in zip(
prompts, responses_group, log_probs_group, rewards_group
):
# 组内baseline
baseline = sum(rewards) / len(rewards)
for resp, lp, r in zip(responses, log_probs, rewards):
# 优势 = 奖励 - baseline
advantage = r - baseline
# GPG梯度
loss = -advantage * lp.mean()
total_loss += loss
n_total += 1
return total_loss / n_total相关内容
- GRPO:组相对策略优化的详细讨论
- PPO:近端策略优化算法
- RLHF:人类反馈强化学习
- 策略梯度定理:理论基础
- Actor-Critic框架:方差缩减方法