4.1 经典 RLHF 流程
InstructGPT 三阶段流程、奖励模型训练、PPO 核心组件、四模型架构及常见不稳定性
引言:从 DPO 回到 RLHF
在第3课中,我们学习了 DPO——一种跳过奖励模型和 RL 循环的偏好优化方法。但要真正理解后训练的全貌,我们需要回到 DPO 的"前辈"——RLHF(Reinforcement Learning from Human Feedback)。
RLHF 是 ChatGPT、Claude 和 Gemini 等商业模型对齐的核心技术。尽管 DPO 在很多场景中可以替代 RLHF,但 RLHF 的在线探索能力在训练推理模型时不可替代。理解 RLHF 也是理解 GRPO(下一节)的必要基础。
InstructGPT 三阶段流程
InstructGPT(Ouyang 等,OpenAI,2022)确立了后训练的经典范式,分为三个阶段:
阶段1:监督微调(SFT)
在人类标注的高质量指令-回复对上进行监督微调,获得初始策略模型 。
这一阶段对应我们第1-2课的内容。SFT 为后续的 RL 训练提供一个良好的起点——如果从纯基座模型开始做 RL,模型连基本的指令跟随都不会,RL 的探索效率极低。
阶段3:PPO 优化
使用 PPO(Proximal Policy Optimization)强化学习算法,优化策略模型以最大化奖励模型的评分,同时通过 KL 惩罚约束策略不偏离 SFT 模型太远。
奖励模型训练
Bradley-Terry 偏好模型
奖励模型的训练基于 Bradley-Terry 偏好模型(与 DPO 使用的是同一个模型)。给定偏好对 ,人类偏好 的概率为:
奖励模型损失
最大化偏好数据的对数似然,等价于最小化以下损失:
注意对比:这个损失与 DPO 损失的形式非常相似!区别在于:RM 损失训练的是一个独立的奖励模型 ,而 DPO 损失直接用策略模型的对数概率比作为隐式奖励。
奖励模型的架构
奖励模型通常基于与策略模型相同的预训练模型初始化,但将最后的语言模型头替换为一个标量输出头:
# 奖励模型架构示意
class RewardModel(nn.Module):
def __init__(self, base_model):
super().__init__()
self.backbone = base_model # 预训练 Transformer
self.reward_head = nn.Linear(hidden_size, 1) # 输出标量
def forward(self, input_ids, attention_mask):
hidden_states = self.backbone(input_ids, attention_mask)
# 取最后一个 token 的隐藏状态
last_hidden = hidden_states[:, -1, :]
reward = self.reward_head(last_hidden)
return reward.squeeze(-1) # shape: (batch_size,)奖励模型的质量至关重要
奖励模型的质量直接决定了 RLHF 的上限:
| RM 质量 | 后果 |
|---|---|
| 高质量 RM | PPO 训练有效,模型对齐良好 |
| 有偏差的 RM | 策略学到 RM 的偏差(如偏向长回复) |
| 低质量 RM | 奖励黑客严重,PPO 训练失败 |
PPO 优化详解
PPO 目标函数
PPO 在 RLHF 中的目标函数为:
这与 DPO 推导的第一步完全一致——DPO 正是从这个目标出发的。区别在于:DPO 通过解析求解绕过了 RL,而 RLHF 直接用 PPO 算法来优化这个目标。
PPO 核心组件
截断代理损失(Clipped Surrogate Loss)
PPO 的核心创新是截断代理目标,它限制每步更新的幅度,确保训练稳定:
其中:
- 是概率比(importance sampling ratio)
- 是优势估计(advantage estimate)
- 是截断参数(通常为 0.2)
截断的直觉:
- 当 (好的 action):允许 增大但不超过
- 当 (坏的 action):允许 减小但不低于
- 这防止了单步更新过大导致的训练崩溃
广义优势估计(GAE)
GAE(Generalized Advantage Estimation)用于计算每个 token 的优势值:
其中 TD 残差 。
在 RLHF 的语境中:
- 每个 token 的生成是一个"action"
- "reward" 通常只在序列结束时给出(即 是整个回复的奖励)
- 是价值模型预测的中间状态价值
KL 散度惩罚
为防止策略偏离参考模型太远,在奖励中加入 KL 惩罚项:
KL 惩罚可以按 token 计算(如上式),也可以作为整体约束。
四模型架构
PPO 在 RLHF 中需要同时维护四个模型,这是其计算开销巨大的主要原因:
| 模型 | 作用 | 是否更新 | 典型大小 |
|---|---|---|---|
| 策略模型(Actor) | 生成回复 | 是 | 7B-70B |
| 参考模型(Reference) | 计算 KL 惩罚 | 否(冻结) | 与策略相同 |
| 奖励模型(Reward) | 评估回复质量 | 否(预训练好) | 7B-13B |
| 价值模型(Critic) | 估计状态价值,计算优势 | 是 | 7B-13B |
内存估算(以7B模型为例,FP16):
加上优化器状态和激活值,实际需要 150-200GB 以上的 GPU 内存,通常需要多卡并行。
四模型架构的工程挑战:需要精心设计的内存管理、模型并行和流水线策略。这也是为什么 RLHF 在实践中远比 DPO 复杂——DPO 只需要2个模型(策略 + 参考),内存需求约为 PPO 的一半。
常见不稳定性
奖励黑客(Reward Hacking)
现象:策略模型学会利用奖励模型的漏洞,生成 RM 评分高但实际质量低的回复。
典型表现:
- 生成过长的回复(很多 RM 对长度有正偏差)
- 使用特定的"讨好"模式(如过度使用"当然!这是一个非常好的问题!")
- 输出包含看似专业但无意义的术语
缓解策略:
- 增大 KL 惩罚系数
- 定期更新奖励模型(对抗性训练)
- 使用多个奖励模型的集成
- 添加长度惩罚
KL 散度爆炸
现象:策略模型快速偏离参考模型,KL 散度急剧增大。
典型表现:
- 模型输出变得不自然、重复或无意义
- 训练损失突然变化
- 生成质量骤降
缓解策略:
- 增大 KL 系数
- 降低学习率
- 减小 PPO 截断参数
- 设置 KL 上限(当 KL > 阈值时提前停止)
价值模型崩溃
现象:价值模型的预测值变得不准确或发散。
典型表现:
- 优势估计噪声过大,PPO 更新方向不稳定
- 训练奖励先升后降
- 不同 prompt 的价值估计方差极大
缓解策略:
- 价值模型使用独立的学习率
- 增加价值模型的训练步数(相对于策略模型)
- 对价值目标进行截断
RLHF vs DPO 对比
全面对比
| 维度 | RLHF (PPO) | DPO |
|---|---|---|
| 核心思想 | 训练 RM → RL 优化策略 | 直接在偏好对上优化 |
| 模型数量 | 4个 | 2个 |
| 训练阶段 | 3个(SFT→RM→PPO) | 2个(SFT→DPO) |
| 实现复杂度 | 极高 | 低 |
| 训练稳定性 | 低(多种不稳定性) | 高 |
| 计算资源 | 极高 | 中等 |
| 在线探索 | 有(关键优势) | 无 |
| 数据效率 | 中等(需要生成+评估) | 高(直接用偏好数据) |
| 推理训练 | 适合(可探索新推理路径) | 不适合 |
| 聊天对齐 | 过度工程(DPO 足够) | 首选 |
何时选择 RLHF vs DPO
实践指南:
- 通用聊天对齐:使用 DPO/SimPO。RLHF 的复杂度不值得。
- 推理能力训练:使用 RLHF/GRPO。DPO 无法让模型探索新的推理策略。
- 安全对齐:DPO 可以作为基线,但追求极致安全可能需要 RLHF。
- 资源有限:DPO,因为内存和计算需求低得多。
- 资源充足且追求极致:RLHF,因为在线探索可能发现更好的策略。
从 PPO 到 GRPO 的进化
RLHF 的四模型架构和不稳定性是巨大的工程负担。GRPO(Group Relative Policy Optimization) 的核心贡献是:
- 消除价值模型:用组统计量替代价值网络,减少一个模型
- 消除奖励模型(在 RLVR 场景下):使用可验证的正确性奖励,再减少一个模型
- 保留在线探索:仍然从当前策略采样,保持 RL 的探索优势
最终,GRPO 将四模型架构简化为二模型(策略 + 参考),同时保留了 PPO 的核心优势。我们将在下一节详细介绍 GRPO。
PPO 在 RLHF 中的完整伪代码
# RLHF with PPO - 伪代码
def rlhf_ppo_training(
policy_model, # π_θ: 策略模型
ref_model, # π_ref: 参考模型(冻结)
reward_model, # r_φ: 奖励模型(冻结)
value_model, # V_ψ: 价值模型
prompts, # 训练提示集
beta=0.01, # KL 惩罚系数
epsilon=0.2, # PPO 截断参数
num_steps=1000,
):
for step in range(num_steps):
# 1. 采样:从策略模型生成回复
prompt = sample(prompts)
response = policy_model.generate(prompt)
# 2. 评估:计算奖励和 KL 惩罚
reward = reward_model(prompt, response)
kl_penalty = compute_kl(policy_model, ref_model, prompt, response)
total_reward = reward - beta * kl_penalty
# 3. 优势计算:使用价值模型和 GAE
values = value_model(prompt, response) # 每个 token 的价值估计
advantages = compute_gae(total_reward, values)
# 4. PPO 更新:截断代理目标
ratio = policy_model.log_prob(response) - old_log_prob(response)
ratio = ratio.exp()
clipped_ratio = ratio.clamp(1 - epsilon, 1 + epsilon)
policy_loss = -min(ratio * advantages, clipped_ratio * advantages).mean()
# 5. 价值模型更新
value_loss = (values - returns).pow(2).mean()
# 6. 参数更新
policy_model.update(policy_loss)
value_model.update(value_loss)