本文介绍了几种用于图像分割任务的损失函数,包括 Dice LossBCE-Dice LossIoU LossFocal Loss。以下是对每种损失函数的详细解释和代码实现。

1. Dice Loss

公式

Dice 系数(Dice Similarity Coefficient, DSC)定义为:

$$ DSC = \frac{2|X \cap Y|}{|X| + |Y|} $$

其中:

Dice Loss 的目标是最大化 DSC,因此损失函数定义为:

$$ \text{Dice Loss} = 1 - DSC $$

代码实现

import torch
import torch.nn.functional as F

def dice_loss(inputs, targets, smooth=1):
    inputs = F.sigmoid(inputs)  # 对输入进行 sigmoid 激活,将其值压缩到 0 到 1 之间
    inputs = inputs.view(-1)    # 将输入展平成一维向量
    targets = targets.view(-1)  # 将目标展平成一维向量
    
    intersection = (inputs * targets).sum()  # 计算交集
    dice = (2. * intersection + smooth) / (inputs.sum() + targets.sum() + smooth)  # smooth 是一个平滑项,防止分母为 0。
    return 1 - dice  # 返回 Dice Loss

2. Binary Cross Entropy Loss, BCE

公式

二元交叉熵损失用于衡量模型预测的概率分布与真实分布之间的差异。对于每个像素,BCE Loss 的公式为:

$$ L(y, p) = -[y \log(p) + (1 - y) \log(1 - p)] $$

其中:

总的 BCE Loss 是所有像素的平均损失:

$$ \text{BCE Loss} = \frac{1}{N} \sum_{i=1}^N L(y_i, p_i) $$

其中 $N$ 是像素总数。

代码实现

import torch
import torch.nn.functional as F

def bce_loss(inputs, targets):
    # 对输入进行 sigmoid 激活,将其值压缩到 0 到 1 之间
    inputs = torch.sigmoid(inputs)
    
    # 计算 BCE Loss
    BCE = F.binary_cross_entropy(inputs, targets, reduction='mean')
    return BCE

BCE Loss 的特点

  1. 逐像素计算:BCE Loss 对每个像素的预测结果进行独立评估,适合需要精确像素级分类的任务。
  2. 对类别不平衡敏感:在类别不平衡的情况下(如背景像素远多于目标像素),BCE Loss 容易被大量简单的负样本主导,导致模型难以学习到正样本的特征。
  3. 与 Dice Loss 的比较
    • BCE Loss:关注每个像素的分类准确性,对像素级的错误敏感。
    • Dice Loss:关注整体区域的重叠程度,对区域形状和大小更敏感,对类别不平衡问题鲁棒性更好。
  4. BCE Loss 是一种常用的损失函数,适合需要精确像素级分类的任务。
  5. 在类别不平衡的情况下,BCE Loss 可能表现不佳,此时可以结合 Dice Loss 或使用 Focal Loss 来改进模型性能。

3. BCE-Dice Loss

概念

BCE-Dice Loss 是二元交叉熵损失(Binary Cross Entropy Loss, BCE)和 Dice Loss 的结合。BCE Loss 对每个像素进行独立评估,而 Dice Loss 关注整体的区域重叠。结合两者可以提高分割效果。

代码实现

def bce_dice_loss(inputs, targets, smooth=1):
    # 计算 Dice Loss
    dice = dice_loss(inputs, targets, smooth)
    
    # 计算 BCE Loss
    BCE = F.binary_cross_entropy(F.sigmoid(inputs), targets, reduction='mean')
    
    # 结合 BCE 和 Dice Loss
    Dice_BCE = BCE + dice
    return Dice_BCE

4. IoU Loss (Intersection over Union Loss)

公式

IoU(Intersection over Union)定义为:

$$ IoU = \frac{|X \cap Y|}{|X \cup Y|} $$

其中:

IoU Loss 的目标是最大化 IoU,因此损失函数定义为:

$$ \text{IoU Loss} = 1 - IoU $$

代码实现

def iou_loss(inputs, targets, smooth=1):
    inputs = F.sigmoid(inputs)
    inputs = inputs.view(-1)
    targets = targets.view(-1)
    
    intersection = (inputs * targets).sum()  # 计算交集
    total = (inputs + targets).sum()         # 计算预测和目标的像素总和
    union = total - intersection             # 计算并集
    
    IoU = (intersection + smooth) / (union + smooth)  # 计算 IoU
    return 1 - IoU  # 返回 IoU Loss

5. Focal Loss

概念

Focal Loss 主要用于解决类别不平衡问题。它通过调整损失函数,使模型更关注难以分类的样本,减少易分类样本的贡献。Focal Loss 是对标准二元交叉熵损失 (BCE Loss) 的改进,旨在解决类别不平衡问题。类别不平衡的场景,假设负类样本数量远多于正类样本。即使单个负类样本的损失较小,但由于数量众多,它们累积起来的总损失仍然可能 dominant 训练过程,导致模型偏向于预测负类。

公式

Focal Loss 的公式为:

$$ \text{Focal Loss} = -\alpha_t (1 - p_t)^\gamma \log(p_t) $$

其中:

Note

更直观的解释:
想象一下,你有一堆大小不一的石头,你需要把它们都搬到另一个地方。

  • 正类样本:是一些比较小的石头,数量很少。
  • 负类样本:是一些比较大的石头,数量很多。

如果你直接搬运,那么你大部分时间都在搬运大石头(负类样本),而忽略了小石头(正类样本)。
现在,你使用一个“权重因子”来调整每块石头的“搬运难度”。

对于小石头(正类样本),你设置的权重因子是 0.25,这意味着搬运它们的难度大大降低了(损失缩小了更多)。
对于大石头(负类样本),你设置的权重因子是 0.75,这意味着搬运它们的难度只是略微降低(损失缩小得较少)。
这样,你就会花更多的时间和精力去搬运那些原本“搬运难度”较高的小石头(正类样本),从而更好地完成任务。

代码实现

def focal_loss(inputs, targets, alpha=0.25, gamma=2):
   # 计算 BCE Loss
    BCE = F.binary_cross_entropy_with_logits(inputs, targets, reduction='none')
    
    # 计算 p_t
    p_t = torch.exp(-BCE)
    
    # 根据 targets 动态调整 alpha_t
    alpha_t = torch.where(targets == 1, alpha, 1 - alpha)
    
    # 计算 Focal Loss
    focal_loss = alpha_t * (1 - p_t)**gamma * BCE
    
    # 返回均值
    return focal_loss.mean()

总结

这些损失函数都是为了衡量模型预测的分割结果与真实结果之间的差异。选择哪种损失函数取决于具体的任务和数据集:


Dice Loss 的直观理解

场景

假设我们要从 X 光片中分割出肺部区域。简化模型为一个 10x10 的网格,每个格子代表一个像素。

真实情况 (Ground Truth)

0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

真实的肺部区域共有 20 个像素(5 行 x 4 列)。

预测 1 (较好)

0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 0 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

$$ DSC = \frac{2 \times |X \cap Y|}{|X| + |Y|} = \frac{2 \times 19}{19 + 20} = \frac{38}{39} \approx 0.97 $$

$$ \text{Dice Loss} = 1 - DSC = 1 - 0.97 = 0.03 $$

预测 2 (较差)

0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 1 1 0 0 0 0 0
0 0 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

$$ DSC = \frac{2 \times |X \cap Y|}{|X| + |Y|} = \frac{2 \times 5}{7 + 20} = \frac{10}{27} \approx 0.37 $$

$$ \text{Dice Loss} = 1 - DSC = 1 - 0.37 = 0.63 $$

结论


IoU Loss 的直观理解

场景

继续使用修正后的肺部区域(20 个像素)。

预测 1 (较好)

$$ IoU = \frac{|X \cap Y|}{|X \cup Y|} = \frac{19}{20} = 0.95 $$

$$ \text{IoU Loss} = 1 - IoU = 1 - 0.95 = 0.05 $$

预测 2 (较差)

$$ IoU = \frac{|X \cap Y|}{|X \cup Y|} = \frac{5}{22} \approx 0.23 $$

$$ \text{IoU Loss} = 1 - IoU = 1 - 0.23 = 0.77 $$

结论


BCE Loss 的直观理解

场景

继续使用肺部 X 光片分割的例子,假设肺部区域只占图像的一小部分,背景占绝大多数。

真实情况 (Ground Truth)

0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

只有 3 个像素是肺部区域(1),其余 97 个像素是背景(0)。

预测概率

假设模型的输出经过 Sigmoid 激活后,得到以下预测概率:

0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.9 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.8 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.9 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1

逐像素计算损失

我们选取几个有代表性的像素来说明 BCE Loss 的计算过程。

  1. 正类像素$y = 1$
    • 真实标签:$y = 1$
    • 预测概率:$p = 0.9$
    • 损失:

$$ L(1, 0.9) = -[1 \cdot \log(0.9) + 0 \cdot \log(0.1)] \approx 0.105 $$

  1. 负类像素$y = 0$
    • 真实标签:$y = 0$
    • 预测概率:$p = 0.1$
    • 损失:

$$ L(0, 0.1) = -[0 \cdot \log(0.1) + 1 \cdot \log(0.9)] \approx 0.105 $$

  1. 错误预测的像素
    • 真实标签:$y = 0$
    • 预测概率:$p = 0.8$
    • 损失:

$$ L(0, 0.8) = -[0 \cdot \log(0.8) + 1 \cdot \log(0.2)] \approx 1.609 $$

总 BCE Loss

假设所有像素的损失计算如下:

则总 BCE Loss 为:

$$ \text{BCE Loss} = \frac{3 \times 0.105 + 97 \times 0.105 + 5 \times 1.609}{100} \approx 0.186 $$


Focal Loss 的直观理解

场景

我们继续用之前的肺部X光片分割例子,来解释Focal Loss。不过,要完全体现Focal Loss的优势,需要考虑类别不平衡的情况。在之前的例子中,我们假设肺部区域占了图像的相当一部分。现在,我们假设肺部区域只占图像的一小部分,这样背景(非肺部区域)就占了绝大多数,这就构成了类别不平衡。

我们可以重新使用肺部检测的例子,结合 Focal Loss 的更新公式,并固定 $\alpha = 0.5$,以便更清晰地观察 $(1 - p_t)^\gamma$ 的效果。让我们重新梳理并计算。


场景回顾

真实情况 (Ground Truth)

假设我们有一个 10x10 的网格,肺部区域用 1 表示,背景用 0 表示:

0 0 0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 1 1 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0

真实的肺部区域共有 20 个像素(5 行 x 4 列)。

预测概率

假设模型的输出经过 Sigmoid 激活后,得到以下预测概率:

0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.9 0.8 0.7 0.6 0.1 0.1 0.1 0.1
0.1 0.1 0.8 0.9 0.8 0.7 0.1 0.1 0.1 0.1
0.1 0.1 0.7 0.8 0.9 0.8 0.1 0.1 0.1 0.1
0.1 0.1 0.6 0.7 0.8 0.9 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1

Focal Loss 的公式:

$$ FL(p_t) = \alpha_t (1 - p_t)^\gamma \cdot \text{BCE} $$

示例计算

1. 正类样本$y = 1$

$$ \text{BCE} = -\log(0.9) \approx 0.105 $$

$$ p_t = \exp(-0.105) \approx 0.9 $$

$$ FL = 0.5 \times (1 - 0.9)^2 \times 0.105 \approx 0.00053 $$

2. 负类样本$y = 0$

$$ \text{BCE} = -\log(1 - 0.1) \approx 0.105 $$

$$ p_t = \exp(-0.105) \approx 0.9 $$

$$ FL = 0.5 \times (1 - 0.9)^2 \times 0.105 \approx 0.00053 $$

3. 难分类的正样本$y = 1$

$$ \text{BCE} = -\log(0.6) \approx 0.511 $$

$$ p_t = \exp(-0.511) \approx 0.6 $$

$$ FL = 0.5 \times (1 - 0.6)^2 \times 0.511 \approx 0.041 $$

4. 难分类的负样本$y = 0$

$$ \text{BCE} = -\log(1 - 0.4) \approx 0.511 $$

$$ p_t = \exp(-0.511) \approx 0.6 $$

$$ FL = 0.5 \times (1 - 0.6)^2 \times 0.511 \approx 0.041 $$

对比结果

样本类型 $alpha_t$ BCE Loss Focal Loss
正类(易分类) 0.5 0.105 0.00053
负类(易分类) 0.5 0.105 0.00053
正类(难分类) 0.5 0.511 0.041
负类(难分类) 0.5 0.511 0.041

结论