
RLHF与PPO:大模型对齐技术详解
前言
大语言模型通过海量文本学习到了强大的语言能力,但如何让模型的输出符合人类期望和价值观?RLHF(Reinforcement Learning from Human Feedback,人类反馈强化学习)是解决这一问题的核心技术。本文从原理到实践,深入解析RLHF及其核心算法PPO。
一、为什么需要RLHF?
1.1 SFT的局限性
监督微调(SFT)让模型学习人类标注的问答对:
python
# SFT的局限
sft_data = [
{"instruction": "如何制作炸弹", "response": "抱歉,我不能帮助这个问题"},
{"instruction": "写一首诗", "response": "春眠不觉晓,处处闻啼鸟..."},
# 人工标注成本高,难以覆盖所有场景
]
# SFT问题:
# 1. 人工标注成本:每条数据$0.5-$2
# 2. 无法覆盖长尾场景:安全性、毒性、偏见
# 3. 难以表达复杂偏好:简洁vs详细、正式vs随意
1.2 人类偏好的复杂性
人类评估维度:
| 维度 | SFT | RLHF |
|---|---|---|
| 真实性 | ❌ 难以保证 | ✅ reward信号 |
| 安全性 | ❌ 需大量规则 | ✅ 惩罚有害输出 |
| 有用性 | 人工标注 | 人类偏好学习 |
| 风格控制 | 困难 | reward模型学习 |
二、RLHF三阶段流程
2.1 阶段一:监督微调(SFT)
python
# 第一步:微调基础语言模型
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
base_model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b")
# 格式化为对话格式
def format_prompt(sample):
return f"<|user|>{sample['instruction']}<|assistant|>{sample['response']}<|end|>"
2.2 阶段二:训练Reward Model
收集人类偏好数据:
python
# 人类偏好数据格式
preference_data = [
{
"prompt": "解释量子纠缠",
"chosen": "量子纠缠是量子力学中两个或多个粒子之间存在的一种特殊关联...", # 人类选择
"rejected": "量子纠缠就是两个粒子连在一起。" # 人类拒绝
},
# 收集10万-100万对比数据
]
# Bradley-Terry模型:P(prefer|A>B) = σ(r(A) - r(B))
# 训练Reward Model预测人类偏好
reward_model = AutoModelForCausalLM.from_pretrained(
base_model,
torch_dtype=torch.float16,
)
def reward_loss(reward_chosen, reward_rejected):
"""
人类偏好损失:chosen的reward应高于rejected
"""
logits = reward_chosen - reward_rejected
return -F.logsigmoid(logits).mean()
2.3 阶段三:强化学习(PPO)
python
# PPO算法核心
class PPO:
def __init__(self, policy, ref_policy, reward_model, clip_ratio=0.2):
self.policy = policy # 当前策略
self.ref_policy = ref_policy # SFT基线(KL散度约束)
self.reward_model = reward_model
self.clip_ratio = clip_ratio
def compute_advantage(self, rewards, values, gamma=0.99, lam=0.95):
"""
GAE (Generalized Advantage Estimation)
优势函数:当前动作比平均水平好多少
"""
advantages = []
gae = 0
for t in reversed(range(len(rewards))):
delta = rewards[t] + gamma * values[t+1] - values[t]
gae = delta + gamma * lam * gae
advantages.insert(0, gae)
return torch.tensor(advantages)
def policy_loss(self, log_probs, old_log_probs, advantages):
"""
PPO-Clip损失:限制策略更新幅度
"""
ratio = torch.exp(log_probs - old_log_probs)
clipped = torch.clamp(ratio, 1-self.clip_ratio, 1+self.clip_ratio)
return -(torch.min(ratio * advantages, clipped * advantages)).mean()
三、InstructGPT完整流程
3.1 数据采集
python
# 人类反馈数据采集平台
human_feedback_pipeline = {
"step1_generate": "给定提示,采样多个模型输出",
"step2_label": "人类对输出对进行比较评分",
"step3_aggregate": "使用Bradley-Terry模型估计奖励",
}
# 典型数据量
DATASET_STATS = {
"SFT_data": "~10k-100k高质量对话",
"reward_model_data": "~100k-1M偏好对比",
"PPO_data": "~10k-100k提示(无需标注)",
}
3.2 PPO训练循环
python
# 简化PPO训练循环
def ppo_train_step(policy, ref_policy, optimizer, prompts, reward_model):
# 1. 用当前策略生成响应
responses = policy.generate(prompts)
# 2. 用reward model打分
reward_scores = reward_model(prompts, responses)
# 3. 计算KL惩罚(防止偏离SFT太远)
kl_penalty = compute_kl_divergence(responses, policy, ref_policy)
# 4. 最终reward = 模型reward - β * KL
final_reward = reward_scores - 0.04 * kl_penalty
# 5. PPO更新
for _ in range(4): # 4个epoch
# 计算优势函数
advantages = compute_gae(final_reward)
# 计算策略损失并更新
policy_loss = ppo_objective(log_probs, old_log_probs, advantages)
optimizer.zero_grad()
policy_loss.backward()
optimizer.step()
return policy_loss.item()
3.3 完整训练代码
python
from transformers import AutoModelForCausalLM, AutoTokenizer
from torch.utils.data import DataLoader
import torch.nn.functional as F
# 加载模型
actor = AutoModelForCausalLM.from_pretrained("llama-2-7b")
ref_model = AutoModelForCausalLM.from_pretrained("llama-2-7b")
reward_model = RewardModel.from_pretrained("reward-model-7b")
# PPO配置
ppo_config = {
"lr": 1e-6,
"clip_ratio": 0.2,
"kl_coef": 0.04, # KL惩罚系数
"num_epochs": 4,
"batch_size": 8,
}
# 训练循环
for step in range(1000):
# 采样提示
prompts = sample_prompts(ppo_train_prompts, batch_size=8)
# 生成响应
responses = actor.generate(prompts, max_length=512)
# Reward评估
rewards = reward_model.get_reward(prompts, responses)
# KL惩罚
kl_penalty = compute_kl(responses, actor, ref_model)
# 最终reward
final_rewards = rewards - ppo_config["kl_coef"] * kl_penalty
# PPO更新
ppo_update(actor, final_rewards)
四、DPO:绕过PPO的替代方案
4.1 DPO原理
DPO(Direct Preference Optimization)绕过了reward model训练和PPO:
python
# DPO损失函数
def dpo_loss(policy_chosen, policy_rejected, ref_chosen, ref_rejected, beta=0.1):
"""
DPO直接优化人类偏好,无需RL
"""
# 策略偏好比
policy_ratio = policy_chosen - policy_rejected
# 参考模型偏好比
ref_ratio = ref_chosen - ref_rejected
# DPO损失
logits = beta * (policy_ratio - ref_ratio)
return -F.logsigmoid(logits).mean()
4.2 DPO vs PPO对比
| 维度 | PPO+RM | DPO |
|---|---|---|
| 训练稳定性 | 需要KL约束、clipping | 更稳定 |
| 计算量 | 需要4个模型(actor/ref/reward/critic) | 只需2个模型 |
| 显存需求 | ~4x模型大小 | ~2x模型大小 |
| 效果 | InstructGPT验证 | 相当或更好 |
| 超参 | 多(clip、kl_coef、gamma等) | 少(主要β) |
4.3 DPO实践
python
# DPO训练示例
from transformers import AutoModelForCausalLM
from datasets import load_dataset
dataset = load_dataset("argilla/DPO-Mix-7K") # 现成偏好数据
def dpo_train():
policy = AutoModelForCausalLM.from_pretrained("llama-2-7b")
ref_model = AutoModelForCausalLM.from_pretrained("llama-2-7b")
for batch in dataloader:
# DPO损失
loss = dpo_loss(
policy(batch["chosen"]),
policy(batch["rejected"]),
ref_model(batch["chosen"]),
ref_model(batch["rejected"]),
)
loss.backward()
optimizer.step()
五、RLHF的挑战与未来
5.1 主要挑战
python
# RLHF的典型问题
challenges = {
"reward_hacking": "模型找到欺骗reward的捷径,而非真正完成目标",
"mode_collapse": "输出变得单调,缺少多样性",
"human_bias": "人类反馈本身带有偏见,模型学会这些偏见",
"训练不稳定": "PPO训练需要仔细调参,容易训崩",
}
5.2 解决方案
python
# 1. Reward Hacking防护
reward_hacking_solution = {
"ensemble_rewards": "多个reward model投票",
"constitutional_ai": "加入规则约束",
"red_team": "对抗性测试",
}
# 2. 输出多样性
diversity_solution = {
"do_sample": True, # 采样而非greedy
"temperature": 0.7, # 温度采样
"nucleus_sampling": True, # Top-p采样
}
# 3. 更多人类反馈
feedback_scaling = {
"RLHF": "~100K对比",
"RLAIF": "用AI反馈替代人类(Google Sparrow)",
"ConstitutionalAI": "用规则+AI反馈(Anthropic)",
}
六、总结
RLHF开启了"让AI对齐人类价值观"的时代:
RLHF技术演进:
├── 第一代:纯SFT(规则驱动)
│
├── 第二代:RLHF+PPO(InstructGPT/GPT-3.5)
│ └── 问题:训练复杂、需4模型
│
└── 第三代:DPO(Direct Preference Optimization)
└── 优势:简化流程、训练更稳定
GPT-4、Claude、Gemini等强大模型都经过了RLHF微调,正是这项技术让AI从"能说话"进化到"会说话"。
延伸阅读:
- InstructGPT论文:arxiv.org/abs/2203.02155
- RLHF综述:arxiv.org/abs/2304.11540
- DPO论文:arxiv.org/abs/2305.18290
- ChatGPT技术解析:如何让AI学会对话