本文介绍了几种用于图像分割任务的损失函数,包括 Dice Loss、BCE-Dice Loss、IoU Loss 和 Focal Loss。以下是对每种损失函数的详细解释和代码实现。
1. Dice Loss
公式
Dice 系数(Dice Similarity Coefficient, DSC)定义为:
$$ DSC = \frac{2|X \cap Y|}{|X| + |Y|} $$
其中:
- $X$和 $Y$分别代表预测的分割区域和真实的分割区域。
- $|X \cap Y|$ 代表 $X$ 和 $Y$ 的交集(重叠部分)的像素数量。
- $|X|$ 和 $|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)] $$
其中:
- $y$ 是真实标签(0 或 1)。
- $p$ 是模型预测该像素为 1 的概率(取值范围为 0 到 1)。
总的 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 的特点
- 逐像素计算:BCE Loss 对每个像素的预测结果进行独立评估,适合需要精确像素级分类的任务。
- 对类别不平衡敏感:在类别不平衡的情况下(如背景像素远多于目标像素),BCE Loss 容易被大量简单的负样本主导,导致模型难以学习到正样本的特征。
- 与 Dice Loss 的比较:
- BCE Loss:关注每个像素的分类准确性,对像素级的错误敏感。
- Dice Loss:关注整体区域的重叠程度,对区域形状和大小更敏感,对类别不平衡问题鲁棒性更好。
- BCE Loss 是一种常用的损失函数,适合需要精确像素级分类的任务。
- 在类别不平衡的情况下,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|} $$
其中:
- $|X \cup Y|$代表 $X$ 和 $Y$ 的并集(所有包含在 $X$ 或 $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) $$
其中:
-
$p_t$ 是模型预测的概率:
- 对于正类 $y=1$, $p_t = p$
- 对于负类 $y=0$, $p_t = 1 - p$
-
$\alpha_t$ 是一个平衡因子,用于调整正负样本的权重:
- 对于正类 $y=1$, $\alpha_t = \alpha$
- 对于负类 $y=0$, $\alpha_t = 1-\alpha$
通过设置 α < 0.5,我们更大程度地降低了负类样本的损失贡献,相对地提高了正类样本的损失贡献(比如没有α 系数的时候,正负样本损失一样,如果α = 0.2,正样本的损失打2折,负样本的只打8折)。这样,模型就会更加关注数量较少的正类样本,从而更好地学习它们的特征。
Note
更直观的解释:
想象一下,你有一堆大小不一的石头,你需要把它们都搬到另一个地方。
- 正类样本:是一些比较小的石头,数量很少。
- 负类样本:是一些比较大的石头,数量很多。
如果你直接搬运,那么你大部分时间都在搬运大石头(负类样本),而忽略了小石头(正类样本)。
现在,你使用一个“权重因子”来调整每块石头的“搬运难度”。
对于小石头(正类样本),你设置的权重因子是 0.25,这意味着搬运它们的难度大大降低了(损失缩小了更多)。
对于大石头(负类样本),你设置的权重因子是 0.75,这意味着搬运它们的难度只是略微降低(损失缩小得较少)。
这样,你就会花更多的时间和精力去搬运那些原本“搬运难度”较高的小石头(正类样本),从而更好地完成任务。
-
$\gamma$ 是一个聚焦参数,用于调整难易样本的权重。
-
对于难分类样本, $p_t$较小, $(1-p_t)^\gamma$ 接近 1,损失基本不受影响。
-
对于易分类样本, $p_t$ 较大, $(1-p_t)^\gamma$ 接近 0,损失被大幅度降低。
-
-
$BCE = -[y \log(p) + (1 - y) \log(1 - p)] = -\log(p_t)$
代码实现
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 和 IoU Loss 在分割任务中表现良好,尤其适合处理类别不平衡问题。
- BCE-Dice Loss 结合了 BCE 和 Dice Loss 的优点,适用于需要同时关注像素级和区域级分割的任务。
- Focal Loss 主要用于解决类别不平衡问题,适用于正负样本比例悬殊的场景。
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
- 交集 $|X \cap Y| = 19$(预测区域与真实区域重叠的像素数)
- $|X| = 19$(预测区域的像素数)
- $|Y| = 20$(真实区域的像素数)
- Dice 系数:
$$ DSC = \frac{2 \times |X \cap Y|}{|X| + |Y|} = \frac{2 \times 19}{19 + 20} = \frac{38}{39} \approx 0.97 $$
- Dice Loss:
$$ \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
- 交集 $|X \cap Y| = 5$(预测区域与真实区域重叠的像素数)
- $|X| = 7$(预测区域的像素数)
- $|Y| = 20$(真实区域的像素数)
- Dice 系数:
$$ DSC = \frac{2 \times |X \cap Y|}{|X| + |Y|} = \frac{2 \times 5}{7 + 20} = \frac{10}{27} \approx 0.37 $$
- Dice Loss:
$$ \text{Dice Loss} = 1 - DSC = 1 - 0.37 = 0.63 $$
结论
- 预测 1 的 Dice 系数更高(0.97),Dice Loss 更低(0.03),表明预测更接近真实情况。
- 预测 2 的 Dice 系数较低(0.37),Dice Loss 较高(0.63),表明预测与真实情况差距较大。
IoU Loss 的直观理解
场景
继续使用修正后的肺部区域(20 个像素)。
预测 1 (较好)
- 交集 $|X \cap Y| = 19$
- 并集 $|X \cup Y| = |X| + |Y| - |X \cap Y| = 19 + 20 - 19 = 20$
- IoU:
$$ IoU = \frac{|X \cap Y|}{|X \cup Y|} = \frac{19}{20} = 0.95 $$
- IoU Loss:
$$ \text{IoU Loss} = 1 - IoU = 1 - 0.95 = 0.05 $$
预测 2 (较差)
- 交集 $|X \cap Y| = 5$
- 并集 $|X \cup Y| = |X| + |Y| - |X \cap Y| = 7 + 20 - 5 = 22$
- IoU:
$$ IoU = \frac{|X \cap Y|}{|X \cup Y|} = \frac{5}{22} \approx 0.23 $$
- IoU Loss:
$$ \text{IoU Loss} = 1 - IoU = 1 - 0.23 = 0.77 $$
结论
- 预测 1 的 IoU 更高(0.95),IoU Loss 更低(0.05),表明预测更接近真实情况。
- 预测 2 的 IoU 较低(0.23),IoU Loss 较高(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
- 对于正类(肺部区域),预测概率较高(如 0.9、0.8)。
- 对于负类(背景区域),预测概率较低(如 0.1)。
逐像素计算损失
我们选取几个有代表性的像素来说明 BCE Loss 的计算过程。
-
正类像素$y = 1$:
- 真实标签:$y = 1$
- 预测概率:$p = 0.9$
- 损失:
$$ L(1, 0.9) = -[1 \cdot \log(0.9) + 0 \cdot \log(0.1)] \approx 0.105 $$
-
负类像素$y = 0$:
- 真实标签:$y = 0$
- 预测概率:$p = 0.1$
- 损失:
$$ L(0, 0.1) = -[0 \cdot \log(0.1) + 1 \cdot \log(0.9)] \approx 0.105 $$
-
错误预测的像素:
- 真实标签:$y = 0$
- 预测概率:$p = 0.8$
- 损失:
$$ L(0, 0.8) = -[0 \cdot \log(0.8) + 1 \cdot \log(0.2)] \approx 1.609 $$
总 BCE Loss
假设所有像素的损失计算如下:
- 正类像素(3 个):每个损失约为 0.105。
- 负类像素(97 个):每个损失约为 0.105。
- 错误预测的像素(假设有 5 个):每个损失约为 1.609。
则总 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
- 对于正类(肺部区域),预测概率较高(如 0.9、0.8)。
- 对于负类(背景区域),预测概率较低(如 0.1)。
Focal Loss 的公式:
$$ FL(p_t) = \alpha_t (1 - p_t)^\gamma \cdot \text{BCE} $$
示例计算
1. 正类样本$y = 1$
-
预测概率:$p = 0.9$
-
BCE Loss:
$$ \text{BCE} = -\log(0.9) \approx 0.105 $$
- $p_t$:
$$ p_t = \exp(-0.105) \approx 0.9 $$
- Focal Loss:
$$ FL = 0.5 \times (1 - 0.9)^2 \times 0.105 \approx 0.00053 $$
2. 负类样本$y = 0$
-
预测概率:$p = 0.1$
-
BCE Loss:
$$ \text{BCE} = -\log(1 - 0.1) \approx 0.105 $$
- $p_t$:
$$ p_t = \exp(-0.105) \approx 0.9 $$
- Focal Loss:
$$ FL = 0.5 \times (1 - 0.9)^2 \times 0.105 \approx 0.00053 $$
3. 难分类的正样本$y = 1$
-
预测概率:$p = 0.6$
-
BCE Loss:
$$ \text{BCE} = -\log(0.6) \approx 0.511 $$
- $p_t$:
$$ p_t = \exp(-0.511) \approx 0.6 $$
- Focal Loss:
$$ FL = 0.5 \times (1 - 0.6)^2 \times 0.511 \approx 0.041 $$
4. 难分类的负样本$y = 0$
-
预测概率:$p = 0.4$
-
BCE Loss:
$$ \text{BCE} = -\log(1 - 0.4) \approx 0.511 $$
- $p_t$:
$$ p_t = \exp(-0.511) \approx 0.6 $$
- Focal Loss:
$$ 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 |
结论
- Focal Loss 通过 $(1 - p_t)^\gamma$ 项显著降低了易分类样本的损失贡献(如易分类的正样本从 0.105 降到 0.00053)。
- Focal Loss 对难分类样本的损失贡献也有所降低,但降低的幅度相对较小(如难分类的正样本从 0.511 降到 0.041)。
- Focal Loss 通过$\alpha_t$ 动态调整正负样本的权重,解决了类别不平衡问题。