Skip to content

16. 其他对齐算法

PPO、DPO、GRPO 是当前对齐三大主流,但它们都有各自的局限——PPO 重、DPO 离线、GRPO 需多次采样。2023-2025 年涌现出一批"轻量替代品",试图在数据形式、模型数量、训练阶段上做减法。本章系统梳理 KTO、ORPO、SimPO、RLOO、ReMax、Online/Iterative DPO 等代表性方法,并以一张大对比表收尾,帮你在实际项目中快速选型。


16.1 KTO:Kahneman-Tversky Optimization

16.1.1 动机:偏好对很贵,单边标签很便宜

DPO 需要 pairwise 偏好对 (yw,yl)。但实际产品中:

  • 用户给单条回答的 👍 / 👎 信号最多;
  • "好回答 / 坏回答"的二元标签比 pairwise 更易收集;
  • 安全标注("这条违规吗?")天然是单边。

KTO (Ethayarajh et al., ICML 2024) 把对齐的目标从"学偏好排序"改成"学好/坏分类"。

16.1.2 前景理论 (Prospect Theory)

Kahneman & Tversky 1979 的前景理论描述人类在不确定性下的决策:

v(z)={zα,z0(收益)λ(z)β,z<0(损失)

关键性质:

  • 参考点依赖:人对"好坏"的判断依赖于一个参考点(不是绝对价值);
  • 损失厌恶 (loss aversion)λ>1,损失带来的痛大于等量收益的快乐;
  • 凹性 / 凸性:收益区凹(diminishing returns),损失区凸(risk-seeking when losing)。

KTO 把这一价值函数显式注入 RLHF 损失。

16.1.3 KTO 损失

记隐式 reward:

rθ(x,y)=βlogπθ(y|x)πref(y|x)

参考点 z0=ExD[βKL(πθπref)](用 batch 估计)。

KTO 损失:

LKTO(θ)=E(x,y)D[w(y)(1v(rθ(x,y)z0))]

其中 v 是简化的 Kahneman-Tversky 价值函数:

v(z)={σ(βz),y 是 desirableσ(βz),y 是 undesirable

权重 w(y)=λDλU(分别对应 desirable / undesirable)。

16.1.4 解读

  • Desirable 样本 (y 标 👍):希望 rθ(x,y)>z0,即"比平均水平更好";
  • Undesirable 样本 (y 标 👎):希望 rθ(x,y)<z0,即"比平均更差";
  • 若已经满足,σ 接近 1,1σ 接近 0,梯度饱和——避免过拟合;
  • λD,λU 处理类别不平衡:如果好样本多坏样本少,设 λU>λD

16.1.5 实现要点

python
def kto_loss(model, ref_model, batch, β=0.1, λ_D=1.0, λ_U=1.0):
    """
    batch:
        input_ids:        [B, T]
        labels:           [B]   1 = desirable, 0 = undesirable
        attention_mask:   [B, T]
    """
    logp = get_log_probs(model, ...)
    with torch.no_grad():
        ref_logp = get_log_probs(ref_model, ...)
    logratio = logp - ref_logp                  # [B]

    # 用 batch 估计参考点 z_0
    with torch.no_grad():
        kl_estimate = (logp.detach() - ref_logp).mean()
        z_0 = β * kl_estimate.clamp(min=0)      # 防止负 KL 估计

    is_desirable = batch["labels"].bool()       # [B]

    # KTO loss per sample
    z = β * logratio - z_0                       # 同尺度的隐式 reward 减参考点
    loss_d = λ_D * (1 - torch.sigmoid(z))[is_desirable]
    loss_u = λ_U * (1 - torch.sigmoid(-z))[~is_desirable]

    loss = (loss_d.sum() + loss_u.sum()) / batch["labels"].size(0)
    return loss

16.1.6 优势与局限

优势

  • 数据格式最灵活:单边二元标签即可;
  • 类不平衡鲁棒:λD,λU 调节;
  • 在数据稀缺、噪声多场景下显著优于 DPO;
  • 在 1B-30B 规模与 DPO 相当或更好。

局限

  • 仍需 reference model;
  • 参考点 z0 用 batch 估计,引入额外方差;
  • 在大量 pairwise 数据可用时不如 DPO 直接。

TRL KTOTrainer 支持。


16.2 ORPO:Odds Ratio Preference Optimization

16.2.1 动机:能否一步到位?

标准 RLHF/DPO 流程:

  1. SFT;
  2. DPO(需要 reference model = SFT 后的模型)。

两阶段,且 DPO 仍需冻结的 reference。能否合二为一?

ORPO (Hong et al., EMNLP 2024) 给出肯定回答:单阶段、无 reference

16.2.2 损失

定义 odds

oddsθ(y|x)=Pθ(y|x)1Pθ(y|x)logoddsθ(y|x)=logPθ(y|x)log(1Pθ(y|x))

ORPO 总损失:

LORPO=LSFT(θ;yw)+λLOR

其中:

  • LSFT 是标准 SFT 损失(在 chosen 上做 NLL);
  • LOR 是 odds-ratio loss:
LOR=logσ(logoddsθ(yw|x)oddsθ(yl|x))

λ 通常取 0.1 - 1.0。

16.2.3 为什么用 odds 而非概率

DPO 的隐式 reward βlog(πθ/πref) 必须有 reference πref。如果直接用 logπθ(yw)logπθ(yl)(无 reference),当 chosen 与 rejected 都得低概率时差值仍可能大,但实际生成质量很差。

odds ratio 的好处:

  • πθ(yw)0 时,oddsθ(yw)0,OR 损失会主动拉高 πθ(yw)
  • 与 SFT 损失互补:SFT 推 chosen,OR 拉开 chosen vs rejected;
  • 自然实现 trust region:odds 函数在 P=0.5 附近线性,远端饱和。

16.2.4 实践细节

ORPO 论文用 length-normalized log probability 作为 logπ 的代理:

logPθ(y|x)1|y|tlogπθ(yt|x,y<t)

避免长度偏差。

python
def orpo_loss(model, batch, λ=0.1):
    """
    batch:
        chosen_input_ids, chosen_attention_mask, chosen_labels
        rejected_input_ids, rejected_attention_mask, rejected_labels
    """
    # SFT loss on chosen
    sft_loss = compute_sft_loss(model, batch["chosen_input_ids"],
                                 batch["chosen_labels"])

    # log P(y|x) length-normalized
    logp_w = get_avg_log_prob(model, batch["chosen_input_ids"],
                               batch["chosen_labels"])      # [B]
    logp_l = get_avg_log_prob(model, batch["rejected_input_ids"],
                               batch["rejected_labels"])    # [B]

    # log odds = logP - log(1 - P)
    # 用稳定数值近似:log(1-P) ≈ log(1 - exp(logp))
    log1mp_w = torch.log1p(-torch.exp(logp_w).clamp(max=1-1e-7))
    log1mp_l = torch.log1p(-torch.exp(logp_l).clamp(max=1-1e-7))

    log_odds_w = logp_w - log1mp_w
    log_odds_l = logp_l - log1mp_l

    # OR loss
    or_loss = -F.logsigmoid(log_odds_w - log_odds_l).mean()

    return sft_loss + λ * or_loss

16.2.5 优势

  • 无 reference model:单模型一次前向;
  • 单阶段:把 SFT 与对齐合并,省一倍训练时间;
  • 在 Phi-2 (2.7B), Llama-2 (7B), Mistral (7B) 上 AlpacaEval 击败 7B/13B SOTA,包括 Llama-2-13B-chat。

LLaMA-Factory、Axolotl、TRL 均支持。


16.3 SimPO:Simple Preference Optimization

16.3.1 动机:DPO 的两个痛点

  1. 冗长偏差 (verbosity bias):DPO 隐式 reward 是 tlogπθ(yt)/πref(yt),与序列长度强相关,导致输出越来越长;
  2. 依赖 reference model:占显存、难维护、与生成 metric 不一致。

SimPO (Meng et al., NeurIPS 2024) 用最简单的方式解决两者。

16.3.2 损失

定义 平均对数似然 作为隐式 reward(不依赖 reference):

rθ(x,y)=β|y|logπθ(y|x)=β|y|t=1|y|logπθ(yt|x,y<t)

SimPO 损失:

LSimPO=E(x,yw,yl)[logσ(β|yw|logπθ(yw|x)β|yl|logπθ(yl|x)γ)]

其中:

  • β 控制 reward 尺度(典型 2.0 - 2.5,比 DPO 大 10-25 倍,因为没 ref 缓冲);
  • γtarget reward margin(典型 0.5 - 1.6):要求 chosen 与 rejected reward 至少差 γ

16.3.3 关键设计

1. Length normalization

logπ(y|x)/|y| 而非 logπ(y|x) 作为 reward:

  • 与生成时的 perplexity-based 解码一致(PPL = exp(1|y|logP));
  • 消除长度偏差;
  • 让不同长度的样本有可比的 reward。

2. Target margin γ

DPO 的 sigmoid loss 在 Δ 时仍有梯度(虽然小),导致 likelihood 持续推高。SimPO 加一个 截止线 γ:当 rwrl>γ 时损失饱和,梯度归零

数学上类似 hinge margin loss:

logσ(Δγ){ΔγΔ<γ(大梯度)0Δγ(饱和)

16.3.4 实证表现

SimPO 在 AlpacaEval 2、Arena-Hard 上显著超过 DPO:

MethodAlpacaEval 2 LCArena-HardLength
Llama-3-8B SFT6.217.01700
+ DPO18.223.12100
+ SimPO22.033.81700

且训练时间减少 ~20%,显存减少 ~10%(无 reference)。Gemma-2-9B-it + SimPO 在 Chatbot Arena <10B 模型中曾占据 #1。

16.3.5 实现

python
def simpo_loss(model, batch, β=2.5, γ=1.6):
    """
    batch:
        chosen_input_ids, chosen_attention_mask, chosen_labels
        rejected_input_ids, rejected_attention_mask, rejected_labels
    """
    logp_w = get_avg_log_prob(model, batch["chosen_input_ids"],
                               batch["chosen_attention_mask"],
                               batch["chosen_labels"])    # [B]
    logp_l = get_avg_log_prob(model, batch["rejected_input_ids"],
                               batch["rejected_attention_mask"],
                               batch["rejected_labels"])  # [B]

    # 注意:β 直接乘到 avg log prob 上
    Δ = β * logp_w - β * logp_l
    loss = -F.logsigmoid(Δ - γ).mean()

    metrics = {
        "loss": loss.item(),
        "rewards/chosen": (β * logp_w).detach().mean().item(),
        "rewards/rejected": (β * logp_l).detach().mean().item(),
        "rewards/margin": Δ.detach().mean().item(),
        "rewards/accuracy": (Δ > γ).float().mean().item(),
    }
    return loss, metrics


def get_avg_log_prob(model, input_ids, attention_mask, labels):
    """response token 的平均 log p(y_t)"""
    out = model(input_ids=input_ids, attention_mask=attention_mask)
    logits = out.logits[:, :-1, :]
    targets = labels[:, 1:]
    mask = (targets != -100).float()

    targets_masked = targets.masked_fill(targets == -100, 0)
    logp = F.log_softmax(logits, dim=-1).gather(2, targets_masked.unsqueeze(-1)).squeeze(-1)

    return (logp * mask).sum(-1) / (mask.sum(-1) + 1e-8)

16.3.6 局限

SimPO 没有 reference,因此无法约束模型偏离 SFT 的程度。如果 β 太大或训练太久:

  • 模型可能收敛到 degenerate 分布;
  • 失去 SFT 学到的多样性。

实践:SimPO 通常只跑 1-2 个 epoch,且在 SFT 之后立即应用。


16.4 RLOO:REINFORCE Leave-One-Out

16.4.1 动机:回归 REINFORCE 的简洁

PPO 的复杂度(GAE + clip + critic)在 LLM 场景下未必必要:

  • LLM 模拟便宜(生成即环境步);
  • 转移确定(next state = state || action);
  • 单步 reward → 不需要时间衰减的 advantage。

Ahmadian et al. (ACL 2024) "Back to Basics" 重新审视 REINFORCE,提出 RLOO

16.4.2 算法

对每个 prompt x,在线采 k 个回答 {y(1),,y(k)},使用 leave-one-out baseline

b(i)=1k1jiR(y(j),x)

REINFORCE 估计:

g^i=(R(y(i),x)b(i))logπ(y(i)|x)

总目标(不用 PPO clip,因为是严格 on-policy):

J(θ)=1ki(R(y(i),x)b(i))logπθ(y(i)|x)

也可加 KL 惩罚:

R(y,x)=R(y,x)βlogπθ(y|x)πref(y|x)

16.4.3 关键性质

  • 无偏b(i)y(i) 独立,不破坏期望;
  • 方差低:相比单样本 baseline (e.g., constant),多样本平均方差更小;
  • 不需 critic:节省 1 个模型;
  • 不需 PPO clip:因为每条样本只用一次(true on-policy);
  • 超参少:仅 kβ

16.4.4 与 GRPO 的对比

RLOO 与 GRPO 非常相似——都用 group baseline。差别:

维度RLOOGRPO
Baselineleave-one-out: 1k1jirjmean: 1Gjrj
Std 归一化
Clip否(true on-policy)PPO-Clip
多 epoch
显存

实证:RLOO 在 Anthropic、Cohere 的实验中全面超过 PPO 和 RAFT。GRPO 在数学推理任务上更优(可能因为 std 归一化对结果二极化场景有效)。

16.4.5 实现

python
def rloo_step(model, ref_model, prompts, reward_fn, k=4, β=0.05):
    """RLOO 一次更新"""
    losses = []
    for x in prompts:
        # 采 k 个回答
        outputs = model.generate(x, num_return_sequences=k, do_sample=True)
        rewards = torch.tensor([reward_fn(x, o) for o in outputs], dtype=torch.float)

        # KL penalty per token
        for i, o in enumerate(outputs):
            with torch.no_grad():
                logp_ref = compute_seq_logprob(ref_model, x, o)
            logp_θ = compute_seq_logprob(model, x, o)

            # KL 加到 reward 中
            r_total = rewards[i] - β * (logp_θ.detach() - logp_ref)

            # leave-one-out baseline
            b = (rewards.sum() - rewards[i]) / (k - 1)
            advantage = r_total - b

            # REINFORCE: -A * log π
            losses.append(-advantage * logp_θ)

    loss = torch.stack(losses).mean()
    return loss

TRL 也支持 RLOOTrainer


16.5 ReMax:Reward Max Baseline

16.5.1 动机:把"贪心生成"当 baseline

Li et al. (2023) "ReMax: A Simple, Effective, and Efficient Reinforcement Learning Method for Aligning Large Language Models" 观察到:

  • LLM 模拟便宜;
  • 转移确定;
  • 轨迹级 reward。

提出最简单的 baseline:贪心解码 (greedy) 的回答的 reward。

16.5.2 算法

对每个 prompt x

  1. 采样:ysampleπθ(|x)
  2. 贪心:ygreedy=argmaxπθ(|x)(argmax 解码);
  3. 估计:
g^=(R(ysample,x)R(ygreedy,x))logπθ(ysample|x)

直觉:

  • 若 sample 比 greedy 好(Rs>Rg),advantage > 0,提升 sample 的概率;
  • 若更差,降低 sample 的概率;
  • Greedy 是当前策略下的"最强 baseline",且与 sample 同分布相关,方差小。

16.5.3 优势

vs PPOReMax
超参-4 (clip ratio, GAE λ, value lr, ppo_epochs)
显存-50% (无 critic)
速度+110% (~2.1×)
性能AlpacaEval 上对 PPO 胜率 63.6%

ReMax 的实测表现常超过 PPO(在合理资源下),是工业落地的强力选项。

16.5.4 实现

python
def remax_step(model, ref_model, prompts, reward_fn, β=0.05):
    losses = []
    for x in prompts:
        # Sample (温度 1.0)
        y_s = model.generate(x, do_sample=True, temperature=1.0,
                              max_new_tokens=512)

        # Greedy
        with torch.no_grad():
            y_g = model.generate(x, do_sample=False)

        r_s = reward_fn(x, y_s)
        r_g = reward_fn(x, y_g)
        advantage = r_s - r_g

        # KL penalty
        with torch.no_grad():
            logp_ref = compute_seq_logprob(ref_model, x, y_s)
        logp_θ = compute_seq_logprob(model, x, y_s)

        kl_pen = β * (logp_θ.detach() - logp_ref)
        adjusted_adv = advantage - kl_pen

        loss = -adjusted_adv * logp_θ
        losses.append(loss)

    return torch.stack(losses).mean()

16.5.5 局限

  • Greedy 不一定是最优 baseline:当温度高、分布平坦时,greedy reward 与平均 reward 相差不大;
  • 多样本依然更稳:RLOO/GRPO 用 k>2 样本,方差更小;
  • 适合"训出来的 sample 比 greedy 好"的场景(偏 RLHF 通用对话)。

16.6 Online / Iterative DPO

16.6.1 动机:弥补离线 DPO 的分布偏移

DPO 用固定数据集 D,但 πθ 训练后偏离 D 的采样分布。这是 DPO 的根本短板(见 §14.5.4)。

解决思路:周期性重新采样 + 重新标注。

16.6.2 Iterative DPO 流程

for iter t = 1..T:
    1. 用当前 π_θ 在新 prompts 上各生成 K 个回答
    2. 用 RM(或 LLM-as-judge)排序,挑出 (y_w, y_l)
    3. 在新偏好对上做 1 个 epoch 的 DPO(含原数据 + 新数据 mix)
    4. π_ref ← 上一轮的 π_θ(或保持原 SFT)

每一轮都让模型在自己当前的输出分布上学习"哪个更好",缓解分布偏移。

16.6.3 Self-Rewarding LM

Yuan et al. (ICML 2024) 进一步把 RM 也内化:

for iter t = 1..T:
    1. π_θ 生成 K 个回答
    2. π_θ 自己用 LLM-as-judge prompt 给回答打分
    3. 用 score 排序得 (y_w, y_l)
    4. DPO 一轮

实验:从 Llama-2-70B 开始迭代 3 轮,Arena 胜率持续提升(M3 > M2 > M1)。模型同时学会"更好回答"和"更好评判"

16.6.4 OAIF (Online AI Feedback)

Guo et al. (2024) 用一个固定的强 LLM 做实时 judge:

for step:
    sample (x, y1, y2) from π_θ
    use a strong LLM to label preference
    DPO step on this pair (online)

接近 PPO 的 online 性质,但用 DPO 的简单损失。在 multiple benchmarks 上接近 PPO + 真实人类标注。

16.6.5 RLAIF / Constitutional AI

更古老但相关的范式:

  • RLAIF (Bai et al., 2022):用 LLM 替代人类标偏好,配合 PPO;
  • Constitutional AI (Anthropic, 2022):定义一组 principles,让模型按 principles 自我批评 + 修订,生成偏好对。

这些是 "AI Feedback" 的开山工作,KTO/DPO 时代的 OAIF/Self-Rewarding 是其继承者。


16.7 RSO 与 NLHF

16.7.1 RSO 回顾

RSO (Liu et al., 2023) 在 §14.6.3 已介绍:

  • 训 RM;
  • 用拒绝采样从 πrefexp(r/β)/Z 近似采样;
  • 在拒绝采样数据上做 DPO/IPO。

它本质上是 离线版 PPO:用 RM 的密度估计模拟 PPO 的 rollout 分布。

16.7.2 NLHF (Nash Learning from Human Feedback)

Munos et al. (DeepMind, 2024) "Nash Learning from Human Feedback":

不再假设单一 BT 模型(线性效用),而是用游戏论视角:

  • 训练一个 preference model(可能非传递);
  • 找到 Nash 均衡的策略。

数学:mirror descent / 多智能体 RL。比 BT/DPO 更通用,可处理 cyclic preference,但实现复杂。

代表算法:Nash-MD (Mirror Descent), SPPO (Self-Play Preference Optimization)。


16.8 算法对比大表

把所有重要算法放在一张表里:

算法需 RM需 RL 采样Reference数据形式关键超参备注
PPO (RLHF)pairwise → RMε,λ,β,cv4 模型,GAE clip,最稳但最复杂
DPOpairwiseβ闭式最优策略推导
IPOpairwiseβ平方损失,避免 DPO 过拟合
cDPOpairwise + label noiseβ,εnoise标签噪声鲁棒
RSO✓ (训 RM 拒绝采样)pairwiseβ从最优策略附近采样
KTObinary (好/坏)β,λD,λU前景理论,无需 pair
ORPOpairwiseλ单模型,单阶段,含 SFT
SimPOpairwiseβ,γ长度归一化,无 ref
GRPO✓ / 规则rollout groupG,ε,β无 critic,group baseline
RLOOrollout kk,β无 critic,leave-one-out
ReMaxrollout + greedyβ无 critic,极简
Online DPORM 或自评pairwise (动态)β反复迭代
OAIFLLM-judgepairwise (LLM 标)β在线 AI feedback
Self-Rewardingπ_θ 自己pairwise (自评)β迭代自我提升
DAPO规则rollout groupG,εlo,εhiGRPO + 双 clip + dyn samp
NLHFpreference modelpairwiseηNash 均衡,处理非传递

16.9 选型决策树

实际项目中怎么选?

开始

  ├── 数据是 pairwise 偏好?
  │   ├── 是
  │   │   ├── 资源充足,追求最强? → PPO 或 Online DPO
  │   │   ├── 中等资源,要快速迭代? → DPO (+ cDPO if noisy)
  │   │   ├── 担心 verbosity?      → SimPO
  │   │   ├── 想合并 SFT 阶段?     → ORPO
  │   │   └── 想避免过拟合?        → IPO
  │   └── 否
  │       ├── 单边二元标签 (好/坏)?  → KTO
  │       ├── 推理任务,可写规则?   → GRPO 或 RLOO
  │       └── 偏好对昂贵但 LLM 强?  → OAIF / Self-Rewarding

  └── 任务类型?
      ├── 数学/代码/可验证      → GRPO + 规则 reward
      ├── 通用对话              → DPO / SimPO / ORPO
      ├── 安全/合规            → KTO + 大量负例
      └── 创意写作             → DPO / SimPO + 多样性 RM

实际工程中常见组合:

  • Tülu-3 (AI2):SFT → DPO → RLVR (rule-based RL),三阶段;
  • Llama-3-Instruct:SFT → 多轮 Iterative DPO;
  • DeepSeek-R1:SFT (cold-start) → GRPO → SFT → GRPO;
  • Mistral-Instruct:SFT → DPO;
  • Gemma-2:SFT → SimPO 或 DPO + RM。

16.10 实现框架对比

框架算法支持特点
TRL (HF)SFT, DPO, IPO, KTO, ORPO, CPO, PPO, RLOO, GRPO, Online DPO最广覆盖,与 transformers/peft 深度集成
OpenRLHFPPO, GRPO, REINFORCE++, RLOORay 分布式,vLLM 生成
veRL (字节)PPO, GRPO, ReMax, RLOO, DAPOHybridFlow,FSDP+vLLM,大规模 RL
DeepSpeed-ChatRLHF (PPO) 全流水线ZeRO-3 + Hybrid Engine
LLaMA-FactoryDPO, ORPO, KTO, SimPO, PPOLoRA / QLoRA 友好
AxolotlSFT, DPO, ORPO, KTOYAML 配置驱动,最易上手
OpenInstruct (AI2)DPO, PPO, GRPO, RLVRTülu 系列开源工具

实战建议:

  • 学习/原型 → TRL;
  • 中小规模产线 → LLaMA-Factory / Axolotl;
  • 大规模 RL → veRL / OpenRLHF;
  • 极简定制 → 自己用 Accelerate + PEFT 写 200 行。

16.11 实战代码:DPO/SimPO/ORPO/KTO 统一框架

下面给一个能切换多种 loss 的统一训练循环(节选):

python
import torch
import torch.nn.functional as F
from enum import Enum

class LossType(Enum):
    DPO = "dpo"
    IPO = "ipo"
    SIMPO = "simpo"
    ORPO = "orpo"
    KTO = "kto"

def compute_loss(model, ref_model, batch, loss_type, **kwargs):
    if loss_type == LossType.DPO:
        return dpo_loss(model, ref_model, batch,
                        β=kwargs.get("β", 0.1),
                        label_smoothing=kwargs.get("label_smoothing", 0.0))
    elif loss_type == LossType.IPO:
        return ipo_loss(model, ref_model, batch, β=kwargs.get("β", 0.1))
    elif loss_type == LossType.SIMPO:
        return simpo_loss(model, batch,
                          β=kwargs.get("β", 2.0),
                          γ=kwargs.get("γ", 1.0))
    elif loss_type == LossType.ORPO:
        return orpo_loss(model, batch, λ=kwargs.get("λ", 0.1))
    elif loss_type == LossType.KTO:
        return kto_loss(model, ref_model, batch,
                        β=kwargs.get("β", 0.1),
                        λ_D=kwargs.get("λ_D", 1.0),
                        λ_U=kwargs.get("λ_U", 1.0))
    else:
        raise ValueError(loss_type)


# 主训练循环
def train(model, ref_model, dataloader, optimizer, loss_type, **loss_kwargs):
    model.train()
    if ref_model is not None:
        ref_model.eval()

    for step, batch in enumerate(dataloader):
        batch = move_to_cuda(batch)
        loss, metrics = compute_loss(model, ref_model, batch, loss_type, **loss_kwargs)

        optimizer.zero_grad()
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
        optimizer.step()

        if step % 10 == 0:
            print(f"step {step}: loss={loss.item():.4f} {metrics}")

16.12 几个值得记住的 take-away

  1. 没有银弹:每个算法都有适用场景与失败模式;
  2. 数据质量 > 算法选择:100K 高质量偏好对 + DPO > 100K 低质量数据 + PPO;
  3. 结合规则 reward:在可验证任务上,规则远胜 RM(DeepSeek-R1 是最好例证);
  4. Length normalization 很关键:SimPO、ORPO、平均 logp 都体现这一点;
  5. Iterative > 单次:在线/迭代版本通常优于离线版本;
  6. Reference refresh 是免费午餐:周期性重锚 ref,几乎所有 RL 类对齐都能用;
  7. 监控比训练更重要:accuracy、margin、KL、生成长度同步监控;
  8. 早停救命:DPO/PPO 都容易过训练,监控 gold metric 决定何时停。

本章小结

  • KTO:用前景理论 + 单边标签,损失饱和避免过拟合;
  • ORPO:odds ratio 损失 + SFT,单阶段无 reference;
  • SimPO:平均 logp 作 reward + target margin,无 reference 且消除长度偏差;
  • RLOO:leave-one-out baseline,REINFORCE 的现代复活;
  • ReMax:以 greedy reward 作 baseline,超参最少;
  • Online/Iterative DPO:周期性重采样缓解分布偏移;
  • OAIF / Self-Rewarding:用 LLM 替代人类标注,闭环迭代;
  • 大对比表 + 选型决策树帮助快速选择算法。

思考题

  1. 从 DPO 推导 SimPO:DPO 的 reward 是 βlogπθπref,SimPO 的 reward 是 β|y|logπθ。如果你硬要把 SimPO 写成"DPO 的某种特殊参考策略"形式,参考策略 πrefSimPO 应该是什么?这种参考策略合理吗?

  2. 比较 KTO vs DPO 在标注成本上的优劣:假设你要训练一个反诈骗 LLM,数据只有"用户标记为诈骗 / 非诈骗"的二元标签,没有 pairwise。你会选 KTO 还是把数据"伪造"成 pairwise(同一 prompt 下取一好一坏拼对)做 DPO?请从有效信息量、噪声、训练稳定性角度论证。

  3. 设计题:你在做一个新的对齐方法,希望融合 ORPO(无 ref)和 SimPO(长度归一)的优点。请草拟一个新的损失形式:(a) 写出公式;(b) 列出至少 1 个超参的物理意义;(c) 预测它相比 ORPO 和 SimPO 的潜在优势与新风险。

基于 MIT 协议发布