Skip to content

损失函数

损失函数(Loss Function)衡量模型预测值与真实值之间的差距,是深度学习训练的”指挥棒”——优化器沿着损失函数的梯度方向更新参数(详见梯度下降与优化器)。本页系统梳理回归、分类、排序、分割和对比学习等场景下的常用损失函数,并给出关键数学推导与代码实现。前置阅读:数值优化与数学基础。

把损失函数想象成”考试评分标准”——不同的评分方式会引导模型学到不同的能力:

  • MSE(均方误差)= 对大错重罚。差 10 分扣 100 分(平方),逼模型优先修正偏差最大的样本。缺点是对异常值过于敏感。
  • MAE(平均绝对误差)= 一视同仁。差 1 分扣 1 分,对异常值更鲁棒,但梯度恒定(始终为 ±1\pm 1),在小误差区域收敛慢。
  • Huber Loss= MSE 和 MAE 的合体:小错按 MSE(平滑收敛),大错按 MAE(不被异常值绑架)。
  • 交叉熵(Cross-Entropy)= 信息论评分。预测概率越偏离真实标签,惩罚越大且呈指数增长——天然适配分类任务。
  • Focal Loss= 给”已经分对的简单样本”降权,让模型集中精力啃”难样本”——解决类别不平衡的利器。
  • Triplet Loss= 人脸识别专用——拉近同一个人,推开其他人。
  • Dice Loss= 分割专用——直接优化区域重叠度(IoU),而不是逐像素的误差。
  • KL 散度损失(KL Divergence Loss)= 知识蒸馏专用——逼学生模型的输出分布去模仿老师模型的”软标签”,而非只学硬标签。
  • DPO 损失(直接偏好优化损失)= 绕过奖励模型,直接从人类偏好数据(“回答 A 比回答 B 好”)训练 LLM。
  • Lovasz Loss= IoU 的平滑可导替身——IoU 本身不可导无法直接用梯度优化,Lovasz 用凸代理解决了这一问题。

均方误差是最经典的回归损失,对预测值与真实值之差取平方后求平均:

MSE=1N∑(ypred−ytrue)2\text{MSE} = \frac{1}{N} \sum (y_{\text{pred}} - y_{\text{true}})^2

梯度对预测值求导为 2(ypred−ytrue)2(y_{\text{pred}} - y_{\text{true}})——误差越大梯度越大,收敛快但异常值(误差极大的样本)会主导梯度方向。

为什么用平方而不是绝对值? 直觉有三点:(1) 平方让损失处处可导(绝对值在零点不可导);(2) 大误差被指数级放大,模型优先修正最差的预测;(3) 在高斯噪声假设下,最小化 MSE 等价于最大似然估计。

偏差-方差分解(Bias-Variance Decomposition)

MSE 可以被精确分解为三部分——偏差的平方、方差和不可约噪声。这是理解”模型为什么过拟合”的核心数学工具。

假设真实关系为 y=f(x)+ϵy = f(x) + \epsilon,其中 ϵ∼N(0,σ2)\epsilon \sim \mathcal{N}(0, \sigma^2) 为不可约噪声,模型在训练集上学到 f^(x)\hat{f}(x)。对单个测试点 x,期望损失为:

E[(y−f^(x))2]=E[(f(x)+ϵ−f^(x))2]=E[(f(x)−f^(x))2]+E[ϵ2]+2⋅E[(f(x)−f^(x))⋅ϵ]=E[(f(x)−f^(x))2]+σ2\begin{aligned} E[(y - \hat{f}(x))^2] &= E[(f(x) + \epsilon - \hat{f}(x))^2] \\ &= E[(f(x) - \hat{f}(x))^2] + E[\epsilon^2] + 2 \cdot E[(f(x) - \hat{f}(x)) \cdot \epsilon] \\ &= E[(f(x) - \hat{f}(x))^2] + \sigma^2 \end{aligned}

最后一项交叉项为 0,因为 ϵ\epsilon 与 f^\hat{f} 独立。现在展开核心项:

E[(f(x)−f^(x))2]=E[(f(x)−E[f^(x)]+E[f^(x)]−f^(x))2]=E[(f(x)−E[f^(x)])2]+2⋅E[(f(x)−E[f^(x)])⋅(E[f^(x)]−f^(x))]+E[(E[f^(x)]−f^(x))2]\begin{aligned} E[(f(x) - \hat{f}(x))^2] &= E[(f(x) - E[\hat{f}(x)] + E[\hat{f}(x)] - \hat{f}(x))^2] \\ &= E[(f(x) - E[\hat{f}(x)])^2] \\ &\quad + 2 \cdot E[(f(x) - E[\hat{f}(x)]) \cdot (E[\hat{f}(x)] - \hat{f}(x))] \\ &\quad + E[(E[\hat{f}(x)] - \hat{f}(x))^2] \end{aligned}

中间项中,(f(x)−E[f^(x)])(f(x) - E[\hat{f}(x)]) 对训练集是常数,提出来后 E[E[f^(x)]−f^(x)]=0E[E[\hat{f}(x)] - \hat{f}(x)] = 0,故中间项为零:

E[(y−f^(x))2]=(f(x)−E[f^(x)])2⏟偏差2 Bias2+E[(f^(x)−E[f^(x)])2]⏟方差 Variance+σ2⏟噪声E[(y - \hat{f}(x))^2] = \underbrace{(f(x) - E[\hat{f}(x)])^2}_{\text{偏差}^2 \text{ Bias}^2} + \underbrace{E[(\hat{f}(x) - E[\hat{f}(x)])^2]}_{\text{方差 Variance}} + \underbrace{\sigma^2}_{\text{噪声}}

最终结论:

E[(y−f^(x))2]=Bias2+Var+σ2E[(y - \hat{f}(x))^2] = \text{Bias}^2 + \text{Var} + \sigma^2
分量含义对应现象
Bias²模型预测的平均值与真实值 f(x) 的偏离欠拟合:模型太简单,无法拟合真实关系
Var模型在不同训练集上预测的波动程度过拟合:模型对训练数据太敏感
σ²数据本身的噪声,无法消除标签采集误差、缺失特征等

核心启示:降低 Bias(用更复杂的模型)通常会增加 Variance,反之亦然——这就是偏差-方差权衡(Bias-Variance Tradeoff)。正则化(如 L2 权重衰减)本质上是用少量 Bias 换取大量 Variance 的降低。

平均绝对误差直接取差的绝对值:

MAE=1N∑∣ypred−ytrue∣\text{MAE} = \frac{1}{N} \sum |y_{\text{pred}} - y_{\text{true}}|

梯度恒为 ±1\pm 1(与误差大小无关),因此对异常值鲁棒;但在 ypred=ytruey_{\text{pred}} = y_{\text{true}} 处不可导,小误差区域收敛慢。在拉普拉斯噪声假设下,最小化 MAE 等价于最大似然估计。

Huber Loss(又称 Smooth L1 Loss)在误差较小时用 MSE、较大时切换为 MAE,用一个阈值 δ\delta 控制切换点:

L={0.5⋅error2if ∣error∣≤δδ⋅∣error∣−0.5⋅δ2if ∣error∣>δL = \begin{cases} 0.5 \cdot \text{error}^2 & \text{if } |\text{error}| \leq \delta \\ \delta \cdot |\text{error}| - 0.5 \cdot \delta^2 & \text{if } |\text{error}| > \delta \end{cases}

兼具 MSE 的平滑收敛和 MAE 的异常值鲁棒性,常用于回归和强化学习(如 DQN 的目标值计算)。

δ 点的连续性与可导性验证

Huber Loss 的设计精髓在于:它在切换点 δ\delta 处既连续又可导(一阶导数连续),这是通过精心选择常数项 0.5δ20.5\delta^2 实现的。

连续性——在 ∣error∣=δ|\text{error}| = \delta 处,两段的值必须相等:

左段: L(δ)=0.5δ2右段: L(δ)=δ2−0.5δ2=0.5δ2\text{左段: } L(\delta) = 0.5 \delta^2 \qquad \text{右段: } L(\delta) = \delta^2 - 0.5\delta^2 = 0.5\delta^2

一阶导数连续性——对 error 求导(设 error = y_pred - y_true,error > 0 时):

左段 (∣error∣<δ):dLd(error)=error→δ右段 (∣error∣>δ):dLd(error)=δ→δ\text{左段 } (|\text{error}| < \delta): \quad \frac{dL}{d(\text{error})} = \text{error} \to \delta \qquad \text{右段 } (|\text{error}| > \delta): \quad \frac{dL}{d(\text{error})} = \delta \to \delta

左导数 = δ\delta,右导数 = δ\delta,二者相等——这正是 0.5δ20.5\delta^2 这个常数项的作用:如果右段常数项不是 0.5δ20.5\delta^2,两段在 δ\delta 点的值或导数就无法同时匹配。Smooth L1 Loss(Fast R-CNN 提出)是 δ=1\delta = 1 的特例。

交叉熵源自信息论,其推导链为:自信息 → 熵 → 交叉熵 → KL 散度 → 分类损失。

第一步:自信息(Self-Information)

一个事件 x 的自信息量定义为:

I(x)=−log⁡p(x)I(x) = -\log p(x)

概率越小的事件,发生时带来的”信息量”越大。掷硬币正面(p=0.5)信息量为 1 bit;掷出六面骰子的某一面(p=1/6)信息量约 2.58 bit。

第二步:熵(Entropy)—— 自信息的期望

分布 p 的熵是所有可能事件的自信息的期望:

H(p)=−∑p(x)⋅log⁡p(x)H(p) = -\sum p(x) \cdot \log p(x)

熵衡量分布的”不确定性”:均匀分布熵最大(最不确定),确定分布熵为零。

第三步:交叉熵(Cross-Entropy)—— 用分布 q 编码分布 p 的代价

如果真实分布是 p,但我们用分布 q 来编码,所需的信息量期望就是交叉熵:

H(p,q)=−∑p(x)⋅log⁡q(x)H(p, q) = -\sum p(x) \cdot \log q(x)

第四步:KL 散度(Kullback-Leibler Divergence)—— p 与 q 的差距

KL(p∥q)=∑p(x)⋅log⁡p(x)q(x)=−∑p(x)log⁡q(x)−[−∑p(x)log⁡p(x)]=H(p,q)−H(p)\begin{aligned} \text{KL}(p \| q) &= \sum p(x) \cdot \log \frac{p(x)}{q(x)} \\ &= -\sum p(x) \log q(x) - \left[-\sum p(x) \log p(x)\right] \\ &= H(p, q) - H(p) \end{aligned}

因此交叉熵与 KL 散度的关系为:

H(p,q)=H(p)+KL(p∥q)H(p, q) = H(p) + \text{KL}(p \| q)

关键洞察:当 p 是固定的真实标签分布时,H(p) 是常数,最小化交叉熵 H(p,q) 等价于最小化 KL 散度——即让模型分布 q 尽可能接近真实分布 p。

第五步:从交叉熵到分类损失

在分类任务中,真实标签是 one-hot 向量 y(只有正确类别为 1,其余为 0),模型输出 softmax 概率为 p。套用交叉熵:

CE=−∑yi⋅log⁡(pi)\text{CE} = -\sum y_i \cdot \log(p_i)

由于 one-hot 中只有一个 yi=1y_i = 1,其余为 0:

CE=−log⁡(pcorrect)\text{CE} = -\log(p_{\text{correct}})

这就完成了从信息论到分类损失的完整推导——分类的交叉熵损失就是”模型对正确类别赋予的概率的自信息的负值”。模型对正确类别越自信(pcorrectp_{\text{correct}} 越大),损失越小。

二元分类是多分类的特例(y 取 0 或 1):

BCE=−[y⋅log⁡(p)+(1−y)⋅log⁡(1−p)]\text{BCE} = -[y \cdot \log(p) + (1-y) \cdot \log(1-p)]

为什么分类不用 MSE? 如果在 softmax 输出上用 MSE,梯度会在预测接近 0 或 1 时趋近于零(梯度消失),导致学习极慢。交叉熵配合 softmax 的梯度恰好是 (p−y)(p - y)——简单且不会梯度消失,这是信息论设计带来的数学优势。

Label Smoothing Cross-Entropy(标签平滑交叉熵)

Section titled “Label Smoothing Cross-Entropy(标签平滑交叉熵)”

标签平滑(Label Smoothing,Szegedy et al., CVPR 2016)将 one-hot 硬标签”软化”——不再给正确类别 100% 概率,而是分一点给其他类别:

ysmooth=(1−ϵ)⋅yonehot+ϵKy_{\text{smooth}} = (1 - \epsilon) \cdot y_{\text{onehot}} + \frac{\epsilon}{K}

其中 ϵ\epsilon 是平滑因子(通常 0.1),K 是类别数。交叉熵变为:

LSCE=−∑ysmooth,i⋅log⁡(pi)=(1−ϵ)⋅CEhard+ϵ⋅CEuniform\text{LSCE} = -\sum y_{\text{smooth},i} \cdot \log(p_i) = (1-\epsilon) \cdot \text{CE}_{\text{hard}} + \epsilon \cdot \text{CE}_{\text{uniform}}

直觉:one-hot 标签告诉模型”正确类别概率必须是 1”——这过于绝对,容易导致过拟合和过度自信。标签平滑相当于告诉模型”你大概率是对的,但保留一点不确定性”,起到正则化效果。在 ImageNet 分类和机器翻译(Transformer)中被广泛使用。

Focal Loss(Lin et al., ICCV 2017)在交叉熵基础上加一个调节因子 (1−p)γ(1-p)^{\gamma},自动降低易分类样本的权重:

FL=−α⋅(1−p)γ⋅log⁡(p)\text{FL} = -\alpha \cdot (1-p)^{\gamma} \cdot \log(p)

当 p 接近 1(已分对)时 (1−p)γ(1-p)^{\gamma} 趋近于 0,损失被大幅压低;当 p 小(难样本)时因子接近 1,损失几乎不变。γ\gamma 通常取 2。这是 RetinaNet 目标检测器成功的关键。

梯度分析:为什么 (1−p)γ(1-p)^{\gamma} 能降低易样本梯度?

以二分类、正确标签 y=1 为例,设模型对正确类别的预测概率为 p。标准交叉熵的损失和梯度为:

CE=−log⁡(p)dCEdp=−1p\text{CE} = -\log(p) \qquad \frac{d\text{CE}}{dp} = -\frac{1}{p}

Focal Loss 的损失和梯度为:

FL=−(1−p)γ⋅log⁡(p)\text{FL} = -(1-p)^{\gamma} \cdot \log(p) dFLdp=γ(1−p)γ−1⋅log⁡(p)−(1−p)γp\frac{d\text{FL}}{dp} = \gamma(1-p)^{\gamma-1} \cdot \log(p) - \frac{(1-p)^{\gamma}}{p}

关键对比——易样本(p→1p \to 1)的梯度量级:

标准 CE 的梯度: ∣dCEdp∣=1p≈1.0Focal 的梯度: ∣dFLdp∣≈(1−p)γp→0\text{标准 CE 的梯度: } \left|\frac{d\text{CE}}{dp}\right| = \frac{1}{p} \approx 1.0 \qquad \text{Focal 的梯度: } \left|\frac{d\text{FL}}{dp}\right| \approx \frac{(1-p)^{\gamma}}{p} \to 0

即:对于已经分对的样本(p→1p \to 1),标准交叉熵仍然贡献约 1.0 量级的梯度;而 Focal Loss 的梯度被 (1−p)γ(1-p)^{\gamma} 因子压缩到接近 0。γ\gamma 越大,压缩越激进。这就是 Focal Loss “聚焦难样本”的数学本质——通过梯度量级的自动缩放,让易样本在反向传播中几乎不产生参数更新。

在目标检测中,背景框(易分对的负样本)通常占 1000:1 的比例。标准 CE 下这些海量易样本的梯度之和会淹没真正有用的难样本信号;Focal Loss 把易样本的梯度压到接近零,让优化器专注于难样本。

SVM(支持向量机)的标准损失,要求正确类的得分比其他类高出至少一个间隔 margin:

L=max⁡(0,margin−(scorrect−sother))L = \max(0, \text{margin} - (s_{\text{correct}} - s_{\text{other}}))

只惩罚间隔内的违例,间隔外则损失为 0——这正是 SVM “最大间隔”思想在损失函数层面的体现。详见SVM 支持向量机。

人脸识别 / 嵌入学习的经典损失。每次取一个锚样本(anchor)、一个正样本(positive,同类)、一个负样本(negative,异类),要求锚与正的距离小于锚与负的距离至少一个 margin:

L=max⁡(0,d(anchor,positive)−d(anchor,negative)+margin)L = \max(0, d(\text{anchor}, \text{positive}) - d(\text{anchor}, \text{negative}) + \text{margin})

其中 d 是距离函数(通常为欧氏距离)。详见自监督与对比学习。

对比损失(Contrastive Loss)与 Triplet Loss 类似,但每次只用一对样本(正对或负对):

正对(同类): L=d(x1,x2)2负对(异类): L=max⁡(0,margin−d(x1,x2))2\text{正对(同类): } L = d(x_1, x_2)^2 \qquad \text{负对(异类): } L = \max(0, \text{margin} - d(x_1, x_2))^2

Cosine Embedding Loss(余弦嵌入损失)

Section titled “Cosine Embedding Loss(余弦嵌入损失)”

余弦嵌入损失用向量夹角的余弦值衡量相似度,要求正对余弦大、负对余弦小:

L={1−cos⁡(a,b)if label=1(正对)max⁡(0,cos⁡(a,b)−margin)if label=−1(负对)L = \begin{cases} 1 - \cos(a, b) & \text{if label} = 1 \text{(正对)} \\ \max(0, \cos(a, b) - \text{margin}) & \text{if label} = -1 \text{(负对)} \end{cases}

其中 cos⁡(a,b)=a⋅b∥a∥∥b∥\cos(a, b) = \frac{a \cdot b}{\|a\| \|b\|},margin 通常取 0.0~0.5。PyTorch 中对应 nn.CosineEmbeddingLoss。

直觉:与 Contrastive Loss 用欧氏距离不同,Cosine Embedding Loss 只看方向不看模长——这对嵌入学习特别有用,因为我们关心的是嵌入在空间中的”角度位置”而非”绝对长度”。在句子相似度、推荐系统中广泛使用。

Dice 系数(Dice Coefficient,又称 F1 score 的集合形式)衡量两个集合的重叠度,Dice Loss = 1 - Dice:

Dice=2∣A∩B∣∣A∣+∣B∣Dice Loss=1−Dice\text{Dice} = \frac{2|A \cap B|}{|A| + |B|} \qquad \text{Dice Loss} = 1 - \text{Dice}

在像素级分割中,A 是预测的前景区域、B 是真实标注区域。Dice Loss 直接优化重叠度,对类别不平衡(前景像素远少于背景)天然友好。详见图像分割。

IoU(Intersection over Union,交并比)= 交集面积 / 并集面积。IoU Loss = 1 - IoU,在目标检测的边界框回归中广泛使用。详见目标检测与 YOLO。

Lovasz Loss(Berman et al., CVPR 2018)是 IoU 的凸代理(convex surrogate)。IoU 本身是阶跃函数(不可导),无法直接用梯度下降优化。Lovasz Loss 利用集合论中的 Lovász 扩展(Lovász extension),将离散的 IoU 连续化为可导函数:

Lovasz-Hinge (二分类): 将 Jaccard 集合损失通过 Lovász 扩展转化为凸函数
Lovasz-Softmax (多分类): 对每个类别做 softmax 概率的 Lovász 扩展

直觉:IoU Loss 当预测稍有偏差时梯度为零(不可导),Lovász Loss 提供了平滑的梯度信号——“离正确分割越近,梯度越温和地引导你继续靠近”。在实践中常与 Cross-Entropy 组合使用,效果优于单独使用 Dice 或 IoU Loss。

知识蒸馏(Knowledge Distillation,Hinton et al., 2015)的核心损失。学生模型(student)学习老师模型(teacher)输出的软标签分布:

KL(qteacher∥qstudent)=∑qteacher(x)⋅log⁡qteacher(x)qstudent(x)\text{KL}(q_{\text{teacher}} \| q_{\text{student}}) = \sum q_{\text{teacher}}(x) \cdot \log \frac{q_{\text{teacher}}(x)}{q_{\text{student}}(x)}

其中 q 通过温度缩放(temperature scaling)获得:

q=softmax(logits/T)q = \text{softmax}(\text{logits} / T)

T > 1 使 softmax 输出更”软”(更平滑),暴露出类间关系(“猫不像狗,但比像卡车更接近”)——这些”暗知识”(dark knowledge)比硬标签包含更丰富的信息。完整蒸馏损失通常是:

L=α⋅KL(qteacherT∥qstudentT)+(1−α)⋅CE(y,qstudent1)L = \alpha \cdot \text{KL}(q_{\text{teacher}}^T \| q_{\text{student}}^T) + (1 - \alpha) \cdot \text{CE}(y, q_{\text{student}}^1)

直觉:硬标签说”这是猫”,软标签说”这大概率是猫,但也有一点像狗和兔子的特征”——后者提供了更密集的学习信号。详见知识蒸馏。

InfoNCE(Informational Noise Contrastive Estimation,信息论噪声对比估计)是现代对比学习的核心损失(SimCLR、MoCo、CLIP 都在用)。给定一个正样本对和 K 个负样本:

L=−log⁡exp⁡(sim(q,k+)/τ)∑exp⁡(sim(q,ki)/τ)L = -\log \frac{\exp(\text{sim}(q, k_+) / \tau)}{\sum \exp(\text{sim}(q, k_i) / \tau)}

其中 sim 是相似度(如余弦相似度),τ\tau 是温度系数。详见自监督与对比学习。

InfoNCE 与交叉熵的等价性推导

InfoNCE 看起来和交叉熵不同,但本质完全一样——只需做变量替换。

将 sim(q, k_i) / τ 记为 logit ziz_i(相似度除以温度就是”未归一化的分数”),则:

LInfoNCE=−log⁡exp⁡(z+)exp⁡(z+)+∑exp⁡(z−)L_{\text{InfoNCE}} = -\log \frac{\exp(z_+)}{\exp(z_+) + \sum \exp(z_-)}

这与多类交叉熵 CE=−log⁡exp⁡(zcorrect)∑exp⁡(zj)\text{CE} = -\log \frac{\exp(z_{\text{correct}})}{\sum \exp(z_j)} 形式完全相同——正样本就是”正确类别”,K 个负样本就是”其他类别”。

InfoNCE = CrossEntropy
正样本 k+ ←→ 正确类别
负样本 k_i ←→ 错误类别
sim(q,k)/τ ←→ logit z_j

唯一的区别在于:分类的 logits 来自分类头的线性层,而 InfoNCE 的 logits 来自样本对之间的相似度。这就是 InfoNCE 被称为”对比版本的交叉熵”的原因——它把对比学习统一到了分类框架中。

偏好学习损失:从 RLHF 到 DPO 及其变体

Section titled “偏好学习损失:从 RLHF 到 DPO 及其变体”

传统的 RLHF(Reinforcement Learning from Human Feedback)需要两阶段:先训练一个奖励模型(Reward Model),再用 PPO 等 RL 算法优化 LLM。2023 年 DPO 的提出改变了这一范式——直接从偏好数据训练,无需 RL。

DPO(Direct Preference Optimization,直接偏好优化,Rafailov et al., NeurIPS 2023)

DPO 的核心洞见:可以通过一个简单的损失函数,将人类偏好数据直接映射到策略优化,绕过显式的奖励模型。给定偏好对(chosen response ywy_w,rejected response yly_l):

LDPO=−log⁡σ(β⋅[log⁡π(yw∣x)πref(yw∣x)−log⁡π(yl∣x)πref(yl∣x)])L_{\text{DPO}} = -\log \sigma\left(\beta \cdot \left[\log \frac{\pi(y_w|x)}{\pi_{\text{ref}}(y_w|x)} - \log \frac{\pi(y_l|x)}{\pi_{\text{ref}}(y_l|x)}\right]\right)

其中 π\pi 是当前策略(LLM),πref\pi_{\text{ref}} 是参考策略(冻结的初始 LLM),β\beta 控制偏离参考策略的程度,σ\sigma 是 sigmoid。直觉上:让模型对 chosen 的对数似然比(相对于参考模型)高于 rejected。

IPO(Identity Preference Optimization,2024):指出 DPO 在偏好确定性高时会过拟合(DPO 损失可以趋于零但泛化变差),用二次损失替代对数损失:

LIPO=(log⁡π(yw∣x)πref(yl∣x)π(yl∣x)πref(yw∣x)−12β)2L_{\text{IPO}} = \left(\log \frac{\pi(y_w|x) \pi_{\text{ref}}(y_l|x)}{\pi(y_l|x) \pi_{\text{ref}}(y_w|x)} - \frac{1}{2\beta}\right)^2

KTO(Kahneman-Tversky Optimization,2024):DPO 需要成对偏好数据(“A 比 B 好”),KTO 只需要二元反馈(“这条回答好/不好”)——数据采集成本更低:

LKTO=σ(β⋅KLdiff,w)⋅v(x,yw)+σ(−β⋅KLdiff,l)⋅v(x,yl)⋅λL_{\text{KTO}} = \sigma(\beta \cdot \text{KL}_{\text{diff},w}) \cdot v(x,y_w) + \sigma(-\beta \cdot \text{KL}_{\text{diff},l}) \cdot v(x,y_l) \cdot \lambda

利用行为经济学的前景理论(Prospect Theory)建模:人对”好”和”不好”的效用函数不对称(损失厌恶)。

方法数据需求优势劣势
RLHF (PPO)偏好数据 + RM理论最优,灵活训练不稳定,需 4 个模型同时在线
DPO成对偏好数据简单稳定,无需 RL需要高质量配对数据
IPO成对偏好数据抗过拟合收敛较慢
KTO二元反馈(好/不好)数据成本最低,效果好效果略逊 DPO

Z-loss(Logit Zapping Loss)

PaLM(Chowdhery et al., 2022)和 GPT-4 报告中提到的辅助损失,用于稳定训练:

Lz=c⋅(log⁡∑exp⁡(zi))2=c⋅(logsumexp(z))2L_z = c \cdot \left(\log \sum \exp(z_i)\right)^2 = c \cdot (\text{logsumexp}(z))^2

惩罚 logits 的绝对值过大。直觉:训练中个别 logit 可能爆炸性增长,导致 softmax 溢出或梯度不稳定。Z-loss 以极小权重(c≈10−4c \approx 10^{-4})将 logsumexp 拉向零,防止 logits 漂移——代价极小,收益是训练稳定性显著提升。

MoE 辅助损失(Load Balancing Loss)

混合专家模型(Mixture of Experts,MoE)中,如果所有 token 都被路由到少数几个专家(expert),会导致负载不均衡和训练崩溃。Load Balancing Loss 强制 token 均匀分布到各专家:

Lbalance=N⋅∑(fi⋅Pi)L_{\text{balance}} = N \cdot \sum (f_i \cdot P_i)

其中 fif_i 是分配到专家 i 的 token 比例,PiP_i 是 router 对专家 i 的平均概率。当所有专家均匀分配时此损失最小。Switch Transformer、GShard、Mixtral 都使用了这一辅助损失。

多模态对比损失新进展

SigLIP(Zhai et al., ICCV 2023)将 CLIP 的 InfoNCE 损失从 softmax 形式改为 sigmoid 形式:

LSigLIP=−log⁡σ(zij⋅(sij⋅t+b))L_{\text{SigLIP}} = -\log \sigma(z_{ij} \cdot (s_{ij} \cdot t + b))

每个图文对独立计算,不需要全 batch 的 softmax 归一化。这使得 batch size 可以大幅扩展(不再受 GPU 显存中 softmax 计算的限制),且实验效果优于 CLIP。

同样是误差(预测值 - 真实值),不同损失函数给出的梯度大小截然不同,这直接决定了模型如何学习:

PyTorch:各类损失函数的基本用法

Section titled “PyTorch:各类损失函数的基本用法”
import torch
import torch.nn as nn
# --- 回归损失 ---
pred = torch.randn(8, 1) # 模型预测值
target = torch.randn(8, 1) # 真实值
mse = nn.MSELoss()(pred, target) # 均方误差
mae = nn.L1Loss()(pred, target) # 平均绝对误差
huber = nn.HuberLoss(delta=1.0)(pred, target) # Huber 损失
# --- 分类损失 ---
logits = torch.randn(8, 10) # 10 类的原始输出
labels = torch.randint(0, 10, (8,)) # 真实类别索引
ce = nn.CrossEntropyLoss()(logits, labels) # 多类交叉熵(内含 softmax)
# Focal Loss 需要手动实现或用第三方库 torchvision.ops
def focal_loss(logits, labels, gamma=2.0, alpha=0.25):
"""简化版 Focal Loss"""
ce = nn.functional.cross_entropy(logits, labels, reduction='none')
p = torch.exp(-ce) # 预测概率
return (alpha * (1 - p) ** gamma * ce).mean()
fl = focal_loss(logits, labels) # Focal Loss
print(f"MSE={mse:.3f} CE={ce:.3f} Focal={fl:.3f}")

从头实现:数值稳定的交叉熵 + Softmax

Section titled “从头实现:数值稳定的交叉熵 + Softmax”

交叉熵与 softmax 合并计算时,直接 log(softmax(z)) 会遇到数值溢出问题(exp 大 logit → inf)。标准技巧是用 LogSumExp 重写:

import torch
import torch.nn.functional as F
def stable_cross_entropy_with_softmax(logits, labels):
"""
从头实现数值稳定的交叉熵损失(合并 softmax + NLL)。
数学推导:
CE = -log softmax(z)[correct]
= -log[ exp(z_correct) / Σ exp(z_j) ]
= -(z_correct - logsumexp(z))
= logsumexp(z) - z_correct
logsumexp(z) = max(z) + log Σ exp(z_j - max(z)) ← 减去 max 防溢出
Args:
logits: (N, C) 未归一化的预测分数
labels: (N,) 正确类别的索引
Returns:
scalar loss
"""
# 第 1 步:数值稳定的 logsumexp
z_max = logits.max(dim=-1, keepdim=True).values # (N, 1) 减最大值防 exp 溢出
exp_shifted = torch.exp(logits - z_max) # (N, C) 全是 ≤1 的值,不会溢出
sum_exp = exp_shifted.sum(dim=-1, keepdim=True) # (N, 1)
log_sum_exp = z_max.squeeze(-1) + torch.log(sum_exp) # (N,) 还原:logsumexp(z)
# 第 2 步:取出正确类别的 logit
z_correct = logits.gather(1, labels.unsqueeze(1)).squeeze(1) # (N,)
# 第 3 步:CE = logsumexp(z) - z_correct
loss_per_sample = log_sum_exp - z_correct # (N,)
return loss_per_sample.mean()
# 验证与 PyTorch 官方实现一致
logits = torch.randn(8, 10)
labels = torch.randint(0, 10, (8,))
my_ce = stable_cross_entropy_with_softmax(logits, labels)
torch_ce = F.cross_entropy(logits, labels)
print(f"从头实现: {my_ce.item():.6f}")
print(f"PyTorch: {torch_ce.item():.6f}")
print(f"误差: {abs(my_ce - torch_ce).item():.2e}") # 应 < 1e-6
# 极端值测试:大 logit 不会溢出(直接 softmax 会 inf)
extreme_logits = torch.tensor([[1000.0, 0.0, 0.0]])
extreme_labels = torch.tensor([0])
print(f"极端值损失: {stable_cross_entropy_with_softmax(extreme_logits, extreme_labels).item():.4f}") # 应 ≈ 0.0
import torch
import torch.nn as nn
import torch.nn.functional as F
def dpo_loss(policy_chosen_logps, # (B,) 策略模型对 chosen 回答的 log 概率
policy_rejected_logps, # (B,) 策略模型对 rejected 回答的 log 概率
ref_chosen_logps, # (B,) 参考模型(冻结)对 chosen 的 log 概率
ref_rejected_logps, # (B,) 参考模型(冻结)对 rejected 的 log 概率
beta=0.1):
"""
Direct Preference Optimization (DPO) 损失。
L = -log σ(β * [Δlog π(chosen) - Δlog π(rejected)])
其中 Δlog π(y) = log π_θ(y|x) - log π_ref(y|x),即当前策略相对于
参考策略的对数似然变化。直觉:让策略模型对 chosen 的相对似然
高于 rejected。
Args:
beta: KL 散度惩罚系数,越大越保守(更接近参考模型)
Returns:
scalar loss, 和三个用于监控的指标
"""
# 对数比率(当前策略 vs 参考策略)
chosen_logratio = policy_chosen_logps - ref_chosen_logps # (B,)
rejected_logratio = policy_rejected_logps - ref_rejected_logps # (B,)
# DPO 的核心:chosen 的相对优势
logits = beta * (chosen_logratio - rejected_logratio) # (B,)
# 损失 = 二元交叉熵,label 全为 1(我们希望 chosen 赢)
loss = -F.logsigmoid(logits).mean()
# 监控指标
chosen_rewards = beta * chosen_logratio.detach()
rejected_rewards = beta * rejected_logratio.detach()
accuracy = (chosen_rewards > rejected_rewards).float().mean() # 偏好准确率
margin = (chosen_rewards - rejected_rewards).mean() # 奖励间隔
return loss, accuracy, margin, chosen_rewards.mean(), rejected_rewards.mean()
# 模拟训练中的一步
B = 4 # batch size
seq_len = 128
# 假设我们已经用策略模型和参考模型分别计算了每个回答的 log 概率
# (实际中需要对序列的 token-level log 概率求和)
torch.manual_seed(42)
policy_chosen = torch.randn(B, requires_grad=True) * 2 - 3 # 模型当前对 chosen 的 logp
policy_rejected = torch.randn(B, requires_grad=True) * 2 - 4 # 模型当前对 rejected 的 logp
ref_chosen = torch.randn(B) * 2 - 3 # 参考模型(不参与梯度)
ref_rejected = torch.randn(B) * 2 - 4
loss, acc, margin, cr, rr = dpo_loss(
policy_chosen, policy_rejected, ref_chosen, ref_rejected, beta=0.1
)
print(f"DPO Loss: {loss.item():.4f}")
print(f"偏好准确率: {acc.item():.2%}")
print(f"奖励间隔: {margin.item():.4f}")
print(f"Chosen reward: {cr.item():.4f} Rejected reward: {rr.item():.4f}")
loss.backward() # 梯度会流入 policy_chosen / policy_rejected
import torch
import torch.nn as nn
import torch.nn.functional as F
def label_smoothing_cross_entropy(logits, labels, smoothing=0.1):
"""
Label Smoothing Cross-Entropy(标签平滑交叉熵)。
将 one-hot 标签软化为:
y_smooth = (1 - ε) * onehot + ε / K
然后计算与模型分布的交叉熵。
Args:
logits: (N, C)
labels: (N,)
smoothing: ε,平滑因子,通常 0.1
"""
K = logits.size(-1) # 类别数
# 构造软标签:(1-ε) 在正确位置,ε/K 在所有位置
with torch.no_grad():
smooth = torch.full_like(logits, smoothing / K) # (N, C) 全部 ε/K
smooth.scatter_(1, labels.unsqueeze(1), 1.0 - smoothing + smoothing / K)
# 计算交叉熵: -Σ y_smooth * log_softmax(logits)
log_probs = F.log_softmax(logits, dim=-1) # (N, C)
loss = -(smooth * log_probs).sum(dim=-1).mean()
return loss
# 对比标准 CE vs Label Smoothing CE
logits = torch.randn(8, 10)
labels = torch.randint(0, 10, (8,))
standard_ce = F.cross_entropy(logits, labels).item()
smoothed_ce = label_smoothing_cross_entropy(logits, labels, smoothing=0.1).item()
print(f"标准交叉熵: {standard_ce:.4f}")
print(f"标签平滑 CE (ε=0.1): {smoothed_ce:.4f}")
# 平滑版本通常略高,因为引入了对其他类别的"预留概率"
import torch.nn as nn
# 锚、正、负样本的嵌入向量(假设已通过同一个编码器提取)
anchor = torch.randn(4, 128)
positive = torch.randn(4, 128) # 与 anchor 同类
negative = torch.randn(4, 128) # 与 anchor 异类
# Triplet Loss:拉近距离 positive,推远 negative
triplet = nn.TripletMarginLoss(margin=1.0, p=2) # p=2 即欧氏距离
loss = triplet(anchor, positive, negative)
print(f"Triplet Loss = {loss.item():.4f}")
"""
绘制常见回归和分类损失函数的曲线,直观对比它们的梯度行为。
运行: python visualize_losses.py
"""
import numpy as np
import matplotlib.pyplot as plt
# ============ 回归损失(误差的函数) ============
error = np.linspace(-3, 3, 500)
mse = error ** 2
mae = np.abs(error)
delta = 1.0
huber = np.where(np.abs(error) <= delta, 0.5 * error ** 2, delta * np.abs(error) - 0.5 * delta ** 2)
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# --- 左图:回归损失 ---
ax = axes[0]
ax.plot(error, mse, label='MSE (L2)', linewidth=2)
ax.plot(error, mae, label='MAE (L1)', linewidth=2)
ax.plot(error, huber, label=f'Huber (δ={delta})', linewidth=2)
ax.set_xlabel('误差 (预测 - 真实)', fontsize=12)
ax.set_ylabel('Loss', fontsize=12)
ax.set_title('回归损失对比', fontsize=14)
ax.legend(fontsize=11)
ax.set_ylim(-0.5, 6)
ax.axhline(y=0, color='gray', linewidth=0.5)
ax.axvline(x=0, color='gray', linewidth=0.5)
ax.grid(True, alpha=0.3)
# --- 右图:分类损失(预测概率的函数,假设正确类别 y=1) ---
p = np.linspace(0.01, 0.99, 500) # 模型对正确类别的预测概率
ce = -np.log(p) # 标准交叉熵
for gamma, color in [(0.5, '#FF9800'), (2.0, '#e91e63'), (5.0, '#9C27B0')]:
focal = (1 - p) ** gamma * (-np.log(p)) # Focal Loss (归一化前)
focal_normalized = focal / focal.max() * ce.max() # 归一化到与 CE 同尺度
axes[1].plot(p, focal_normalized, label=f'Focal (γ={gamma})', linewidth=2, color=color, linestyle='--')
axes[1].plot(p, ce, label='Cross-Entropy', linewidth=3, color='#2196F3')
axes[1].set_xlabel('预测概率 p (正确类别)', fontsize=12)
axes[1].set_ylabel('Loss', fontsize=12)
axes[1].set_title('分类损失对比(归一化)', fontsize=14)
axes[1].legend(fontsize=11)
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('loss_functions_comparison.png', dpi=150, bbox_inches='tight')
plt.show()
print("图表已保存: loss_functions_comparison.png")

回归损失与分类损失曲线对比

读图要点:

  • 左图(回归):MSE 在大误差处急剧上升(对异常值敏感),MAE 线性增长(恒定梯度),Huber 在小误差处与 MSE 重合、大误差处与 MAE 平行。
  • 右图(分类):当 p→1p \to 1(已分对),标准交叉熵仍有显著损失值,而 Focal Loss 的损失快速趋近于 0(γ\gamma 越大越激进)。这正是 Focal Loss 降低易样本权重的视觉体现。
  • 回归默认用 MSE,如果数据有较多异常值,换 Huber Loss 或 MAE。MAE 梯度恒定,建议配合自适应优化器(如 Adam)使用。
  • 分类默认用 CrossEntropyLoss:PyTorch 的 nn.CrossEntropyLoss 内部已做 softmax,不要在模型最后一层再加 softmax,否则等于做了两次。
  • 多标签分类用 BCEWithLogitsLoss:每个类别独立做二分类,不要用 CrossEntropyLoss。
  • 类别极不平衡时用 Focal Loss:如目标检测中背景框远多于前景框。γ=2\gamma = 2、α=0.25\alpha = 0.25 是 RetinaNet 中的经典默认值。
  • 分割任务中 Dice + CE 组合常见:Dice 处理类别不平衡,CE 提供稳定的逐像素监督,二者加权求和效果通常优于单一损失。Lovász Loss 是更高级的替代。
  • Triplet Loss 的关键在采样策略:随机选 negative 太容易(模型学不到东西)或太难(训练崩溃)。半难挖掘(Semi-Hard Mining)是实际中常用的折中方案。
  • InfoNCE 的温度 τ\tau 很敏感:τ\tau 太大判别力弱、太小梯度不稳定。SimCLR 用 0.5、CLIP 用 0.07 经 logistic 缩放。
  • 知识蒸馏用 KL 散度损失:温度 T 通常取 4~8。T 太小学生学不到”暗知识”,T 太大学生输出过于平滑、丧失自身判断。
  • DPO 训练用 β\beta 控制偏离度:β\beta 太小模型偏离参考模型太远(可能输出有害内容),β\beta 太大学不到偏好信号。常见值 0.1~0.5。
  • 图像分类:ImageNet 训练用多类交叉熵,Inception/ResNet 后期常用 Label Smoothing CE。详见CNN 卷积神经网络。
  • 目标检测:RetinaNet / YOLO 用 Focal Loss 解决正负样本极度不平衡。详见目标检测与 YOLO。
  • 图像分割:U-Net 等用 Dice Loss 或 Dice + CE 组合;Lovász Loss 用于直接优化 IoU。详见图像分割。
  • 人脸识别:FaceNet 用 Triplet Loss 学习人脸嵌入,ArcFace 用改进的 Additive Margin Softmax。详见自监督与对比学习。
  • 大语言模型预训练:GPT 系列用 token 级别的交叉熵(预测下一个词),PaLM/GPT-4 辅以 Z-loss 稳定训练。详见语言模型演进。
  • LLM 对齐(Alignment):RLHF 用 PPO + 奖励模型;DPO 及其变体(IPO/KTO)用偏好损失直接优化。详见RLHF 与大模型训练。
  • 对比学习:SimCLR / CLIP 用 InfoNCE 学习通用视觉-语言嵌入;SigLIP 用 sigmoid 变体扩展 batch size。详见自监督与对比学习。
  • 知识蒸馏:DistilBERT 等用 KL 散度损失将大模型压缩为小模型。详见知识蒸馏。
类库语言说明
torch.nnPythonPyTorch 内置损失函数:MSELoss、CrossEntropyLoss、BCEWithLogitsLoss、TripletMarginLoss、CosineEmbeddingLoss 等
torch.nn.functionalPython函数式接口,灵活组合自定义损失(如 Focal Loss、DPO Loss)
tf.keras.lossesPythonTensorFlow / Keras 损失函数模块,覆盖类型与 PyTorch 对应
torchvision.opsPython提供 sigmoid_focal_loss 等视觉专用损失的官方实现
segmentation_models_pytorchPython分割库,内置 Dice Loss、Lovasz Loss 等分割专用损失
trlPythonHugging Face 的 Transformer RL 库,提供 DPO、PPO、KTO 等 LLM 对齐损失的现成实现
术语英文解释
损失函数Loss Function衡量模型预测与真实标签之间差距的函数,训练的目标是最小化它
均方误差MSE / L2 Loss预测值与真实值之差的平方均值,对大误差惩罚重
平均绝对误差MAE / L1 Loss预测值与真实值之差的绝对值均值,对异常值鲁棒
Huber LossHuber Loss小误差区域用 MSE、大误差区域切换为 MAE,兼具两者优点
偏差-方差分解Bias-Variance Decomposition将 MSE 分解为偏差² + 方差 + 不可约噪声的理论框架
交叉熵Cross-Entropy信息论度量,分类任务的标准损失,惩罚预测概率偏离真实标签
标签平滑交叉熵Label Smoothing CE将 one-hot 标签软化为 (1−ϵ)⋅onehot+ϵ/K(1-\epsilon) \cdot \text{onehot} + \epsilon / K,起到正则化效果
Focal LossFocal Loss交叉熵加调节因子,降低易分类样本权重,解决类别不平衡
Hinge LossHinge LossSVM 的标准损失,要求正确类得分比其他类高出至少一个间隔
Triplet LossTriplet Loss拉近同类嵌入、推远异类嵌入的损失,用于人脸识别等嵌入学习
对比损失Contrastive Loss基于样本对的损失,正对拉近、负对推远
余弦嵌入损失Cosine Embedding Loss用余弦相似度衡量嵌入方向差异的损失,关注方向而非模长
Dice LossDice Loss基于集合重叠度的损失,常用于图像分割,对类别不平衡友好
Lovász LossLovász LossIoU/Jaccard 的凸代理,将离散的 IoU 连续化为可导函数
InfoNCEInfoNCE对比学习的核心损失,本质是”正样本 vs 一组负样本”的分类问题
KL 散度损失KL Divergence Loss衡量两个概率分布差异的损失,知识蒸馏的核心损失
DPO 损失DPO Loss直接偏好优化损失,绕过奖励模型直接从人类偏好数据训练 LLM
Z-lossZ-loss惩罚 logsumexp 的辅助损失,防止 logits 爆炸,稳定大模型训练
温度系数Temperature τInfoNCE / 知识蒸馏中控制分布锐度的超参数

经典论文

  • Lin et al.,「Focal Loss for Dense Object Detection」(ICCV 2017):Focal Loss 原始论文(RetinaNet),解决目标检测中正负样本极度不平衡问题,引用量极高。
  • Schroff et al.,「FaceNet: A Unified Embedding for Face Recognition」(CVPR 2015):Triplet Loss 和 FaceNet 论文,奠定了人脸识别嵌入学习的基础。
  • Oord et al.,「Representation Learning with Contrastive Predictive Coding」(2018):InfoNCE 损失的提出论文,现代对比学习的理论源头。
  • Milletari et al.,「V-Net: Fully Convolutional Neural Networks for Volumetric Medical Image Segmentation」(2016):Dice Loss 的提出论文,3D 医学图像分割。
  • Szegedy et al.,「Rethinking the Inception Architecture for Computer Vision」(CVPR 2016):Label Smoothing 的提出论文。
  • Hinton et al.,「Distilling the Knowledge in a Neural Network」(2015):知识蒸馏开山之作,KL 散度损失 + 温度缩放。
  • Berman et al.,「The Lovász-Softmax Loss」(CVPR 2018):Lovász Loss 原始论文,IoU 的凸代理。
  • Goodfellow et al.,「Deep Learning」第 5–6 章:深度学习经典教材,系统讲解 MSE、交叉熵等损失函数的数学推导。

2023–2025 前沿论文

  • Rafailov et al.,「Direct Preference Optimization: Your Language Model is Secretly a Reward Model」(NeurIPS 2023):DPO 原始论文,RLHF 的新范式,绕过显式奖励模型直接从偏好数据训练。
  • Azar et al.,「A General Theoretical Paradigm to Understand Learning from Human Feedback」(2024):IPO 的提出论文,指出 DPO 的过拟合问题并用恒定学习率替代。
  • Ethayarajh et al.,「KTO: Model Alignment as Prospect Theoretic Optimization」(ICML 2024):KTO 论文,只需二元反馈数据(而非成对偏好),利用前景理论建模。
  • Zhai et al.,「Sigmoid Loss for Language Image Pre-Training」(ICCV 2023):SigLIP 论文,将 InfoNCE 的 softmax 损失替换为 sigmoid 形式,大幅扩展 batch size。
  • Chowdhery et al.,「PaLM: Scaling Language Modeling with Pathways」(2022):Z-loss 辅助损失在大模型训练中的应用。
  • Shazeer et al.,「Outrageously Large Neural Networks: The Sparsely-Gated Mixture-of-Experts Layer」(ICLR 2017):MoE 辅助负载均衡损失的起源。