概述
将大型语言模型 (LLM) 与人类价值观和偏好相结合是一项挑战。传统方法,例如 [从人类反馈中强化学习]((RLHF)通过整合人类输入来完善模型输出,为这一领域的研究铺平了道路。然而,RLHF 可能非常复杂且资源密集,需要大量的计算能力和数据处理。 直接偏好优化 (DPO)作为一种新颖且更精简的方法出现,为这些传统方法提供了一种有效的替代方案。通过简化优化过程,DPO 不仅减少了计算负担,还增强了模型快速适应人类偏好的能力
偏好协调的必要性
在深入研究 DPO 之前,我们必须先了解为什么将 LLM 与人类偏好相结合如此重要。尽管 LLM 具有令人印象深刻的能力,但经过大量数据集训练的 LLM 有时会产生不一致、有偏见或与人类价值观不一致的输出。这种不一致可以表现为多种方式:
- 生成不安全或有害的内容
- 提供不准确或误导性的信息
- 训练数据中存在偏差
为了解决这些问题,研究人员开发了利用人工反馈来微调 LLM 的技术。其中最突出的方法是 RLHF。
了解 RLHF:DPO 的前身
人类反馈强化学习 (RLHF) 一直是将 LLM 与人类偏好相结合的首选方法。让我们分解 RLHF 流程以了解其复杂性:
a) 监督微调 (SFT):该过程首先在高质量响应数据集上对预先训练的 LLM 进行微调。此步骤可帮助模型为目标任务生成更相关、更连贯的输出。
b) 奖励模型:训练单独的奖励模型来预测人类偏好。这涉及:
- 根据给定的提示生成响应对
- 让人类评价他们喜欢哪种反应
- 训练模型来预测这些偏好
c) 强化学习:经过微调的 LLM 随后使用强化学习进一步优化。奖励模型提供反馈,引导 LLM 生成符合人类偏好的反应。
下面是一个简化的 Python 伪代码,用于说明 RLHF 过程:
虽然 RLHF 有效,但它有几个缺点:
- 它需要训练和维护多个模型(SFT、奖励模型和 RL 优化模型)
- RL 过程可能不稳定,并且对超参数敏感
- 计算成本高昂,需要通过模型进行多次前向和后向传递
这些限制促使人们寻找更简单、更有效的替代方案,从而导致了 DPO 的发展。
直接偏好优化:核心概念
此图对比了两种将 LLM 输出与人类偏好相一致的不同方法:基于人类反馈的强化学习 (RLHF) 和直接偏好优化 (DPO)。RLHF 依靠奖励模型通过迭代反馈循环来指导语言模型的策略,而 DPO 则使用偏好数据直接优化模型输出以匹配人类偏好的响应。此比较突出了每种方法的优势和潜在应用,为未来 LLM 如何训练以更好地符合人类期望提供了见解。
DPO 背后的关键思想:
a) 隐性奖励模型:DPO 将语言模型本身视为隐式奖励函数,从而消除了对单独奖励模型的需求。
b) 基于策略的制定:DPO 不优化奖励函数,而是直接优化策略(语言模型)以最大化首选响应的概率。
c) 闭式解:DPO 利用数学洞察力,可以对最佳策略提供闭式解,从而避免进行迭代 RL 更新。
实施 DPO:实用代码演练
下图展示了使用 PyTorch 实现 DPO 损失函数的代码片段。该函数在改进语言模型如何根据人类偏好对输出进行优先排序方面起着至关重要的作用。以下是关键组件的细分:
- 函数签名:本
dpo_loss
函数接受几个参数,包括策略日志概率(pi_logps
),参考模型对数概率(ref_logps
),以及代表优先和非优先完成情况的指数(yw_idxs
,yl_idxs
)此外,beta
参数控制KL惩罚的强度。 - 对数概率提取:代码从策略和参考模型中提取首选和不首选完成的对数概率。
- 对数比率计算:针对策略模型和参考模型,计算了优先完成和不优先完成的对数概率之间的差异。该比率对于确定优化的方向和幅度至关重要。
- 损失和奖励计算:损失计算如下:
logsigmoid
函数,而奖励则通过缩放策略和参考日志概率之间的差异来确定beta
.
使用 PyTorch 的 DPO 损失函数
DPO 的数学原理
DPO 是对偏好学习问题的一个巧妙的重新表述。下面是分步分解:
a)起点:KL 约束奖励最大化
原始 RLHF 目标可以表示为:
地点:
- πθ 是我们正在优化的策略(语言模型)
- r(x,y) 是奖励函数
- πref 是参考策略(通常是初始 SFT 模型)
- β 控制 KL 散度约束的强度
b) 最优策略形式: 可以证明,该目标的最优策略采取如下形式:
π_r(y|x) = 1/Z(x) * πref(y|x) * exp(1/β * r(x,y))
其中 Z(x) 是归一化常数。
c) 奖励策略二元性: DPO 的关键见解是用最优策略来表达奖励函数:
r(x,y) = β * log(π_r(y|x) / πref(y|x)) + β * log(Z(x))
d) 偏好模型假设偏好遵循 Bradley-Terry 模型,我们可以将偏好 y1 而非 y2 的概率表示为:
p*(y1 ≻ y2 | x) = σ(r*(x,y1) - r*(x,y2))
其中 σ 是逻辑函数。
e) DPO 目标 将我们的奖励策略二元性代入偏好模型,我们得出 DPO 目标:
L_DPO(πθ; πref) = -E_(x,y_w,y_l)~D [log σ(β * log(πθ(y_w|x) / πref(y_w|x)) - β * log(πθ(y_l|x) / πref(y_l|x)))]
可以使用标准梯度下降技术来优化该目标,而无需 RL 算法。
实施 DPO
现在我们了解了 DPO 背后的理论,让我们看看如何在实践中实现它。我们将使用 蟒蛇 和 PyTorch 对于此示例:
import torch
import torch.nn.functional as F
class DPOTrainer:
def __init__(self, model, ref_model, beta=0.1, lr=1e-5):
self.model = model
self.ref_model = ref_model
self.beta = beta
self.optimizer = torch.optim.AdamW(self.model.parameters(), lr=lr)
def compute_loss(self, pi_logps, ref_logps, yw_idxs, yl_idxs):
"""
pi_logps: policy logprobs, shape (B,)
ref_logps: reference model logprobs, shape (B,)
yw_idxs: preferred completion indices in [0, B-1], shape (T,)
yl_idxs: dispreferred completion indices in [0, B-1], shape (T,)
beta: temperature controlling strength of KL penalty
Each pair of (yw_idxs[i], yl_idxs[i]) represents the indices of a single preference pair.
"""
# Extract log probabilities for the preferred and dispreferred completions
pi_yw_logps, pi_yl_logps = pi_logps[yw_idxs], pi_logps[yl_idxs]
ref_yw_logps, ref_yl_logps = ref_logps[yw_idxs], ref_logps[yl_idxs]
# Calculate log-ratios
pi_logratios = pi_yw_logps - pi_yl_logps
ref_logratios = ref_yw_logps - ref_yl_logps
# Compute DPO loss
losses = -F.logsigmoid(self.beta * (pi_logratios - ref_logratios))
rewards = self.beta * (pi_logps - ref_logps).detach()
return losses.mean(), rewards
def train_step(self, batch):
x, yw_idxs, yl_idxs = batch
self.optimizer.zero_grad()
# Compute log probabilities for the model and the reference model
pi_logps = self.model(x).log_softmax(-1)
ref_logps = self.ref_model(x).log_softmax(-1)
# Compute the loss
loss, _ = self.compute_loss(pi_logps, ref_logps, yw_idxs, yl_idxs)
loss.backward()
self.optimizer.step()
return loss.item()
# Usage
model = YourLanguageModel() # Initialize your model
ref_model = YourLanguageModel() # Load pre-trained reference model
trainer = DPOTrainer(model, ref_model)
for batch in dataloader:
loss = trainer.train_step(batch)
print(f"Loss: {loss}")
挑战和未来方向
虽然 DPO 比传统 RLHF 方法具有显著优势,但仍然存在挑战和有待进一步研究的领域:
a)可扩展至更大的模型:
随着语言模型的规模不断扩大,如何有效地将 DPO 应用于具有数千亿个参数的模型仍然是一个悬而未决的挑战。研究人员正在探索以下技术:
- 高效的微调方法(例如,LoRA、前缀调整)
- 分布式训练优化
- 梯度检查点和混合精度训练
使用 LoRA 与 DPO 的示例:
from peft import LoraConfig, get_peft_model
class DPOTrainerWithLoRA(DPOTrainer):
def __init__(self, model, ref_model, beta=0.1, lr=1e-5, lora_rank=8):
lora_config = LoraConfig(
r=lora_rank,
lora_alpha=32,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM"
)
self.model = get_peft_model(model, lora_config)
self.ref_model = ref_model
self.beta = beta
self.optimizer = torch.optim.AdamW(self.model.parameters(), lr=lr)
# Usage
base_model = YourLargeLanguageModel()
dpo_trainer = DPOTrainerWithLoRA(base_model, ref_model)
开发能够有效适应偏好数据有限的新任务或领域的 DPO 技术是一个活跃的研究领域。正在探索的方法包括:
- 用于快速适应的元学习框架
- 基于提示的 DPO 微调
- 将学习从一般偏好模型转移到特定领域
c)处理模糊或冲突的偏好:
现实世界的偏好数据通常包含歧义或冲突。提高 DPO 对此类数据的稳健性至关重要。潜在的解决方案包括:
- 概率偏好建模
- 主动学习解决歧义
- 多代理偏好聚合
概率偏好建模的示例:
class ProbabilisticDPOTrainer(DPOTrainer):
def compute_loss(self, pi_logps, ref_logps, yw_idxs, yl_idxs, preference_prob):
# Compute log ratios
pi_yw_logps, pi_yl_logps = pi_logps[yw_idxs], pi_logps[yl_idxs]
ref_yw_logps, ref_yl_logps = ref_logps[yw_idxs], ref_logps[yl_idxs]
log_ratio_diff = pi_yw_logps.sum(-1) - pi_yl_logps.sum(-1)
loss = -(preference_prob * F.logsigmoid(self.beta * log_ratio_diff) +
(1 - preference_prob) * F.logsigmoid(-self.beta * log_ratio_diff))
return loss.mean()
# Usage
trainer = ProbabilisticDPOTrainer(model, ref_model)
loss = trainer.compute_loss(pi_logps, ref_logps, yw_idxs, yl_idxs, preference_prob=0.8) # 80% c
d)将DPO与其他对准技术相结合:
将 DPO 与其他对齐方法相结合可以产生更强大、更强大的系统:
- 明确约束满足的宪法人工智能原则
- 用于复杂偏好引出的辩论和递归奖励建模
- 用于推断底层奖励函数的逆向强化学习
DPO 与体质 AI 相结合的示例:
class ConstitutionalDPOTrainer(DPOTrainer):
def __init__(self, model, ref_model, beta=0.1, lr=1e-5, constraints=None):
super().__init__(model, ref_model, beta, lr)
self.constraints = constraints or []
def compute_loss(self, pi_logps, ref_logps, yw_idxs, yl_idxs):
base_loss = super().compute_loss(pi_logps, ref_logps, yw_idxs, yl_idxs)
constraint_loss = 0
for constraint in self.constraints:
constraint_loss += constraint(self.model, pi_logps, ref_logps, yw_idxs, yl_idxs)
return base_loss + constraint_loss
# Usage
def safety_constraint(model, pi_logps, ref_logps, yw_idxs, yl_idxs):
# Implement safety checking logic
unsafe_score = compute_unsafe_score(model, pi_logps, ref_logps)
return torch.relu(unsafe_score - 0.5) # Penalize if unsafe score > 0.5
constraints = [safety_constraint]
trainer = ConstitutionalDPOTrainer(model, ref_model, constraints=constraints)
实际考虑和最佳实践
在为实际应用实施 DPO 时,请考虑以下提示:
a) 数据质量:偏好数据的质量至关重要。确保您的数据集:
- 涵盖多种输入和期望行为
- 具有一致且可靠的偏好注释
- 平衡不同类型的偏好(例如事实性、安全性、风格)
b) 超参数调整:虽然 DPO 的超参数比 RLHF 少,但调整仍然很重要:
- β(beta):控制偏好满足度与参考模型偏差之间的权衡。从以下值开始 0.1-0.5.
- 学习率:使用比标准微调更低的学习率,通常在以下范围内: 1e-6 至 1e-5.
- 批次大小:更大的批次大小(32-128) 通常对偏好学习很有效。
c) 迭代细化:DPO可以迭代应用:
- 使用 DPO 训练初始模型
- 使用经过训练的模型生成新的响应
- 收集有关这些回应的新偏好数据
- 使用扩展的数据集重新训练
直接偏好优化性能
该图深入研究了 GPT-4 等 LLM 与人类判断在各种训练技术(包括直接偏好优化 (DPO)、监督微调 (SFT) 和近端策略优化 (PPO))中的性能对比。该表显示,GPT-4 的输出越来越符合人类偏好,尤其是在摘要任务中。GPT-4 与人类审阅者之间的一致性水平表明该模型能够生成与人类评估者产生共鸣的内容,几乎与人类生成的内容一样接近。
案例研究和应用
为了说明 DPO 的有效性,让我们看一些实际应用及其一些变体:
- 迭代 DPO:此变体由 Snorkel (2023) 开发,将拒绝采样与 DPO 相结合,从而实现更精细的训练数据选择过程。通过对多轮偏好采样进行迭代,该模型能够更好地泛化并避免过度拟合嘈杂或有偏见的偏好。
- 首次公开募股(迭代偏好优化):IPO 由 Azar 等人 (2023) 提出,增加了一个正则化项来防止过度拟合,这是基于偏好的优化中常见的问题。此扩展允许模型在遵循偏好和保留泛化能力之间保持平衡。
- 韩国旅游观光局 (知识转移优化):Ethayarajh 等人 (2023) 的最新变体 KTO 完全摒弃了二元偏好。相反,它专注于将知识从参考模型转移到策略模型,以优化与人类价值观的更顺畅和更一致的一致性。
- 用于跨领域学习的多模态 DPO 作者:Xu 等人(2024 年):一种将 DPO 应用于不同模态(文本、图像和音频)的方法,展示了其在将模型与人类偏好相结合方面跨不同数据类型的多功能性。这项研究强调了 DPO 在创建能够处理复杂、多模态任务的更全面的 AI 系统方面的潜力。
结论
直接偏好优化代表了语言模型与人类偏好相一致的重大进步。它的简单性、效率和有效性使其成为研究人员和从业人员的强大工具。
通过利用直接偏好优化的强大功能并牢记这些原则,您可以创建不仅具有令人印象深刻的功能而且与人类价值观和意图紧密结合的语言模型。
原文地址:https://www.unite.ai/direct-preference-optimization-a-complete-guide/