- 人工智能
- 计算机视觉
- 预训练
【免费下载链接】PaddleSeg
Easy-to-use image segmentation library with awesome pre-trained model zoo, supporting wide-range of practical tasks in Semantic Segmentation, Interactive Segmentation, Panoptic Segmentation, Image Matting, 3D Segmentation, etc.
Dice Loss 是 PaddleSeg 官方提供的、广泛用于医学影像分割任务的损失函数之一,其核心思想是用 Dice 系数度量预测分割图与真实标注(GT)之间的集合相似度。本文基于 DiceLoss_en.md 文档,结合 dice_loss.py 源码实现与configs/_base_/下的真实配置,完整讲解 Dice Loss 的数学原理、API 参数、底层计算流程以及如何在 YAML 配置中启用它——读完后你可以直接在 UNet 等分割模型的训练配置中正确接入 DiceLoss,并理解ignore_index、smooth、weight三个参数各自的作用。
Dice 系数与 Dice Loss 的数学原理
Dice 系数(Dice coefficient)是一种用于度量两个集合之间相似程度的函数。在语义分割任务中,可以将它理解为"当前模型的预测结果与真实世界标注之间的相似程度"。
假设X表示预测分割图(predicted segmentation map),Y表示真实标注分割图(GT segmentation map),则 Dice 系数的定义为:
Dice = 2|X∩Y| / (|X|+|Y|)其中|X∩Y|是预测与标注逐位置相乘后求和得到的交集大小,|X|与|Y|分别是两个集合的基数(cardinality,即对应元素之和)。
Dice Loss 的完整计算过程包括三步:
- 用预测分割图与 GT 分割图之间进行逐位置点乘(dot multiplication),得到交集;
- 对点乘结果的每个位置进行累计求和(cumulative sum);
- 计算1 − Dice的值作为损失函数的输出,即:
Dice = 1 − 2(|X∩Y| / (|X|+|Y|))当预测与标注完全一致时,|X∩Y| = |X| = |Y|,Dice 系数为 1,损失为 0;预测与标注完全不重叠时,损失趋近于 1。因此 Dice Loss 直接优化的是"预测与真实之间的重叠度",这与医学影像中"小目标、前景占比极低"的分割场景高度契合——例如视网膜血管分割中血管像素只占图像的很小比例,此时基于像素级交叉熵的损失容易被背景主导,而 Dice Loss 天然对前景/背景不平衡不敏感。
拉普拉斯平滑(Laplacian smoothing)
你可以在分子分母上同时加上一个平滑系数smooth,从而:
- 避免除 0 异常:当
|X|+|Y| = 0(例如整个 batch 的预测与标注都为空)时,分母为 0,加平滑后不再触发除零错误; - 减少过拟合:设置较大的平滑值(即拉普拉斯平滑)可以防止损失在某些极端样本上剧烈波动。
平滑后的公式为:
Dice_smooth = 1 − 2((|X∩Y|+smooth) / (|X|+|Y|+smooth))API 签名与参数说明
PaddleSeg 中的 DiceLoss 定义在 paddleseg/models/losses/dice_loss.py,通过@manager.LOSSES.add_component注册进损失函数管理器,因此可以直接在 YAML 配置中用type: DiceLoss引用。
文档中给出的类签名如下:
class paddleseg.models.losses.DiceLoss( ignore_index = 255, smooth = 0. )而从当前仓库源码看,实际构造函数为(注意weight参数与smooth的默认值以源码为准):
class DiceLoss(nn.Layer): def __init__(self, weight=None, ignore_index=255, smooth=1.0): super().__init__() self.weight = weight self.ignore_index = ignore_index self.smooth = smooth self.eps = 1e-8参数详解
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ignore_index | int64, optional | 255 | 指定在标注图中要忽略的像素值,这些像素对输入梯度不产生贡献。当标注图中存在无法标注(或很难标注)的像素时,可将其标注为某个特定灰度值,计算损失时其与原图像对应位置的像素不作为损失函数的自变量 |
smooth | float, optional | 文档写作0,当前源码默认1.0 | 添加到分子分母的平滑系数,用于防止除 0 异常;设置更大的平滑值(拉普拉斯平滑)可避免过拟合 |
weight | list[float], optional | None | 每个类别的权重,用于类别不平衡场景;传入时其长度必须等于类别数num_class,否则源码会直接断言报错 |
源码级实现:DiceLoss 的完整前向计算流程
forward方法是理解 Dice Loss 内部行为的关键,其流程如下(见 dice_loss.py):
- 读取类别数:
num_class = logits.shape[1],即模型输出的通道数; - 校验权重:若指定了
weight,断言num_class == len(self.weight),否则抛出 "The lenght of weight should be euqal to the num class"; - 构造忽略掩码:
mask = labels != self.ignore_index,再将 mask 增加一个维度并转成 float32,之后用于把被忽略位置的值置 0; - one-hot 化标签:先把被忽略的标签临时赋值为 0(
labels[labels == self.ignore_index] = 0),再调用F.one_hot(labels, num_class)并转置为[N, C, H, W]形状; - Softmax 归一化预测:对
logits在通道维度执行F.softmax(logits, axis=1),得到逐类的概率图; - 逐类计算并加权平均:遍历每一个类别,调用
dice_loss_helper计算该类的 Dice 损失,若指定weight则乘以对应类别权重,最后把所有类的损失累加后除以类别数。
dice_loss_helper:核心公式的落地
辅助函数 dice_loss_helper 真正实现了平滑 Dice 公式:
logit = paddle.reshape(logit, [0, -1]) label = paddle.reshape(label, [0, -1]) mask = paddle.reshape(mask, [0, -1]) logit *= mask label *= mask intersection = paddle.sum(logit * label, axis=1) cardinality = paddle.sum(logit + label, axis=1) dice_loss = 1 - (2 * intersection + smooth) / (cardinality + smooth + eps) dice_loss = dice_loss.mean()关键点:
- 三个张量都 reshape 成
[batch, -1],把空间维度展平,从而把"逐位置点乘 + 累计求和"变成简单的矩阵乘法与sum; logit *= mask与label *= mask实现了ignore_index的"零贡献"语义——被忽略位置的预测与标签都被置 0,既不进入交集也不进入基数;- 公式
1 − (2 * intersection + smooth) / (cardinality + smooth + eps)与文档中的Dice_smooth = 1−2((|X∩Y|+smooth)/(|X|+|Y|+smooth))一一对应,其中eps = 1e-8是源码额外加上的极小量,进一步兜底除零; - 每个样本(batch 内的每一行)先各自计算 Dice 损失,最后取
.mean()得到该类的平均损失。
在 PaddleSeg 配置文件中使用 DiceLoss
PaddleSeg 采用"配置驱动"的训练方式,损失函数在 YAML 的loss字段中声明。以视网膜血管分割基准数据集 CHASE_DB1 的配置 configs/base/chase_db1.yml 为例:
loss: types: - type: DiceLoss coef: [1]同样的用法也出现在 configs/base/drive.yml、configs/base/hrf.yml 与 configs/base/stare.yml 中——这四个数据集全部是医学影像/眼底血管分割任务,正好印证了文档所述"Dice Loss 广泛用于医学影像分割"的定位。
完整的训练配置通过_base_继承机制组合。例如 UNet 在 CHASE_DB1 上的训练入口 configs/unet/unet_chasedb1_128x128_40k.yml:
_base_: '../_base_/chase_db1.yml' batch_size: 4 iters: 40000 model: type: UNet num_classes: 2 use_deconv: False pretrained: Null继承自 base 配置后,loss中的 DiceLoss 自动生效:模型输出 2 个类别(血管/背景),DiceLoss 遍历两个类别分别计算再取平均。
loss 配置的通用规则
根据 paddleseg/cvlibs/config.py 中的说明,loss配置支持多损失:
loss.types是一个损失对象列表,其顺序必须与模型输出的顺序一致;coef表示对应损失的权重系数,其数量必须与模型输出数量相同;- 若多个模型输出使用同一种损失类型,
types中可以只写一个损失类型,否则types的数量必须与coef一致。
训练时,paddleseg/core/train.py 中的check_logits_losses会强制校验"logits 数量 == 损失类型数量",不满足直接抛出RuntimeError;随后loss_computation按coef_i * loss_i(logits, labels)计算每一项损失并求和作为总损失。
ignore_index 的自动同步机制
还有一个值得注意的工程细节:ignore_index并不一定需要你在 YAML 中手写。根据 paddleseg/cvlibs/builder.py 的_build_loss逻辑:
- 当训练数据集类带有
IGNORE_INDEX属性时(PaddleSeg 内置数据集均有该属性),构建器会检查损失配置中的ignore_index是否与数据集一致; - 若损失配置里没写
ignore_index,构建器会自动补上数据集的IGNORE_INDEX并给出 warning 提示; - 若显式写了但与数据集不一致,则直接断言报错:"the ignore_index in loss and train_dataset must be the same"。
因此,使用内置数据集时通常无需在 DiceLoss 配置中重复指定ignore_index;使用自定义数据集时,则建议在配置中显式设置与标注一致的忽略值(默认255对应"无法标注/很难标注的像素")。
参数选择与使用建议
smooth:默认的1.0(当前源码默认值)即可稳定训练,同时避免除零;若追求与文档公式完全一致的"裸"形式可设为0,但强烈建议保留平滑值,它在空标注的 batch 中能防止梯度异常;ignore_index:医学影像标注中常存在边界模糊、难以标注的区域,将其标为255(或你自定义的灰度值)即可让这些像素不参与梯度计算,避免误导模型;weight:当数据集存在严重的类别不平衡(例如多类别医学分割中某些器官极小)时,可为每个类别设置权重,源码会逐类乘权重后取平均;注意权重列表长度必须严格等于num_class;- 适用场景:DiceLoss 对前景/背景不平衡不敏感,特别适合视网膜血管(CHASE_DB1/DRIVE/HRF/STARE)、器官、病灶等小目标分割;在类别极度不平衡且希望直接优化交并比类指标时,它通常比纯交叉熵收敛更快、指标更高。
小结
本文从 DiceLoss_en.md 出发,梳理了 Dice 系数到平滑 Dice Loss 的数学推导,并对照 dice_loss.py 源码逐行还原了forward与dice_loss_helper的实现细节,最后结合 configs/base/chase_db1.yml 等真实配置给出了可直接复用的接入方式。掌握 DiceLoss 的参数语义与底层计算,你就能够在医学影像分割、小目标分割等不平衡场景下快速搭建训练配置,并为后续尝试MixedLoss(如 DiceLoss 与交叉熵的组合)打下基础。
- 人工智能
- 计算机视觉
- 预训练
【免费下载链接】PaddleSeg
Easy-to-use image segmentation library with awesome pre-trained model zoo, supporting wide-range of practical tasks in Semantic Segmentation, Interactive Segmentation, Panoptic Segmentation, Image Matting, 3D Segmentation, etc.
相关推荐
医学影像分割终极指南:Keras中Tversky损失函数轴参数配置全解析
医学影像分割终极指南:Keras中Tversky损失函数轴参数配置全解析 在医学影像分割领域,Tversky损失函数已成为解决类别不平衡问题的关键工具。本文将深
人工智能深度学习机器学习预训练PaddleSeg 损失函数模块全解析:13 类核心损失函数的原理、参数与配置实战
PaddleSeg 损失函数模块全解析:13 类核心损失函数的原理、参数与配置实战 PaddleSeg 在 paddleseg.models.losses 子模
人工智能计算机视觉预训练PaddleSeg 中 L1Loss 损失函数详解:从数学原理到源码实现与训练配置
PaddleSeg 中 L1Loss 损失函数详解:从数学原理到源码实现与训练配置 L1Loss(L1 范数损失,又称最小绝对值偏差损失)是图像分割任务中最基础
人工智能计算机视觉预训练
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考