DPO 算法原理与代码实现:让 LLM 对齐变得简单
DPO 让 LLM 对齐训练变得像 SFT 一样简单。本文从 RLHF 痛点讲起,手撕 DPO Loss 核心代码,用 trl 跑通完整训练流程。Bonus 包含稳定性分析和数学推导,一篇搞定 DPO。本文是「动手学大模型」系列第12章 Part2 的配套博客。
转载提示:本文转载自 bbruceyuan 原文。原作者:bbruceyuan。原文发布日期:2026-01-10。本文已按站点规范移除原文中的推广/导流内容,仅保留技术分析与示例。0. 阅读收获 (takeaway) 本文目标是搞懂 DPO(Direct Preference Optimization)算法,阅读完本文你将获得:理解 DPO 的核心思想:为什么 DPO 可以替代 RLHF 中的 PPO掌握 DPO 与 RLHF 的关键区别:从 4 个模型到 2 个模型手撕 DPO Loss:理解损失函数到底在算什么Bonus 1:为什么 DPO 比 PPO 训练更稳定Bonus 2:DPO 损失函数的完整数学推导源代码位于 Github -动手学习大模型-中文版-第 12.1章——动手学习 DPO 本文代码运行于:Featurize 蒜粒方块 GPU 算力平台,不喜欢看文字的同学可以看 B站视频-chaofa用代码打点酱油,YouTube-chaofa用代码打点酱油,视频号:chaofa用代码打点酱油1. 为什么需要 DPO? 在聊 DPO 之前,我们先快速回顾一下 LLM 训练的三个阶段(参考 OpenAI InstructGPT):预训练(Pre-training):在海量文本上训练,让模型学会"说话"监督微调(SFT):用高质量的指令数据微调,让模型学会"听话"对齐(Alignment):让模型的输出符合人类偏好,学会"说人话" 假设读者对于前两个步骤已经有所了解,这篇文章的重点是第三步"对齐"。1.1 RLHF 的问题 OpenAI 在训练 ChatGPT 的时候用的是 RLHF(Reinforcement Learning from Human Feedback),整个流程大概是这样的: DPO 原论文中的 RLHF vs DPO 流程对比 RLHF 确实有效,但问题也很明显:需要 4 个模型:Actor(待训练)、Reference(冻结的 SFT 模型)、Reward Model(奖励模型)、Critic(价值函数)PPO 算法复杂:超参数一堆,训练不稳定,调参调到怀疑人生资源消耗大:4 个模型同时跑,显存吃不消 之前在 DeepSeek-R1 论文解读 里也提到过,DPO 是 RLHF 的一种替代方案,但 DeepSeek 最终还是用了 GRPO(一种改进的 PPO)。不过对于大多数场景来说,DPO 已经够用了。1.2 DPO 的卖点 DPO 的核心思路是:既然 RLHF 这么麻烦,能不能把强化学习的部分去掉,直接用监督学习的方式来做对齐? 答案是可以的。DPO 的作者通过一系列数学推导(后面 Bonus 部分会讲),证明了可以把 RLHF 的优化目标转换成一个简单的损失函数,只需要 2 个模型就能搞定:Actor:待训练的模型 $\pi_\theta$Reference:冻结的 SFT 模型 $\pi_{ref}$ 不需要单独训练 Reward Model,也不需要 PPO 那套复杂的东西。训练过程和 SFT 差不多,非常稳定。2. DPO 的核心思想2.1 偏好数据长什么样? DPO 需要的数据格式很简单,就是一个 prompt 配上两个回答:一个好的(chosen),一个差的(rejected)。# DPO 偏好数据示例 { "prompt": "介绍一下 chaofa用代码打点酱油 这个博主", "chosen": "chaofa用代码打点酱油 是一位专注于大模型技术的博主,他在 B站、YouTube 等平台分享 LLM 相关的技术内容,包括动手学大模型系列教程。他的内容特点是注重代码实现和原理讲解,帮助读者从零理解大模型的各种技术细节。", "rejected": "不知道,没听说过,说不定是个弱智。" } 简单说就是:同一个问题,告诉模型哪个回答是好的,哪个是不好的。这种数据可以通过人工标注获得,也可以用更强的模型(比如 gemini/claude/gpt)来生成。 TRICK: 非同源模型的数据训练的时候,可以先用 "chosen" 数据 SFT,不然可能导致 chosen 和 rejected 概率都变低。2.2 DPO 想做什么? DPO 的目标其实就两个:让模型更喜欢生成 chosen 回答:提高 chosen 的生成概率不要偏离原来的 SFT 模型太远:保持模型的基本能力,防止"忘记"之前学到的东西 第二点很重要,如果只追求第一点,模型可能会为了迎合偏好数据而变得很奇怪(比如每个回答都很长、很啰嗦)。所以需要用参考模型来"拉住"它。2.3 DPO 损失函数 好了,到了最核心的部分。DPO 的损失函数长这样: $$\mathcal{L}{\mathrm{DPO}}(\pi\theta; \…
正在初始化 WebAssembly 引擎…
首次编译原生模块可能需要数秒
就绪后,页面交互将以接近原生的速度运行