CS336 · 第 15 课

Mid/Post-training:SFT 与 RLHF

预训练得到通用 next-token predictor 后,模型还会经历高质量 continued training、指令示范与偏好优化。本课把这些阶段的训练信号分开:SFT 学目标 response,preference/RLHF 再处理多个可行回答之间的取舍。

授课:Tatsu Hashimoto 预计用时:80 分钟 难度:中等 → 较高

Spring 2026 官方来源:Lecture 15 PDF · 课程日程

本页是中文学习导读;讲次主题、教师与材料版本以 Stanford 官方页面和讲义为准。

本讲问题:Base model 学会的是预测文本,不是遵循用户意图。Alignment 需要先用示范定义期望行为,再用偏好信号处理多个合理输出之间的取舍。

30 秒知识地图

Base model → instruction / response demonstrations → SFT → preference pairs → reward / preference optimization → 检查 helpfulness、honesty 与 reward hacking。

本课问题与 prerequisite refresher

预训练学的是 next-token distribution,不等于学会服从 instruction。SFT 提供目标 response tokens;preference learning 比较同一 prompt 下的候选;RL 再改变采样 policy。先分清 demonstration、preference pair、reward model、policy 与 reference policy。

三种信号的对象不同

SFT: prompt + target response → token cross-entropy → policy
Preference: prompt + chosen/rejected → comparison objective → reward/preference model
RLHF: policy rollouts → reward - KL pressure → advantage → policy update

human preference label ≠ scalar reward truth
reward model score ≠ real-world helpfulness
KL penalty ≠ safety guarantee

为什么 SFT 常只对 response 算 loss

序列是 [system][user][assistant]。Prompt tokens 是条件,assistant tokens 是要模仿的目标;mask prompt loss 可避免训练目标被长 prompt 主导。若把所有 tokens 都算 loss,模型主要学复述输入格式也可能得到低 loss,却没有更好回答。

Reward hacking 反例

若偏好数据中较长答案常获胜,reward model 可能把长度当代理;policy 于是堆砌文字提高 reward,却降低真实质量。KL 约束防止一步漂得太远,但 reference policy 本身有缺陷时,靠近它不等于 honest 或 safe。必须用独立 eval 与 adversarial probes 检查。


什么是 Alignment?

核心问题:预训练模型 p(x) 是 token 上的概率分布。它学会的是"什么 token 最可能出现",而非"什么回答最有用"。Alignment 是将模型行为从"likely"调整到"helpful, harmless, honest"的过程。

Base Model vs Instruct Model

Base ModelInstruct Model
训练目标预测下一个 token遵循指令、有帮助
行为续写文本回答问题、完成任务
示例输入"The cat"→"sat on the mat"输入"What is 2+2?"→"2+2=4"
能力语言建模、知识+ 指令跟随、对话

Alignment 的三种方法

方法数据训练方式复杂度
SFT(input, output) 对监督学习低
RLHF偏好对 (chosen, rejected)强化学习高
DPO偏好对 (chosen, rejected)监督学习中

训练流程概览

Base Model (预训练完成)
    ↓ SFT (Supervised Fine-Tuning)
SFT Model (能遵循指令)
    ↓ RLHF (Reinforcement Learning from Human Feedback)
RLHF Model (符合人类偏好)

SFT:监督微调

核心思想

SFT 是最直接的 alignment 方法:收集高质量的 (instruction, response) 对,用标准的监督学习微调模型。

# SFT 的数据格式
{
    "instruction": "解释什么是机器学习",
    "output": "机器学习是人工智能的一个分支,它允许计算机从数据中学习...",
}

# 或者多轮对话格式
{
    "messages": [
        {"role": "user", "content": "你好"},
        {"role": "assistant", "content": "你好!有什么可以帮助你的吗?"},
        {"role": "user", "content": "解释什么是机器学习"},
        {"role": "assistant", "content": "机器学习是..."},
    ]
}

SFT 数据的特点

SFT 数据来源

来源方法代表
人工标注标注员撰写高质量回答Llama 2 instruction data
强模型蒸馏用 GPT-4 生成回答Alpaca, OpenHermes
用户共享收集真实人机对话ShareGPT
现有数据集转换 NLP 数据集为指令格式Flan, Super-Natural Instructions

SFT 训练细节

# SFT 的损失函数(与预训练相同,但只在 response 上计算)

# 对于每个样本 (instruction, response):
# 1. 拼接为: [instruction_tokens, response_tokens]
# 2. 计算 loss 时,instruction 部分 mask 掉
# 3. 只在 response token 上计算 cross-entropy loss

def sft_loss(model, instruction, response):
    # 拼接输入
    input_ids = tokenize(instruction + response)
    # 创建 mask:只对 response 部分计算 loss
    mask = [0] * len(tokenize(instruction)) + [1] * len(tokenize(response))
    # 前向传播
    logits = model(input_ids)
    # 计算 loss(只对 response 部分)
    loss = cross_entropy(logits[mask], input_ids[mask])
    return loss

# 训练参数:
# - 学习率: 比预训练低 10-100 倍 (如 1e-6 到 1e-5)
# - Epochs: 1-3(容易过拟合)
# - Batch size: 适中(32-128)

SFT 的局限:

SFT 数据的数量 vs 质量

Llama 2 的发现:27,540 个人工标注的高质量样本,效果优于数百万个开源数据样本。质量远比数量重要。


RLHF 概述

为什么需要 RLHF?

SFT 只能让模型"模仿"训练数据。但很多时候我们需要模型在多个合理回答中选择最好的那个——这超出了 SFT 的能力:

RLHF 的三步流程

Step 1: SFT
Base Model → SFT Model (初始化 policy)

Step 2: Reward Model
收集偏好数据 → 训练 Reward Model R(s, a)

Step 3: PPO 优化
用 Reward Model 作为奖励信号,通过 PPO 优化 policy

Reward Model

Reward Model 学会预测"人类更喜欢哪个回答":

# 偏好数据收集
# 给定同一个 prompt,模型生成多个回答
# 人类标注者排序: A > B > C

# Reward Model 训练
# 输入: (prompt, response)
# 输出: 标量 reward

# 损失函数 (Bradley-Terry 模型):
# L = -E[log(σ(R(prompt, chosen) - R(prompt, rejected)))]

# 即: 让 chosen 的 reward 高于 rejected

class RewardModel(nn.Module):
    def __init__(self, base_model):
        super().__init__()
        self.transformer = base_model
        # 替换 classification head 为标量输出
        self.reward_head = nn.Linear(hidden_dim, 1)

    def forward(self, input_ids, attention_mask):
        outputs = self.transformer(input_ids, attention_mask)
        # 取最后一个 token 的隐藏状态
        last_hidden = outputs.last_hidden_state[:, -1, :]
        reward = self.reward_head(last_hidden)
        return reward.squeeze(-1)

PPO 优化

PPO (Proximal Policy Optimization) 的核心思想:
用 Reward Model 的输出作为奖励
通过 policy gradient 优化语言模型
同时用 KL 惩罚防止模型偏离太远

对每个 prompt:
1. 用当前 policy π 生成 response
2. 用 Reward Model 计算 reward R(prompt, response)
3. 计算 KL 惩罚: KL(π || π_SFT)
4. 总奖励 = R - β × KL
5. 用 PPO 更新 policy

PPO 的 loss:
L = -E[min(ratio × advantage, clip(ratio, 1-ε, 1+ε) × advantage)]
其中 ratio = π_new(a|s) / π_old(a|s)

PPO 的完整流程

# RLHF/PPO 训练循环:

for batch in prompts:
    # 1. 生成 responses
    responses = policy.generate(batch.prompt)

    # 2. 计算 rewards
    rewards = reward_model(batch.prompt, responses)

    # 3. 计算 KL 惩罚
    kl_penalty = compute_kl(policy, sft_model, batch.prompt, responses)

    # 4. 总奖励
    total_reward = rewards - beta * kl_penalty

    # 5. 计算 advantage (使用 GAE)
    advantages = compute_gae(total_reward, values)

    # 6. PPO 更新
    for _ in range(ppo_epochs):
        new_log_probs = policy.log_prob(batch.prompt, responses)
        ratio = exp(new_log_probs - old_log_probs)
        loss = -min(ratio * advantages,
                    clip(ratio, 1-eps, 1+eps) * advantages)
        loss.backward()
        optimizer.step()

偏好数据收集

如何收集偏好?

方法 1: 直接比较
给定 prompt,生成 4 个 responses
人类标注者排序: A > C > B > D
生成偏好对: (A, C), (A, B), (A, D), (C, B), (C, D), (B, D)

方法 2: 成对比较
给定 prompt,生成 2 个 responses
人类标注者选择: A > B
生成一个偏好对: (A, B)

方法 3: Elo 评分 (类似 Chatbot Arena)
多次比较,计算每个 response 的 Elo 分数

偏好数据的质量

Llama 2 的发现:偏好数据的质量比数量重要。少量高质量偏好对(~10K)比大量低质量偏好对更有效。一致性(inter-annotator agreement)是关键指标。


RLHF 的挑战

Reward Hacking

模型学会"欺骗" reward model,而非真正提高质量:

Reward hacking 的表现:
1. 生成 reward model 喜欢但人类不喜欢的回答
2. 利用 reward model 的盲点
3. 生成"安全但无用"的回答(reward model 不给负分)

例: Reward model 偏好长回答
→ 模型生成冗长、重复的回答
→ Reward 高,但人类不喜欢

缓解方法:
1. KL 惩罚(防止偏离 SFT 太远)
2. 定期更新 reward model
3. 人类在环评估

KL 散度的作用

KL 惩罚: KL(π_RLHF || π_SFT)
防止模型偏离 SFT 分布太远

为什么需要 KL?
- 没有 KL: 模型可能找到 reward model 的漏洞
- 有 KL: 模型必须在"提高 reward"和"保持接近 SFT"之间权衡

KL 惩罚的大小 (β):
- β 太小: 几乎无约束,reward hacking 风险高
- β 太大: 模型几乎不更新,RLHF 无效
- 最优 β: 需要实验确定

其他挑战

挑战表现缓解
标注者不一致不同标注者有不同偏好多数投票、一致性过滤
Reward model 过拟合在训练分布外表现差正则化、更大模型
模式崩塌模型输出多样性下降温度调参、diversity reward
长度偏差偏好长回答长度归一化
计算成本需要多个模型同时运行模型压缩、蒸馏

SFT vs RLHF 对比

维度SFTRLHF
数据(input, output) 对(prompt, chosen, rejected) 三元组
训练方式监督学习强化学习 (PPO)
计算成本低高(需要 4 个模型)
能力上限受限于训练数据可以超越训练数据
风格控制直接模仿通过 reward 间接控制
Reward hacking无有(主要风险)
实现复杂度低高

关键洞察:SFT 和 RLHF 不是互斥的。实际系统中通常先用 SFT 让模型"入门",再用 RLHF 进一步"调优"。SFT 提供基础能力,RLHF 提供风格和安全。


实践要点

SFT 实践 Checklist

数据覆盖多种任务类型

数据经过人工审核或来自高质量来源

使用统一的对话格式

只在 response 上计算 loss

使用较低的学习率 (1e-6 到 1e-5)

训练 1-3 个 epoch(避免过拟合)

在 held-out 验证集上监控 loss

RLHF 实践 Checklist

SFT model 质量足够好(作为初始化)

偏好数据覆盖多种 prompt 类型

标注者一致性 > 80%

Reward model 在验证集上准确率 > 70%

PPO 训练时监控 KL 散度

定期做人类评估(不只看 reward 分数)

保存多个 checkpoint,选择 reward 和 KL 的平衡点


知识检查

问题 1:SFT 训练时,loss 在哪些 token 上计算?

问题 2:什么是 Reward Hacking?

问题 3:RLHF 中 KL 惩罚的作用是什么?

问题 4:SFT 和 RLHF 的关系是什么?


Concept Check · SFT loss mask

Prompt 900 tokens、response 100 tokens。若全部 token 等权算 loss,哪类目标更容易主导?

答案:prompt reconstruction 占 90% positions,可能压过 response imitation;response-only mask 把 prompt 作为条件。

若认为每个样本只算一次所以长度无关,你忽略了 token-level cross-entropy 的求和/平均对象。

你现在应该能够解释

通往第 16 课

人类偏好昂贵且主观;下一课转向数学答案、代码测试等可验证奖励,并追踪 rollout group 如何形成相对 advantage。

如果只能记住 5 件事

SFT

监督学习,高质量 (input, output) 对

RLHF

Reward model + PPO,从偏好中学习

Reward Hacking

主要风险,KL 惩罚缓解

实践

质量 > 数量,SFT + RLHF 结合


延伸阅读

Reference · 延伸阅读与一手资料