瓶颈:PPO 的显存重负与 DPO 的局限
多年来,Proximal Policy Optimization (PPO) 一直是 RLHF(人类反馈强化学习)的黄金标准。然而,它带来了巨大的基础设施负担:你需要同时在显存中加载四个模型(Actor、Critic、Reference 和 Reward Model)。对于 70B+ 参数的模型来说,除非是头部大厂,否则微调成本高不可攀。
Direct Preference Optimization (DPO) 通过移除强化学习循环,将对齐视为对偏好对(Preference Pairs)的监督分类问题,从而解决了显存问题。但是,DPO 在思维链(Chain-of-Thought, CoT)优化方面表现乏力。它依赖于静态数据集,无法像 RL 那样内在地鼓励模型去探索不同的推理路径。
这就轮到 Group Relative Policy Optimization (GRPO) 登场了。随着 DeepSeek R1/V3 研究 的普及,GRPO 彻底移除了 Critic 模型。它不再估计价值函数(Value Function),而是针对同一个提示词生成一组输出,计算奖励,并利用组平均值作为基线(Baseline)。这种方法在大幅降低显存占用的同时,保留了 RL 的探索优势,使其成为优化数学和代码推理能力的最佳选择。
架构逻辑:GRPO 如何消灭价值函数
在标准的 PPO 中,优势函数(Advantage function) $A_t$ 的计算依赖于一个价值网络(Critic)。GRPO 则用一组采样输出的平均奖励来替代它。
算法流程
- 采样 (Sampling): 对于每个提示词 $q$,从旧策略 $\pi_{\theta_{old}}$ 中采样一组 $G$ 个输出 ${o_1, o_2, …, o_G}$。
- 打分 (Scoring): 应用奖励模型(或基于规则的验证器)获得奖励 $r_1, …, r_G$。
- 优势计算 (Advantage Calculation): 基于组内的相对表现计算每个输出的优势值。
- 优化 (Optimization): 最大化 GRPO 目标函数,其中包括 KL 散度惩罚,以保持模型不偏离参考策略太远。
工作流可视化
graph TD
subgraph "GRPO 工作流"
A["输入提示词 (q)"] --> B{"策略模型 (Policy)"}
B --"采样 G 个输出"--> C["输出集 {o1, o2... oG}"]
C --> D["奖励函数 / 验证器"]
D --"计算奖励"--> E["计算组均值 & 标准差"]
E --> F["计算优势值 (Ai)"]
F --> G["更新策略 (无 Critic 网络)"]
end
subgraph "传统 PPO"
X["输入"] --> Y["Actor"]
X --> Z["Critic (价值网络)"]
Y --> R["奖励模型"]
R & Z --> CALC["GAE 估计"]
end
代码实现
我们将使用 Hugging Face TRL (Transformer Reinforcement Learning) 库来实现 GRPO,该库近期已集成了对组相对策略的支持。
前置条件
- 硬件: 单张 A100 (80GB) 或同等显存,足以训练 7B-14B 模型。GRPO 非常节省显存。
- 依赖库:
trl>=0.11.0,transformers,torch。
Python 实现脚本
本脚本演示了如何使用确定性奖励函数(即“验证器”)而非神经奖励模型来对齐模型以解决数学问题。这复刻了 DeepSeek-Math 的核心思路。
import torch
from datasets import load_dataset
from trl import GRPOTrainer, GRPOConfig
from transformers import AutoTokenizer, AutoModelForCausalLM
# 1. 配置
# 注意:我们不需要加载 Critic 模型
MODEL_ID = "deepseek-ai/deepseek-coder-6.7b-instruct"
OUTPUT_DIR = "./grpo-reasoning-adapter"
training_args = GRPOConfig(
output_dir=OUTPUT_DIR,
num_train_epochs=1,
per_device_train_batch_size=4,
gradient_accumulation_steps=2,
learning_rate=5e-6,
beta=0.04, # KL 惩罚系数
max_grad_norm=1.0,
logging_steps=10,
save_strategy="steps",
# GRPO 特有参数
num_generations=8, # 组大小 (G)。越大基线估计越准,但显存开销越大。
max_completion_length=512,
bf16=True
)
# 2. 奖励函数 (验证器)
# 在此场景中,我们使用简单的算术检查器。
# 在生产环境中,这里应该解析模型的 <answer> 标签并与标准答案(Ground Truth)对比。
def arithmetic_reward_func(prompts, completions, answer, **kwargs):
rewards = []
for comp, true_ans in zip(completions, answer):
# 启发式规则:检查标准答案数字是否出现在输出中
# DeepSeek 在这里使用了更严格的解析逻辑
score = 1.0 if str(true_ans) in comp else 0.0
# 行为整形 (Shaping):如果答案错误且废话连篇,给予额外惩罚
if score == 0.0 and len(comp) > 200:
score -= 0.1
rewards.append(score)
return rewards
# 3. 加载数据与模型
dataset = load_dataset("gsm8k", "main", split="train[:1%]") # 仅使用极小集用于演示
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
tokenizer.pad_token = tokenizer.eos_token
# 加载 4-bit 模型以进一步节省显存(如需)
model = AutoModelForCausalLM.from_pretrained(
MODEL_ID,
torch_dtype=torch.bfloat16,
device_map="auto",
attn_implementation="flash_attention_2"
)
# 4. 初始化 GRPO Trainer
trainer = GRPOTrainer(
model=model,
reward_processing_class=tokenizer, # 内部处理 Tokenization
args=training_args,
train_dataset=dataset,
reward_funcs=arithmetic_reward_func, # 支持多个奖励函数
)
# 5. 执行训练
if __name__ == "__main__":
print(f"Starting GRPO with Group Size: {training_args.num_generations}")
trainer.train()
trainer.save_model(OUTPUT_DIR)
实现步骤详解
- 定义验证器 (Verifier): 与需要偏好数据集(Chosen vs Rejected)的 DPO 不同,GRPO 需要提示词和标准答案。
reward_funcs的逻辑至关重要。对于代码任务,这里运行单元测试;对于数学任务,这里检查数值等价性。 - 设置组大小 ($G$): 在
GRPOConfig中,num_generations参数控制 $G$。- 低 $G$ (如 4): 优势估计方差大,训练不稳定。
- 高 $G$ (如 16+): 基线更准,但训练时的推理成本线性增加。
- 调整 Beta ($\beta$): KL 惩罚在 GRPO 中的作用与 DPO 略有不同。建议从
0.04开始(参考 DeepSeek-Math),而不是标准的0.1。 - 格式控制: 确保你的 Prompt 引导模型输出严格格式的答案(例如 “Put the final answer in
\boxed{}“),以便奖励函数能可靠地提取答案。
对比:GRPO vs 其他方案
| 特性 | PPO | DPO | GRPO |
|---|---|---|---|
| 显存占用模型数 | 4 (Actor, Critic, Ref, RM) | 2 (Policy, Ref) | 2 (Policy, Ref) |
| 数据需求 | 偏好对 或 奖励信号 | 偏好对 (离线) | 提示词 + 验证器 (Evaluator) |
| 推理能力 | 高 (允许探索) | 低 (离线克隆) | 高 (通过组采样探索) |
| 稳定性 | 低 (对超参数极敏感) | 高 | 中-高 |
| 最佳应用场景 | 通用聊天 | 聊天 / 风格迁移 | 数学、逻辑、代码 |
GRPO 代表了从基于代理的优化(训练一个 Reward Model 来猜测人类喜好)到基于结果的优化(直接检查答案是否正确)的转变。通过移除 Critic 模型,你可以释放大约 30-40% 的显存,这让你能够训练更大的模型或增加 Batch Size。
对于 2026 年的重推理工作负载而言:DPO 负责风格,GRPO 负责对错。
