损失函数的定义与作用
什么是损失函数?
- 损失函数(Loss Function)——是一个衡量预测结果与真实结果之间差异的函数 ,也称为误差函数。它通过计算模型的预测值与真实值之间的不一致程度,来评估模型的性能。
损失函数的作用
- 简单来说,测试数据通过模型计算会得到一个预测值,而损失函数就是反应预测值与真实值之间的差距,损失值越小,那么说明模型预测效果越好。
- 损失函数的作用:损失函数除了反应模型拟合数据的优劣,还经常用于指导神经网络的参数优化。在神经网络的训练过程,损失函数通过反向传播,梯度下降实现参数更新。
常用的损失函数
回归任务与分类任务的损失对比
| 对比维度 | 回归任务损失 | 分类任务损失 |
|---|---|---|
| 输出类型 | 连续值 | 离散类别(概率分布) |
| 计算方式 | 直接计算数值间的距离 | 计算概率分布的差异 |
| 典型函数 | MSE、MAE | 交叉熵、Hinge Loss |
- 总结
- 回归损失:衡量数值准确性,适用于连续值的预测。
- 分类损失:衡量概率匹配性,适用于离散标签预测。
回归任务常用的损失函数
1. MSE均方误差
-
**均方误差(MSE)**是回归任务中最常用的损失函数之一,用于衡量模型预测值与真实值之间的差异。它的核心思想是计算预测误差的平方均值,使较大的误差受到更严重的惩罚。
-
均方误差的数学定义如下:
- 是样本数量。
- 是第个真实值。
- 是第个预测值。
-
均方误差的特点
-
优点:
可导性:MSE 是光滑可导的函数,便于梯度下降优化。 对大误差敏感:平方操作使较大的误差被放大,促使模型更关注异常值。
-
缺点:
对异常值敏感:如果数据中存在离群点(Outliers),MSE 会变得很大,影响模型训练。
量纲问题:由于计算的是平方误差,MSE 的单位是原单位的平方(如预测房价时,单位是“元²”),解释性稍差。
-
-
均方误差的代码实现:
-
numpy实现:
import numpy as np def mean_squared_error(y_true, y_pred): return np.mean((y_true - y_pred) ** 2) # 示例 y_true = np.array([3, -0.5, 2, 7]) # 真实值 y_pred = np.array([2.5, 0.0, 2, 8]) # 预测值 mse = mean_squared_error(y_true, y_pred) print(f"MSE: {mse:.4f}") # 输出: MSE: 0.3750 -
pytorch实现:
import torch import torch.nn as nn # 定义 MSE 损失 mse_loss = nn.MSELoss() # 输入必须是张量(Tensor) y_true = torch.tensor([3.0, -0.5, 2.0, 7.0]) y_pred = torch.tensor([2.5, 0.0, 2.0, 8.0]) loss = mse_loss(y_pred, y_true) print(f"MSE: {loss.item():.4f}") # 输出: MSE: 0.3750
-
2. MAE平均绝对误差
-
平均绝对误差(MAE)是回归任务中常用的损失函数,用于衡量模型预测值与真实值之间的绝对差异的平均值。与均方误差(MSE)不同,MAE 对误差的惩罚是线性的,因此对异常值(Outliers)的敏感度较低。
-
平均绝对误差的数学定义如下:
其中:
- 是样本数量。
- 是第个真实值。
- 是第个预测值。
-
平均绝对误差的特点
-
优点: 对异常值鲁棒性强:由于采用绝对值而非平方,MAE 不会过度放大异常值的影响,适用于噪声较多的数据。
直观易解释:MAE 的单位与原始数据一致(如预测房价时,单位是“元”),便于业务理解。
梯度稳定:梯度始终为 ±1,优化过程更稳定(相比 MSE 的梯度随误差增大而增大)。
-
缺点
在优化中可能收敛较慢:由于梯度恒定,模型在接近最优解时可能调整较慢(MSE 的梯度会逐渐减小,收敛更快)。
不可导的点:在 yi=y^iy**i=y^i 处不可导(但实际优化中可通过次梯度方法处理)。
-
-
平均绝对误差的代码实现:
-
numpy实现:
import numpy as np def mean_absolute_error(y_true, y_pred): return np.mean(np.abs(y_true - y_pred)) # 示例 y_true = np.array([3, -0.5, 2, 7]) # 真实值 y_pred = np.array([2.5, 0.0, 2, 8]) # 预测值 mae = mean_absolute_error(y_true, y_pred) print(f"MAE: {mae:.4f}") # 输出: MAE: 0.5000 -
pytorch实现:
import numpy as np def mean_absolute_error(y_true, y_pred): return np.mean(np.abs(y_true - y_pred)) # 示例 y_true = np.array([3, -0.5, 2, 7]) # 真实值 y_pred = np.array([2.5, 0.0, 2, 8]) # 预测值 mae = mean_absolute_error(y_true, y_pred) print(f"MAE: {mae:.4f}") # 输出: MAE: 0.5000
-
3. 两种损失函数的对比
| 损失函数 | MAE | MSE |
|---|---|---|
| 误差惩罚方式 | 绝对值(线性) | 平方(非线性) |
| 对异常值敏感性 | 鲁棒(低敏感) | 敏感(放大异常值) |
| 梯度性质 | 恒定(±1) | 随误差增大而增大 |
| 适用场景 | 数据含噪声/异常值 | 需要强调大误差的任务 |
| 单位 | 与原数据一致(如“元”) | 原数据的平方(如“元²”) |
-
总结
-
选MAE
数据中存在异常值或者需要直观的误差解释。
-
选MSE
需要强调误差或者模型优化依赖于梯度下降。
-
分类任务常用的损失函数
Cross Entropy Loss交叉熵损失
-
交叉熵损失函数经常用于分类问题中,特别是在神经网络做分类问题时,也经常使用交叉熵作为损失函数,此外,由于交叉熵涉及到计算每个类别的概率,所以交叉熵几乎每次都和sigmoid(或softmax)函数一起出现。
-
交叉熵损失函数的数学定义如下:
-
二分类
在二分类情况中,模型预测的结果只有两种情况,所以预测为正类与负类的概率可以写为:。
此时损失函数可以写为:
其中:
- 是样本数量。
- 是样本的label,正类为1,负类为0。
- 是样本预测为正类的概率。
-
多分类
在多分类情况中,模型预测的结果有多种可能,此时每类的概率可以写为:。
此时损失函数可以写为:
其中:
- 是类别的数量。
- 是样本的真实类别等于取1,否则取0。
- 是观测样本属于类别的预测概率。
-
-
交叉熵损失的特点
-
优点
梯度优化友好
- 对数函数使梯度与误差成比例,避免 MSE 在饱和区的梯度消失问题(如 Sigmoid 输出接近 0/1 时)。
概率解释性强
- 直接优化预测概率与真实分布的匹配度,符合分类任务的评估目标。
对错误预测惩罚大
- 当预测概率 远离真实标签时,损失急剧增大(如真实 =1,预测 =0.1 时 L≈2.3)。
-
缺点
对噪声标签敏感
- 若真实标签错误(如错误标注),交叉熵会给出高惩罚,可能导致模型过拟合噪声。
需概率输入
- 预测值必须经过 Sigmoid(二分类)或 Softmax(多分类)压缩到 [0, 1]。
-
-
交叉熵的代码实现
-
二分类任务:(由于二分类问题和多分类问题在pytorch实现有差别,所以需要分开进行演示) 二分类使用BCELoss()Binary Cross-Entropy方法
import torch import torch.nn as nn # 定义 Sigmoid 激活和 BCELoss sigmoid = nn.Sigmoid() bce_loss = nn.BCELoss() # 模型的原始输出,未经过激活函数,值域为 (−∞,+∞)。 y_pred = torch.tensor([[1.2], [-0.5], [0.3]]) # 形状 [3, 1] # 真实标签(0 或 1) y_true = torch.tensor([[1.0], [0.0], [1.0]]) # 形状 [3, 1] # 将预测值通过 Sigmoid 压缩到 [0, 1] y_pred_sigmoid = sigmoid(y_pred) # 得到概率 # 计算损失 loss = bce_loss(y_pred_sigmoid, y_true) print("BCELoss:", loss.item()) -
多分类任务: 多分类任务使用CrossEntropyLoss()方法,理论上数据需要经过softmax,但该方法内部集成了softmax方法,所以无需显性使用softmax。
import torch import torch.nn as nn # 设置随机种子(保证可复现) torch.manual_seed(40) # 多分类任务:输入无需 Softmax loss_function = nn.CrossEntropyLoss() y_pred = torch.randn(3, 5) # 3个样本,5个类别(原始分数) y_true = torch.tensor([1, 0, 4]) # 真实类别索引 loss = loss_function(y_pred, y_true) print(loss)
-