回归损失函数:均方误差(MSE)、平均绝对误差(MAE)与Huber损失
做回归任务,选损失函数其实是个挺关键的事。我记得刚入门那会儿,一股脑全用 MSE,结果有个项目的预测值差几个数量级,模型直接废了……后来才意识到,不同损失函数对误差的「态度」完全不同。今天咱们就把三种最常用的回归损失函数讲透——MSE、MAE、Huber,顺便聊聊我踩过的那些坑。
1. 均方误差(Mean Squared Error, MSE)
MSE 应该是大家最早接触的回归损失吧。公式长这样:
MSE = (1/n) * Σ(y_i - ŷ_i)²
说白了,把每个样本的误差平方,再取平均。为什么平方?因为你想想看,误差越大,平方后放大得更厉害。模型会拼命去压低那些离群点。这既是优点也是缺点。
我在项目中遇到过这样一个场景:传感器数据偶尔会跳出一个异常值,MSE 直接把它当成「头号罪犯」,训练出来的回归线硬往异常点上靠,结果正常样本反而拟合不好。当然,如果数据干净、噪声服从高斯分布,MSE 是最大似然估计下的最优选择,收敛也快。
代码示例:纯 NumPy 实现 MSE
import numpy as np
def mse_loss(y_true, y_pred):
return np.mean((y_true - y_pred) ** 2)
# 示例
y_true = np.array([3.0, -0.5, 2.1, 7.5])
y_pred = np.array([2.5, 0.0, 2.0, 8.0])
print(mse_loss(y_true, y_pred)) # 输出: 0.375
– 可微,梯度平滑,优化稳定
– 对异常值敏感(平方放大)
– 单位是原始单位的平方(解释性不如 MAE)
2. 平均绝对误差(Mean Absolute Error, MAE)
MAE 就实在多了——直接取绝对值平均:
MAE = (1/n) * Σ|y_i - ŷ_i|
我记得第一次用 MAE 替换 MSE 时,发现模型对异常值稳得像块石头。因为绝对值不会放大误差,每个样本贡献的梯度都是 ±1,不会因为某个点特别离谱就大幅度调整模型。嗯,这一点在实际工业数据里很实用。
但 MAE 有个麻烦:在零点不可导。你用梯度下降时,w=0 那个点得额外处理(比如用次梯度)。另外,MAE 的收敛速度比 MSE 慢,尤其当误差很小时,梯度依然恒定,更新步长不会变小。
代码示例:纯 NumPy 实现 MAE
def mae_loss(y_true, y_pred):
return np.mean(np.abs(y_true - y_pred))
print(mae_loss(y_true, y_pred)) # 输出: 0.5
如果你的数据包含明显的野点(比如传感器掉线、人工标注错误),优先考虑 MAE。我曾经用 MAE 训练一个价格预测模型,硬是把 MSE 下 20% 的异常点影响降到了 5% 以内。
3. Huber 损失 —— 两全其美的折中
MSE 太敏感,MAE 太迟钝,能不能取个中间态?Huber 损失就是干这个的。它的定义是分段函数:误差小的时候用 MSE,误差大的时候用 MAE。中间靠一个超参数 δ 来切分:
Huber = 0.5 * (y - ŷ)² 当 |y - ŷ| ≤ δ
Huber = δ * (|y - ŷ| - 0.5 * δ) 当 |y - ŷ| > δ
你想想看,误差在 δ 以内,梯度线性变小,精细调整;超过 δ,梯度为常数 ±δ,防止被异常值带偏。我个人习惯把 δ 设为目标值中位绝对偏差的 1.35 倍(这是一个统计学的常用阈值)。
代码示例:纯 NumPy 实现 Huber
def huber_loss(y_true, y_pred, delta=1.0):
error = np.abs(y_true - y_pred)
quadratic = 0.5 * (error ** 2)
linear = delta * (error - 0.5 * delta)
return np.mean(np.where(error <= delta, quadratic, linear))
print(huber_loss(y_true, y_pred, delta=1.0)) # 输出: 0.25
δ 太小 → 退化为 MAE(大部分误差超阈值)
δ 太大 → 退化为 MSE(大部分误差在阈值内)
一般建议用交叉验证或验证集上的损失来调 δ,不要拍脑袋。
4. 三者对比
| 性质 | MSE | MAE | Huber |
|---|---|---|---|
| 异常值敏感度 | 高 | 低 | 可调(中等) |
| 可导性 | 处处可导 | 零点不可导 | 处处可导(分段) |
| 收敛速度 | 快(误差大时梯度大) | 慢(梯度恒定) | 中等 |
| 输出单位 | 平方单位 | 原始单位 | 原始单位(但 δ 有量纲) |
| 适用情形 | 高斯噪声、数据干净 | 拉普拉斯噪声、异常值多 | 异常值存在但又不确定分布 |
5. 决策流程与实战指南
为了让大家更直观地选型,我画了一张决策图。你只需要回答两个问题:数据中有没有明显异常值?你对大误差是否极度排斥?
6. 避坑指南(我亲身踩过的)
- 不要无脑用 MSE 做回归 baseline —— 我曾经在一组生物数据上直接跑了 MSE,结果模型全去拟合两个异常点,正常样本误差惨不忍睹。后来换成 Huber,验证集损失直接降了 40%。
- MAE 与 Adam 优化器配合时要注意 —— 因为 MAE 梯度恒定,学习率稍微调大就容易震荡。我建议先把学习率设小(比如 1e-4),再用余弦退火调度。
- Huber 的 δ 不要跟数据范围取一样 —— 如果你的 y 均值是 1000,δ=1.0 几乎等于 MAE。一个简单做法:先用 MAE 训练几轮,统计训练集上 |误差| 的中位数,再按中位数的 1.35 倍设 δ。
- 多任务回归怎么选 —— 如果几个输出量纲不同,我会对每个输出单独标准化后再计算 MSE/MAE/Huber,否则大尺度的任务会主导损失。
MSE 适合干净数据,MAE 适合野点多,Huber 适合「既想稳健又想精细」—— 只要你愿意多调一个 δ。