DPO — Direct Preference Optimization
是什么
DPO(Direct Preference Optimization,直接偏好优化)是把 instructgpt 那条 RLHF 流水线做”减法”——把”训 reward model + 用 PPO 跑强化学习”两步硬活,合并成”用人工偏好数据直接 fine-tune LM”一步。
日常类比:以前的 RLHF 像请家长(reward model)先给两个回答打分,再让小孩(policy)按家长反馈调整。DPO 让你跳过家长——直接给小孩看”这一对里哪个好哪个坏”,让他自己学。
数据形式:每条是 {prompt, chosen, rejected} 三元组——同一个 prompt 下两个回答,标注员选哪个更好。DPO 的目标就是让模型对 chosen 的概率上升、对 rejected 的概率下降。
为什么重要
不理解 DPO,下面这些事都没法解释:
- 为什么 2023 下半年开始的开源 LLM 后训练(Llama 2 / Llama 3 / Zephyr / Tülu)几乎一夜切掉了 PPO
- 为什么”做对齐”的工程门槛从”需要 RL 专家”降到”会 fine-tune 就行”
- 为什么 Hugging Face TRL 的
DPOTrainer30 行代码就能跑——同等任务用 PPO 实现要 300+ 行加一堆调参 - 为什么显存不够的小团队也能做对齐——PPO 要同时载 4 个模型,DPO 只要 2 个
DPO 出现之前,“想做 RLHF 但调不动 PPO”的小团队只能用 best-of-N rejection 凑合。DPO 之后,只要会 SFT 就能做对齐——这是开源对齐生态在 2023-2024 大爆发的关键工程前置。
核心要点
DPO 的全部魔法可以拆成 三个洞察:
-
数学等价:作者证明”先训 reward model 再用 RL 找最优 policy”和”直接对成对偏好做分类”在数学上是同一件事。前者那个最难调的 PPO 阶段,原来可以用一个 closed-form 解析式跳过。
-
Loss 是一行 BCE:
L = -log σ( β·log[π(chosen|x)/π_ref(chosen|x)]- β·log[π(rejected|x)/π_ref(rejected|x)] )π_ref是 SFT 后的 frozen 模型(基准),π是正在训的模型。这一行就是全部——本质是个 binary cross-entropy:“chosen 比 rejected 好”作为标签。 -
KL 约束自动成立:PPO 需要显式加
β·KL[π||π_ref]项防止 policy 漂移。DPO 把这个约束藏在 log ratio 里——β·log(π/π_ref)这一项天然约束 π 不能离 π_ref 太远,不需要再加额外约束。
一句话:DPO = “用偏好对做 BCE,π/π_ref 的 log ratio 是隐式 reward,β 是 KL 强度旋钮”。
实践案例
案例 1:数据长什么样
Anthropic HH 数据集里典型的一条:
{ "prompt": "How can I improve my sleep?", "chosen": "Try keeping a consistent bedtime, avoiding screens 1h before sleep...", "rejected": "Just take sleeping pills."}标注员看了两个回答,选 chosen。DPO 把整个数据集的 chosen 推高、rejected 压低,policy 自然学到”helpful + safe”的回答风格。
案例 2:30 行 PyTorch 写完
import torch.nn.functional as F
def dpo_loss(logp_w, logp_l, ref_logp_w, ref_logp_l, beta=0.1): # implicit reward = β · log(π/π_ref) logits = beta * ((logp_w - ref_logp_w) - (logp_l - ref_logp_l)) return -F.logsigmoid(logits).mean()logp_* 是 response 上所有 token 的 log probability 求和。两次前向(一次 chosen 一次 rejected),算 ratio,logsigmoid 完事。
案例 3:Hugging Face TRL 一行调用
from trl import DPOTrainertrainer = DPOTrainer(model, ref_model, train_dataset=preference_data, beta=0.1)trainer.train()整个开源生态——Zephyr-7B / Tülu / Nous-Hermes 等——基本都是这条路径。Llama 3 的对话能力调优也用了 DPO(叠加 iterative rejection sampling)。
踩过的坑
-
β 调错就崩:β 太大,π 几乎不动;β 太小,π 漂离 π_ref 太远,generation 灾难性下降。典型值 0.1。
-
数据质量 > loss 公式:换数据集(从 UltraFeedback 到自生成 + GPT-4 重标注)收益可达 10%;换 loss 形式(DPO → SimPO)收益往往只有 1-2%。
-
chosen 和 rejected 都很差时 DPO 会推高烂答案:DPO 只看相对——它没办法区分”绝对好”和”相对好”。如果数据里 chosen 也是垃圾,policy 仍然学到这个垃圾的方向。
-
长度偏差:chosen 在数据集里通常更长,DPO 训完后 generation 普遍变长,有时是 padding 出来的废话。SimPO 的 length normalization 就是针对这个问题。
-
offline 的天花板:DPO 是 offline 的——policy 漂出 dataset 分布后没有 supervision。这是它和 PPO 的根本区别——PPO 可以一边训一边 rollout 探索,DPO 只能在固定 pair 上训。这也是 2024 一堆 online DPO 变种出现的原因。
适用 vs 不适用场景
适用:
- 开源 LLM 后训练(数据有限、显存紧、调参预算少)
- 已有成对偏好数据(Anthropic HH / UltraFeedback / 自家产品的对比标注)
- 单轮对话 / 摘要 / 简单 instruction following
不适用:
- 需要 absolute reward(best-of-N rejection sampling 时 DPO model 算不出绝对分数)
- 需要长期探索新分布(数学推理 / 代码 agent,这种场景 PPO + RM + iterative 仍然占优)
- 只有单边数据(点赞 / 点踩,没有成对)—— 改用 KTO
历史小故事(可跳过)
- 2017:Christiano et al. 首次把人类成对偏好作为 RL 信号(Deep RL from Human Preferences)。
- 2020:OpenAI summarization preference paper 把 RLHF + LLM 拼起来做摘要。
- 2022:instructgpt (Ouyang et al.) 让 ChatGPT 雏形浮出水面,RLHF 三阶段(SFT + RM + PPO)成为标准。
- 2023-05:Rafailov 等斯坦福团队挂出 DPO 论文,标题 “Your Language Model is Secretly a Reward Model” 一夜刷屏。
- 2023 年底:Zephyr-7B、Tülu 用 DPO 把开源 LLM 对齐质量推到接近 GPT-3.5。
- 2024:Llama 3、DeepSeek 系列采用 DPO 作为后训练核心,IPO / KTO / SimPO / ORPO 等变种涌现。
instructgpt 的 PPO 流水线像 RLHF 的”汇编语言”——能用但调不动;DPO 像”高级语言”——把同样的事用一行 BCE 写完。
学到什么
- 能用一行 closed-form 跳过的事,就别用 RL 硬算——DPO 的数学起点是”KL-constrained reward maximization 有解析解”
- 隐式 reward 的思路——
π/π_ref的 log ratio 自动是合法的 reward function,不必显式训 RM - 工程价值 > 理论新颖性——DPO 的核心数学是 BT preference + 变分法的标准操作,但能把整个 RLHF 流水线砍半,这是真正的工程创新
- 数据 > 算法——loss 形式的优化空间已经很小,真正大的 gain 来自数据质量
延伸阅读
- 论文 PDF:Rafailov et al. 2023 — Direct Preference Optimization
- Sebastian Raschka 的 DPO 系列博客(推导讲得最 friendly)
- Hugging Face TRL 官方 DPO tutorial(带代码)
关联
- instructgpt —— DPO 直接简化的对象;InstructGPT 的三阶段 RLHF 是 DPO 的前身
- ppo —— DPO 替代的 RL 算法;PPO 用 actor-critic + on-policy rollout,DPO 用 offline pair + BCE
- llama —— Llama 2/3 的对话能力调优都用 DPO
- gpt-3 —— DPO 的训练对象通常是 GPT-3 / Llama 这类 base LLM
- attention —— 所有现代 LLM 的核心组件;DPO 不修改架构,只换 loss