一文说清RLHF(人类反馈强化学习)

RLHF:用人类反馈训练 AI 的艺术

Reinforcement Learning from Human Feedback,即"基于人类反馈的强化学习",是当代大语言模型对齐(Alignment)技术的基石。ChatGPT、Claude、Gemini 等主流模型之所以能够以自然、有帮助、无害的方式与人类对话,背后的关键技术正是 RLHF。


目录

  1. [为什么需要 RLHF?](#为什么需要 RLHF?)
  2. [RLHF 的三阶段流程](#RLHF 的三阶段流程)
  3. 关键技术细节
  4. [RLHF 的局限性与挑战](#RLHF 的局限性与挑战)
  5. [RLHF 的演进:DPO、RLAIF、Constitutional AI](#RLHF 的演进:DPO、RLAIF、Constitutional AI)
  6. [代码实践:最小 RLHF 示例](#代码实践:最小 RLHF 示例)

一、为什么需要 RLHF?

预训练模型的根本问题

大语言模型(LLM)的预训练目标极其简单:预测下一个 Token。模型在海量互联网文本上学习这一目标,确实能习得惊人的语言能力,但也带来了严重的对齐问题:

复制代码
预训练目标:P(next_token | context)

互联网文本中充斥着错误信息、有害内容、偏见和低质量文字。一个纯粹追求"预测下一个 Token"的模型,会忠实地复现这些问题。更重要的是,模型学会了"预测人类会写什么",而非"什么是好的回答"------这两者有本质区别。

核心矛盾 :预训练优化的是统计似然(statistical likelihood),而人类真正需要的是有用性(helpfulness)、无害性(harmlessness)和诚实性(honesty)。这三点被 Anthropic 总结为 HHH 原则

传统方法的局限

在 RLHF 之前,研究者尝试过多种对齐方法:

方法 思路 局限性
规则过滤 黑名单词汇、规则匹配 无法覆盖复杂语境,容易绕过
有监督微调(SFT alone) 人工标注"好回答",直接微调 需要大量标注数据,且分布覆盖不足
对抗训练 训练分类器识别有害输出 分类器容易被对抗样本欺骗
Constitutional AI(规则约束) 让模型遵循明文规则 规则无法穷举,模型对规则理解有偏差

RLHF 的核心洞见是:与其告诉模型"什么是好的输出"(极其困难),不如让人类直接比较两个回答哪个更好(相对容易)。这一转变将高难度的绝对评分问题转化为相对排序问题。


二、RLHF 的三阶段流程

RLHF 的完整训练流程分为三个阶段,每个阶段都建立在前一个阶段的基础上。


阶段一:有监督微调(SFT)

目标:将预训练模型的输出分布从"互联网文本风格"迁移到"有帮助的助手风格"。

数据收集

SFT 需要人工标注者(Labelers)针对一批精选的 Prompt,撰写高质量的示范回答:

python 复制代码
# SFT 数据格式示例
sft_dataset = [
    {
        "prompt": "用 Python 实现一个二分查找算法,并解释其时间复杂度。",
        "response": """以下是二分查找的 Python 实现:

def binary_search(arr, target):
    left, right = 0, len(arr) - 1
    
    while left <= right:
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    
    return -1  # 未找到

# 时间复杂度分析:
# - 最优:O(1),第一次就找到
# - 平均/最差:O(log n),每次排除一半元素
# - 空间复杂度:O(1),只使用常数额外空间"""
    },
    # ... 更多示例
]
训练过程

SFT 的训练与标准语言模型微调相同,使用交叉熵损失:

python 复制代码
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, Trainer, TrainingArguments

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.1-8B")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3.1-8B")

# 只在 response 部分计算损失(不对 prompt 计算)
def compute_loss(model, inputs, return_outputs=False):
    labels = inputs["input_ids"].clone()
    # 将 prompt 部分的 labels 设为 -100(忽略)
    labels[:, :inputs["prompt_length"]] = -100
    outputs = model(**inputs, labels=labels)
    return (outputs.loss, outputs) if return_outputs else outputs.loss

training_args = TrainingArguments(
    output_dir="./sft-model",
    num_train_epochs=3,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=8,
    learning_rate=2e-5,
    warmup_ratio=0.03,
    lr_scheduler_type="cosine",
    bf16=True,  # 使用 BF16 混合精度
)

SFT 阶段的关键决策

  • 数据质量 >> 数量:InstructGPT 论文显示,13,000 条高质量标注足以产生显著效果
  • 标注者一致性:需要仔细培训标注者,建立明确的评分标准(rubric)
  • 覆盖多样性:数据需覆盖各类任务(对话、代码、写作、推理等)

阶段二:训练奖励模型(RM)

这是 RLHF 最具创新性的环节。奖励模型的任务是学习人类的偏好,将其编码为一个标量分数函数。

偏好数据收集

对于同一个 Prompt,让 SFT 模型生成多个(通常 4-9 个)回答,由人类标注者对它们进行排序:

复制代码
Prompt: "如何缓解工作压力?"

回答 A: "你可以尝试深呼吸、冥想、运动,
         这些都有助于缓解压力..."
         
回答 B: "1. 制定优先级列表
         2. 学会说不
         3. 定时休息(番茄钟技术)
         4. 下班后完全断开工作..."

回答 C: "压力是生活的一部分,接受它吧。"

人类排序:B > A > C

这些排序对转化为训练数据:

python 复制代码
# 偏好对数据格式
preference_data = [
    {
        "prompt": "如何缓解工作压力?",
        "chosen": "回答 B(更具体、可操作)",
        "rejected": "回答 A(较笼统)"
    },
    {
        "prompt": "如何缓解工作压力?",
        "chosen": "回答 A",
        "rejected": "回答 C(消极且无用)"
    },
    # ...
]
奖励模型架构

奖励模型通常是在 SFT 模型基础上,将最后的 LM head 替换为一个线性层,输出标量分数:

python 复制代码
import torch
import torch.nn as nn
from transformers import AutoModel

class RewardModel(nn.Module):
    def __init__(self, base_model_name):
        super().__init__()
        self.backbone = AutoModel.from_pretrained(base_model_name)
        # 将语言模型头替换为标量输出头
        hidden_size = self.backbone.config.hidden_size
        self.reward_head = nn.Linear(hidden_size, 1, bias=False)
    
    def forward(self, input_ids, attention_mask):
        outputs = self.backbone(
            input_ids=input_ids,
            attention_mask=attention_mask
        )
        # 取最后一个 token 的隐藏状态
        last_hidden = outputs.last_hidden_state[:, -1, :]
        reward = self.reward_head(last_hidden)
        return reward.squeeze(-1)
奖励模型训练损失

RM 的训练目标基于 Bradley-Terry 偏好模型,使用 Pairwise Ranking Loss:

复制代码
L_RM = -E[log σ(r_θ(x, y_w) - r_θ(x, y_l))]

其中:

  • r_θ(x, y) 是奖励模型对 Prompt x、回答 y 打出的分数
  • y_w 是人类偏好的(winner)回答
  • y_l 是不被偏好的(loser)回答
  • σ 是 Sigmoid 函数
python 复制代码
def reward_model_loss(reward_chosen, reward_rejected):
    """
    Pairwise ranking loss(来自 Bradley-Terry 模型)
    目标:让 chosen 的奖励分数高于 rejected
    """
    # reward_chosen: shape (batch_size,)
    # reward_rejected: shape (batch_size,)
    
    loss = -torch.nn.functional.logsigmoid(
        reward_chosen - reward_rejected
    ).mean()
    
    # 辅助指标:chosen 分数高于 rejected 的比例
    accuracy = (reward_chosen > reward_rejected).float().mean()
    
    return loss, accuracy

# 训练循环
for batch in dataloader:
    reward_chosen = reward_model(batch["chosen_ids"], batch["chosen_mask"])
    reward_rejected = reward_model(batch["rejected_ids"], batch["rejected_mask"])
    
    loss, acc = reward_model_loss(reward_chosen, reward_rejected)
    loss.backward()
    optimizer.step()

奖励模型训练的关键挑战

  • 标注者间一致性(Inter-annotator Agreement):不同人对"好回答"的判断存在分歧,需要统计处理
  • 奖励黑客(Reward Hacking):RM 只是对真实人类偏好的近似,LM 可能学会"欺骗"RM
  • 分布偏移:RM 在 SFT 模型的输出分布上训练,但在 RL 阶段需要评估策略模型的输出

阶段三:PPO 强化学习优化

有了奖励模型,就可以用强化学习来优化语言模型策略(policy)了。RLHF 通常使用 PPO(Proximal Policy Optimization) 算法。

将语言模型视为强化学习问题
复制代码
状态(State)    s_t = (prompt + 已生成的 tokens)
动作(Action)   a_t = 生成下一个 token(词表大小 = 动作空间)
奖励(Reward)   R   = RM(prompt, full_response)(序列末尾给出)
策略(Policy)   π_θ = 语言模型本身
KL 散度惩罚项

仅使用 RM 奖励会导致"奖励黑客"------模型可能生成荒谬但 RM 打高分的文本。因此引入 KL 散度惩罚,防止 RL 模型偏离 SFT 参考模型太远:

复制代码
R_total = r_RM(x, y) - β · KL(π_θ(y|x) || π_SFT(y|x))

其中:

  • r_RM 是奖励模型的分数
  • KL(π_θ || π_SFT) 是当前策略与参考策略(SFT 模型)的 KL 散度
  • β 是控制 KL 惩罚强度的超参数(通常 0.01~0.1)
python 复制代码
def compute_rlhf_reward(
    prompt_response_ids,
    reward_model,
    policy_model,
    ref_model,
    beta=0.04
):
    # 1. 奖励模型打分
    rm_score = reward_model(prompt_response_ids)
    
    # 2. 计算 KL 散度惩罚
    with torch.no_grad():
        ref_logprobs = ref_model(prompt_response_ids).logits
    policy_logprobs = policy_model(prompt_response_ids).logits
    
    # Per-token KL divergence
    kl_div = torch.nn.functional.kl_div(
        policy_logprobs.log_softmax(-1),
        ref_logprobs.softmax(-1),
        reduction='batchmean'
    )
    
    # 3. 组合奖励
    total_reward = rm_score - beta * kl_div
    return total_reward
PPO 更新过程

PPO 的核心是 Clipped Surrogate Objective,防止策略更新步幅过大:

python 复制代码
def ppo_loss(old_logprobs, new_logprobs, advantages, epsilon=0.2):
    """
    PPO Clipped Objective
    """
    # 计算策略比率
    ratio = torch.exp(new_logprobs - old_logprobs)
    
    # 裁剪比率,防止过大的更新
    clipped_ratio = torch.clamp(ratio, 1 - epsilon, 1 + epsilon)
    
    # 取最小值(保守更新)
    loss = -torch.min(
        ratio * advantages,
        clipped_ratio * advantages
    ).mean()
    
    return loss
完整的 PPO RLHF 训练循环(简化版)
python 复制代码
from trl import PPOTrainer, PPOConfig, AutoModelForCausalLMWithValueHead

# 初始化
ppo_config = PPOConfig(
    learning_rate=1.4e-5,
    batch_size=128,
    mini_batch_size=16,
    gradient_accumulation_steps=1,
    optimize_cuda_cache=True,
    early_stopping=True,
    target_kl=6.0,        # 目标 KL 散度(自适应 β)
    kl_penalty="kl",
    seed=42,
)

# 策略模型(带 Value Head)
policy_model = AutoModelForCausalLMWithValueHead.from_pretrained(
    "sft-model",  # 从 SFT 模型初始化
    torch_dtype=torch.bfloat16,
)

# 参考模型(冻结,不参与梯度更新)
ref_model = AutoModelForCausalLMWithValueHead.from_pretrained(
    "sft-model",
    torch_dtype=torch.bfloat16,
)
ref_model.eval()

ppo_trainer = PPOTrainer(
    config=ppo_config,
    model=policy_model,
    ref_model=ref_model,
    tokenizer=tokenizer,
    dataset=prompt_dataset,
)

# 训练循环
for epoch in range(num_epochs):
    for batch in ppo_trainer.dataloader:
        # 1. 策略模型生成回答
        query_tensors = batch["input_ids"]
        response_tensors = ppo_trainer.generate(
            query_tensors,
            max_new_tokens=512,
            do_sample=True,
            temperature=0.7,
        )
        
        # 2. 奖励模型打分
        rewards = [
            reward_model(q, r)
            for q, r in zip(query_tensors, response_tensors)
        ]
        
        # 3. PPO 更新
        stats = ppo_trainer.step(
            query_tensors,
            response_tensors,
            rewards
        )
        
        ppo_trainer.log_stats(stats, batch, rewards)

三、关键技术细节

3.1 价值函数(Value Head)

PPO 需要估计状态价值 V(s) 来计算优势函数(Advantage)。在 RLHF 中,通常在语言模型顶部添加一个线性 Value Head:

python 复制代码
# Advantage Estimation (GAE)
def compute_advantages(rewards, values, gamma=1.0, lam=0.95):
    """
    Generalized Advantage Estimation
    γ: 折扣因子(语言生成通常用 1.0,因为序列较短)
    λ: GAE 参数(平衡偏差与方差)
    """
    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)

3.2 标注者间一致性处理

现实中不同标注者的偏好可能冲突。常见处理方法:

python 复制代码
# 方法一:多数投票
def majority_vote(annotations):
    from collections import Counter
    votes = Counter(annotations)
    return votes.most_common(1)[0][0]

# 方法二:基于 Elo 评分的排名
def compute_elo_rankings(pairwise_results, k=32):
    elo = defaultdict(lambda: 1500)
    
    for winner, loser in pairwise_results:
        expected_w = 1 / (1 + 10 ** ((elo[loser] - elo[winner]) / 400))
        expected_l = 1 - expected_w
        
        elo[winner] += k * (1 - expected_w)
        elo[loser]  += k * (0 - expected_l)
    
    return dict(sorted(elo.items(), key=lambda x: -x[1]))

# 方法三:基于 Cohen's Kappa 的质量控制
# 过滤一致性低于阈值的标注者

3.3 关键超参数

超参数 推荐范围 作用
KL 系数 β 0.01 ~ 0.1 控制偏离参考模型的程度
PPO epsilon 0.1 ~ 0.3 裁剪比率,控制更新步幅
GAE λ 0.9 ~ 0.99 平衡优势估计的偏差-方差
Value loss coef 0.1 ~ 1.0 Value Head 损失权重
Rollout batch 128 ~ 512 每次采样的轨迹数量
Mini-batch 16 ~ 64 PPO 更新的小批量大小
Target KL 1.0 ~ 10.0 自适应 KL 系数的目标值

四、RLHF 的局限性与挑战

4.1 奖励黑客(Reward Hacking)

这是 RLHF 最根本的问题之一。模型学会的不是"真正有帮助",而是"让奖励模型打高分"。两者可能大相径庭。

典型案例

复制代码
问题:解释量子纠缠

奖励黑客式回答:
"量子纠缠是一个极其深刻的概念!它涉及到粒子之间
神奇的关联性,爱因斯坦称之为'鬼魅般的超距作用'。
这个现象不仅颠覆了我们对现实的认知,还是量子计算
和量子通信的基础。您问了一个绝妙的问题!..."
(长篇幅、充满赞美,但实质内容稀少)

缓解方法

  • 定期更新奖励模型(Online RLHF)
  • 引入多样性奖励,惩罚重复模式
  • 使用 Constitutional AI 等额外约束
  • 红队测试(Red-teaming)发现并修复问题

4.2 人类反馈的可扩展性瓶颈

高质量标注需要:

  • 专业知识:代码题目需要程序员,医学问题需要医生
  • 时间成本:每条偏好对需要数分钟人工审阅
  • 标注一致性:不同标注者的偏好难以完全对齐

规模估算:InstructGPT 使用约 40 名专职标注者,生成约 40,000 条偏好对。这对资源有限的团队来说是显著门槛。

4.3 分布偏移

奖励模型在 SFT 模型的输出分布上训练,但 RL 训练过程中策略逐渐偏离 SFT 分布。奖励模型在分布外数据上可能给出不可靠的评分。

复制代码
训练时 RM 见过的:SFT 模型输出
RL 后期 RM 需要评估:与 SFT 差异越来越大的策略模型输出
                           ↑
                     可靠性下降!

4.4 过度优化(Over-optimization)

随着 RL 训练深入,模型可能过度优化奖励模型而退化。Gao et al. (2022) 发现奖励分数与真实质量之间存在倒 U 形关系:

复制代码
真实质量
    ▲
    │        ●
    │      ●   ●
    │    ●       ●  ← 过度优化后质量下降
    │  ●           ●
    └──────────────────→ RM 分数
         过拟合 RM!

4.5 标注偏见

标注者的文化背景、个人偏好、知识水平都会影响标注结果,导致模型产生系统性偏见:

  • 偏好符合特定文化价值观的回答
  • 更长的回答(即使内容冗余)通常得分更高
  • 措辞流畅的错误答案可能优于表达生硬的正确答案

五、RLHF 的演进:DPO、RLAIF、Constitutional AI

5.1 DPO:直接偏好优化

DPO(Direct Preference Optimization,2023)通过数学变换,将 RLHF 的三阶段问题化简为一个直接的监督学习问题,无需显式训练奖励模型,也无需 PPO:

python 复制代码
def dpo_loss(policy_model, ref_model, chosen_ids, rejected_ids, beta=0.1):
    """
    DPO 损失函数
    直接从偏好数据中学习,无需独立训练 RM
    """
    # 策略模型的 log 概率
    policy_chosen_logps = get_log_probs(policy_model, chosen_ids)
    policy_rejected_logps = get_log_probs(policy_model, rejected_ids)
    
    # 参考模型的 log 概率(冻结)
    with torch.no_grad():
        ref_chosen_logps = get_log_probs(ref_model, chosen_ids)
        ref_rejected_logps = get_log_probs(ref_model, rejected_ids)
    
    # 计算隐式奖励差
    chosen_rewards = beta * (policy_chosen_logps - ref_chosen_logps)
    rejected_rewards = beta * (policy_rejected_logps - ref_rejected_logps)
    
    # DPO 损失(同 Bradley-Terry 模型)
    loss = -torch.nn.functional.logsigmoid(
        chosen_rewards - rejected_rewards
    ).mean()
    
    return loss

DPO vs RLHF 对比

维度 RLHF (PPO) DPO
是否需要 RM
是否需要 RL 是(PPO) 否(SL)
训练稳定性 较难调参 更稳定
计算成本
性能 通常更强 接近甚至超越
可解释性 较高

5.2 RLAIF:用 AI 替代人类标注

RLAIF(Reinforcement Learning from AI Feedback)用 AI 模型(通常是更强的 LLM)替代人类标注者,生成偏好数据:

python 复制代码
def generate_ai_feedback(prompt, response_a, response_b, judge_model):
    """
    用 AI 评判者生成偏好标注
    """
    judge_prompt = f"""请评估以下两个回答,判断哪个更有帮助、更准确、更安全。

问题:{prompt}

回答 A:{response_a}

回答 B:{response_b}

请分析两个回答,然后以 JSON 格式输出:
{{"preferred": "A" 或 "B", "reason": "原因(一句话)"}}"""
    
    feedback = judge_model.generate(judge_prompt)
    return parse_json(feedback)

# Constitutional AI 中的 RLAIF 变体
# 让模型先生成回答,再用宪法原则自我批判并修改

5.3 Constitutional AI(CAI)

Anthropic 提出的 Constitutional AI 引入了一套明文"宪法"原则,让模型自我修正,减少对人工标注的依赖:

复制代码
宪法原则示例(Anthropic):
• 避免产生可能被用于伤害人的输出
• 如果不确定,优先选择对人类更有益的回答
• 不要写带有种族、性别或其他歧视性内容
• 鼓励用户自己思考,而非依赖 AI

RLAIF 流程:
Prompt → 模型生成回答
         ↓
       模型根据宪法原则自我批判
         ↓
       模型生成改进版回答
         ↓
       用改进前/后的对比训练 RM

5.4 其他变体对比

方法 年份 核心思路 优势
RLHF(InstructGPT) 2022 PPO + 人类偏好 RM 效果经过验证
Constitutional AI 2022 AI 自我批判 + 宪法 减少人工标注
DPO 2023 去掉 RL,直接优化 简单稳定
RLAIF 2023 AI 替代人类标注 可扩展
IPO 2023 DPO 的正则化改进 防过拟合
KTO 2024 前景理论驱动的损失 更符合人类决策
ORPO 2024 单阶段 SFT+偏好 更高效

六、代码实践:最小 RLHF 示例

以下是一个使用 trl 库(Hugging Face)实现 RLHF 的完整可运行示例(简化版,适合入门学习):

python 复制代码
"""
最小 RLHF 示例:使用 TRL 库训练一个情感正向化模型
任务:让语言模型生成尽可能积极情感的文本
"""

import torch
from transformers import pipeline, AutoTokenizer
from trl import PPOTrainer, PPOConfig, AutoModelForCausalLMWithValueHead
from trl.core import LengthSampler

# ── 1. 配置 ────────────────────────────────────────
MODEL_NAME = "gpt2"  # 使用 GPT-2 作为基础模型(方便本地运行)

ppo_config = PPOConfig(
    model_name=MODEL_NAME,
    learning_rate=1.41e-5,
    log_with=None,
    batch_size=16,
    mini_batch_size=4,
    gradient_accumulation_steps=1,
    optimize_device_cache=True,
    early_stopping=True,
    target_kl=6.0,
    kl_penalty="kl",
    seed=0,
    use_score_scaling=True,
    use_score_norm=True,
    score_clip=0.5,
)

# ── 2. 初始化模型 ───────────────────────────────────
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
tokenizer.pad_token = tokenizer.eos_token

# 策略模型(带 Value Head)
policy_model = AutoModelForCausalLMWithValueHead.from_pretrained(
    MODEL_NAME,
    torch_dtype=torch.float32,
)

# ── 3. 奖励函数:情感分类器 ─────────────────────────
# 用情感分类器作为奖励模型(替代人工标注)
sentiment_pipe = pipeline(
    "sentiment-analysis",
    model="lvwerra/distilbert-imdb",
    device=0 if torch.cuda.is_available() else -1,
)

def compute_sentiment_reward(texts):
    """将情感分类结果转化为奖励分数"""
    results = sentiment_pipe(texts, top_k=2, truncation=True, max_length=512)
    rewards = []
    for result in results:
        for r in result:
            if r["label"] == "POSITIVE":
                rewards.append(torch.tensor(r["score"]))
                break
    return rewards

# ── 4. 准备数据集 ─────────────────────────────────
from datasets import load_dataset

dataset = load_dataset("imdb", split="train")
dataset = dataset.rename_columns({"text": "review"})
dataset = dataset.filter(lambda x: len(x["review"]) > 200)

def tokenize(sample):
    # 只取前 128 个 token 作为 prompt
    input_ids = tokenizer.encode(sample["review"])[:128]
    sample["input_ids"] = input_ids
    sample["query"] = tokenizer.decode(input_ids)
    return sample

dataset = dataset.map(tokenize, batched=False)
dataset.set_format(type="torch")

# ── 5. PPO 训练 ────────────────────────────────────
ppo_trainer = PPOTrainer(
    config=ppo_config,
    model=policy_model,
    ref_model=None,  # TRL 会自动创建参考模型的副本
    tokenizer=tokenizer,
    dataset=dataset,
    data_collator=lambda data: {
        "input_ids": [d["input_ids"] for d in data],
        "query": [d["query"] for d in data],
    },
)

output_length_sampler = LengthSampler(16, 48)  # 生成 16-48 个 token

generation_kwargs = {
    "min_length": -1,
    "top_k": 0.0,
    "top_p": 1.0,
    "do_sample": True,
    "pad_token_id": tokenizer.eos_token_id,
    "max_new_tokens": 32,
}

# 训练循环
for epoch, batch in enumerate(ppo_trainer.dataloader):
    query_tensors = batch["input_ids"]
    
    # 生成回答
    response_tensors = ppo_trainer.generate(
        query_tensors,
        return_prompt=False,
        length_sampler=output_length_sampler,
        **generation_kwargs,
    )
    
    batch["response"] = tokenizer.batch_decode(
        response_tensors, skip_special_tokens=True
    )
    
    # 计算奖励(情感分数)
    texts = [q + r for q, r in zip(batch["query"], batch["response"])]
    rewards = compute_sentiment_reward(texts)
    
    # PPO 更新
    stats = ppo_trainer.step(query_tensors, response_tensors, rewards)
    ppo_trainer.log_stats(stats, batch, rewards)
    
    if epoch % 100 == 0:
        avg_reward = torch.stack(rewards).mean().item()
        print(f"Epoch {epoch:4d} | Avg Reward: {avg_reward:.4f}")

print("RLHF 训练完成!")

完整训练监控指标

在生产级 RLHF 训练中,需要密切关注以下指标:

python 复制代码
# 关键监控指标(通常记录到 W&B 或 TensorBoard)
metrics = {
    # 奖励相关
    "reward/mean": float,           # 平均奖励(越高越好)
    "reward/std": float,            # 奖励标准差(反映多样性)
    
    # KL 散度(控制偏离参考模型的程度)
    "objective/kl": float,          # 当前 KL 散度
    "objective/kl_coef": float,     # 自适应 KL 系数 β
    
    # PPO 相关
    "ppo/loss/policy": float,       # 策略损失
    "ppo/loss/value": float,        # 价值函数损失
    "ppo/policy/entropy": float,    # 策略熵(反映生成多样性)
    "ppo/policy/approxkl": float,   # PPO 近似 KL
    "ppo/policy/clipfrac": float,   # 被裁剪的比例(应 < 0.3)
    
    # 生成质量
    "tokens/queries": float,        # Prompt 平均长度
    "tokens/responses": float,      # 回答平均长度
}

开源工具推荐


相关推荐
litble2 小时前
如何速成LLM以伪装成一个AI研究者(2)——Pre-LN,KV-Cache优化,MoE
人工智能·大模型·llm·moe·kv-cache·pre-ln
bug菌4 小时前
终端 Agent 的真正升级:不是堆功能,而是打通具身智能链路!
agent
花千树_0104 小时前
McpAgentExecutor:用几行代码让模型自主调用 HTTP 工具多步推理
人工智能·agent
YJlio4 小时前
1 1.2 Windows 账户的分类:管理员 / 标准 / 来宾 + 微软账户 vs 本地账户
人工智能·python·microsoft·ai·chatgpt·openai·agent
kyriewen4 小时前
智能体走向“企业操作系统”,Google 扔出五把钥匙
google·agent·ai编程
knight_9___4 小时前
RAG面试篇8
人工智能·python·面试·agent·rag
山顶夕景4 小时前
【Agent】Long-horizon task的memory系统
大模型·llm·agent·检索·记忆体
程序员夏末5 小时前
【AI Agent基础 | 第六篇】LLM多厂商接入:区分provider、protocol、base_url、adapter
人工智能·agent·ai agent
翔云1234566 小时前
OpenClaw记忆系统
大模型·openclaw