这两年经常有人拿着同一个问题来找我:损失函数是怎么想出来的?尤其是刚接触深度学习的人,看着框架里的 CrossEntropyLoss 和 MSELoss,总觉得这些名字像是某种魔法咒语;面试被问到“为什么分类不用均方误差”时,只能背答案,背完还是觉得没底。其实答案早就藏在一个统计学的经典概念里——极大似然估计。只要把损失函数理解成负对数似然,你会发现几乎所有常见损失函数都不是拍脑袋发明出来的,而是某种概率假设的自然结果。这篇文章就把这条线索完整捋一遍,从 MLE 出发推出回归里的 MSE、分类里的交叉熵,再延伸到语言模型、目标检测框回归和正则项。不管你现在是刚入门、正在准备面试,还是已经写了不少训练代码,这套理解都值得花二十分钟过一遍。
先把结论放在最前面:损失函数不是一个需要人为挑选的“距离函数”,它是一个概率模型的倒影。给定输入 x 和参数 θ,真正重要的是我们假设标签 y 服从什么样的分布 p(y|x,θ)。如果这个假设合理,那么对一批独立样本求联合概率,再取负对数,得到的就是损失。至于为什么不是直接最大化概率而是要取负对数,后面会详细说。现在只需要记住,MSE 和交叉熵这两个最常见的名字,都只是负对数似然在两个最普通分布假设下的具体长相。
1. 从“距离”到“概率”:损失函数背后的世界观
1.1 先忘掉“误差”,想想数据是怎么生成的
大多数人第一眼看到损失函数,脑子里出现的是“预测和真实值之间的差距有多大”。均方误差自然被理解成欧氏距离,交叉熵被理解成信息论里的编码代价。这些理解不能说错,但它们都是事后的几何或信息论解释,没法回答一个更根本的问题:为什么恰好是这个“距离”,而不是另一个?MLE 换了一个视角:你根本不需要单独去定义“距离”,你只需要回答一个问题——在已知输入 x 和模型参数 θ 的情况下,我假设真实标签 y 是从哪个概率分布里采样出来的。一旦这个分布写出来,把观测数据代入,得到关于 θ 的似然函数;再取负对数,就是损失函数。
为了更直观,把数据想象成抛硬币。假设一枚硬币出现正面的概率是 p,你抛了 10 次得到 7 次正面,那自然会选择让“看到这 10 次结果”这件事发生概率最大的 p,也就是 0.7。这就是 MLE 的直觉。机器学习里模型没有真实 p,但我们有一堆 (x,y) 对,于是把 p 换成 p(y|x,θ),把“一次抛硬币”换成“每个样本的预测分布”,问题就转化成一个标准的参数估计问题。模型 f(x,θ) 在这里扮演的角色,是把输入映射成某个概率分布参数的载体,而不是直接输出一个“答案”。
1.2 极大似然估计的骨相:乘积、对数、负号
多个样本独立同分布时,联合概率等于每个样本的似然乘积。直接最大化这个乘积会碰两个麻烦:一是成千上万个小于 1 的小数乘在一起很容易下溢到 0,数值上直接崩掉;二是乘积形式的导数非常难看,指标稍多就没法算。所以取 log,乘法变加法,log 又是单调递增函数,不会改变最优参数的位置。为了符合我们“最小化损失”的工程习惯,再加个负号,于是所有故事浓缩成一个式子:Loss(θ) = - Σᵢ log p(yᵢ | xᵢ; θ)。
需要强调,这里的 log 以 e 为底还是以 2 为底不影响优化结果,但通常写成 ln。模型输出的形式也不是拍脑袋定的:回归里 f(x,θ) 可以直接作为高斯分布的均值;分类里 f(x,θ) 输出的 logit 要通过 softmax 之类的方式映射成类别概率。这些细节决定了最终损失函数长什么样。理解了这个框架之后,你会发现所谓“调损失函数”,本质上是在调整你对数据生成过程的假设;而假设变了,替换的应该是 p(y|x,θ) 而不是某个现成的距离公式。
2. 回归任务中的MSE:高斯噪声假设下的必然产物
2.1 手推一遍:MSE是怎么从高斯分布里长出来的
回归任务最常见的选择是均方误差。为什么不选别的?MLE 给了一个特别干净的答案:因为你假设标签 y 是在模型输出周围叠加了高斯噪声得到的。设模型输出为 f(x,θ),真实标签为 y,那么 y = f(x,θ) + ε,其中 ε 服从均值为 0、方差为 σ² 的正态分布。于是给定 x 和 θ 时,y 的条件概率密度可以写成:
p(y|x,θ) = 1 / √(2πσ²) · exp( -(y - f(x,θ))² / (2σ²) )
对这个式子取负对数,得到每个样本的损失:
NLL = (y - f)² / (2σ²) + 0.5 · ln(2πσ²)
注意第二项和第一项里的 σ² 在训练 θ 时都是常数(至少在很多标准回归任务里,我们不会去建模 σ),优化时直接扔掉。于是我们悲催地发现,最小化负对数似然等价于最小化 (y - f)²,也就是 MSE。所以 MSE 不是“因为它在欧氏空间里直观”才被选中,而是因为高斯噪声假设下的负对数似然恰好长成平方差的样子。
这个推导最值钱的地方,是它告诉我们 MSE 隐含的前提:误差独立、同方差、服从正态分布。当数据真实满足这些前提时,MLE 有很好的统计性质,比如一致性和渐近正态性;当数据不满足时,MSE 虽然还能算出一个数,但它已经不再是对应分布假设下的最优解。举个现实例子:如果数据里有几个标注错到离谱的点,MSE 会给这些点极大的权重,因为平方项把误差放大了,拟合线很容易被拉歪。这种时候你换成 MAE 或 Huber,往往更稳,原因也要从分布假设里去找。
2.2 异方差场景:预测方差才是真正的 MLE
标准的回归任务通常假设所有样本的噪声方差 σ² 都一样,这在很多真实任务里是站不住脚的。比如从图片估计深度,远处物体的深度误差明显比近处大;从文本预测情感分数,用户评分方差也和内容本身有关。与其假装用一个全局常数方差,不如把方差也变成模型的输出。假设模型不仅输出均值 f(x,θ),还输出一个尺度项 s = log σ²,那么高斯 NLL 就可以写成:
L = exp(-s) · (y - f)² + s
这里多出来的 exp(-s) 是权重:当模型认为当前样本的不确定性大时,自动减少 MSE 惩罚;第二项则是正则项,防止模型把方差预测到无限大。这个形式看起来很复杂,但从 MLE 的角度看只是“直接最大化高斯似然”而已,没有任何额外玄学。
实操中这个损失项在不少需要不确定性估计的任务里非常有效。它给我最深的印象是:依赖方差项做自适应加权之后,模型对标注噪声大的样本态度会温和很多,整体指标往往也更好。如果你只背过 MSE 的公式,永远推不出这个变体;但只要沿着“数据是怎么生成的”去想,一切顺其自然。
2.3 高斯假设不成立:MAE、Huber 与鲁棒回
刚才说高斯噪声对应 MSE。那如果噪声不是高斯分布而是拉普拉斯分布呢?拉普拉斯分布的密度函数里有绝对值项 |y - f|,取负对数后得到的就是平均绝对误差 MAE。所以 MAE 的真实身份是拉普拉斯噪声假设下的负对数似然。从分布形状上看,拉普拉斯分布比高斯分布有更厚的尾部,也就是说它对极端值出现的概率容忍度更高,反映到损失上就是离群点带来的惩罚从平方变成一次,没那么容易被极端值带跑。
但 MAE 也有自己的麻烦:它在误差为 0 时不可导,梯度在正负之间跳变,训练后期拟合容易震荡。于是工程上常用的妥协方案是 Huber 或 Smooth L1:小误差时按二次走,梯度平滑;大误差时按一次走,限制梯度过大。用我自己的话总结就是,MSE 适合噪声干净、分布接近高斯的数据;MAE 适合离群点多、你不想被极端标注带偏的数据;Smooth L1 则是两头的折中,也是目标检测框回归里常见的配置。真正决定选型的,不是“哪个公式好看”,而是你对数据里噪声来源的预判。
3. 分类任务中的交叉熵:离散分布背后的标准答案
3.1 二分类:伯努利分布与二元交叉熵
分类任务和回归任务在数据生成方式上完全不同。二分类标签 y 只有 0 或 1 两个取值,你用高斯分布去描述它显然很别扭。模型需要输出的其实是一个概率 π = P(y=1|x,θ),此时最自然的假设是 y 服从伯努利分布。单个样本的概率质量函数写成:
P(y|π) = π^y · (1-π)^(1-y)
取负对数就得到 -[y·ln π + (1-y)·ln(1-π)],这正是二元交叉熵。模型一般先输出一个 logit z,再通过 sigmoid 函数转成 π = 1/(1+exp(-z))。很多人第一次看到 sigmoid 觉得它是“压缩到 0 到 1 之间的魔术”,但从统计角度看,它其实是 logit 到伯努利分布成功概率的逆链接函数;logit 的物理含义是 log(π/(1-π)),也就是对数优比。这样理解,整个模型结构就变成一个概率模型的一部分,而不是一堆层叠函数的偶然组合。
3.2 多分类:Softmax 加上交叉熵
多分类的推导和二分类几乎一模一样,只是把伯努利分布换成类别分布。假设共有 K 个类别,标签是 one-hot 向量 y,模型用 softmax 把 K 个 logit 变成一组和为 1 的概率 p_k = exp(z_k) / Σⱼ exp(z_j)。单个样本的负对数似然就是:
L = - Σₖ y_k · ln p_k = - ln p_c
其中 c 是正确类别。所以多分类交叉熵看起来在算“真实标签分布和预测分布之间的距离”,本质上就是在最大化正确类别的对数概率。框架里通常把 softmax 和交叉熵合在一起实现,数值上更稳定;如果你自己用原语实现,请不要先算 softmax 再取 log,而是用 log_softmax 再加 NLL,否则在极端概率下很容易出现 NaN。
理解这一点后,很多高级操作也变得好懂。比如知识蒸馏里的温度 T,本质是把 softmax 变成 exp(z_k / T),温度高于 1 时概率分布变得更平滑,等于人为调整了模型输出的分布锐度,而不是在改损失函数本身。再比如 label smoothing,是把 one-hot 标签变成了一个更软的分布,对应到 MLE 里就是不再相信训练标注是绝对正确的类别,这个理解比背“防止过拟合”要深刻得多。
3.3 分类为什么不用MSE?这是面试里绕不开的坎
这个问题我已经被问过不止十次,现在统一给一个完整回答。首先,从概率假设角度,MSE 等价于假设标签是带高斯噪声的连续值,可分类标签明明是离散的 0/1 或 one-hot 向量,这个假设从根本上就错了。用 MSE 训练分类模型,等价于你在让模型逼近 one-hot 向量的欧氏距离,而不是在最大化正确类别的似然,优化目标都偏了。
其次,梯度行为也很有说服力。设 p = σ(z),真实标签 y ∈ {0,1}。如果是二元交叉熵,对 logit z 的梯度为:
∂BCE / ∂z = p - y
这个梯度和误差成正比,预测偏得越多,梯度越大,信号非常直接。如果用均方误差 L = (p-y)²,那么:
∂MSE / ∂z = 2(p-y) · p · (1-p)
注意后面多了一个 p(1-p)。当预测概率接近 0 或 1 时,这个因子会趋近于 0,即使模型还分得很离谱,梯度也可能已经被压得极小。换句话说,MSE 在分类任务里容易把模型拖进梯度非常稀疏的饱和区,训练前期“半天学不动”。这件事很多人在实验里见过,但只有从梯度公式上看才真正搞清楚原因。
当然,MSE 也不是完全不能用,早期也有拿它做分类的,只是收敛慢、稳定性差。面试时如果被问到这个问题,你不需要背什么“交叉熵是信息论度量”这种话,只需要在白板上写两行梯度公式,再补一句“分类标签的真实生成过程是离散分布,用高斯假设不合理”,基本就能把面试官说服。
4. MLE还能解释更“现代”的事:语言模型、检测框与正则项
4.1 语言模型:每个位置都在做一个多分类MLE
语言模型训练的核心目标是预测下一个词。给定前面的 token 序列,模型输出词表上每个 token 的概率,真实下一个词是其中一个类别;这本质上就是一个多分类任务。所以你在预训练代码里看到的交叉熵损失,就是在对词表的类别分布做极大似然估计。训练时每个位置都被当成一个独立样本,所有位置的负对数似然加起来再平均,就是最终 loss。
评估语言模型常用的困惑度 PPL 也和 MLE 直接相关。PPL = exp(平均负对数似然),也就是 exp( mean NLL )。于是低困惑度意味着模型对下一个 token 的预测概率高,也就是模型给语料分配的概率高。这个指标不是工程师随手发明的“评分数值”,它本身就是 MLE 目标的指数变换。理解了这条线,你会明白“语言模型就是想给文本序列建一个好的概率分布”这句话到底在说什么。
4.2 目标检测框回归:从 Smooth L1 到不确定性输出
做目标检测的人应该对 Smooth L1 很熟,它几乎成了框回归的标准损失。从 MLE 视角回看,经典思路是假设每个框坐标的偏差服从高斯分布,那自然该用 MSE;但训练数据里总有一些标注特别粗糙的框,平方误差会给这些离群框超大梯度,让训练不稳定。于是工程上选择用 Smooth L1:误差小时按二次,误差大时按一次。这不是凭空降下来的“参数技巧”,而是对极端噪声更稳健的一种分布假设的近似。
更进一步,我们完全可以走高斯 NLL 路线:让模型不仅预测框的位置,还预测每个坐标的方差或对数方差。这样模型会自动降低对标注质量差的样本的惩罚力度,相当于给了回归任务一个自适应权重。这种方案在需要输出可靠置信度的任务里很有价值。我自己的感受是,单看 Distance 公式的人很难想到还有这种设计,但只要沿着“标签是怎么生成、噪声有多大”这个思路走,每一步都很自然——这也是 MLE 视角对设计新损失函数最直接的帮助。
4.3 正则项的先验解释:MLE 之上加一个 MAP
正则项也经常被误解成纯工程手段。从贝叶斯统计角度看,最小化“负对数似然 + 正则项”,对应的是最大化后验概率 MAP。MAP 等于先验乘以似然:P(θ|D) ∝ P(D|θ) · P(θ)。取负对数后,前一项是原来的损失,后一项是参数的负对数先验。如果给参数 θ 加上高斯先验 N(0, 1/λ),负对数先验就得到 λ||θ||²/2,这就是 L2 正则;如果加拉普拉斯先验,就得到 L1 正则,也解释了为什么 L1 容易产生稀疏解。
这个视角的实用价值在于,它把“模型结构 + 损失函数 + 正则项”打包成了一个统一建模过程。下次你在代码里加 weight decay,想的不只是“防止过拟合”,而是“我给参数先验地认为 θ 不应该太大”。损失函数和正则项不再是一堆需要记忆的公式,而是同一个概率模型的两块拼图。
5. 实战中的检查清单与避坑指南
5.1 设计损失函数时,先写一行 p(y|x,θ)
我自己这几年的一个习惯是:拿到一个新任务,不急着在框架里选损失函数,而是先在纸上写一行“这条数据里的 y 是怎么生成的?”然后把它翻译成概率分布。如果 y 是连续实数且噪声大致均匀,用高斯分布,得到 MSE;如果 y 是二分类标签,用伯努利分布,得到 BCE;如果 y 是多分类标签,用类别分布,得到交叉熵;如果 y 是计数值而且比较稀疏,泊松分布可能更合适,对应的损失里会出现 y·log μ - μ 的形态,而不是硬套 MSE。
这给了一个非常清晰的选型流程:先定分布,再取负对数,最后删掉常数项。顺着这条路走,你会慢慢发现自己开始“设计”损失函数,而不是只能从工具箱里挑。很多看起来高大上的损失,比如带噪声自适应权重的回归损失、带温度的蒸馏损失,本质上都是对底层的 p(y|x,θ) 做了某种结构化改造;理解了原型,再去读它们的推导,通篇都是顺的。
5.2 面试和答疑时最高效的一串回答
如果你正被“为什么分类用交叉熵不用 MSE”这类问题折磨,下面这张表可以直接拿来当速查。
| 典型问题 | 一句话核心 | 想再深挖就补这一句 |
|---|---|---|
| 为什么回归用 MSE? | 因为假设误差是高斯噪声,MSE 是该假设下的负对数似然。 | 如果不满足,可换 MAE、Huber。 |
| 为什么分类用交叉熵? | 分类标签来自伯努利/类别分布,交叉熵就是该分布的负对数似然。 | 它等价于最大化正确类别的对数概率。 |
| 为什么分类不用 MSE? | MSE 假设标签是连续高斯噪声,且 sigmoid 下梯度会饱和。 | 交叉熵的梯度是 p-y,MSE 的梯度多一个 p(1-p)。 |
| 正则项是干嘛的? | 它对应参数的先验,MAP 后验 = 似然 × 先验。 | 高斯先验给 L2,拉普拉斯先验给 L1。 |
| 损失函数能自己设计吗? | 能,先定 p(y | x,θ),再取负对数。 |
面试时不要停留在“因为大家说交叉熵好”这种层面。有条件就主动在白板上写两个梯度对比,再补一句“分类标签的生成过程不可能是正态的”,这个回答基本就把问题闭环了。
5.3 自己动手验证:一个很小的二分类对比实验
我建议每个想彻底搞懂这个话题的人都动手做个小实验。用最简单的线性二分类模型,造一组随机二维数据,分别用二元交叉熵和均方误差训练;初始化、学习率、训练轮数全都保持一致。你会在训练曲线上看到非常典型的差异:交叉熵那边训练几十步之后准确率快速上升,MSE 这边前几十步 loss 下降很慢,模型看起来“在原地磨蹭”。这正是 3.3 里那个 p(1-p) 饱和因子在起作用。
代码不需要写很复杂,核心逻辑甚至可以缩成两行梯度函数:
def bce_grad(p, y): return p - y def mse_grad(p, y): return 2 * (p - y) * p * (1 - p)拿这两行去对比,当 p 接近 0.5、1 或 0 时,哪个梯度更稳定、哪个更容易消失,一目了然。类似的实验也可以在回归任务上做:给数据里加几个离群点,用 MSE 和 Smooth L1 各拟合一次,你会发现 MSE 的直线明显被离群点拽歪,而 Smooth L1 要稳得多。有些知识嘴上说了十遍,不如自己跑一次曲线来得痛快。
5.4 容易踩的坑:五个使用损失函数时的真实教训
第一,不要在 softmax 之后手写 log 再交叉熵。框架里通常把 softmax 和 NLL 融合实现了,逻辑上更稳定;自己拆开容易在极端概率下触发浮点溢出。第二,使用 BCE 时要把输入当 logit 还是概率看清楚,不同框架的接口约定不一样,弄反了会导致模型永远不收敛。第三,为了鲁棒性直接换 MAE 要谨慎,MAE 在零误差处不可导,训练末期可能震荡;想兼顾就用 Smooth L1 或 Huber。第四,如果你自己实现了高斯 NLL 做不确定性回归,别忘了保留 s = log σ² 那一项,以及标准差规范化公式里的常数;漏项等于改了整个概率模型。第五,不要拿分类问题的交叉熵去套回归标签,也不要拿回归的 MSE 去套离散计数,省事一时爽,调试悔断肠。
最后说个我自己养成的习惯:现在遇到任何想调的损失函数,我都会先在纸面写一行 p(y|x,θ),再写一句“这条数据是怎么生成的”,然后才打开代码改损失。很多看起来玄乎的 trick——难样本加权、预测方差、温度缩放——一旦都能对应到概率模型的某一块,思路马上就清楚了。MLE 不是这篇里某个单独的知识点,而是所有损失函数背后的通用语言。如果你看完只记住一件事,希望是:遇到损失函数不要背公式,先问它想建模的数据分布是什么。这个习惯,比收藏一堆 Loss 模板值钱得多。