这几个缩写回答的不是同一个问题:SFT 和 DPO 主要涉及训练目标与数据组织,LoRA 则涉及参数更新方式。比较方案前,先把这两条轴分开。

用“数据与目标”区分训练阶段

方法 典型的数据形式 重点
SFT 输入上下文与期望回答 学习示范回答的条件生成
DPO 同一上下文下的偏好回答对 根据相对偏好调整策略
LoRA 本身不规定是示范还是偏好数据 用低秩增量更新选定权重

因此可以用 LoRA 实现某次 SFT,也可以在适当配置下用于 DPO。DPO 不是“必然优于 SFT”的升级按钮;偏好对是否可靠、评估集是否独立,仍然决定结论是否可信。方法定义可查 DPO 原论文。

算一次 LoRA 的参数量

LoRA 原论文使用可训练的低秩分解矩阵表示权重增量,并冻结相应的原始权重。对一个 d_out × d_in 权重,两个因子的参数量为 r * (d_in + d_out),这里暂不计算偏置等其他参数。

def lora_parameter_counts(din, dout, rank):
    if min(din, dout, rank) <= 0:
        raise ValueError("dimensions and rank must be positive")
    dense = din * dout
    adapter = rank * (din + dout)
    return dense, adapter

dense, adapter = lora_parameter_counts(4096, 4096, 8)
assert dense == 16777216
assert adapter == 65536
assert adapter / dense == 1 / 256
print("adapter fraction:", adapter / dense)

这只说明一个矩阵上的可训练参数比例。实际训练显存还受激活值、优化器、精度、序列长度、批大小和目标模块影响,不能把这个比例直接当成整次训练的显存下降比例。

两处不能照搬的简化说法

第一,回答部分计算损失是一种常见配置,不代表所有 SFT 都必须采用同样的 loss mask。遮蔽某些 token 的损失项,也不等于把与这些输入相关的所有梯度或参数“冻结”。真正的参数冻结来自训练配置。

第二,不能把某个示例中的少量样本、训练耗时或 loss 下降直接当成通用效果保证。训练 loss 是拟合目标,不等于独立测试集上的任务质量,更不等于模型已具备新的通用能力。

我的验收顺序

先检查数据格式与训练/验证划分,再检查实际参与更新的参数、token 和损失项;最后比较同一套独立评估上的输出。偏好数据还需核对两个回答是否对应同一问题、偏好理由是否一致,以及错误回答是否被误标成更优。

课程对应与整理边界

对应疏锦行《26大模型专题》的《03_SFT微调与LoRA》《04_DPO偏好对齐》及对应视频目录。本文整理方法之间的关系并补充适用边界;算术示例为独立编写,不代表已实际训练这些模型,视频口头补充尚未完整核验。

原课程