
损失函数详解:每种函数只需 2 分钟即可理解其数学原理
图片作者 | Canva
引言
我必须说,随着机器学习的热度不断攀升,很多人在没有真正理解幕后原理的情况下,就直接跳到了应用层面。*我们使用任何机器学习模型的最终目标是什么?* 你可能会说,*“做出准确的预测。”* 说得有理。
但是,你实际上如何告诉你的模型,“你做得差不多了”或者“你离得太远了”?它怎么知道自己犯了错误——又错得有多离谱?
这时,**损失函数**就派上用场了。它告诉我们模型的预测值与实际答案的差距有多大。
在本文中,我将分解损失函数到底是什么,带领你了解一些最常见的损失函数(会包含数学公式,但不会是令人生畏的那种),并帮助你理解它们为何重要——这样你就不会仅仅停留在“它能让模型变得更好”的模糊认识上,而是真正知道它是如何做到的。
我保证,这不会像枯燥的数学课本那样让你云里雾里。
什么是损失函数?
我们已经初步了解了它的非正式概念,为了清晰起见,我们再给出一个正式的定义。
损失函数本质上是一个数学函数,它衡量你的模型预测输出与真实值(也称为“地面真实值”或“标签”)之间的差异。它就像一个分数,告诉你模型的预测有多糟糕。
训练机器学习模型的目标是找到正确的参数(权重和偏置),以最小化这种损失。换句话说:
损失越小,模型表现越好。
在继续之前,我想澄清一个常见的混淆:损失函数和成本函数之间的区别。人们常常把这两个术语混为一谈。严格来说,它们并不相同——所以我们来弄清楚:
- 损失函数:衡量单个数据点的误差
- 成本函数:指所有训练样本上的平均损失
因此,在训练过程中,成本函数通常是被最小化的对象,因为我们关心模型在平均情况下的表现。但在底层,它是为每个样本计算的损失函数。
损失函数的类型(附带数学公式 + 直观理解)
让我们来分解一些常用的损失函数。我会包含一些数学公式,是的,但也会解释它们为何如此工作以及通常在何处使用它们。
1. 均方误差 (Mean Squared Error)
这是回归任务的首选损失函数。它简单、广泛使用且易于理解。它对误差(实际值与预测值之间的差)进行平方,因此较大的误差会受到更严厉的惩罚。这是 MSE 的公式:
\[
\text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i – \hat{y}_i)^2
\]
其中
- \( n \): 数据点的数量
- \( y_i \): 第 i 个数据点的实际值
- \( \hat{y}_i \): 第 i 个数据点的预测值
所以,对于每个预测,你将预测值从实际值中减去,对该差值进行平方(这使得所有误差都变成正数并放大了较大的误差),然后对所有结果取平均。较低的 MSE 意味着预测值更接近实际值。
示例:假设你的模型对房价的预测如下:
预测值:[180,000, 250,000]
实际值:[175,000, 265,000]
MSE 将是:
\[
\text{MSE} = \frac{(175,000 – 180,000)^2 + (265,000 – 250,000)^2}{2} = \frac{(-5,000)^2 + 15,000^2}{2} = \frac{25,000,000 + 225,000,000}{2} = 125,000,000
\]
这是一个相当大的数字——但请记住,单位是平方的,所以直接解释它可能会有些棘手。现在,我想把重点转移到实际讨论——MSE 的优点以及它可能出错的地方。
✅ MSE 的优点:
如果你的数据干净,并且你希望你的模型高度重视大的错误,MSE 会很有帮助。它严厉惩罚大的误差——这在预测错误成本很高的情况下(例如医疗剂量或财务预测)很有用。
🚫 MSE 可能出错的地方
但是,如果你的数据集中存在异常值——比如,有一栋房子比其他的都贵十倍——MSE 可能会搞砸事情。那个数据点可能会完全主导损失,你的模型最终会试图去迎合那个异常值,而对其他数据点表现得更糟。
2. 平均绝对误差 (Mean Absolute Error)
MAE 没有对误差进行平方,而是直接取实际值和预测值之间的绝对差。因此,每个误差都以线性方式做出贡献,无论它的大小如何。这是 MAE 的公式:
\[
\text{MAE} = \frac{1}{n} \sum_{i=1}^{n} \left| y_i – \hat{y}_i \right|
\]
其中
- \( n \): 数据点的数量
- \( y_i \): 第 i 个数据点的实际值
- \( \hat{y}_i \): 第 i 个数据点的预测值
你将预测值从实际值中减去,取绝对值(这样负误差就不会抵消正误差),然后对所有样本取平均。
示例:让我们看同一个房价示例:
预测值:[180,000, 250,000]
实际值:[175,000, 265,000]
MAE 将是:
\[
\text{MAE} = \frac{|175{,}000 – 180{,}000| + |265{,}000 – 250{,}000|}{2} = \frac{5{,}000 + 15{,}000}{2} = \frac{20{,}000}{2} = 10{,}000
\]
所以,这里的平均绝对误差是 10,000——这可以直接用原始单位(在此例中是美元)来解释,这实际上非常有帮助。现在,让我们谈谈 MAE 何时表现良好以及何时可能不足。
✅ MAE 的优点:
如果你的数据集包含异常值,MAE 的处理方式比 MSE 好得多。因为它不对误差进行平方,所以即使一个预测值偏差很大,它也不会因此夸大问题。它对每一个错误都一视同仁——无论是差了 5 还是差了 50。这使得 MAE 成为你同等重视所有错误并希望获得更鲁棒结果时的好选择。
🚫 MAE 可能出错的地方
MAE 在优化方面可能有点棘手。它不像 MSE 那样容易处理,因为绝对值函数在零点不可导。这会使训练过程稍微复杂或变慢,尤其是对于基于梯度的优化方法。
3. Huber 损失 (Huber Loss)
既然你已经看到了 MSE 如何对大误差惩罚得太严厉,而 MAE 又将所有误差一视同仁(但难以优化),你可能会想:“我们能否得到介于两者之间的一种损失?” 嗯,Huber 损失就是为此而生的。当误差很小时,它的行为类似 MSE;当误差很大时,它的行为类似 MAE。这是它的公式:
\[
L_\delta(y, \hat{y}) =
\begin{cases}
\frac{1}{2}(y – \hat{y})^2 & \text{如果 } |y – \hat{y}| \leq \delta \\
\delta \cdot \left(|y – \hat{y}| – \frac{1}{2} \delta\right) & \text{如果 } |y – \hat{y}| > \delta
\end{cases}
\]
其中
- \( y_i \): 第 i 个数据点的实际值
- \( \hat{y}_i \): 第 i 个数据点的预测值
- \(\delta\) (delta):一个阈值,决定何时从平方误差切换到线性误差
用通俗的话来说:
- 如果误差很小(小于或等于某个阈值 \(\delta\ )),我们使用平方误差——就像 MSE。
- 如果误差很大(大于 \(\delta\ )),我们切换到使用绝对误差——就像 MAE——但会做一些微调以保持平滑。
这使得 Huber 损失对异常值具有鲁棒性,同时在任何地方都可导,而 MAE 却不能。
示例:假设真实值为 \( y = 3 \),你的模型预测 \( \hat{y} = 2.5 \),且 \( \delta = 1 \)(小误差)。
\[
|3 – 2.5| = 0.5 \leq 1 \implies L_\delta = \frac{1}{2} (0.5)^2 = 0.125
\]
如果你的模型预测 \( \hat{y} = 5 \)(大误差):
\[
|3 – 5| = 2 > 1 \implies L_\delta = 1 \times \left( 2 – \frac{1}{2} \times 1 \right) = 1.5
\]
✅ Huber 损失的优点:
当你的数据中有一些异常值,但又想避免它们像 MSE 那样主导损失时,Huber 损失效果很好。你还可以根据你希望模型容忍的程度来调整 δ。较小的 δ 意味着你对大误差的容忍度更高(更接近 MAE 的行为),而较大的 δ 则更像 MSE。
🚫 何时可能无效:
如果你的数据非常干净,MSE 可能更简单、更有效。如果你的数据集非常嘈杂,纯 MAE 可能仍然更好。此外,δ 引入了一个需要调整的超参数。
4. 铰链损失 (Hinge Loss)
好了,现在我们来谈谈分类问题。特别是二元分类,你希望你的模型不仅正确,而且有信心地正确。这时,铰链损失就很有用了。你经常会看到它与支持向量机 (SVM) 等算法一起使用。其理念是:不仅仅是正确分类——还要有裕度。这是它的公式:
\[
L(y, \hat{y}) = \max(0, 1 – y \cdot \hat{y})
\]
其中
- \( y \): 实际标签(注意:铰链损失要求标签为 -1 或 +1,而不是 0 或 1)
- \( \hat{y} \): 预测值(通常是原始分数或决策函数,而不是概率)
我们来分解一下。你将真实标签与预测分数相乘——如果你的模型以足够的裕度正确预测(例如,预测 +1 的真实值为 +1,且结果是一个大数字,如 5),则损失变为零。
完美。
但是,如果模型预测了正确的类别但不够自信,或者更糟——预测了错误的类别——你就会得到一个非零的损失,这会促使模型做得更好。
示例:假设真实标签为 \( y = +1 \) 且预测得分为 \( \hat{y} = 0.8 \)
\[
L = \max(0, 1 – (1)(0.8)) = 0.2
\]
在这里,模型预测正确但不够自信,所以损失为正。
\[
L = \max(0, 1 – (1)(2.5)) = 0
\]
现在模型非常自信地正确预测,所以损失为零。
✅ 铰链损失的优点:
如果你使用 SVM 或类似的需要最大化决策裕度的模型,铰链损失是你的首选。它不仅关心正确性——它关心你有多正确。这就像在说,“是的,你做对了,但这只是运气还是你真的懂?”因此,它非常适合需要清晰的决策边界和“自信”的预测概念的情况。
🚫 MSE 可能出错的地方:
铰链损失不能用于概率。如果你的模型输出概率(例如,使用 sigmoid 的逻辑回归或神经网络),那么这不是正确的损失函数。此外,它并非处处可导(尤其是在铰链点),这可能使某些框架中的优化变得有点棘手。而且你必须记住使用 -1 和 +1 作为标签——使用 0/1 会搞砸。
5. 二元交叉熵 (Binary Cross-Entropy)
当你处理二元分类问题时(例如垃圾邮件 vs. 非垃圾邮件,或猫 vs. 狗),BCE 是经典的损失函数。它设计用于与概率配合得很好——因此你的模型输出是一个介于 0 和 1 之间的值,表示输入属于类别 1 的可能性。在数学上,n 个数据点的损失由下式给出:
\[
L = – \frac{1}{n} \sum_{i=1}^n \left[ y_i \log(\hat{y}_i) + (1 – y_i) \log(1 – \hat{y}_i) \right]
\]
其中
- \( n \): 数据点的数量
- \( y_i \in \{0, 1\} \): 第 i 个数据点的实际值
- \( \hat{y}_i \in (0, 1) \): 第 i 个数据点属于类别 1 的预测概率
如果真实标签 \( y_i \) 是 1,则第一项 \( y_i \log(\hat{y}_i) \) 起主导作用,只有当预测概率 \( \hat{y}_i \) 接近 1 时,损失才会很低。另一方面,如果真实标签是 0,则第二项 \( (1 – y_i) \log(1 – \hat{y}_i) \) 发挥作用,只有当预测概率 \( \hat{y}_i \) 接近 0 时,损失才会很小。这里的对数至关重要——它会严厉惩罚自信但错误的预测,这意味着,如果你的模型对真实的阳性预测了一个非常低的概率,损失会急剧上升。
示例:假设真实标签是 \( y = +1 \) 且预测概率是 \( \hat{y} = 0.9 \)
\[
L = – \left(1 \times \log 0.9 + 0 \times \log 0.1\right) = – \log 0.9 \approx 0.105
\]
如果预测概率是 \( \hat{y} = 0.1 \)(错误且自信):
\[
L = – \log 0.1 \approx 2.302
\]
损失高得多,表明预测很差。
✅ BCE 的优点:
它特别有用,因为它产生了一个平滑的损失曲面,像随机梯度下降这样的基于梯度的优化算法可以有效地对其进行处理。当你的模型输出是概率(来自 sigmoid 或 softmax)时,并且你的任务严格是二元分类时,它是理想的选择。
🚫 何时可能遇到困难:
如果你的数据集包含嘈杂或错误标记的样本,BCE 可能会过度惩罚这些点,可能导致你的模型在泛化方面遇到困难。此外,如果你的类别高度不平衡(例如 90% 的负样本和 10% 的正样本),仅 BCE 可能不足以平衡学习,因为它可能导致你的模型只预测多数类,并仍然获得一个虚假的低损失。
6. 分类交叉熵 (Categorical Cross-Entropy)
分类交叉熵基本上是二元交叉熵的扩展,但用于多类分类问题。它不像只有两个类别(0 或 1),而是处理多个类别——比如将图像分类为猫、狗或鸟。你的真实标签 yi 表示为一个独热编码向量(只有一个类别是 1,其余都是 0),而你的模型输出一个在所有类别上的预测概率分布 \hat{y}_i。公式如下:
\[
\text{Loss} = – \sum_{c=1}^{C} y_{i,c} \log(\hat{y}_{i,c})
\]
其中
- \( C \): 总类别数
- \( y_{i,c} \in \{0,1\} \): 第 c 类的真实标签
- \( \hat{y}_{i,c} \in (0,1) \): 第 c 类的预测概率
这个公式的作用基本上是从预测分布中提取真实类别的对数概率,并在概率较低时惩罚模型。所以,如果模型对实际类别预测的概率很低,损失就会急剧上升。如果模型自信且正确,损失就很低。
示例:假设真实标签是猫:\( y = [1, 0, 0] \),你的模型预测 \( \hat{y} = [0.7, 0.2, 0.1] \)。代入公式:
\[
\text{Loss} = – \big(1 \times \log 0.7 + 0 \times \log 0.2 + 0 \times \log 0.1 \big) = – \log 0.7 \approx 0.357
\]
现在,如果模型预测 \( \hat{y} = [0.1, 0.7, 0.2] \)(错误地偏向狗),损失将变为:
\[
\log 0.1 \approx 2.302
\]
这高得多,告诉模型这是一个糟糕的预测。
✅ 分类交叉熵的优点:
当你有清晰、互斥的类别,并且希望你的模型对正确的类别充满信心时,它效果非常好。对数惩罚确保了错误但自信的预测会受到严厉惩罚,促使模型谨慎而准确。
🚫 何时可能遇到困难:
如果你的类别不是互斥的(例如,多标签问题,一个样本可以同时属于多个类别),那么分类交叉熵不是最佳选择。此外,如果你的数据集不平衡(一个类别出现的次数远远多于其他类别),模型可能会倾向于多数类别,除非你使用类别加权或重采样等技术来处理。
7. 库尔巴克-莱布勒散度 (Kullback-Leibler Divergence, KL Divergence)
KL 散度与我们之前讨论过的其他损失函数有些不同。它本身不完全是一个传统的损失函数,而是一种衡量一个概率分布与另一个概率分布差异的方法。将其想象成一种衡量当你假设数据遵循一个分布,但实际上它遵循另一个分布时,你会感到多么惊讶。
在数学上,如果你有两个概率分布 P(真实分布)和 Q(预测分布),KL 散度衡量当 Q 用于近似 P 时损失了多少信息。公式如下:
\[
D_{\mathrm{KL}}(P \| Q) = \sum_{i} P(i) \log \frac{P(i)}{Q(i)}
\]
在这里,P(i) 是事件 i 的真实概率,Q(i) 是相同事件的预测概率。
一个关键点:KL 散度是不可交换的,这意味着:
\[
D_{\mathrm{KL}}(P \| Q) \neq D_{\mathrm{KL}}(Q \| P)
\]
这意味着它衡量 Q 如何近似 P,但反之则不然。在实践中,KL 散度常用于概率模型,如变分自编码器,你想衡量你的预测分布与真实分布的接近程度。
示例:假设三个类别的真实分布是:
P = [0.7, 0.2, 0.1]
你的模型预测:
Q = [0.6, 0.3, 0.1]
将这些值代入公式:
\[
D_{\mathrm{KL}}(P \| Q) = 0.7 \log \frac{0.7}{0.6} + 0.2 \log \frac{0.2}{0.3} + 0.1 \log \frac{0.1}{0.1}
\]
\[
= 0.7 \times 0.154 + 0.2 \times (-0.405) + 0.1 \times 0 = 0.1078 – 0.081 + 0 = 0.0268
\]
因此,KL 散度约为 0.027,相当低,表明 Q 非常接近 P。
✅ KL 散度的优点:
KL 散度在需要匹配整个概率分布的场景中效果很好,例如在变分推理、语言建模或生成模型中。它能捕捉到超越准确性的细微差别,尤其是在输出是概率的情况下。
🚫 何时可能遇到困难:
由于 KL 散度是不可交换的,错误地使用它(交换 P 和 Q)可能会导致误导性的结果。此外,如果对于某个 P(i) > 0 的 i,Q(i) = 0,则散度将变为无穷大,这可能在训练过程中引起问题。这意味着它需要仔细的数值处理。
结论
损失函数可能看起来只是模型配置中的又一个复选框——但实际上,它们在幕后做了所有繁重的工作。它们是模型学习的方式。
所以下次训练模型时,不要只是随便选择一个看起来流行的损失函数。问问自己:
- 我正在解决什么类型的问题?
- 哪种类型的错误更重要?
- 我应该如何衡量这些错误?
一旦你理解了这些,你就不仅仅是在构建模型——你是在以最有效的方式教授它们。
我非常喜欢你在文章中区分了损失函数和成本函数。干得好,解释得很棒。
精彩的讨论,清晰、简洁、总结得很好,我很喜欢!
谢谢你的解释。我觉得这些材料很有帮助。