偏好优化方法配置全解:基于 TRL 的 DPO / ORPO / KTO / SimPO 实战指南
【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents
本指南完整解读preference-optimization技能的配置核心文档 method-configs.md,该文档为 DPO、ORPO、KTO、SimPO 四种偏好优化方法提供可直接落地的 TRL 配置块,并配套方法选型表、迭代式 on-policy DPO 生产模式、Pair 构建规则与灾难性遗忘排查路径。读完本文,你将掌握在当前 TRL API(processing_class而非tokenizer=)下配置四种方法的完整参数清单、Unsloth 加速封装方式,以及如何规避学习率过高导致的通用能力退化。
文档定位:方法选型表的可执行落点
method-configs.md不是一份独立的教程,而是 preference-optimization/SKILL.md 中Method Selection 方法选型表路由后的"可执行配置层"。SKILL.md 中的选型表决定了何时使用哪种方法:
| 数据形态 | 方法 | 关键参数 |
|---|---|---|
| 偏好对(默认场景) | DPO | β=0.1,LR 5e-7–1e-6,1–2 轮 |
| 内存受限或没有 SFT checkpoint | ORPO | reference-free,将 SFT 与偏好目标融合进单一 loss |
| 无配对的正负反馈 | KTO | 每个样本一个二元标签,无需配对 |
| 存在长度偏差且有 sweep 预算 | SimPO | reference-free;需按 sweep 网格调参 |
配置文档中的所有示例都遵循两条硬性约定:
- 从不写死基座模型。每个示例统一使用
BASE_MODEL/SFT_CHECKPOINT占位符,具体加载哪个 checkpoint 由 finetuning-method-selection 的 model-catalog.md 决定——该文件是整个 llm-finetuning 插件中唯一命名基座模型家族的位置,按参数规模分档维护。 - 全部遵循当前 TRL API 约定。Trainer 一律使用
processing_class=tokenizer,而不是已被移除/废弃的tokenizer=。这与 lora-qlora-recipes 的 unsloth-trl-mapping.md 中建立的约定一致——该文件明确指出tokenizer=是移植旧代码时最常见的过期 API 错误。
DPO:默认偏好优化方案
标准 TRL 配置块
DPO 是文档中"默认情况"下的首选方法。核心配置块如下:
from trl import DPOConfig, DPOTrainer dpo_args = DPOConfig( output_dir="./outputs-dpo", beta=0.1, # settled default learning_rate=7e-7, # 5e-7-1e-6 range — lower than SFT LR num_train_epochs=2, # 1-2 epochs, not more per_device_train_batch_size=4, gradient_accumulation_steps=4, bf16=True, # never fp16 — see lora-qlora-recipes Failure Modes logging_steps=10, seed=3407, ) trainer = DPOTrainer( model=SFT_CHECKPOINT, # policy — starts as a copy of the reference ref_model=None, # None = TRL derives a frozen reference from `model` args=dpo_args, train_dataset=preference_pairs, # {"prompt", "chosen", "rejected"} processing_class=tokenizer, # current TRL — not tokenizer= ) trainer.train()几个关键点需要展开:
beta=0.1是 settled default:SKILL.md 中明确写死 β=0.1,这是默认基准,不建议在未验证前自行调整。- 学习率必须低于 SFT 阶段:DPO 的 LR 区间是 5e-7–1e-6,文档特别强调"低于产生该 checkpoint 的 SFT LR"。把 SFT 规模的学习率直接搬进 DPO 运行,是这里最常见的错误配置,而不是边缘情况。
ref_model=None的语义:TRL 会自动从model派生一个冻结的参考模型。这个细节在第 1 轮迭代中至关重要——只有第 1 轮才能使用ref_model=None。- 训练轮次 1–2 轮封顶,不要更多。
迭代式 on-policy DPO 生产模式
文档明确说明:单次离线 DPO 只是一个起点,不是生产模式。生产管线应当迭代式、on-policy 地运行:
- 从当前 policy checkpoint 采样 completions;
- 对 completions 打分或排序(reward model、judge 或任务 grader);
- 以当前 checkpoint 作为参考模型,运行一轮 DPO;
- 产出的 checkpoint 同时成为下一轮的 policy 和 reference。
如此循环。关键规则是:每一轮的参考模型都是上一轮的输出,而不是固定的初始 checkpoint。在代码层面,这意味着:
第 1 轮使用
ref_model=None;之后的每一轮,都要把上一轮保存的 checkpoint 显式作为ref_model传入新的DPOTrainer实例。
这保证了偏好信号始终是 on-policy 的,而不是对着一个越来越过时的分布打分。SKILL.md 建议:单次 DPO 运行仍可作为合理的第一迭代,但应当规划至少再跑一轮,而不是把第一轮当成成品。
Unsloth 封装
在内存受限场景下,可以用 Unsloth 对 DPO 做加速封装。PatchDPOTrainer()必须在构造DPOTrainer之前执行:
from unsloth import FastLanguageModel, PatchDPOTrainer PatchDPOTrainer() # must run before constructing DPOTrainer model, tokenizer = FastLanguageModel.from_pretrained( model_name=SFT_CHECKPOINT, max_seq_length=2048, load_in_4bit=True, ) model = FastLanguageModel.get_peft_model(model, r=32, lora_alpha=64) # DPOConfig/DPOTrainer usage is unchanged from the plain-TRL block above注意lora_alpha=64 = 2 × r=32,这与 lora-qlora-recipes 的 SKILL.md 中"lora_alpha = 2 * r是 settled convention"的约定完全一致(NeurIPS 2025 "intruder dimensions" 结论)。Unsloth 的load_in_4bit=True即 QLoRA 路径,等价于BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16),具体映射见 unsloth-trl-mapping.md。
ORPO:内存受限或无 SFT checkpoint 时的选择
from trl.experimental.orpo import ORPOConfig, ORPOTrainer orpo_args = ORPOConfig( output_dir="./outputs-orpo", beta=0.1, # λ in the ORPO odds-ratio term, ≈0.1 learning_rate=2e-5, # 8e-6-5e-5 range num_train_epochs=2, per_device_train_batch_size=4, gradient_accumulation_steps=4, bf16=True, logging_steps=10, seed=3407, ) trainer = ORPOTrainer( model=BASE_MODEL, # no separate SFT checkpoint needed — reference-free args=orpo_args, train_dataset=preference_pairs, # {"prompt", "chosen", "rejected"} processing_class=tokenizer, ) trainer.train()ORPO 的选型逻辑非常清晰:它把 SFT 与偏好目标融合进单一 loss,并且reference-free——不携带 DPO 那种参考模型的内存开销。这正是它在内存压力下、或尚不存在独立 SFT checkpoint 时被路由进来的全部原因。注意:
- 它的
model直接是BASE_MODEL,不需要 SFT checkpoint; - 参数
beta=0.1对应 ORPO odds-ratio 项中的 λ,近似 0.1; - 它的学习率区间(8e-6–5e-5)与 DPO 不同,量级更高,不要照搬 DPO 的 LR。
从选型角度看,SKILL.md 给出的路由场景是:"GPU 预算不足以覆盖一次独立 SFT 加一个 DPO 参考模型"——这正是 ORPO 的适用区间。
KTO:无配对二元反馈
from trl import KTOConfig, KTOTrainer kto_args = KTOConfig( output_dir="./outputs-kto", beta=0.1, learning_rate=5e-7, # same range as DPO num_train_epochs=1, per_device_train_batch_size=4, gradient_accumulation_steps=4, bf16=True, logging_steps=10, seed=3407, ) trainer = KTOTrainer( model=SFT_CHECKPOINT, ref_model=None, args=kto_args, train_dataset=labeled_examples, # {"prompt", "completion", "label": bool} processing_class=tokenizer, ) trainer.train()KTO 的数据形态与 DPO/ORPO 完全不同:{"prompt", "completion", "label": bool},即每个样本独立携带一个二元标签,样本之间无需配对。
label=True标记合意完成(点赞),label=False标记不合意完成(点踩);- 一个健康的数据集必须同时包含两种标签,不能是全正例或全负例集合;
- 路由原则:当反馈是 unpaired 的二元信号(thumbs-up/down)时,用 KTO,不要把无配对反馈强行合成伪配对去迁就 DPO。
SimPO:修复长度偏差,但必须 Sweep
SimPO 是 reference-free 且做了长度归一化的方法。文档给出了重要提醒:它公开报道的收益是在严格调参下的上限(ceiling),不是任何一个单一配置就能复现的基线。因此必须按网格 sweep,而不是随便挑一个点就信任它。
必须执行的 Sweep 网格
| 超参数 | Sweep 范围 |
|---|---|
| 有效批量大小 | 128(固定) |
| 学习率 | 3e-7 – 1e-6 |
| β | 2.0 – 2.5 |
| γ/β(target reward margin) | 0 – 1 |
TRL 实现:通过 CPOTrainer 使用 SimPO
关键实现事实:TRL 是通过CPOTrainer配合loss_type="simpo"来实现 SimPO 的,因此配置入口在trl.experimental.cpo:
from trl.experimental.cpo import CPOConfig, CPOTrainer # TRL implements SimPO via CPOTrainer with loss_type="simpo" simpo_args = CPOConfig( output_dir="./outputs-simpo", loss_type="simpo", beta=2.25, # sweep 2.0-2.5 cpo_alpha=0.0, # 0 disables the CPO NLL term for pure SimPO simpo_gamma=0.5, # gamma/beta sweep point, 0-1 learning_rate=5e-7, # sweep 3e-7-1e-6 num_train_epochs=1, per_device_train_batch_size=4, gradient_accumulation_steps=32, # 4 * 32 = 128 effective batch bf16=True, logging_steps=10, seed=3407, ) trainer = CPOTrainer( model=SFT_CHECKPOINT, args=simpo_args, train_dataset=preference_pairs, # {"prompt", "chosen", "rejected"} processing_class=tokenizer, ) trainer.train()参数解读:
cpo_alpha=0.0:置 0 即关闭 CPO 的 NLL 项,得到纯粹的 SimPO;simpo_gamma=0.5:这是 γ/β(目标奖励边界)的一个 sweep 点,取值范围 0–1;- 有效批量 = 4 × 32 = 128:固定值,通过
gradient_accumulation_steps=32配合per_device_train_batch_size=4实现; - β 的取值(2.25 起点)与 DPO 的 0.1 完全不同,量级差异显著,切勿混淆。
文档特别要求:在信任任何一个单一配置点之前,针对独立的偏好准确率检查做一个小型 sweep(独立变动beta、learning_rate、simpo_gamma)。不经 sweep 就选出的 SimPO 配置,与该方法引用的已发布结果不具备可比性。
选型边界
从 preference-optimization 的 SKILL.md 看,SimPO 的路由条件是"观察到 DPO 输出偏好更长回答(与质量无关),且有时间跑 sweep"。如果 sweep 预算并不存在,就用 DPO——SimPO 只在有预算时才有意义。
通用注意点:bf16 与灾难性遗忘
一律 bf16,绝不 fp16
四个配置块中bf16=True全部是硬性要求。文档内注释直接指向 lora-qlora-recipes 的 Failure Modes:fp16 在非 BF16 硬件上训练是 loss 尖峰和静默发散(silent divergence)的已知来源。在运行前先检查硬件支持:
python -c "import torch; print(torch.cuda.is_bf16_supported())"灾难性遗忘的诊断与处理顺序
文档的核心论断是:偏好微调后 checkpoint 丢失通用能力,几乎总是学习率过高——而不是方法本身的固有属性。典型症状:偏好微调任务上输出流畅,但在无关的 held-out 能力检查(通用 QA、SFT 阶段本已掌握的格式遵循)上表现退化。
处理顺序有严格优先级:
- 把学习率降到该方法选型表区间内的低端——这能解决大多数案例;
- 若低 LR 仍遗忘,把轮次从 2 降到 1;
- 仅当 1-2 都无效时,才考虑通用数据 replay 混合——在偏好训练中混入 10-30% 的通用指令数据,这与 lora-qlora-recipes 风格 SFT 中防遗忘的缓解手段相同。
同时文档提醒对称的另一侧:过低的 LR 会导致偏好信号欠训练(模型行为完全没有变化)。如果降低 LR 同时消除了遗忘和预期的行为变化,下一个要动的杠杆是轮次或数据质量,而不是把 LR 调回去。
与上游技能的衔接:数据从哪里来
method-configs.md 是配置层,其上游数据构建在 preference-optimization 的 SKILL.md 的 Pair Construction 一节,再由 trace-to-training-data 提供机制实现:
- DPO/ORPO 的 pair 必须来自同一任务的通过/失败轨迹对(同任务两次尝试),而非从不同任务各取最优与最差样本;
- 拒绝样本(rejected member)应在奖励分布的μ−2σ处选取,绝不取绝对最小值——朴素的 best-vs-worst 构造会随规模扩大而退化;
sorted_by_reward = sort(trajectories, key=reward) chosen = sorted_by_reward[-1] # highest reward mu, sigma = mean(rewards), stdev(rewards) rejected = closest(sorted_by_reward, mu - 2 * sigma) # NOT sorted_by_reward[0] — the absolute minimum # is the naive best-vs-worst construction that # degrades as scale increases.此外,trace-to-training-data还提供了 judge 打分差值筛选(保留 chosen-minus-rejected 差值最高的子集)等机制,用来在不损失信号的前提下压缩 pair 规模。整个数据链路与配置链路闭合:trace-to-training-data产出 pair →method-configs.md提供配置 →llm-finetuning-training-engineer消费配置生成可运行脚本。
选型背后的低杠杆真相
最后需要理解方法选型在整个偏好优化工作中的"权重"。SKILL.md 引用的 2026 年 240-H100-run 研究(arXiv 2603.19335)给出了两个关键数字:损失函数选择的杠杆约 1 个百分点,模型规模的杠杆约 50 个百分点;且 20 个 DPO 变体中有 0 个击败 vanilla DPO;排名还会随规模反转——在小规模试点中胜出的变体,在部署规模下可能落败。
这带来的实用结论是:不要把选型决策花在 DPO 变体的反复对比上,选型表已经足够;在部署规模上重新验证任何排名,小模型上验证过的方法对比结果不能直接迁移到生产尺寸。这也是为什么本文基于的选型表刻意保持简短——它编码的是那约 1 个百分点的杠杆,而不是一个被同一研究证伪的变体排名。
总结
method-configs.md是一份高度可执行的偏好优化配置参考:DPO 是默认方案(β=0.1、低 LR、1–2 轮、迭代式 on-policy 生产模式),ORPO 在内存受限时免去参考模型与独立 SFT,KTO 消化无配对二元反馈,SimPO 修复长度偏差但必须按网格 sweep。四个配置块共同遵守当前 TRL 的processing_class约定、一律 bf16、使用占位符模型名,并把灾难性遗忘的排查锚定在学习率这一首要杠杆上。配合 preference-optimization/SKILL.md 的选型表、method-configs.md 的配置块与 trace-to-training-data 的数据构建,即可形成一条从数据到配置再到训练的完整闭环。
【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考