损失函数详解#
目录#
损失函数概述#
什么是损失函数?#
损失函数(Loss Function) 衡量模型预测值与真实值之间的差异。
作用#
- 指导训练:告诉模型如何调整参数
- 评估性能:衡量模型好坏
- 优化目标:最小化损失函数
基本要求#
- 可微:便于梯度下降
- 非负:损失应该 ≥ 0
- 单调性:预测越准确,损失越小
回归损失函数#
1. 均方误差(MSE)#
公式#
$$ \text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 $$特点#
- 对大误差敏感:平方项放大误差
- 可微:梯度连续
- 应用:回归问题
梯度#
$$ \frac{\partial \text{MSE}}{\partial \hat{y}} = -2(y - \hat{y}) $$2. 平均绝对误差(MAE)#
公式#
$$ \text{MAE} = \frac{1}{n} \sum_{i=1}^{n} |y_i - \hat{y}_i| $$特点#
- 对异常值鲁棒:线性惩罚
- 不可微:在0点不可微(需次梯度)
- 应用:需要鲁棒性的回归
3. Huber损失#
结合MSE和MAE的优点:
$$ L_\delta(y, \hat{y}) = \begin{cases} 0.5(y - \hat{y})^2 & \text{if } |y - \hat{y}| \leq \delta \\ \delta|y - \hat{y}| - 0.5\delta^2 & \text{if } |y - \hat{y}| > \delta \end{cases} $$特点:
- 小误差时类似MSE
- 大误差时类似MAE
- 对异常值鲁棒
4. 平滑L1损失#
$$ \text{SmoothL1} = \begin{cases} 0.5x^2 & \text{if } |x| < 1 \\ |x| - 0.5 & \text{if } |x| \geq 1 \end{cases} $$其中 $x = y - \hat{y}$ 。
分类损失函数#
1. 交叉熵损失(Cross-Entropy)#
二分类#
$$ \text{BCE} = -(y \cdot \log(\hat{y}) + (1-y) \cdot \log(1-\hat{y})) $$其中 $y \in \{0, 1\}$ ,$\hat{y} \in [0, 1]$ 。
多分类#
$$ \text{CE} = -\sum_{i} y_i \cdot \log(\hat{y}_i) $$其中 $y$ 是One-Hot编码,$\hat{y}$ 是Softmax输出。
特点#
- 概率解释:适合分类问题
- 梯度友好:梯度形式简单
- 最常用:分类任务的标准选择
2. Focal Loss#
解决类别不平衡问题:
$$ \text{FL} = -\alpha(1-\hat{y})^\gamma \cdot \log(\hat{y}) $$其中:
- $\alpha$ :平衡因子
- $\gamma$ :聚焦参数(通常2)
特点:
- 降低易分类样本的权重
- 关注难分类样本
- 适合目标检测等任务
3. 标签平滑(Label Smoothing)#
将硬标签转换为软标签:
$$ y_{\text{smooth}} = (1-\varepsilon) \cdot y + \frac{\varepsilon}{K} $$其中 $K$ 是类别数,$\varepsilon$ 是平滑系数(通常0.1)。
效果:
- 防止过拟合
- 提高泛化能力
其他损失函数#
1. 对比损失(Contrastive Loss)#
用于学习相似性:
$$ L = (1-y) \cdot d^2 + y \cdot \max(0, \text{margin} - d)^2 $$其中 $d$ 是距离,$y$ 是相似性标签。
2. Triplet Loss#
学习相对距离:
$$ L = \max(0, d(a, p) - d(a, n) + \text{margin}) $$其中:
- $a$ :锚点
- $p$ :正样本
- $n$ :负样本
3. Dice Loss#
用于分割任务:
$$ \text{Dice} = \frac{2|X \cap Y|}{|X| + |Y|} $$ $$ \text{Dice Loss} = 1 - \text{Dice} $$4. IoU Loss#
目标检测和分割:
$$ \text{IoU} = \frac{|X \cap Y|}{|X \cup Y|} $$ $$ \text{IoU Loss} = 1 - \text{IoU} $$损失函数选择#
回归任务#
| 任务 | 推荐损失函数 |
|---|---|
| 一般回归 | MSE |
| 异常值多 | MAE, Huber |
| 需要鲁棒性 | Smooth L1 |
分类任务#
| 任务 | 推荐损失函数 |
|---|---|
| 二分类 | BCE |
| 多分类 | Cross-Entropy |
| 类别不平衡 | Focal Loss, Weighted CE |
| 需要正则化 | Label Smoothing |
其他任务#
| 任务 | 推荐损失函数 |
|---|---|
| 目标检测 | Focal Loss, IoU Loss |
| 语义分割 | Dice Loss, Cross-Entropy |
| 相似性学习 | Contrastive Loss, Triplet Loss |
代码实现#
PyTorch实现#
import torch
import torch.nn as nn
import torch.nn.functional as F
# MSE损失
mse_loss = nn.MSELoss()
loss = mse_loss(pred, target)
# MAE损失
mae_loss = nn.L1Loss()
loss = mse_loss(pred, target)
# 交叉熵损失
ce_loss = nn.CrossEntropyLoss()
loss = ce_loss(logits, target) # logits未经过Softmax
# 二分类交叉熵
bce_loss = nn.BCELoss()
loss = bce_loss(probs, target) # probs经过Sigmoid
# BCE with Logits(数值稳定)
bce_logits_loss = nn.BCEWithLogitsLoss()
loss = bce_logits_loss(logits, target)
# Smooth L1
smooth_l1_loss = nn.SmoothL1Loss()
loss = smooth_l1_loss(pred, target)自定义损失函数#
Focal Loss#
class FocalLoss(nn.Module):
def __init__(self, alpha=1, gamma=2):
super(FocalLoss, self).__init__()
self.alpha = alpha
self.gamma = gamma
def forward(self, inputs, targets):
ce_loss = F.cross_entropy(inputs, targets, reduction='none')
pt = torch.exp(-ce_loss)
focal_loss = self.alpha * (1 - pt) ** self.gamma * ce_loss
return focal_loss.mean()Dice Loss#
class DiceLoss(nn.Module):
def __init__(self):
super(DiceLoss, self).__init__()
def forward(self, inputs, targets, smooth=1):
inputs = F.softmax(inputs, dim=1)
inputs_flat = inputs.view(-1)
targets_flat = targets.view(-1)
intersection = (inputs_flat * targets_flat).sum()
dice = (2. * intersection + smooth) / (inputs_flat.sum() + targets_flat.sum() + smooth)
return 1 - dice组合损失#
class CombinedLoss(nn.Module):
def __init__(self, alpha=0.5):
super(CombinedLoss, self).__init__()
self.alpha = alpha
self.ce_loss = nn.CrossEntropyLoss()
self.dice_loss = DiceLoss()
def forward(self, inputs, targets):
ce = self.ce_loss(inputs, targets)
dice = self.dice_loss(inputs, targets)
return self.alpha * ce + (1 - self.alpha) * dice加权损失#
# 类别权重
class_weights = torch.tensor([1.0, 2.0, 3.0]) # 不同类别权重
weighted_ce = nn.CrossEntropyLoss(weight=class_weights)
loss = weighted_ce(logits, targets)标签平滑#
class LabelSmoothingCrossEntropy(nn.Module):
def __init__(self, smoothing=0.1):
super().__init__()
self.smoothing = smoothing
def forward(self, pred, target):
log_prob = F.log_softmax(pred, dim=-1)
nll_loss = -log_prob.gather(dim=-1, index=target.unsqueeze(dim=-1)).squeeze(dim=-1)
smooth_loss = -log_prob.mean(dim=-1)
loss = (1.0 - self.smoothing) * nll_loss + self.smoothing * smooth_loss
return loss.mean()总结#
- MSE:回归任务最常用
- 交叉熵:分类任务标准选择
- Focal Loss:解决类别不平衡
- Dice/IoU Loss:分割和检测任务
- 选择原则:根据任务特点选择
关键要点:
- 损失函数指导模型学习方向
- 回归用MSE,分类用交叉熵
- 特殊任务需要特殊损失函数
- 可以组合多个损失函数