SFT-RLHF-DPO 的关系

一句话速记

LLM “对齐”三阶段:① SFT(Supervised Fine-Tuning):用 (instruction, response) 数据教模型”格式 + 知识”——最简单也最常用;② RLHF(PPO):先训 reward model,再用强化学习把模型行为推向 reward 高的方向,工程复杂、显存爆、调参难;③ DPO(Direct Preference Optimization):直接用 (chosen, rejected) 偏好对优化,绕过 reward model 和 RL,等价于 RLHF 但工程上简单 10 倍——现在多数偏好学习选 DPO,不再上 PPO

通俗解释(5 分钟版)

为什么需要这三个阶段

  • 预训练(PT):让模型学会语言(无监督,next token prediction)
  • 但 PT 完的模型是”补全机”,不会按指令回答——给它 “1+1=” 可能续写 “2 是一个偶数…”
  • 要让它”听话”,需要对齐

三阶段对齐 = 三个不同形态的数据 + 三个不同 loss

┌────────────────────────────────────────────────────────────────┐
│                                                                  │
│  PT(预训练,先有这个)                                          │
│       数据:互联网爬的纯文本                                     │
│       学:next token                                              │
│       结果:会说话,但不会按指令做事                             │
│                                                                   │
│  ▼                                                                │
│                                                                   │
│  SFT(监督微调)                                                  │
│       数据:(instruction, response) 对                           │
│       例:("写一首关于猫的诗", "白毛浮绿水...")                   │
│       学:让模型见到 instruction 时复现 response                 │
│       Loss:cross-entropy on response token                      │
│       结果:会按指令回答,但回答可能不够好/不安全/瞎说          │
│                                                                   │
│  ▼                                                                │
│                                                                   │
│  RLHF (PPO) 或 DPO (偏好对齐)                                   │
│       数据:(prompt, chosen response, rejected response)         │
│       例:("如何造炸弹", chosen="不能教这", rejected="先准备...")│
│       学:让模型多输出像 chosen 的、少输出像 rejected 的          │
│       Loss:RLHF 用 PPO 复杂;DPO 直接用偏好数据                  │
│       结果:模型更安全、更有用、更"和人类口味对齐"               │
│                                                                   │
└────────────────────────────────────────────────────────────────┘

SFT —— 学格式和知识

数据格式(chat template):

{
  "messages": [
    {"role": "system", "content": "你是有用助手"},
    {"role": "user", "content": "1+1 等于几"},
    {"role": "assistant", "content": "1+1 等于 2"}
  ]
}

模型见到 user message 后,目标是输出和 assistant 一样。Loss 只对 assistant token 算(mask 掉前面的 instruction 部分)。

踩坑点

  • chat template 跟 base 模型必须对齐(Llama-3 用 <|begin_of_text|>...<|eot_id|>,Qwen 用 <|im_start|>...<|im_end|>),格式错就退化
  • 数据质量比数量重要——10K 高质量 > 100K 一般
  • 必有 eval set,过拟合表现得很微妙(loss 还在降,输出已经退化)

RLHF —— 难度大、显存爆

经典 RLHF 三步走(OpenAI ChatGPT 那篇论文):

   step 1: SFT(先做)
   step 2: 训 Reward Model
       数据:(prompt, response_a, response_b, label="a 好" or "b 好")
       Loss:让 RM 给 chosen 的 score > rejected 的 score
   step 3: PPO 优化 SFT 模型
       同时跑:
           policy(要训的模型,初始 = SFT model)
           reference(冻结的 SFT model 副本,防止跑偏)
           reward model(冻结,给打分)
           value model(critic,估计未来 reward)
       PPO loss = max reward - β·KL(policy || reference)

为什么难

  • 同时驻 4 个模型显存 = 4x 内存 → 必须分布式
  • 强化学习训练不稳定(reward hacking、KL 爆炸)
  • 超参敏感:β(KL 惩罚权重)、learning rate、batch size 都难调
  • 工程链条长 → 不少团队尝试后放弃

DPO —— 直接绕过 RL

Rafailov et al., 2023 的核心洞察

数学上可以证明:用 PPO + reward model 解 RLHF 的最优解,等价于 直接用 (chosen, rejected) 偏好数据 + 一个简单 loss 优化。

DPO loss(直觉版):

   L_DPO = -log σ( β · [ log(π(chosen|prompt) / π_ref(chosen|prompt)) 
                        - log(π(rejected|prompt) / π_ref(rejected|prompt)) ] )
   
   人话:
       让 policy 给 chosen 的概率比 ref 高
       让 policy 给 rejected 的概率比 ref 低
       两者 gap 越大,loss 越小

带来的好处

  • 不需要训 reward model
  • 不需要跑 RL(PPO)
  • 只需要 2 个模型在显存(policy + reference frozen),比 PPO 省一半
  • 训练稳定、超参少、收敛快

代价

  • 需要高质量偏好数据对(chosen/rejected)—— 数据是核心难度
  • 极端场景(reward 设计很复杂的)DPO 表达力略弱,但绝大多数场景够用

当前业界共识

  • 中小团队 / 学术 / 大多数产品:DPO 是默认选择
  • 大模型公司核心模型:仍可能用 RLHF(更精细控制)+ DPO 后期补充

关键细节 / 数学直觉

1)数据规模典型量级

阶段典型数据量
SFT1K-100K 样本(小项目几千够用)
Reward Model10K-100K 偏好对
RLHF (PPO)用 RM 给奖励,prompt 数千-数万
DPO5K-50K 偏好对

2)DPO 简化代码

from trl import DPOTrainer, DPOConfig
 
config = DPOConfig(
    output_dir="./dpo-out",
    beta=0.1,            # KL 惩罚强度
    num_train_epochs=1,
    learning_rate=5e-7,  # DPO 通常很小
)
 
trainer = DPOTrainer(
    model=policy_model,
    ref_model=ref_model,   # 冻结的 SFT model
    args=config,
    train_dataset=preference_dataset,  # 含 prompt/chosen/rejected
    tokenizer=tokenizer,
)
trainer.train()

3)超参敏感度

超参推荐影响
beta(KL 强度)0.1(DPO) / 0.01-0.1(PPO)大 → 模型变化小,安全;小 → 变化大,可能跑偏
learning_rateDPO 5e-7 ~ 1e-6比 SFT 小 100-1000x!否则灾难遗忘
epochsDPO 1-3多轮容易过拟合偏好数据

4)DPO 的变体

业界已经有一堆 DPO 变体:

  • IPO(Identity Preference Optimization):解决 DPO 在偏好”明确”时容易过拟合
  • KTO(Kahneman-Tversky Optimization):不需要 (chosen, rejected) 对,单条带”好/坏”标签即可
  • ORPO:把 DPO 和 SFT 合到一个 loss,省一步
  • SimPO:去掉 reference model,进一步省显存

选哪个:实战首选 DPO,遇到问题再调研变体。

5)Constitutional AI / RLAIF

不依赖人类标注,而是用 AI 标注偏好

  • 给一个原则 prompt(“宁可拒绝也不给暴力建议”)
  • 让一个强模型当裁判生成 (chosen, rejected) 对
  • 然后跑 DPO

适合安全对齐(数据可大量生成);事实精度类任务还是要人工。

6)和 SFT 怎么搭

实操典型流水线:

   base 模型
      │
      ▼
   SFT (1-3 轮高质量数据)  ← 必做
      │
      ▼
   DPO (1 轮偏好数据)      ← 强烈推荐做
      │
      ▼
   线上部署 → 拿用户反馈 → 加入新一批偏好数据 → 再 DPO

只 SFT 通常已经能上线 demo;SFT+DPO 是生产级常见组合;RLHF/PPO 留给最大型项目。

延伸追问

  • Q: SFT 完直接 DPO 还是先 reward model? → DPO 不需要 RM,直接训。RM 在 RLHF 路线才用——除非你想做 BoN(Best-of-N)推理时 rerank。
  • Q: DPO 会不会遗忘 SFT 学到的能力? → 会一些。beta 大一点(0.1-0.3)+ learning rate 小(5e-7)能缓解。也可以混入一部分 SFT 数据一起训(“DPO+SFT”)。
  • Q: 偏好数据从哪来? → ① 人工标注(贵但准)② AI 标注(RLAIF,便宜但有偏见)③ 用户日志(用户点赞/踩、A/B test)④ 公开数据集(HH-RLHF、UltraFeedback)。
  • Q: 微调 vs 提示工程的边界? → SFT/DPO 适合:① 输出格式稳定 ② 领域知识/语料有量 ③ prompt 已经很长。只是改语气、加示例、限制行为 → 优先 prompt 工程 + few-shot,便宜快。

我的记法

  • 三阶段:PT → SFT → 偏好对齐(RLHF 或 DPO)
  • SFT 学格式 + 知识RLHF/DPO 学”啥更好”
  • RLHF 复杂(4 个模型 + RL 不稳);DPO 简单(2 个模型 + 监督 loss)
  • 当下默认:SFT + DPO,RLHF 留给大型项目
  • 数据:高质量 > 大量chat template 必须对齐
  • 一句话:「DPO 是 RLHF 的简化数学等价物,工程上 10 倍简单」

状态

  • 已背速记
  • 能讲通俗版
  • 能答追问
  • 用 trl 跑通过 SFT 和 DPO 的 demo 训练

参考资料