损失函数详解#

目录#

  1. 损失函数概述
  2. 回归损失函数
  3. 分类损失函数
  4. 其他损失函数
  5. 损失函数选择
  6. 代码实现

损失函数概述#

什么是损失函数?#

损失函数(Loss Function) 衡量模型预测值与真实值之间的差异。

作用#

  1. 指导训练:告诉模型如何调整参数
  2. 评估性能:衡量模型好坏
  3. 优化目标:最小化损失函数

基本要求#

  • 可微:便于梯度下降
  • 非负:损失应该 ≥ 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()

总结#

  1. MSE:回归任务最常用
  2. 交叉熵:分类任务标准选择
  3. Focal Loss:解决类别不平衡
  4. Dice/IoU Loss:分割和检测任务
  5. 选择原则:根据任务特点选择

关键要点

  • 损失函数指导模型学习方向
  • 回归用MSE,分类用交叉熵
  • 特殊任务需要特殊损失函数
  • 可以组合多个损失函数