前言
Fine-tune Mistral-7b with Direct Preference Optimization – Maxime Labonne Pre-trained Large Language Models (LLMs) can only perform next-token prediction, making them unable to answer questions. This is why these base models are then fine-tuned on pairs of instructions and answers to act as helpful assistants. However, this process can still be flawed: fine-tuned LLMs can be biased, toxic, harmful, etc. This is where Reinforcement Learning from Human Feedback (RLHF) comes into play.
RLHF provides different answers to the LLM, which are ranked according to a desired behavior (helpfulness, toxicity, etc.). The model learns to output the best answer among these candidates, hence mimicking the behavior we want to instill. Often seen as a way to censor models, this process has recently become popular for improving performance.
The core concept of PPO revolves around making smaller, incremental updates to the policy, as larger updates can lead to instability or suboptimal solutions. From experience, this technique is unfortunately still unstable (loss diverges), difficult to reproduce (numerous hyperparameters, sensitive to random seeds), and computationally expensive.
This is where Direct Preference Optimization (DPO) comes into play. DPO simplifies control by treating the task as a classification problem. Concretely, it uses two models: the trained model (or policy model) and a copy of it called the reference model. During training, the goal is to make sure the trained model outputs higher probabilities for preferred answers than the reference model. Conversely, we also want it to output lower probabilities for rejected answers. It means we’re penalizing the LLM for bad answers and rewarding it for good ones.
By using the LLM itself as a reward model and employing binary cross-entropy objectives, DPO efficiently aligns the model’s outputs with human preferences without the need for extensive sampling, reward model fitting, or intricate hyperparameter adjustments. It results in a more stable, more efficient, and computationally less demanding process.
Proximal Policy Optimization (PPO) vs. Direct Preference Optimization (DPO)
- PPO(近端策略优化):是一个过程导向的算法。它通过一个独立的奖励模型给动作打分,然后用强化学习的方式一步步“调教”模型,像训练一只宠物,做得好给零食,做得不好给惩罚。
- DPO(直接偏好优化):是一个结果导向的算法。它绕过了奖励模型和强化学习,直接把“人类偏好”转化为损失函数,用监督学习的方式一步到位地更新模型,像拿着标准答案改作业,直接告诉模型哪个回答更好。
下面是深度的技术对比,分为四个维度:
1. 核心架构(管道差异)
这是两者最根本的区别。
- PPO(四阶段管道): SFT模型 → 奖励模型(RM)→ 强化学习(RL)微调。 它需要先训练一个独立的奖励模型来模拟人类偏好,然后让策略模型(Actor)生成文本,奖励模型给文本打分,PPO算法根据这个分数更新策略。为了不让模型“跑偏”,PPO还引入了一个参考模型(通常是SFT模型)来计算KL散度惩罚。
- DPO(两阶段管道): SFT模型 → 直接偏好优化。 它不需要奖励模型,也不需要复杂的强化学习循环。它利用数学变换(Bradley-Terry模型),将“偏好概率”直接推导为关于策略网络参数的损失函数。你只需要准备好(提示词,获胜回答,失败回答)三元组,直接像训练分类任务一样反向传播即可。
2. 算法复杂度与训练稳定性
- PPO:极其复杂且脆弱。它涉及4个模型(Actor、Critic、Reference、Reward Model),且需要在线采样(生成新文本)。超参数极多(学习率、裁剪范围、KL系数、GAE系数等),极其容易崩溃(Loss Spike),需要非常老练的工程师才能调好,训练成本极高。
- DPO:简洁且稳定。它只需要加载两个模型(策略模型和参考模型,参考模型冻结),且使用离线数据。本质上就是跑一个交叉熵损失函数,训练过程像SFT一样平滑,显存占用和训练时间远小于PPO。
3. 数学原理的本质差异
这是技术面试最常问的点。
- PPO:基于重要性采样(Importance Sampling)和约束优化。 它通过置信域(Clipped Surrogate Objective)限制新旧策略的差异,确保模型在探索奖励最大化的同时,不会一步走歪。其优化目标是最大化 奖励信号 + KL散度惩罚。
- DPO:基于分类损失(Classification Loss)。 它的核心洞察是:强化学习的“奖励最大化”在数学上等价于“偏好排序的最大似然”。因此,它的损失函数直接是: \(L_{DPO} = -\log \sigma \left( \beta \cdot \log \frac{\pi_\theta(y_w|x)}{\pi_{ref}(y_w|x)} - \beta \cdot \log \frac{\pi_\theta(y_l|x)}{\pi_{ref}(y_l|x)} \right)\) 其中$y_w$ 是获胜回答,$y_l$是失败回答。简单说,DPO强迫模型拉大“好回答”和“坏回答”之间概率比的差距。
4. 生成质量与多样性(最终效果)
- PPO:由于存在在线探索(Online Exploration),模型在训练中会不断尝试生成新的句子。如果奖励模型泛化能力强,PPO能探索出远超训练数据集质量的答案,上限极高。但若奖励模型被攻击(Reward Hacking),模型会输出无意义的乱码但分数极高。
- DPO:由于是离线静态数据,它只是“模仿”偏好数据中的优秀回答,创造性不如PPO。但它天然带有隐式的KL约束(因为公式里有分母 πrefπref),所以模型极其“保守”,几乎不会出现灾难性遗忘,生成文本的流畅度通常优于PPO的中间阶段。
实战选择建议(什么时候用哪个?)
| 场景 | 推荐算法 | 理由 |
|---|---|---|
| 公司资源有限,没有强化学习团队 | DPO | 不需要调成千上万的RL超参,单卡或A100 8卡即可完成,效果好且稳定。 |
| 数据量极少,且偏好差异明显 | DPO | DPO在少量高质数据上收敛极快,而PPO在数据少时奖励模型本身就不准。 |
| 模型极大(如 70B),成本敏感 | DPO | DPO只需全量参数微调一次,PPO需要同时加载4个大模型,显存消耗是DPO的4倍以上。 |
| 追求SOTA(最先进)效果,有顶级RL工程师 | PPO | 目前OpenAI、Anthropic的旗舰模型(如Claude 3)依然使用RLHF(PPO变体),因为其探索能力能让模型突破数据瓶颈。 |
| 任务需要模型编写复杂代码/推理 | PPO | 使用过程奖励模型(Process Reward Model)的PPO可以在推理链上逐步给予反馈,DPO难以做到细粒度的步骤级优化。 |
一个进阶陷阱(需要注意的点)
DPO并不总是优于PPO。 DPO在数学上虽然推导严谨,但它依赖于一个强假设:偏好具有传递性(Bradley-Terry假设)。在真实世界中,人类的偏好往往是不一致的(例如:A比B好,B比C好,但C比A好)。在这种情况下,DPO的损失函数会产生误导,而PPO由于有个独立的奖励模型,能更好地平滑这种不一致性。
目标上的差异
PPO是 回归预测 DPO是分类预测?
这个类比非常敏锐,且基本正确,但在数学上需要稍微“拨正”一下,否则容易在面试或深入推导时露馅。
更严谨的表达应该是:
- PPO 本质上是“回归(Regression)” —— 预测一个连续的打分(标量值),然后让模型输出朝高分方向移动。
- DPO 本质上是“排序/对比学习(Ranking/Contrastive)” —— 预测两个回答之间的相对概率(Odds),而不是把它们分到固定的类别里。
为了让你彻底厘清这个误区,我分三层来讲:
1. 为什么你说“DPO是分类”是对了一半?
从损失函数的形式上看,DPO确实长得像分类:
- DPO的梯度下降过程,本质上是在做 二值逻辑回归(Binary Logistic Regression)。
- 它把“获胜回答”当作正例(Label=1),“失败回答”当作负例(Label=0),然后计算交叉熵损失。
- 从编程实现的角度看,你确实是在跑一个
binary_cross_entropy,这和你训练一个垃圾邮件分类器毫无二致。
2. 但为什么严谨地说,DPO不是分类预测?
因为分类预测(Classification)的标签是绝对且固定的,比如“猫” vs “狗”。无论你输入什么图片,模型只输出一个绝对标签。
而DPO的输入是一个Pair(成对数据),它预测的是:
获胜概率=e奖励we奖励w+e奖励l获胜概率=e奖励w+e奖励l**e奖励w
注意看,分母里包含了两个回答。这意味着:同样的“获胜回答”,如果换了一个更厉害的“失败回答”来做对比,DPO的预测概率会动态改变。
- 这叫相对排序(Relative Ranking),而不是绝对分类。
- 用更专业的术语说,这是 Bradley-Terry 模型,本质是成对对比学习(Pairwise Contrastive Learning),和主流的对比学习(如 SimCLR)更接近。
3. 为什么说 PPO 是“回归预测”?
这个你说得完全正确。PPO的优化目标非常直接:
- 奖励模型(Reward Model)输出一个连续值,比如 +2.5 分。
- PPO的Actor网络要做的,就是调整参数,让生成的文本在奖励模型上得到的预测分数(标量)尽可能大。
- 这完全就是回归任务的思维:拟合一个连续的目标值(Target)。
进阶陷阱(面试官最爱问的)
如果你在面试中说出“DPO是分类”,面试官可能会追问:
“既然DPO像分类,为什么分类任务通常需要大量标注数据,而DPO在数据量很少时反而比PPO效果好?”
标准回答思路: 因为分类任务是绝对映射(输入 -> 唯一答案),需要覆盖整个输入空间,数据少了就过拟合。 而DPO是相对映射(输入 -> 好/坏对比),它只需要知道两者谁更优即可。即使没见过的输入,只要模型能维持住两个输出的概率差异(Odds Ratio),就能表现良好。这得益于它隐式地利用了参考模型(πrefπref)作为锚点,相当于自带正则化,所以小样本下很稳。
总结(帮你记忆)
| 维度 | PPO | DPO |
|---|---|---|
| 任务类型 | 回归(Regression) | 成对排序(Pairwise Ranking) |
| 预测目标 | 绝对奖励值(如 +3.2) | 相对胜率(如 A 比 B 好 70%) |
| 损失函数本质 | 策略梯度 / MSE(拟合分数) | 交叉熵(对比两个输出的logits差异) |
| 数据依赖 | 依赖奖励模型的泛化能力 | 依赖成对数据的相对优劣 |
一句话修正你的认知: PPO在“预测分数”做回归,DPO在“比较优劣”做对比学习;但因为对比学习最终套用了二分类的交叉熵壳子,所以你直觉上觉得它是分类,这在工程实现上是对的,但在数学定义上是“相对概率预测”。
DPO实现原理
把”人类偏好”直接转化为损失函数,用标准的监督学习(交叉熵)来训练模型,完全绕过奖励模型和强化学习。
二、数学原理(看懂损失函数)
1. 准备数据
你需要的数据格式是三元组:
(prompt, chosen_response, rejected_response)
[
{
"prompt": "什么是人工智能?",
"chosen": "人工智能是研究...",
"rejected": "AI就是..."
},
{
"prompt": "什么是机器学习?",
"chosen": "机器学习是...",
"rejected": "ML就是..."
}
]
2. DPO 损失函数
\[L_{DPO} = -\log \sigma \left( \beta \cdot \log \frac{\pi_\theta(y_w|x)}{\pi_{ref}(y_w|x)} - \beta \cdot \log \frac{\pi_\theta(y_l|x)}{\pi_{ref}(y_l|x)} \right)\]解读每个符号:
- $\pi_\theta$:正在训练的模型(策略模型)
- $\pi_{ref}$:参考模型(通常是 SFT 后的模型,冻结不更新)
- $y_w$:获胜回答(chosen)
- $y_l$:失败回答(rejected)
- $\beta$:温度系数,控制偏好差异的敏感度(通常 0.1~0.5)
- $\sigma$:sigmoid 函数,将值映射到 0~1
直观理解:
- 模型要提高 $y_w$ 的相对概率(分子变大)
- 模型要降低 $y_l$ 的相对概率(分母变大)
- 用 $\pi_{ref}$ 作为锚点,防止模型偏离太远
PPO 和 DPO 中的 Reference Model 本质区别
1. 存在目的(为什么需要它?)
PPO 的 Reference Model(行为约束)
PPO 的核心是在线探索。模型在尝试生成各种新句子来获取高分时,极易走火入魔(生成语法正确但毫无意义的乱码,即 Reward Hacking)。
目的:作为坏榜样。PPO 用它来计算当前模型(Actor)输出的文本与参考模型输出的文本之间的 KL 散度(分布距离),并将这个距离作为惩罚项(Penalty)扣在奖励分数上。你离我越远,我扣你分越狠,强行拉住模型别跑偏。
DPO 的 πref(偏好锚点)
DPO 没有奖励模型,也没有在线探索,只是拿现成的静态数据做对比学习。
目的:作为基准秤。它不直接参与约束计算,而是作为一个倍率分母。DPO 并不关心模型输出了什么新文本,它只关心:对于同一个固定的 prompt,训练模型(πθ)给好回答的概率,相比参考模型(πref)提升了多少倍?(即计算比值 πθ / πref)
2. 作用时机与计算方式
PPO(作用在动作空间上)
PPO 每生成一个 Token,就要计算一次当前模型(Actor)和参考模型(Ref)的概率分布差异(KL divergence)。
公式: \(\text{Reward}_{final} = \text{Reward}_{model} - \beta \cdot KL(\text{Actor} \parallel \text{Ref})\)
这里的 KL 计算的是整个词表(Vocab)上的分布差。它不考虑回答好不好,只要概率分布变了一点,就要扣分。这是全局漂移惩罚。
DPO(作用在特定答案上)
DPO 只在计算 Loss 时,提取出 chosen 和 rejected 这两个特定句子的 log 概率。
公式: \(L_{DPO} = -\log \sigma \left( \beta \cdot \log \frac{\pi_\theta(y_w|x)}{\pi_{ref}(y_w|x)} - \beta \cdot \log \frac{\pi_\theta(y_l|x)}{\pi_{ref}(y_l|x)} \right)\)
它不计算模型整个输出空间的分布差异。它只拿出好答案和坏答案这两个点,用 πref 当尺子量一下:相比于原来的水平,你现在给好答案涨了多少概率?给坏答案降了多少概率?这叫特定样本隐式约束。
3. 训练中的角色(被动 vs 主动)
PPO(主动的裁判员)
每一步更新,Reference Model 都必须参与前向计算(计算 KL),计算出的 KL 值直接影响当前这一步的梯度方向和大小。它是一个活跃的惩罚因子,时刻干预训练过程。
DPO(被动的参照物)
πref 只在计算 Loss 的时候参与一次除法运算,而且它不参与损失函数的梯度回传(with torch.no_grad())。它更像一个固定的标尺,只是站在那里告诉你原来这个模型的概率是多高,方便模型知道自己进步了多少。
4. 直观比喻
| 模型 | 比喻 |
|---|---|
| PPO 的 Reference Model | 训猛兽的笼子。猛兽(Actor)必须只能在笼子(Ref)允许的范围内活动,只要肢体(输出分布)超出笼子边界,立刻电击(KL惩罚)。 |
| DPO 的 πref | 健身房的体重秤。记录下昨天(SFT阶段)的体重(概率),今天锻炼(DPO训练)后,再上秤称一下,看相对于昨天,肌肉(好回答)涨了多少,肥肉(坏回答)减了多少。秤本身不提供约束力,只提供对比基准。 |
5. 终极对比表
| 维度 | PPO 的 Reference Model | DPO 的 πref |
|---|---|---|
| 核心用途 | KL 散度惩罚项(防止分布漂移) | 概率比值基准(度量相对提升) |
| 计算对象 | 整个词表的概率分布 | 仅限 Chosen 和 Rejected 两个句子 |
| 是否参与梯度 | 不更新,但参与每步前向计算(算KL) | 不更新,参与 Loss 计算(被除) |
| 约束性质 | 显式强制约束(硬性扣分) | 隐式对比约束(通过比值反向传播) |
| 直观类比 | 驯兽师的笼子边界 | 健身房的体重秤 |
| 对训练的影响 | 直接修改 Reward 信号 | 间接修改 Loss 梯度方向 |
6. 工程差异(显存占用)
PPO
因为要算分布,所以必须时刻加载 Ref 模型在前向传播中,显存占用极大(4个模型同时跑:Actor + Critic + Ref + Reward)。
DPO
因为只取两个点的 logit 做除法,不关心全局分布,可以把 πref 计算好的概率提前存起来,训练时甚至不需要加载 πref(仅需加载预计算好的参考概率值)。这是 DPO 极致节省显存的数学基础。
7. 核心总结
- PPO 的 Ref:显式约束,实时计算 KL 惩罚,防止模型在探索中崩溃。
- DPO 的 πref:隐式约束,作为概率比值的分母,通过 Loss 梯度间接限制模型偏离程度。
代码实战:
Fine-tune Mistral-7b with Direct Preference Optimization – Maxime Labonne