超越YOLOv7 | YOLOv6论文

各种Tricks大放异彩!!

论文: https://arxiv.org/abs/2209.02976

github:https://github.com/meituan/YOLOv6

多年来,YOLO 系列一直是高效目标检测的行业标准。YOLO 社区蓬勃发展,丰富了其在众多硬件平台和丰富场景中的使用。在这份技术报告力求将其极限推向新的高度,以坚定不移的行业应用心态向前迈进。

考虑到真实环境中对速度和准确性的不同要求,作者广泛研究了来自工业界或学术界的最新目标检测进展。具体来说,从最近的网络设计、训练策略、测试技术、量化和优化方法中大量吸收了一些想法。最重要的是,整合思想和实践,构建了一套不同规模的部署网络,以适应多样化的用例。

在 YOLO 作者的慷慨许可下,作者将其命名为 YOLOv6。作者也热烈欢迎用户和贡献者进一步增强。YOLOv6-N 在 NVIDIA Tesla T4 GPU 上以 1234 FPS 的吞吐量在 COCO 数据集上达到 35.9% 的 AP。YOLOv6-S 以 495 FPS 的速度达到 43.5% 的 AP,优于同规模的其他主流检测器(YOLOv5-SYOLOX-S 和 PPYOLOE-S)。

YOLOv6-S 量化版本甚至带来了 869 FPS 的最新 43.3% AP。此外,与具有相似推理速度的其他检测器相比,YOLOv6-M/L 还实现了更好的准确度性能(即 49.5%/52.3%)。

1、简介

YOLO 系列因其在速度和准确性之间的出色平衡而成为工业应用中最流行的检测框架。YOLO 系列的开创性作品是YOLOv1-3,随着后期的实质性改进,开创了单阶段检测器的新路。YOLOv4 将检测框架重组为几个独立的部分(backboneneck 和 head),并验证了当时的 bag-of-freebies 和 bag-of-specials,设计了一个适合在单 GPU 上训练的框架。目前,YOLOv5YOLOXPPYOLOE 和 YOLOv7 都是高效检测器部署的竞争候选者。不同大小的模型通常通过缩放技术获得。

在本报告中,作者凭经验观察了几个促使更新 YOLO 框架的重要因素:

  1. RepVGG 的重参化是一种高级技术,尚未在检测中得到很好的利用。作者还注意到 RepVGG Block 的简单模型缩放变得不切实际,为此作者认为小型和大型网络之间的网络设计的优雅一致性是不必要的。普通的单路径架构对于小型网络是更好的选择,但对于较大的模型,参数的指数增长和单路径架构的计算成本使其不可行;
  2. 基于重参化的检测器的量化也需要细致处理,否则由于其在训练和推理过程中的异构配置,将难以处理性能下降。
  3. 以前的工作往往不太关注部署,其延迟通常在 V100 等高成本机器上进行比较。在实际服务环境方面存在硬件差距。通常,像 Tesla T4 这样的低功耗 GPU 成本更低,并且提供相当好的推理性能。
  4. 考虑到架构差异,标签分配和损失函数设计等高级特定领域策略需要进一步验证;
  5. 对于部署,可以容忍训练策略的调整,提高准确度性能但不增加推理成本,例如知识蒸馏。

考虑到上述观察,带来了 YOLOv6 的诞生,它在准确性和速度方面实现了迄今为止最好的权衡。在图 1 中展示了 YOLOv6 与其他类似规模的同行的比较。为了在不大幅降低性能的情况下提高推理速度,研究了包括训练后量化 (PTQ) 和量化感知训练 (QAT) 在内的尖端量化方法,并将它们纳入 YOLOv6 以实现部署就绪网络的目标。

将 YOLOv6 的主要方面总结如下:

  • 针对不同场景中的工业应用重新设计了一系列不同规模的网络。不同规模的架构各不相同,以实现最佳的速度和准确性权衡,其中小型模型具有简单的单路径主干,大型模型建立在高效的多分支块上。
  • 为 YOLOv6 注入了一种self-distillation策略,在分类任务和回归任务上都执行。同时,动态调整来自教师和标签的知识,以帮助学生模型在所有训练阶段更有效地学习知识。
  • 广泛验证标签分配、损失函数和数据增强技术的先进检测技术,并有选择地采用它们以进一步提高性能。
  • 在 RepOptimizer 和通道蒸馏的帮助下改进了检测的量化方案,这带来了具有 43.3% 的 COCO AP 和 869 FPS 的吞吐量的快速准确的检测器,批量大小为 32。

2、YOLOv6方法全解

YOLOv6 的改造设计包括以下组件,网络设计、标签分配、损失函数、数据增强、行业便利改进以及量化和部署:

网络设计:

  • Backbone:与其他主流架构相比, RepVGG 主干在相似的推理速度下在小型网络中具有更强的特征表示能力,但由于参数和计算成本的爆炸式增长,它很难扩展以获得更大的模型。在这方面,将 RepBlock 作为小型网络的构建块。对于大型模型,修改了一个更高效的 CSP Block,名为 CSPStackRep 块。
  • Neck:YOLOv6 的 Neck 采用 YOLOv4 和 YOLOv5 之后的 PAN。使用 RepBlocks 或 CSPStackRep Blocks 增强 Neck 以获得 Rep-PAN
  • Head:简化了 Decoupled Head,使其更高效,称为Efficient Decoupled Head

标签分配:

通过大量实验评估了 YOLOv6 上标签分配策略的最新进展,结果表明 TAL 更有效且对训练更友好。

损失函数:

主流的Anchor-Free检测器的损失函数包括分类损失、框回归损失和目标损失。对于每个损失,用所有可用的技术系统地对其进行试验,最后选择 VariFocal Loss 分类损失,SIoU/GIoU 损失作为回归损失。

行业便利的改进:

引入了额外的常见实践和技巧来提高性能,包括self-distillation和更多的训练时期。对于self-distillation,分类和框回归分别由教师模型监督。多亏了 DFL使得框回归的蒸馏成为可能。此外,来自Soft Label和Hard Label的信息比例通过余弦衰减动态下降,这有助于学生在训练过程中的不同阶段选择性地获取知识。此外,作者遇到了性能受损的问题,而在评估时没有添加额外的灰色边框,为此提供了一些补救措施。

量化和部署:

为了解决量化基于重参化模型的性能下降问题,使用 RepOptimizer 训练 YOLOv6 以获得对 PTQ 友好的权重。进一步采用 QAT 和通道蒸馏和图优化来追求极致性能。量化 YOLOv6-S 达到了最新的技术水平,AP 为 42.3%,吞吐量为 869 FPS(batch size=32)。

2.1、网络设计

单阶段目标检测器一般由以下部分组成:BackboneNeckHeadBackbone主要决定特征表示能力,同时,它的设计对推理效率有至关重要的影响,因为它承载了很大一部分计算成本。Neck用于将低层次的物理特征与高层次的语义特征进行聚合,然后构建各个层次的金字塔特征图。Head由几个卷积层组成,它根据Neck融合的多级特征预测最终检测结果。从结构的角度来看,它可以分为Anchor-BaseAnchor-Free,或者更确切地说是参数耦合Head和参数解耦Head

在 YOLOv6 中,基于硬件友好的网络设计原则,提出了两个可缩放的可重参数BackboneNeck以适应不同大小的模型,以及一个具有混合通道策略的高效解耦HeadYOLOv6 的整体架构如图 2 所示。

1、Backbone

如上所述,Backbone网络的设计对检测模型的有效性和效率有很大的影响。以前,已经表明多分支网络通常可以比单路径网络实现更好的分类性能,但它通常伴随着并行度的降低并导致推理延迟的增加。相反,像 VGG 这样的普通单路径网络具有高并行性和更少内存占用的优势,从而带来更高的推理效率。最近在 RepVGG 中,提出了一种结构重参化方法,将训练时多分支拓扑与推理时普通架构解耦,以实现更好的速度-准确度权衡。

受上述工作的启发,设计了一个高效的可重参化Backbone,表示为 EfficientRep。对于小型模型,Backbone的主要组成部分是训练阶段的 RepBlock,如图 3(a)所示。并且每个 RepBlock 在推理阶段被转换为具有 ReLU 激活函数的 3×3 卷积层(表示为 RepConv)的堆栈,如图 3(b)所示。通常,3×3 卷积在主流 GPU 和 CPU 上进行了高度优化,并且具有更高的计算密度。因此,EfficientRep Backbone 充分利用了硬件的计算能力,在显着降低推理延迟的同时增强了表示能力。

然而,作者注意到随着模型容量的进一步扩大,单路径普通网络中的计算成本和参数数量呈指数增长。为了在计算负担和准确性之间取得更好的平衡,修改了一个 CSPStackRep Block 来构建中型和大型网络的Backbone。如图 3(c) 所示,CSPStackRep Block 由3个 1×1 卷积层和一堆子块组成,该子块由两个 RepVGG Block 或 RepConv(分别在训练或推理时)和一个残差连接组成。此外,采用跨级部分(CSP)连接来提高性能,而不会产生过多的计算成本。与 CSPRepResStage 相比,它的外观更加简洁,并考虑了准确性和速度之间的平衡。

2、Neck

在实践中,多尺度的特征集成已被证明是目标检测的关键和有效部分。采用来自 YOLOv4 和 YOLOv5 的修改后的 PAN 拓扑作为检测Neck的基础。此外,将 YOLOv5 中使用的 CSPBlock 替换为 RepBlock(适用于小型模型)或 CSPStackRep Block(适用于大型模型),并相应调整宽度和深度。YOLOv6 的Neck表示为 Rep-PAN

3、Head

Efficient decoupled head

YOLOv5 的检测头是一个耦合Head,在分类和定位分支之间共享参数,而 FCOS 和 YOLOX 中的检测头将两个分支解耦,并且在每个分支中引入了额外的两个 3×3 卷积层以提高性能。

在 YOLOv6 中采用混合通道策略来构建更高效的解耦Head。具体来说,将中间 3×3 卷积层的数量减少到只有一个。头部的宽度由BackboneNeck的宽度乘数共同缩放。这些修改进一步降低了计算成本,以实现更低的推理延迟。

Anchor-free

Anchor-free检测器因其更好的泛化能力和解码预测结果的简单性而脱颖而出。其后处理的时间成本大大降低。有两种类型的Anchor-free检测器:基于Anchor和基于关键点。在 YOLOv6 中,我们采用了基于Anchor点的范式,其框回归分支实际上预测了Anchor点到边界框4个边的距离。

2.2、Label Assignment

标签分配负责在训练阶段为预定义的Anchor分配标签。以前的工作已经提出了各种标签分配策略,从简单的基于 IoU 的策略和内部真实方法到其他更复杂的方案。

SimOTA OTA 将目标检测中的标签分配视为最佳传输问题。它从全局角度为每个真实对象定义了正/负训练样本。SimOTA 是 OTA 的简化版本,它减少了额外的超参数并保持了性能。在 YOLOv6 的早期版本中使用 SimOTA 作为标签分配方法。然而,在实践中,作者发现引入 SimOTA 会减慢训练过程。而且陷入不稳定训练的情况并不少见。因此,希望更换 SimOTA

任务对齐学习任务对齐学习(Task Alignment Learning,TAL)最早是在TOOD中提出的,其中设计了一个分类分数和预测框质量的统一度量。IoU 被这个指标替换以分配对象标签。在一定程度上缓解了任务错位(分类和框回归)的问题。TOOD 的另一个主要贡献是关于任务对齐的头部(T-head)。T-head 堆叠卷积层以构建交互式特征,在其之上使用任务对齐预测器 (TAP)。PP-YOLOE 改进了 T-head,将 T-head 中的 layer attention 替换为轻量级的 ESE attention,形成 ET-head。然而,我们发现 ET-head 会降低模型中的推理速度,并且没有准确度增益。因此,保留了高效解耦头的设计。

此外,作者观察到 TAL 可以带来比 SimOTA 更多的性能提升并稳定训练。因此,采用 TAL 作为 YOLOv6 中的默认标签分配策略。

2.3、损失函数

1、Classification Loss

提高分类器的性能是优化检测器的关键部分。Focal Loss 修改了传统的交叉熵损失,以解决正负样本之间或难易样本之间的类别不平衡问题。为了解决训练和推理之间质量估计和分类的不一致使用,Quality Focal LossQFL)进一步扩展了Focal Loss,联合表示分类分数和分类监督的定位质量。而 VariFocal Loss (VFL) 源于 Focal Loss,但它不对称地对待正样本和负样本。通过考虑不同重要性的正负样本,它平衡了来自两个样本的学习信号。Poly Loss 将常用的分类损失分解为一系列加权多项式基。它在不同的任务和数据集上调整多项式系数,通过实验证明比交叉熵损失和Focal Loss损失更好。

在 YOLOv6 上评估所有这些高级分类损失,最终采用 VFL

2、Box Regression Loss

框回归损失提供了精确定位边界框的重要学习信号。L1 Loss 是早期作品中的原始框回归损失。逐渐地,各种精心设计的框回归损失如雨后春笋般涌现,例如 IoU-series 损失和概率损失。

IoU-series Loss IoU loss 将预测框的四个边界作为一个整体进行回归。它已被证明是有效的,因为它与评估指标的一致性。IoU的变种有很多,如GIoUDIoUCIoUα-IoUSIoU等,形成了相关的损失函数。我们在这项工作中对 GIoUCIoU 和 SIoU 进行了实验。并且SIoU应用于YOLOv6-NYOLOv6-T,而其他的则使用GIoU

Probability Loss Distribution Focal Loss (DFL) 将框位置的基本连续分布简化为离散化的概率分布。它在不引入任何其他强先验的情况下考虑了数据中的模糊性和不确定性,这有助于提高框定位精度,尤其是在ground-truth框的边界模糊时。在 DFL 上,DFLv2 开发了一个轻量级的子网络,以利用分布统计数据与真实定位质量之间的密切相关性,进一步提高了检测性能。然而,DFL 输出的回归值通常比一般框回归多 17 倍,从而导致大量开销。额外的计算成本阻碍了小型模型的训练。而 DFLv2 由于额外的子网络,进一步增加了计算负担。在实验中,DFLv2 在模型上为 DFL 带来了类似的性能提升。因此,只在 YOLOv6-M/L 中采用 DFL

3、Object Loss

Object loss 最早是在 FCOS 中提出的,用于降低低质量边界框的得分,以便在后处理中将其过滤掉。它还被用于 YOLOX 以加速收敛并提高网络精度。作为像 FCOS 和 YOLOX 这样的Anchor-free框架,在 YOLOv6 中尝试过 object loss。不幸的是,它并没有带来很多积极的影响。

2.4、行业便利的改进

1、More training epochs

经验结果表明,检测器的性能随着训练时间的增加而不断进步。作者将训练持续时间从 300 个 epoch 延长到 400 个 epoch,以达到更好的收敛性。

2、Self-distillation

为了在不引入太多额外计算成本的情况下进一步提高模型精度,应用了经典的知识蒸馏技术,最小化了教师和学生预测之间的 KL-divergence。将老师限制为学生本身,但经过预训练,因此称之为自我蒸馏。

请注意,KL-divergence通常用于衡量数据分布之间的差异。然而,目标检测中有两个子任务,其中只有分类任务可以直接利用基于 KL-divergence的知识蒸馏。由于 DFL 损失,也可以在框回归上执行它。知识蒸馏损失可以表示为:

其中Ldet  是使用预测和标签计算的检测损失。引入超参数α来平衡两个损失。在训练的早期阶段,来自老师的软标签更容易学习。随着训练的继续,学生的表现将与老师相匹配,因此硬标签将更多地帮助学生。在此基础上,将余弦权重衰减应用于 α,以动态调整来自硬标签和来自教师的软标签的信息。

3、Gray border of images

作者注意到在 YOLOv5 和 YOLOv7 的实现中评估模型性能时,每个图像周围都有一个半步长的灰色边框。虽然没有添加有用的信息,但它有助于检测图像边缘附近的对象。这个技巧也适用于 YOLOv6

然而,额外的灰色像素明显降低了推理速度。没有灰色边框,YOLOv6 的性能会变差。假设该问题与马赛克增强中的灰色边框填充有关。进行了在最后一个时期关闭马赛克增强的实验(也称为淡入淡出策略)以进行验证。对此,改变了灰色边框的区域,将带有灰色边框的图像直接调整为目标图像大小。结合这两种策略,模型可以在不降低推理速度的情况下保持甚至提高性能。

2.5、量化与部署

对于工业部署,通常的做法是采用量化来进一步加快运行时间而不会对性能造成太大影响。训练后量化(PTQ)直接量化模型,只需要一个小的校准集。而量化感知训练(QAT)通过访问训练集进一步提高了性能,这通常与蒸馏结合使用。然而,由于在 YOLOv6 中大量使用了重参化块,以前的 PTQ 技术无法产生高性能,而在训练和推理期间在匹配假量化器时很难结合 QAT

1、Reparameterizing Optimizer

RepOptimizer 在每个优化步骤提出梯度重参化。该技术也很好地解决了基于重参化模型的量化问题。因此,以这种方式重建 YOLOv6 的重参化块,并使用 RepOptimizer 对其进行训练以获得对 PTQ 友好的权重。特征图的分布在很大程度上变窄了,这极大地有利于量化过程。

2、Sensitivity Analysis

通过将量化敏感操作部分转换为浮点计算来进一步提高 PTQ 性能。为了获得灵敏度分布,通常使用几个指标,均方误差 (MSE)、信噪比 (SNR) 和余弦相似度。通常为了比较,可以选择输出特征图(在激活某个层之后)来计算这些带有和不带量化的指标。作为替代方案,通过打开和关闭特定层的量化来计算验证 AP 也是可行的。

在使用 RepOptimizer 训练的 YOLOv6-S 模型上计算所有这些指标,并选择前 6 个敏感层以浮动运行。

3、使用 Channel-wise Distillation 进行量化感知训练

如果 PTQ 不足,建议使用量化感知训练 (QAT) 来提高量化性能。为了解决训练和推理过程中假量化器不一致的问题,有必要在 RepOptimizer 上构建 QAT。此外,通道蒸馏(后来称为 CW Distill)适用于 YOLOv6 框架,如图 5 所示。这也是一种自我蒸馏方法,其中教师网络是 FP32 精度的学生本身。

实验

消融实验

1、label assignment

2、损失函数

3、自蒸馏

4、Gray border of images

5、PTQ

6、QAT

SOTA对比

TensorRT部署实践对比

T4 GPU

V100 GPU

Diffusion Model 综述

Diffusion Models: A Comprehensive Survey of Methods and Applications来自加州大学&Google Research的Ming-Hsuan Yang、北京大学崔斌实验室以及CMU、UCLA、蒙特利尔Mila研究院等众研究团队,首次对现有的扩散生成模型(diffusion model)进行了全面的总结分析,从diffusion model算法细化分类、和其他五大生成模型的关联以及在七大领域中的应用等方面展开,最后提出了diffusion model的现有limitation和未来的发展方向

论文:https://arxiv.org/abs/2209.00796

摘自:AI科技评论

github链接:https://github.com/YangLing0818/Diffusion-Models-Papers-Survey-Taxonomy(扩散模型论文汇总)

介绍

扩散模型(diffusion models)是深度生成模型中新的SOTA。扩散模型在图片生成任务中超越了原SOTA:GAN,并且在诸多应用领域都有出色的表现,如计算机视觉,NLP、波形信号处理、多模态建模、分子图建模、时间序列建模、对抗性净化等。此外,扩散模型与其他研究领域有着密切的联系,如稳健学习、表示学习、强化学习。然而,原始的扩散模型也有缺点,它的采样速度慢,通常需要数千个评估步骤才能抽取一个样本;它的最大似然估计无法和基于似然的模型相比;它泛化到各种数据类型的能力较差。如今很多研究已经从实际应用的角度解决上述限制做出了许多努力,或从理论角度对模型能力进行了分析。然而,现在缺乏对扩散模型从算法到应用的最新进展的系统回顾。为了反映这一快速发展领域的进展,我们对扩散模型进行了首个全面综述。我们设想我们的工作将阐明扩散模型的设计考虑和先进方法,展示其在不同领域的应用,并指出未来的研究方向。此综述的概要如下图所示:

尽管diffusion model在各类任务中都有着优秀的表现,它仍还有自己的缺点,并有诸多研究对diffusion model进行了改善。为了系统地阐明diffusion model的研究进展,我们总结了原始扩散模型的三个主要缺点,采样速度慢,最大化似然差、数据泛化能力弱,并提出将的diffusion models改进研究分为对应的三类:采样速度提升、最大似然增强和数据泛化增强。我们首先说明改善的动机,再根据方法的特性将每个改进方向的研究进一步细化分类,从而清楚的展现方法之间的联系与区别。在此我们仅选取部分重要方法为例, 我们的工作中对每类方法都做了详细的介绍,内容如图所示:

在分析完三类扩散模型后,我们将介绍其他的五种生成模型GAN,VAE,Autoregressive model, Normalizing flow, Energy-based model。考虑到扩散模型的优良性质,研究者们已经根据其特性将diffusion model与其他生成模型结合,所以为了进一步展现diffusion model 的特点和改进工作,我们详细地介绍了diffusion model和其他生成模型的结合的工作并阐明了在原始生成模型上的改进之处。Diffusion model在诸多领域都有着优异的表现,并且考虑到不同领域的应用中diffusion model产生了不同的变形,我们系统地介绍了diffusion model的应用研究,其中包含如下领域:计算机视觉,NLP、波形信号处理、多模态建模、分子图建模、时间序列建模、对抗性净化。对于每个任务,我们定义了该任务并介绍利用扩散模型处理任务的工作,我们将本项工作的主要贡献总结如下:

  • 新的分类方法:我们对扩散模型和其应用提出了一种新的、系统的分类法。具体的我们将模型分为三类:采样速度增强、最大似然估计增强、数据泛化增强。进一步地,我们将扩散模型的应用分为七类:计算机视觉,NLP、波形信号处理、多模态建模、分子图建模、时间序列建模、对抗性净化。
  • 全面的回顾:我们首次全面地概述了现代扩散模型及其应用。我们展示了每种扩散模型的主要改进,和原始模型进行了必要的比较,并总结了相应的论文。对于扩散模型的每种类型的应用,我们展示了扩散模型要解决的主要问题,并说明它们如何解决这些问题。
  • 未来研究方向:我们对未来研究提出了开放型问题,并对扩散模型在算法和应用方面的未来发展提供了一些建议。

扩散模型基础

生成式建模的一个核心问题是模型的灵活性和可计算性之间的权衡。扩散模型的基本思想是正向扩散过程来系统地扰动数据中的分布,然后通过学习反向扩散过程恢复数据的分布,这样就了产生一个高度灵活且易于计算的生成模型。

1.Denoising Diffusion Probabilistic Models(DDPM)

一个DDPM由两个参数化马尔可夫链组成,并使用变分推断以在有限时间后生成与原始数据分布一致的样本。前向链的作用是扰动数据,它根据预先设计的噪声进度向数据逐渐加入高斯噪声,直到数据的分布趋于先验分布,即标准高斯分布。反向链从给定的先验开始并使用参数化的高斯转换核,学习逐步恢复原数据分布。用表示原始数据及其分布,则前向链的分布是可由下式表达:

这说明前向链是马尔可夫过程,是加入t步噪音后的样本,是事先给定的控制噪声进度的参数。当 趋于1时,可以近似认为服从标准高斯分布。当很小时,逆向过程的转移核可以近似认为也是高斯的:

我们可以将变分下界作为损失函数进行学习:

2.Score-Based Generative Models(SGM)

上述DDPM可以视作SGM的离散形式。SGM构造一个随机微分方程(SDE)来平滑的扰乱数据分布,将原始数据分布转化到已知的先验分布:

和一个相应的逆向SDE,来将先验分布变换回原始数据分布:

因此,要逆转扩散过程并生成数据,我们需要的唯一信息就是在每个时间点的分数函数。利用score-matching的技巧我们可以通过如下损失函数来学习分数函数:

对两种方法的进一步介绍和两者关系的介绍请参见我们的文章。原始扩散模型的三个主要缺点,采样速度慢,最大化似然差、数据泛化能力弱。最近许多研究都在解决这些缺点,因此我们将改进的扩散模型分为三类:采样速度提升、最大似然增强和数据泛化增强。在接下来的三、四、五节我们将对这三类模型进行详细的介绍。

采样加速方法

在应用时,为了让新样本的质量达到最佳,扩散模型往往需要进行成千上万步计算来获取一个新样本。这限制了diffusion model的实际应用价值,因为在实际应用时,我们往往需要产生大量的新样本,来为下一步处理提供材料。研究者们在提高diffusion model采样速度上进行了大量的研究。我们对这些研究进行了详细的阐述。我们将其细化分类为三种方法:Discretization Optimization,Non-Markovian Process,Partial Sampling。

1.Discretization Optimization

方法优化求解diffusion SDE的方法。因为现实中求解复杂SDE只能使用离散解来逼近真正的解,所以该类方法试图优化SDE的离散化方法,在保证样本质量的同时减少离散步数。SGM 提出了一个通用的方法来求解逆向过程,即对前向和后向过程采取相同的离散方法。如果给定了前向SDE的离散方式:

那么我们就可以以相同的方式离散化逆向SDE:

这种方法比朴素DDPM效果略好一点。进一步,SGM向SDE求解器中加入了一个矫正器,从而让每一步生成的样本都有正确的分布。在求解的每一步,求解器给出一个样本后,矫正器都使用马尔可夫链蒙特卡罗方法来矫正刚生成的样本的分布。实验表明向求解器中加入矫正器比直接增加求解器的步数效率更高。

2.Non-Markovian Process方法突破了原有Markovian Process的限制,其逆过程的每一步可以依赖更多以往的样本来进行预测新样本,所以在步长较大时也能做出较好的预测,从而加速采样过程。其中主要的工作DDIM,不再假设前向过程是马尔可夫过程,而是服从如下分布:

DDIM的采样过程可以视为离散化的神经常微分方程,其采样过程更高效,并且支持样本的内插。进一步的研究发现DDIM可以视作流形上扩散模型PNDM的特例。3.Partial Sampling方法通过在generation process中忽略一部分的时间节点,而只使用剩下的时间节点来生成样本,直接减少了采样时间。例如,Progressive Distillation从训练好的扩散模型中蒸馏出效率更高的扩散模型。对于训练好的一个扩散模型,Progressive Distillation会从新训练一个扩散模型,使新的扩散模型的一步对应于训练好的扩散模型的两步,这样新模型就可以省去老模型一半的采样过程。具体算法如下:

不断循环这个蒸馏过程就能让采样步骤指数级下降。

最大似然估计加强

扩散模型在最大似然估计的表现差于基于似然函数的生成模型,但最大化似然估计在诸多应用场景都有重要意义,比如图片压缩, 半监督学习, 对抗性净化。由于对数似然难以直接计算,研究主要集中在优化和分析变分下界(VLB)。我们对提高扩散模型最大似然估计的模型进行了详细的阐述。我们将其细化分类为三类方法:Objectives Designing,Noise Schedule Optimization,Learnable Reverse Variance。

1.Objectives Designing方法利用扩散 SDE推倒出生成数据的对数似然与分数函数匹配的损失函数的关系。这样通过适当设计损失函数,就可以最大化 VLB 和对数似然。Song et al. 证明了可以设计损失函数的权重函数,使得plug-in reverse SDE 生成样本的似然函数值小于等于损失函数值,即损失函数是似然函数的上界。分数函数拟合的损失函数如下:

我们只需将权重函数设为扩散系数g(t)即可让损失函数成为似然函数的VLB,即:

2.Noise Schedule Optimization通过设计或学习前向过程的噪声进度来增大VLB。VDM证明了当离散步数接近无穷时,损失函数完全由信噪比函数SNR(t)的端点决定:

那么在离散步数接近无穷时,可以通过学习信噪比函数SNR(t)的端点最优化VLB,而通过学习信噪比函数中间部分的函数值来实现模型其他方面的改进。

3.Learnable Reverse Variance方法学习反向过程的方差,从而较少拟合误差,可以有效地最大化VLB。Analytic-DPM证明,在DDPM和DDIM中存在反向过程中的最优期望和方差:

使用上述公式和训练好的分数函数,在给定前向过程的条件下,最优的VLB可以近似达到。

数据泛化增强

扩散模型假设数据存在于欧几里得空间,即具有平面几何形状的流形,并添加高斯噪声将不可避免地将数据转换为连续状态空间,所以扩散模型最初只能处理图片等连续性数据,直接应用离散数据或其他数据类型的效果较差。这限制了扩散模型的应用场景。数个研究工作将扩散模型推广到适用于其他数据类型的模型,我们对这些方法进行了详细地阐释。我们将其细化分类为两类方法:Feature Space Unification,Data-Dependent Transition Kernels。1.Feature Space Unification方法将数据转化到统一形式的latent space,然后再latent space上进行扩散。LSGM提出将数据通过VAE框架先转换到连续的latent space 上后再在其上进行扩散。这个方法的难点在于如何同时训练VAE和扩散模型。LSGM表明由于潜在先验是intractable的,分数匹配损失不再适用。LSGM直接使用VAE中传统的损失函数ELBO作为损失函数,并导出了ELBO和分数匹配的关系:

该式在忽略常数的意义下成立。通过参数化扩散过程中样本的分数函数,LSGM可以高效的学习和优化ELBO。

2.Data-Dependent Transition Kernels方法根据数据类型的特点设计diffusion process 中的transition kernels,使扩散模型可以直接应用于特定的数据类型。D3PM为离散型数据设计了transition kernel,可以设为lazy random-walk,absorbing state等。GEODIFF为3D分子图数据设计了平移-旋转不变的图神经网络,并且证明了具有不变性的初分布和transition kernel可以导出具有不变性的边缘分布。假设是一个平移-旋转变换,如:

那么生成的样本分布也有平移-旋转不变性:

和其他生成模型的联系

在下面的每个小节中,我们首先介绍其他五类重要的生成模型,并分析它们的优势和局限性。然后我们介绍了扩散模型是如何与它们联系起来的,并说明通过结合扩散模型来改进这些生成模型。VAE,GAN,Autoregressive model, Normalizing flow, Energy-based model和扩散模型的联系如下图所示:

  1. DDPM可以视作层次马尔可夫VAE(hierarchical Markovian VAE)。但DDPM和一般的VAE也有区别。DDPM作为VAE,它的encoder和decoder都服从高斯分布、有马尔科夫行;其隐变量的维数和数据维数相同;decoder的所有层都共用一个神经网络。
  2. DDPM可以帮助GAN解决训练不稳定的问题。因为数据是在高维空间中的低维流形中,所以GAN生成数据的分布和真实数据的分布重合度低,导致训练不稳定。扩散模型提供了一个系统地增加噪音的过程,通过扩散模型向生成的数据和真实数据添加噪音,然后将加入噪音的数据送入判别器,这样可以高效地解决GAN无法训练、训练不稳定的问题。
  3. Normalizing flow通过双射函数将数据转换到先验分布,这样的作法限制了Normalizing flow的表达能力,导致应用效果较差。类比扩散模型向encoder中加入噪声,可以增加Normalizing flow的表达能力,而从另一个视角看,这样的做法是将扩散模型推广到前向过程也可学习的模型。
  4. Autoregressive model在需要保证数据有一定的结构,这导致设计和参数化自回归模型非常困难。扩散模型的训练启发了自回归模型的训练,通过特定的训练方式避免了设计的困难。
  5. Energy-based model直接对原始数据的分布建模,但直接建模导致学习和采样都比较困难。通过使用扩散恢复似然,模型可以先对样本加入微小的噪声,再从有略微噪声的样本分布来推断原始样本的分布,使的学习和采样过程更简单和稳定。

扩散模型的应用

在本节中,我们分别介绍了扩散模型在计算机视觉、自然语言处理、波形信号处理、多模态学习、分子图生成、时间序列以及对抗学习等七大应用方向中的应用,并对每类应用中的方法进行了细分并解析。例如在计算机视觉中可以用diffusion model进行图像补全修复(RePaint):

在多模态任务中可以用diffusion model进行文本到图像的生成(GLIDE):

还可以在分子图生成中用diffusion model进行药物分子和蛋白质分子的生成(GeoDiff):

应用分类汇总见表:

未来研究方向

  1. 应用假设再检验。我们需要检查我们在应用中普遍接受的假设。例如,实践中普遍认为扩散模型的前向过程会将数据转换为标准高斯分布,但事实并非如此,更多的前向扩散步骤会使最终的样本分布与标准高斯分布更接近,与采样过程一致;但更多的前向扩散步骤也会使估计分数函数更加困难。理论的条件很难获得,因此在实践中操作中会导致理论和实践的不匹配。我们应该意识到这种情况并设计适当的扩散模型。
  2. 从离散时间到连续时间。由于扩散模型的灵活性,许多经验方法可以通过进一步分析得到加强。通过将离散时间的模型转化到对应的连续时间模型,然后再设计更多、更好的离散方法,这样的研究思路有前景。
  3. 新的生成过程。扩散模型通过两种主要方法生成样本:一是离散化反向扩散 SDE,然后通过离散的反向 SDE 生成样本;另一个是使用逆过程中马尔可夫性质对样本逐步去噪。然而,对于一些任务,在实践中很难应用这些方法来生成样本。因此,需要进一步研究新的生成过程和视角。
  4. 泛化到更复杂的场景和更多的研究领域。虽然目前diffusion model已经应用到多个场景中,但是大多数局限于单输入单输出的场景,将来可以考虑将其应用到更复杂的场景,比如text-to-audiovisual speech synthesis。也可以考虑和更多的研究领域相结合。

part2:【扩散模型笔记整理】从DDPM到Imagen

扩散模型(Diffusion Model)

1. 概述

  • 如图所示,扩散模型分两个过程:扩散(diffusion, 从x0到xT的过程逐步加入噪声)和去噪(denoise, 从xT到x0逐步去噪)。训练的时候,需要利用扩散加噪来生成训练样本;推理的时候,输入一个噪音,逐步去噪输出原始信号(比如图像、语音)。

参考文献:Denoising Diffusion Probabilistic Models

2. 扩散和去噪(Diffusion&Denoise)

  • 首先介绍一下高斯分布的表达,记作X∽N(μ,σ2):

扩散过程每一步都加入一个方差为βt∈(0,1)的高斯噪声可以用马尔科夫链来表示:

  • 这里的βt是一个0到1的等比序列(β0=0),此时表示原始图像;第T步的时候,βt=1,表示标准高斯噪声N∽(0,I)。因而实际上扩散过程是一个从原始图像变为标准高斯分布的过程。加噪和高斯采样等价,无非就是改变了一下高斯采样的均值中心点。
  • 实际训练的时候,我们可以直接用下面的公式一次性算出某一步的加噪图片作为训练素材,无需逐步迭代。
  • 去噪过程和扩散过程反过来:从一张随机采样的高斯噪声图片逐步去噪得到我们想要生成的图像。表达式:
  • 去噪过程,需要用模型预测加入的高斯噪声,得到原始的无噪声的图像。上式表示,利用模型算出原始第n步的未加噪图像,实质上只要算出均值和方差,再做一个采样得到原始图像。而为了算出μ,我们需要预测出噪声ϵ,反推出原始图像的均值中心,方差项可以由网络预测也可以取常数(前者效果好)。下节将介绍模型的训练和推理过程。

3. 训练和采样(Training&Sampling)

  • 训练其实就是扩散过程,而采样其实就是去噪过程。
  • 算法如上图所示,训练training的过程实际上是随机采第t步的加噪图像,输入带噪图片以及步数t,模型预测噪声ϵ,模型训练目标:预测噪声与实际加入噪声的误差越小越好。
  • 采样sampling的过程(生成过程)为:将有噪声的图像(第一张图像为随机采样的高斯分布噪声)减去模型预测的噪声(噪声前面的其它参数可以由上面加噪的过程反向推导出来)不断把噪声去掉以恢复出原始的图像。
  • 方差项σ也可以由模型来预测。

参考文献: Improved Denoising Diffusion Probabilistic Models

引导扩散模型(Guided Diffusion)

前文已经讲述扩散模型的原理,然而我们随机输入一张高斯噪声显然不能按照人的意愿生成我们想要的内容,因而需要额外的引导guidance以得到我们需要的图像。一种想法是使用外部模型(分类器or广义的判别器)的输出作为引导条件来指导扩散模型的去噪过程,从而得到我们想要的输出;还有一种则比较直观一些:我们直接把我们想要的引导条件condition也作为模型输入的一部分,从而让扩散模型见到这个条件后就可以直接生成我们想要的内容。

下文将讲解classifier guidance和semantic guidance diffusion model(后者包括前者,前者是比较简单的一个应用),除此之外,由于额外的判别器会拖慢推理速度,因此后来有人提出了 classifier-free guidance diffusion model来替代前面的那种方案,也即把条件作为模型的输入,直接生成我们需要的图像。

1. Classifier Guidance Diffusion Model

  • 这种方法不用额外训练扩散模型,直接在原有训练好的扩散模型上,通过外部的分类器来引导生成期望的图像。唯一需要改动的地方其实只有sampling过程中的高斯采样的均值,也即采样过程中,期望噪声图像的采样中心越靠近判别器引导的条件越好。
  • 上图总结了采样算法。Algorithm 1和 Algorithm 2其实是等价的(1是直接预测均值和方差,2是预测噪声的误差)。直接看Algorithm 1可知,实质上改变的只有高斯分布的均值中心,将扩散方向“引导”成我们想要的内容。具体而言,用分类模型pϕ对生成的图片进行分类,得到预测分数与目标类别的交叉熵,将其对带噪图像求梯度用梯度引导下一步的生成采样。(实际使用的时候,需要把这个分类器也在带噪数据额外训练一下)
  • 因为我们实际使用的模型预测的是噪音,实际计算为Algorithm 2,可以由1推导而来。(具体推导过程可以参考文献)

参考文献:Diffusion Models Beat GANs on Image Synthesis

2. Semantic Guidance Diffusion

  • 介绍完前面的 classifier guidance后,显然我们可以把分类器替换成其它任意的判别器,也即更换引导条件,从而实现利用不同的语义信息来指导扩散模型的去噪过程。比如说,我们可以实现text-guidance和image-guidance等。
  • 实质上就是把classifier guidance的条件推广,表达为:
  • Fϕ表示就是新的引导条件,这里展示的是分类的,其实也可以换成相似度之类的分数指标。具体可以有以下的例子:图像引导、文本引导、图像+文本引导。


参考文献:More Control for Free! Image Synthesis with Semantic Diffusion Guidance

3. Classifier-Free Guidance Diffusion

  • 正如前文提到的,额外引入一个网络来指导,推理的时候比较复杂(扩散模型需要反复迭代,每次迭代都需要额外算一个分数)。然而,直接将引导条件作为模型的输入,直到Classifier-Free Diffusion Guidance被提出前似乎效果也一般般。Classifier-Free Diffusion Guidance这篇文章的贡献就是提出了一个等价的结构替换掉了外部的判别器,从而可以直接用一个扩散模型来做条件生成任务。
  • 实际做法只是改变了模型输入的内容,有conditional(除了随机高斯噪声输入外,把引导信息的embedding也加进来)和unconditional 的 sample输入。两种输入都会被送到同一个diffusion model从而让其能够具有无条件和有条件生成的能力。得到这两种输入的输出后,就可以用来引导扩散模型进行训练。
  • 回忆一下前面的 classifier guidance的噪音更新方式:
  • 实质上,这个classifier-free用另一个近似的等价结构替换掉了后面那一项:
  • 其中,ϵθ(xt,y) 表示conditional的输入,而ϵθ(xt)则表示unconditional输入,用这两项之差乘以一个系数来替换掉原来的那项。至于为什么可以这么直接替换,其实可以用贝叶斯公式推导而来:
  • 因而,实际上这个过程就训练了一个 implicit classifier,从而移除外部的分类器。

参考文献:Classifier-Free Diffusion Guidance

GLIDE

  • 这篇文章主要就是用到了前面所说的classifier-free扩散模型,只不过把输入的condition换成了文本信息,从而实现文本生成图像,此外还利用diffusion model实现了超分辨率。一些效果展示如下,可以看到,其实已经可以生成一些比较逼真的图片了。
  • 具体可以表达为:
  • 这里无非就是把原来的label y换成了 caption,实际上就是运用了足够量的image-text pair从而可以把caption当作是某种程度上的label。(随机替换为空序列以实现unconditional的训练方式)
动图封面
  • 由于此时的生成图像质量一般般,文章也提供了图像编辑的方式(具体操作为:将选中区域mask掉,将图像也作为一个condition连同文本输入到模型中去):

DALL·E 2

概况

  • 第一版DALL·E用的是GAN+CLIP重排序的结构。
  • DALL·E 2可以把diffusion model和CLIP结合在一起,生成效果十分惊艳,可以直接去官网浏览一下。DALL·E 2 (openai.com)
  • 包括prior网络用于将caption转换为CLIP image embedding,一个decoder把image embedding作为condition来生成图像。prior有两种:一种是autoregressive model、一种是diffusion model(后者效果更好一些);decoder就是diffusion model。总之,这里相比前面的变化主要在于加入了prior,以及把condition换成了CLIP的embedding。

Decoder

  • 具体而言,把CLIP image embedding作为condition输入到diffusion model中,同时把CLIP image embedding映射成4个额外的tokens接到GLIDE text encoder的输出。
  • 除了用于生成图像的diffusion model,这部分还有2个额外用于超分辨率的diffusion model,生成高清图像。

Prior

这部分的内容是为了将caption y转换为 CLIP image embedding,以用于后面decoder的图像生成。

  • 一种是auto-regressive model,将image embedding转换为一串离散的编码,并且基于condition caption y自回归地预测。(这里不一定要condition on caption(GLIDE的方法——额外用一个Transformer处理caption),也可以condition on CLIP text embedding)。此外,这里还用到了PCA来降维,降低运算复杂度。
  • 一种是diffusion model。这是一个decoder-only Transformer,输入是encoded text+CLIP text embedding+noised CLIP image embedding+额外token(类似class embedding)输入,其输出一个unnoised CLIP image embedding(取那个额外的embedding)。

Variations

  • 这部分是为了给一张图,生成相似的图像。做法很简单:用CLIP把图像编码,把这个CLIP image embedding作为condition引导decoder生成图像。除此之外,还可以对2张图像的CLIP embedding进行插值,以实现风格迁移。( spherical interpolation 几何球面线性插值)。这里证明了CLIP语义空间的可解释性

量化结果

  • 本文方法又称unCLIP(其实本质上就是把CLIP生成的embedding进行decode),相比GLIDE有小幅的提高。

Paper List

  1. (DDPM) Denoising Diffusion Probabilistic Models. NIPS 20. (Diffusion and deep-learning-based 图像生成开山之作)
  2. More Control for Free! Image Synthesis with Semantic Diffusion Guidance. arXiv 21. (对DDIM进行了推广,引入了一般形式的判别器引导)
  3. Denoising Diffusion Implicit Models. ICLR 21. (提出了一种新的sampling的方法,可以通过改变eta来skip一些step,进而达到加速sampling的目的)
  4. Improved denoising diffusion probabilistic models. ICML 21.
  5. Classifier-Free Diffusion Guidance. NIPSW 21. (引入了等价结构替代了分类器引导)
  6. GLIDE: Towards Photorealistic Image Generation and Editing with Text-Guided Diffusion Models. ICML 22.
  7. Hierarchical Text-Conditional Image Generation with CLIP Latents. NIPS 22 在投. (DALL-E 2)
  8. Photorealistic Text-to-Image Diffusion Models with Deep Language Understanding. NIPS 22 在投. (Imagen, SOTA)
  9. High-Resolution Image Synthesis with Latent Diffusion Models. CVPR 22. (隐空间LDM)

医学分割图像数据集汇总

(更多数据集请看医学影像数据集集锦:https://github.com/linhandev/dataset

数据集数据集大小 说明 链接
Kvasir-SEG1000 张(对)Kvasir-seg是 胃肠道息肉图像和相应分割面罩的开放式数据集,由医生手动注释,然后由经验丰富的胃肠病学家进行验证。Kvasir-SEG 数据集(大小 46.2 MB)包含来自 Kvasir Dataset v2 的 1000 个息肉图像及其对应的地面实况。Kvasir-SEG 中包含的图像的分辨率从 332×487 到 1920×1072 像素不等。https://datasets.s
imula.no/kvasir-seg/
CVC-ClinicDB600张CVC-ClinicDB 是从结肠镜检查视频中提取的帧数据库。CVC-ClinicDB 数据库由两种不同类型的图像组成:原始图像和息肉掩膜  https://polyp.grand-cha
llenge.org/CVCClinicDB/
CVC-ColonDB300张结肠镜检查视频的注释视频序列。它包含 15 个简短的结肠镜检查序列,来自 15 项不同的研究。在每个序列中显示一个息肉。 
Synapse multi-organ CT50从正在进行的结直肠癌化疗试验和回顾性腹疝研究的组合中随机选择了 50 份腹部 CT 扫描。50 次扫描是在门静脉造影阶段捕获的,具有可变的体积大小 (512 x 512 x 85 – 512 x 512 x 198) 和视场(约 280 x 280 x 280 mm 3 – 500 x 500 x 650 mm 3) . 平面内分辨率从 0.54 x 0.54 mm 2到 0.98 x 0.98 mm 2不等,而切片厚度范围从 2.5 mm 到 5.0 mm。标准注册数据由NiftyReg生成。https://www.syn
apse.org/#!Synapse:syn3193805/wiki/217789
MoNuSeg22,000张数据集是通过仔细注释几名患有不同器官肿瘤并在多家医院被诊断出的患者的组织图像获得的。该数据集是通过从TCGA存档下载以 40 倍放大倍率捕获的 H&E 染色组织图像创建的。H&E 染色是增强组织切片对比度的常规方案,通常用于肿瘤评估(分级、分期等)。考虑到多个器官和患者的细胞核外观的多样性,以及多家医院采用的丰富染色方案,训练数据集将能够开发出强大且可推广的细胞核分割技术,开箱即用。https://monuseg.gr
and-challenge.org/Data/
胰腺分割数据集 美国国立卫生研究院临床中心对 53 名男性和 27 名女性受试者进行了 82 次腹部对比增强 3D CT 扫描(门静脉静脉注射对比剂后约 70 秒)。17 名受试者是在肾切除术前扫描的健康肾脏捐赠者。其余 65 名患者由放射科医师从既无重大腹部病变也无胰腺癌病变的患者中选出。受试者的年龄范围为 18 至 76 岁,平均年龄为 46.8 ± 16.7。CT 扫描具有 512×512 像素的分辨率,具有不同的像素大小和 1.5 – 2.5 mm 之间的切片厚度,在 Philips 和 Siemens MDCT 扫描仪(120 kVp 管电压)上获得。 http://academictorre
nts.com/details/80ecfefc
abede760cdbdf63e38986501f7becd49
MICCAI胰腺分割数据集282目标:肝脏和肿瘤 模式:门静脉期 CT 大小: 420 3D 卷(282 培训 +139 测试) 来源:纪念斯隆凯特琳癌症中心 挑战:标签不平衡与大(背景)、中(胰腺)和小(肿瘤)结构https://drive.google.com
/drive/folders/1HqEgzS8BV2
c7xYNrZdEAnrHk7osJJ–2
LiTS肝脏分割数据集131+70LiTS数据集包含131组训练扫描和70组测试扫描,其中70组测试数据标签不公开。LiTS训练集中包含3DIRCADB中的所有数据,所以不要合并这两个数据集。Medical Segmentation Decathlon中肝脏分割的数据集就是LiTS。https://sliver07.gran
d-challenge.org/
covid19-ct-scans20数据来自Ieee8023,对20组扫描进行了左右肺和感染区的标注。https://www.kaggle.co
m/andrewmvd/covid19-ct-scans
Medical Segmentation Decathlon2,633医学分割十项全能是医学图像分割数据集的集合。它总共包含 2,633 张三维图像,这些图像是从多个感兴趣的解剖结构、多种模式和多个来源收集的。具体来说,它包含以下身体器官或部位的数据:大脑、心脏、肝脏、海马体、前列腺、肺、胰腺、肝血管、脾脏和结肠。http://medicald
ecathlon.com/
GlaS165GlaS 

结肠组织学图像挑战中的腺体分割
本次挑战中使用的数据集包含 165 张图像,这些图像来自 T3 或 T42 期结直肠腺癌的 16 个 H&E 染色组织切片。
每个切片属于不同的患者,切片是在实验室的不同场合处理的。
因此,该数据集在染色分布和组织结构方面表现出很高的受试者间变异性。
使用像素分辨率为 0.465µm 的 Zeiss MIRAX MIDI 幻灯片扫描仪将这些组织切片数字化为全幻灯片图像 (WSI)。
https://warwick.ac.uk/fac/cross_fac/tia/data/glascontest/
2018 Data Science Bowl该数据集包含大量分割的核图像。
这些图像是在各种条件下获得的,并且在细胞类型、放大倍率和成像方式(明场与荧光)方面有所不同。
该数据集旨在挑战算法泛化这些变化的能力。
出自UNet++: A Nested U-Net Architecture for Medical Image Segmentation
https://www.kaggle.com/c/data-science-bowl-2018/overview
ACDC150该数据集由 150 个检查(全部来自不同的患者)组成,分为 5 个均匀分布的亚组(4 个病理组和 1 个健康受试者组),如下所述。
此外,每位患者都附带以下附加信息:体重、身高以及舒张期和收缩期瞬间。
https://acdc.creatis.insa-lyon.fr/description/databases.html

参考:Medical Image Segmentation: https://paperswithcode.com/task/medical-image-segmentation

医学图像分割综述 Medical Image Segmentation Using Deep Learning:A Survey

摘自:MFEI

Abstract

  • 深度学习已经广泛的应用于医疗影像分割领域,大量的论文记录了深度学习在该领域的成功
  • 本文中提出了关于深度学习医疗影像分割的综合专题调查
  • 本文主要有两项贡献
    • 与传统文献做对比
    • 本文关注的是监督和弱监督学习方法,不包括无监督方法。对于监督学习方法,我们从三个方面分析了文献:骨干网络的选择、网络块的设计和损失函数的改进。对于弱监督学习方法,我们分别根据数据增强、迁移学习和交互式分割来研究文献。

1 INTRODUCTION

图1 An overview of deep learning methods on medical image segmentation

  • 早期的医学图像分割方法往往依赖于边缘检测、模板匹配技术、统计形状模型、主动轮廓和机器学习等,虽然有大量的方法被报道并在某些情况下取得了成功,但由于特征表示和困难,图像分割仍然是计算机视觉领域中最具挑战性的课题之一,特别是从医学图像中提取鉴别特征比正常RGB图像更困难,因为普通RGB图像往往存在模糊、噪声、低对比度等问题。
  • 由于深度学习的快速发展,医学图像分割不再需要手工制作的特征,卷积神经网络成功的实现了图像的分层和特征表示,从而成为图像处理和计算机视觉中最热门的研究课题。由于用于特征学习的cnn对图像噪声、模糊、对比度等不敏感,它们为医学图像提供了良好的分割结果。
  • 目前图像分割任务有两类,语义分割和实例分割。语义分割是一种像素级分类,它为图像中的每个像素分配一个相应的类别。与语义分割相比,实例分割不仅需要实现像素级的分类,还需要根据特定的类别来区分实例。
  • 很少有应用于医疗影像分割的实力分割,因为每个器官和组织是很不同的。本文综述了深度学习技术在医疗图像分割方面的研究进展。
  • 监督学习的优点是可以基于精心标记的数据来训练模型,但很难获得大量的医学图像标记数据。无监督学习不需要标记数据,但学习的难度增加了。弱监督学习是在监督学习和无监督学习之间,因为它只需要一小部分标记的数据,大多数数据是未标记的。
  • 通过对以上调查的研究,研究者可以学习医学图像分割的最新技术,然后为计算机辅助诊断和智能医疗做出更重要的贡献。然而这些调查存在两个问题。
    • 1)大多按时间顺序总结了医学图像分割的发展,因此忽略了医学图像分割深度学习的技术分支。
    • 2)这些调查只介绍了相关的技术发展,而没有关注医学图像分割的任务特征,如少镜头学习、不平衡学习等,这限制了基于任务驱动的医学图像分割的改进。

为了解决这两个问题我们提出了一个新的Survey,在这项工作中我们的主要贡献如下:

  • 深度学习医疗影像分割技术从粗到细的分支,如图1所示
  • 对于监督学习的方法,我们从三个方面分析了文献:
    • 骨干网络的选择
    • 网络块的设计
    • 损失函数的改进

回顾了来自处理少镜头数据或类不平衡数据的三个方面的文献:数据增强、迁移学习和交互分割。

  • 收集了目前常见的公共医学图像分割数据集,最后我们讨论了这一领域的未来研究趋势和发展方向

2 SUPERVISED LEARNING

2 An overview of network architectures based on supervised learning.

A. Backbone Networks

研究人员提出了编码器-解码器架构,这是最流行的端到端体系结构之一,如FCN,U-Net,Deeplab等。这些结构中编码器通常用于提取图像特征,而解码器通常用于将提取的特征恢复到原始图像大小,并输出最终的分割结果。虽然端到端结构对于医学图像分割是实用的,但它降低了模型的可解释性。

  • U-Net


图3 U-Net architecture
U-Net解决了一般的CNN网络用于医学影响分割的问题,因为它采用了完美的对称结构和跳过连接。与普通的图像分割不同,医学图像通常包含噪声,边界模糊。因此仅依靠图像的低级特征,很难检测到医学图像中的物体或识别物体。同时,由于缺乏图像的细节信息,仅依靠图像的语义特征也不可能获得准确的边界。而U-Net通过跳跃连接结合低分辨率和高分辨率的特征图,有效地融合了低层次和高级层次的图像特征,是医学图像分割任务的完美解决方案。

  • 3D Net


图4 V-Net architecture
在实践中,由于CT和MRI图像等大多数医学数据都以三维体积数据的形式存在,因此使用三维卷积核可以更好地挖掘数据的高维空间相关性。基于这一想法,C¸ ic¸ek等人[34]将U-Net架构扩展到3D数据的应用中,并提出了直接处理3D医疗数据的3DU-Net。由于计算资源的限制,三维U-Net只包含3个下采样,不能有效地提取深层图像特征,导致对医学图像的分割精度有限。
此外,米列塔利等人提出了类似的结构,V-Net,如图4所示。众所周知,残差连接可以避免梯度的消失,加速网络的收敛速度,很容易设计出更深层次的网络结构,可以提供更好的特征表示。与3DU-Net相比,V-Net采用残差连接设计跟深层次的网络(4次下采样)从而获得更好的性能。
然而,由于大量的参数,这些3D网络也遇到了高计算成本和GPU内存使用的问题。

  • Recurrent Neural Network (RNN)


图5 Recurrent residual convolution unit
RNN最初被设计用于处理序列问题。长短期记忆(LSTM)网络[39]是最流行的rnn之一。通过引入自循环,它可以长时间保持梯度流动。在医学图像分割中,RNN已经被用来建模图像序列的时间依赖性。Alom等人[40]提出了一种结合ResUNet与RNN的医学图像分割方法。该方法实现了递归残差卷积层的特征积累,改进了图像分割任务的特征表示。图5为递归残差卷积单元。
显然,RNN可以通过考虑上下文信息关系来捕获图像的局部和全局空间特征。然而,在医学图像分割中,获取完整和有效的时间信息需要良好的医学图像质量(例如,较小的切片厚度和像素间距)。因此,RNN的设计对于提高医学图像分割的性能并不常见。

  • Skip Connection
    虽然skip connection可以融合低分辨率和高分辨率的信息,从而提高特征表示能力,但由于低分辨率和高分辨率特征之间的语义差距较大,导致特征映射模糊。为了改进skip connection,Ibtehaz等人[43]提出了包含Residual Path(ResPath)的MultiResUNet,这使得编码器特征在与解码器中的相应特征融合之前执行一些额外的卷积操作。Seo等人[44]提出mUNet,Chen等[45]提出FED-Net。mU-Net和FED-Net都在跳跃连接中添加了卷积操作,以提高医学图像分割的性能。
  • Cascade of 2D and 3D
    对于图像分割任务,级联模型通常训练两个或两个以上的模型来提高分割精度。该方法在医学图像分割中尤为流行。级联模型大致可分为三种框架类型
    • 粗-细分割
      • 它使用两个二维网络的级联进行分割,其中第一个网络进行粗分割,然后使用另一个网络模型基于之前的粗分割结果实现精细分割。
  • 检测分割
    • 首先使用R-CNN或者YOLO等网络模型进行目标位置识别,然后使用另一个网络基于之前的粗糙分割结果进行进一步的分割
  • 混合分割
    • 由于大多数医学图像是三维数据,二维卷积神经网络不能学习三维时间信息,而三维卷积神经网络往往需要较高的计算成本。所以一些伪三维的分割方法被提出。Oda等[58]提出了一种三平面的方法,从医学CT体积中有效地分割腹动脉区域。Vu等人[59]将相邻切片的叠加作为中心切片预测的输入,然后将得到的二维特征图输入标准的二维网络进行模型训练。虽然这些伪三维方法可以从三维体数据中分割对象,但由于利用了局部时间信息,它们只能获得有限的精度提高。
    • 与伪三维网络相比,混合级联二维三维网络更受欢迎。Li等人[60]提出了一种混合密集连接的U-Net(H-DenseUNet)用于肝脏和肝肿瘤的分割。该方法首先采用一个简单的Resnet获得一个粗糙的肝脏分割结果,利用二维DenseUNet有效地提取二维图像特征,然后利用三维数据集提取三维图像特征,最后设计一个混合特征融合层,共同优化二维和三维特征。
  • Others
    • GAN已经广泛应用于计算机视觉的多个领域。生成对抗的思想也被用于图像分割。但由于医学图像通常显示低对比度,不同组织之间或组织之间的边界和病变模糊,医学图像数据标签稀疏。Luc等[65]首先将生成对抗网络应用于图像分割,将生成网络用于分割模型,将对抗网络训练为分类器。
    • 结合有关器官形状和位置的先验知识可能对提高医学图像分割效果至关重要,在医学图像分割效果中,由于成像技术的限制,图像被损坏,因此包含了伪影。然而,关于如何将先验知识整合到CNN模型中的工作很少。Oktay等人[68]提出了一种新的通用方法,将形状和标签结构的先验知识结合到解剖约束神经网络(ACNN)中,用于医学图像分析任务。通过这种方式,神经网络的训练过程可以被约束和引导,以做出更解剖学和有意义的预测,特别是在输入图像数据信息不足或足够一致的情况下(例如,缺少对象边界)。上述研究表明由于在神经网络的训练过程中采用了先验知识约束,改进后的模型具有更高的分割精度,且具有更强的鲁棒性。

B. Network Function Block

  • Dense Connection


图6 Dense connection architecture
密集连接通常用于构造一种特殊的卷积神经网络。对于密集连接网络,每一层的输入来自前向传播过程中所有层的输出。受密集连接的启发,Guan等[70]提出了一种改进的U-Net,将它的每个子块替换为密集连接形式,如图6所示。虽然密集的连接有助于获得更丰富的图像特征,但它往往在一定程度上降低了特征表示的鲁棒性,增加了参数的数量。


图7 UNet++
Zhou等人[71]将所有U-Net层(从1层到4层)连接在一起,如图7所示。这种结构的优点是,它允许网络自动学习不同层的特征的重要性。并且对跳跃连接进行了重新设计,可以将具有不同语义尺度的特征聚合在解码器中,从而形成了一个高度灵活的特征融合方案。缺点是由于密集连接的使用,参数的数量增加了。因此,将一种剪枝方法集成到模型优化中,以减少参数的数量。

  • Inception


图8 Inception architecture
对于CNNs来说,深层网络往往比浅层网络具有更好的性能,但也会有梯度消失、难收敛、内存使用要求大等问题。Inception结构克服了这些问题,它在不增加网络深度的情况下并行合并卷积核,具有更好的性能。该结构能够利用多尺度卷积核提取更丰富的图像特征,并进行特征融合以获得更好的特征表示。
图8显示了inception的架构,它包含四个级联分支,随着无卷积次数的逐渐增加,从1到1、3和5,每个分支的接受域分别为3、7、9和19。因此,该网络可以从不同的尺度中提取特征。由于该架构比较复杂,导致模型修改困难

  • Depth Separability
    为了提高网络模型的泛化能力,减少对内存使用的需求,许多研究者将重点研究了复杂医学三维体数据的轻量级网络。
    Howard et.al[76]提出了移动网络将普通卷积分解为深度可分卷积和点态卷积。普通卷积运算的数量通常为DK×DK×M×N,其中M为输入特征映射的维数,N为输出特征映射的维数,DK为卷积核的大小。然而,信道卷积操作的次数为DK×DK×1×M,点卷积为1×1×M×N。与普通卷积相比,深度可分离卷积的计算代价是普通卷积的计算代价(1/N+1/D2K)倍。
    深度可分卷积是减少模型参数数量的一种有效方法,但它可能会导致医学图像分割精度的损失,因此需要采用其他方法(如深度监督)[78]来提高分割精度。
  • Attention Mechanism
    对于神经网络,attention block可以根据不同的重要性选择性地改变输入或给输入变量分配不同的权值。近年来,大多数结合深度学习和视觉注意机制的研究都集中在利用mask形成注意机制上。mask的原理是设计一个新的层,通过训练和学习从图像中识别出关键特征,然后让网络只关注图像中的有趣区域。
    • Local Spatial Attention


图9 The attention block in the attention U-Net
普通的pooling相当于信息合并,这很容易导致关键信息丢失。针对这个问题,设计了一个称为spatial transformer的块,通过执行空间变换来提取图像的关键信息。受此启发,Oktay等人[83]提出了attention U-Net。改进后的U-Net在融合来自编码器和相应的解码器的特征之前,使用一个注意块来改变编码器的输出。注意块输出门控信号来控制不同空间位置的像素的特征重要性。图9显示了该体系结构。这个块通过1×1卷积结合Relu和sigmoid函数,生成一个权重映射,通过与编码器的特征相乘来进行修正。

  • Channel Attention


图10 The channel attention in the SE-Net
通道注意力模块可以实现特征重新校准,利用学习到的全局信息,选择性地强调有用特征,抑制无用特征。
Hu等人[84]提出了SE-Net,将通道关注引入了图像分析领域,该方法通过三个步骤实现了对信道的注意力加权;图10显示了该体系结构。首先是压缩操作,对输入特征进行全局平均池化,得到1×1×通道特征图。第二种是激励操作,将信道特征相互作用以减少信道数,然后将减少后的信道特征重构回信道数。最后利用sigmoid函数生成[0,1]的特征权值映射,将尺度放回原始输入特征。

  • Mixture Attention
    空间注意机制和通道注意机制是改进特征表示的两种常用策略。然而,空间注意忽略了不同通道信息的差异,并平等地对待每个通道。相反,通道注意力直接汇集全局信息,而忽略每个通道中的局部信息,这是一个相对粗糙的操作。因此,结合两种注意机制的优势,研究者设计了许多基于mixed domain attention block的模型。
    Wang等人[86]在U-Net的收缩路径和扩展路径之间的中心瓶颈中嵌入了一个注意块,并提出了网格网。此外,他们还比较了通道注意、空间注意和两种注意的不同组合在医学图像分割中的表现。他们的结论是,以通道为中心的注意力是提高图像分割性能的最有效的方法。
    虽然上述的注意机制提高了最终的分割性能,但它们只执行局部卷积的操作。该操作侧重于相邻卷积核的区域,但忽略了全局信息。此外,降采样的操作会导致空间信息的丢失,这尤其不利于医学图像的分割。
  • Non-local Attention


图11 The global aggregation block in the Non-Local U-Net
最近,Wang等人[87]提出了一种Non-local U-Net来克服局部卷积的缺点。Non-local U-Net在上采样和下采样部分均采用自注意机制和全局聚合块提取全图像信息,提高最终分割精度,图11显示了global aggregation block 。Non-local block是一种通用块,可以很容易地嵌入到不同的卷积神经网络中,以提高其性能。
该注意机制对提高图像分割精度是有效的。事实上,空间注意寻找有趣的目标区域,而通道注意寻找有趣的特征。混合注意机制可以同时利用空间和渠道。然而,与非局部注意相比,传统的注意机制缺乏利用不同目标与特征之间关联的能力,因此基于非局部注意的cnn在图像分割任务中通常比正常的cnn具有更好的性能。

  • Multi-scale Information Fusion
    物体之间的大尺度范围是医学图像分割的挑战之一。例如,中晚期的肿瘤可能比早期的肿瘤要大得多。感知场的大小大致决定了我们可以使用多少上下文信息。一般的卷积或池化只使用单个内核,例如,一个3×3内核用于卷积,一个2×2内核用于池化。
    • Pyramid Pooling:多尺度池化的并行操作可以有效地改善网络的上下文信息,从而提取出更丰富的语义信息。He et al.[88]首先提出了spatial pyramid pooling(SPP)来实现多尺度特征提取。SPP将图像从细空间划分为粗空间,然后收集局部特征,提取多尺度特征。受SPP的启发,设计了一个多尺度信息提取块,并将其命名为multi-kernel pooling(RMP)[75],它使用四个不同大小的池内核对全局上下文信息进行编码。然而,RMP中的上采样操作不能由于池化而恢复细节信息的丢失,这通常会扩大接受域,但降低了图像的分辨率。
    • Atrous Spatial Pyramid Pooling:为了减少池化操作造成的详细信息损失,研究人员提出了atrous convolution而不是池化操作。与普通卷积相比,atrous convolution可以在不增加参数数量的情况下有效地扩大接受域。


图12 The gridding effect (the way of treating images as a chessboard causes the loss of information continuity).
然而,ASPP在图像分割方面存在两个严重的问题。第一个问题是局部信息的丢失,如图12所示,其中我们假设卷积核为3×3,三次迭代的膨胀率为2。第二个问题是,这些信息在很大的距离上可能是无关的。

  • Non-local and ASPP:


图13 The combination of ASPP and Non-local architecture
atrous convolution可以有效地扩大接受域,收集更丰富的语义信息,但由于网格效应,导致了细节信息的丢失。因此,有必要添加约束或建立像素关联来提高无效卷积性能。最近,Yang等人提出了[92]的ASPP和非局部组合块用于人体部位的分割,如图13所示。ASPP使用多个不同规模的并行无性卷积来捕获更丰富的信息,而非本地操作捕获了广泛的依赖关系。该组合具有ASPP和非局部化的优点,在医学图像分割方面具有良好的应用前景。


C. Loss Function

除了通过设计网络主干和函数块来提高分割速度和精度外,设计新的损失函数也可以改进分割精度

  • Cross Entropy Loss
    对于图像分割任务,交叉熵是最流行的损失函数之一。该函数将预测的类别向量和实际的分割结果向量进行像素级的比较。
  • Weighted Cross Entropy Loss
    交叉熵损失对图像平均处理每个像素,输出一个平均值,忽略类不平衡,导致损失函数依赖于包含最大像素数的类的问题。因此,交叉熵损失在小目标分割中的性能往往较低。为了解决类的不平衡的问题,Long等人[32]提出了加权交叉熵损失(WCE)来抵消类的不平衡。对于二值分割的情况,将加权交叉熵损失定义为


其中,β用于调整正样本和负样本的比例,它是一个经验值。如果是β>1,则假阴性的数量将会减少;事实上,交叉熵是加权交叉熵的一个特例,当β=1时,假阳性的数量就会减少。当β=1时。为了同时调整阳性和阴性样本的权重 的权重,我们可以使用平衡交叉熵 (BCE)损失函数,其定义为

  • Dice Loss
    Dice是一个流行的医学影像分割性能评价指标。这个指标本质上是分割结果与相应的真实值之间重叠的度量。Dice的值为0-1之间,计算公式为


其中A为预测分割结果,B为真实分割结果。

  • Tversky Loss
    Dice loss的正则化版本,以控制假阳性和假阴性对损失函数的贡献,TL被定义为


其中,p∈0, 1和0≤pˆ≤1。p和pˆ分别为地面真实值和预测分割。如果β=为0.5,则TL相当于Dice

  • Generalized Dice Loss
    Dice loss虽然一定程度上解决了分类失衡的问题,但却不利于严重的分类不平衡。例如小目标存在一些像素的预测误差,这很容易导致Dice的值发生很大的变化。Sudre等人提出了Generalized Dice Loss (GDL)


GDL优于Dice损失,因为不同的区域对损失有相似的贡献,并且GDL在训练过程中更稳定和鲁棒。

  • Boundary Loss
    为了解决类别不平衡的问题,Kervadec等人[95]提出了一种新的用于脑损伤分割的边界损失。该损失函数旨在最小化分割边界和标记边界之间的距离。作者在两个没有标签的不平衡数据集上进行了实验。结果表明,Dice los和Boundary los的组合优于单一组合。复合损失的定义为


其中第一部分是一个标准的Dice los,它被定义为


第二部分是Boundary los,它被定义为

  • Exponential Logarithmic Loss
    在(9)中,加权Dice los实际上是得到的Dice值除以每个标签的和,对不同尺度的对象达到平衡。因此,Wong等人结合focal loss [96] 和dice loss,提出了用于脑分割的指数对数损失(EXP损失),以解决严重的类不平衡问题。通过引入指数形式,可以进一步控制损失函数的非线性,以提高分割精度。EXP损失函数的定义为


其中,两个新的参数权重分别用ωdice和ωcross表示。Ldice是指数对数骰子损失,而交叉损失是交叉熵损失


其中x是像素位置,i是标签,l是位置x处的地面真值。pi(x)是从softmax输出的概率值。
在(17)中,fk是标签k出现的频率,该参数可以减少更频繁出现的标签的影响。γDice和γcross都用于增强损失函数的非线性。


3 WEAKLY SUPERVISED LEARNING

图14 The weakly supervised learning methods for medical image segmentation.

A. Data Augmentation

在缺乏大量标记数据集的情况下,数据增强是解决这一问题的有效解决方案,然而一般的数据扩展方法产生的图像与原始图像高度相关。与常用的数据增强方法相比,GAN是目前最流行的数据增强策略,因为GAN克服了对原始数据的依赖问题。

  • Traditional Methods
    一般的数据增强方法包括提高图像质量,如噪声抑制,亮度、饱和度、对比度等图像强度的变化,以及旋转、失真、缩放等图像布局的变化。传统数据增强中最常用的方法是参数变换(旋转、平移、剪切、位移、翻转等)。由于这种转换是虚拟的,没有计算成本,并且对医学图像的标注很困难,所以总是在每次训练之前进行。
  • Conditional Generative Adversarial Nets(cGAN)


图15 The cGAN architecture
原始GAN生成器可以学习数据的分布,但生成的图片是随机的,这意味着生成器的生成过程是一种非引导的状态。相比之下,cGAN在原始GAN中添加了一个条件,以指导G的生成过程。图15显示了cGAN的体系结构。
Guibas等人[107]提出了一个由GAN和cGAN组成的网络架构。将随机变量输入GAN,生成眼底血管标签的合成图像,然后将生成的标签图输入条件GAN,生成真实的视网膜眼底图像。最后,作者通过检查分类器是否能够区分合成图像和真实图像来验证合成图像的真实性
虽然cGAN生成的图像存在许多缺陷,如边界模糊和低分辨率,但cGAN为后来用于图像样式转换的CycleGAN和StarGAN提供了一个基本的思路。


B. Transfer Learning

通过利用模型的训练参数来初始化一个新的模型,迁移学习可以实现对有限标签数据的快速模型训练。一种方法是在ImageNet上微调预先训练好的模型,而另一种方法是对跨领域的数据进行迁移训练。

  • Pre-trained Model
    转移学习通常用于解决数据有限的问题在医学图像分析,一些研究人员发现,使用预先训练的网络自然图像如ImageNet编码器在U-Net-like网络,然后对医疗数据进行微调可以进一步提高医学图像的分割效果。
    在ImageNet上进行预训练的模型可以学习到医学图像和自然图像都需要的一些共同的基础特征,因此再训练过程是不必要的,而执行微调对训练模型是有用的。然而,当将预训练好的自然场景图像模型应用于医学图像分析任务时,领域自适应可能是一个问题。此外,由于预先训练好的模型往往依赖于二维图像数据集,因此流行的迁移学习方法很难适用于三维医学图像分析。如果带有注释的医疗数据集的数量足够大,那么就有可能这样做
  • Domain Adaptation


图16 The Cycle GAN architecture
如果训练目标域的标签不可用,而我们只能访问其他域的标签,那么流行的方法是将源域上训练好的分类器转移到没有标记数据的目标域。CycleGAN是一种循环结构,主要由两个生成器和两个鉴别器组成。图16为CycleGAN的体系结构。


C. Interactive Segmentation

手工绘制医学图像分割标签通常是繁琐而耗时的,特别是对于绘制三维体数据。交互式分割允许临床医生交互式地纠正由模型生成的初始分割图像,以获得更准确的分割。有效的交互式分割的关键是,临床医生可以使用交互式方法,如鼠标点击和轮廓框,来改进来自模型的初始分割结果。然后,该模型可以更新参数,生成新的分割图像,从临床医生那里获得新的反馈。

例:Wang等人[121]提出了利用两个神经网络级联的DeepIGeoS,对二维和三维医学图像进行交互分割。第一个CNN被称为P-Net,它输出一个粗糙的分割结果。在此基础上,用户提供交互点或短线来标记错误的分割区域,然后使用它们作为第二个CNNR-Net的输入,获得校正的结果。对二维胎儿MRI图像和三维脑肿瘤图像进行了实验,实验结果表明,与传统的图形切割、随机游走、ITK-Snap等交互式分割方法相比,DeepIGeoS大大减少了用户交互的需求,减少了用户时间。


D. Others Works

半监督学习可以使用一小部分已标记数据和任意数量的未标记数据来训练模型,它的损失函数通常由两个损失函数的和组成。第一个是仅与标记数据相关的监督损失函数。第二个是无监督损失函数或正则化项,与标记和未标记数据相关。

弱监督分割方法从边框或图像级标签或少量标注的图像数据中学习图像分割,而不是使用大量的像素级标注,以获得高质量的分割结果。事实上,少量的注释数据和大量的未注释数据更符合真实的临床情况。然而,在实践中,弱监督学习的性能很少能为医学图像分割任务提供可接受的结果,特别是对三维医学图像。因此,这是一个值得在未来探索的方向。


4 CURRENTLY POPULAR DIRECTION

A. Network Architecture Search

到目前为止,NAS[130]在提高图像分类精度方面取得了重大进展。NAS可以被认为是自动机器学习的一个子域,与超参数优化和元学习有很强的重叠。

大多数深度学习医疗影像分割依赖于U-Net网络,并根据不同的任务对网络结构进行一些改变,但在实际应用中,非网络结构因素可能对提高分割效果也有重要意义。

Isensee等人[136]认为,对网络结构进行过多的人工调整会导致对给定数据集的过拟合,因此提出了一种医学图像分割框架no-new-unet(nnU-Net),以适应任何新的数据集。nnUnet会根据给定数据集的属性自动调整所有超参数,而不需要手动干预。因此,nnU-Net只依赖于普通的2DUNet、3DUNet、UNet级联和一个鲁棒的训练方案。它侧重于预处理(重采样和归一化)、训练(损失、优化器设置、数据增强)、推理(基于补丁的策略、测试时间增强集成、模型集成等)的阶段,以及后处理(例如,增强的单通域)。在实际应用中,网络结构设计的改进通常依赖于没有足够的可解释性理论支持的经验,此外,更复杂的网络模型表明过拟合的风险更高。

为了对高分辨率的二维图像(如CT、MRI和组织病理学图像)进行实时图像分割,压缩神经网络模型的研究已成为医学图像分割的一个流行方向。NAS的应用可以有效地减少模型参数的数量,实现了较高的分割性能。尽管NAS的性能令人惊叹,但我们无法解释为什么特定架构的性能良好。因此,更好地理解对性能有重要影响的机制,以及探索这些特性是否可以推广到不同的任务,对于未来的研究也很重要。

B. Graph Convolutional Neural Network

GCN是研究非欧几里得域的强大工具之一。图是一种由节点和边组成的数据结构。早期的图神经网络(GNNs)主要处理严格的图形问题,如分子结构的分类。在实践中,欧几里得空间(如图像)或序列(如文本),以及许多常见的场景可以转换为图,可以使用GCN技术建模。

Gao等人设计了一种新的基于GCN的图池(gUnPool)和图解池(gUnpool)操作,并提出了一种编码-解码器模型,即graph U-Net。graph U-Net通过添加少量的参数,比流行的unet获得了更好的性能。与传统的深度卷积神经网络相比,当深度值超过4时,增加网络的深度并不能提高graph U-Net的性能。然而,当深度值小于或等于4时,图U-Net比流行的U-Net表现出更强的特征编码能力。

基于GCN的方法比传统的和最近的基于深度学习的方法提供了更好的性能和更强的鲁棒性。由于图结构具有较高的数据表示效率和较强的特征编码能力,因此其在医学图像分割中的结果很有前景。

C. Interpretable Shape Attentive Neural Network

目前,许多深度学习算法倾向于通过使用近似适合输入数据的“记忆”模型来做出判断。因此,这些算法不能被充分地解释,并为每个具体的预测提供令人信服的证据。因此,研究深度神经网络的可解释性是目前的一个热点。

Sun等人[142]提出了SAU-Net,重点关注模型的可解释性和鲁棒性。该架构试图通过使用二次形状流来解决医学图像中边缘分割精度较差的问题。特别是,形状流和规则的纹理流可以并行地捕获丰富的与形状相关的信息。此外,解码器还使用了空间注意机制和通道注意机制来解释模型在U-Net各分辨率下的学习能力。最后,通过提取学习到的形状和空间注意图,我们可以用15个方法来解释每个解码器块的高度激活区域。学习到的形状图可以用来推断由模型学习到的有趣类别的正确形状。SAU-Net能够通过门控形状流学习对象的鲁棒形状特征,并且通过使用注意力的内置显着性映射比以前的工作更容易解释。

Wickstrøm等人[143]探索了卷积神经网络中结直肠息肉语义分割的不确定性和可解释性,作者开发了用于解释网络梯度的引导反向传播[144]的中心思想。通过反向传播,得到输入中每个像素对应的梯度,使网络所考虑的特征能够可视化。在反向传播过程中,由于图像中梯度值大且正的像素需要得到高度的重视,而应抑制梯度值大且梯度值负的像素。如果这些负梯度包含在重要像素的可视化中,它们可能会导致描述性特征的噪声可视化。为了避免产生有噪声的可视化,引导反向传播过程改变了神经网络的反向传播,使每一层的负梯度设置为零,从而只允许正梯度向后流过网络并突出这些像素。

目前,医学图像分析的解释主要是采用注意力和类激活图(CAM)等可视化方法。因此,对医学图像分割深度学习可解释性的研究将是未来的热门方向。

D. Multi-modality Data Fusion

多模态数据融合可以提供更丰富的目标特征,有助于提高目标检测和分割结果,因此在医学图像分析中得到了广泛的应用。

虽然众所周知,多模态融合网络通常显示更好的性能比单模式网络分割任务,多模型融合导致一些新的问题,如如何设计多模式网络有效地结合不同的模式,如何利用不同模式之间的潜在关系,如何将多个信息集成到分割网络提高分割性能等。此外,将多模态数据融合集成到一个有效的单参数网络中,有助于简化部署,提高临床实践中模型的可用性。


5 DISCUSSION AND OUTLOOK

A. Medical Image Segmentation Datasets

B. Popular evaluation metrics

为了有效地衡量医学图像分割模型的性能,人们提出了大量的指标来评价分割的有效性。对图像分割性能的评价依赖于像素质量、区域质量和表面距离质量。

目前比较流行的指标有像素质量指标包括像素精度(PA)。区域质量指标包括Dice score、体积重叠误差(VOE)和相对体积差(RVD)。表面距离质量度量包括平均对称表面距离(ASD)和最大对称表面距离(MSD)。

  • PA
    像素精度只是找到正确分类的像素的比率,除以像素总数。对于K个+1类(K个前景类和背景),像素精度定义为:


其中,pij是第i类预测为属于第j类的像素数。

  • Dice score
    它是一种常用的图像分割度量方法(在医学图像分析中更常用),它可以定义为预测地图和地面真实地图重叠面积的两倍,除以两幅图像的像素总数。对Dice score的定义为:
  • VOE
    它是Jaccard index的补充,其定义为:
  • RVD
    它是一种非对称度量,定义为:
  • ASD
    表面距离度量是参考和预测病变的表面距离的相关度量。
    设S(A)表示a的表面体素集合。任意体素v到S(A)的最短距离定义为:


ASD is defined as:

  • MSD
    它也被称为对称豪斯多夫距离,与ASD相似,但取的最大距离而不是平均值:

本文所有图片公式均来自论文原文

扩散模型DDPM

摘自:https://zhuanlan.zhihu.com/p/563661713

“What I cannot create, I do not understand.” — Richard Feynman

https://github.com/xiaohu2015/nngen/tree/main/models/diffusion_models

论文:https://arxiv.org/abs/2006.11239

近段时间最火的方向无疑是基于文本用AI生成图像,继OpenAI在2021提出的文本转图像模型DALLE之后,越来越多的大公司卷入这个方向,如谷歌在今年相继推出了ImagenParti。一些主流的文本转图像模型如DALL·E 2,stable-diffusion和Imagen采用了扩散模型Diffusion Model)作为图像生成模型,这也引发了对扩散模型的研究热潮。相比GAN来说,扩散模型训练更稳定,而且能够生成更多样的样本,OpenAI的论文Diffusion Models Beat GANs on Image Synthesis也证明了扩散模型能够超越GAN。简单来说,扩散模型包含两个过程:前向扩散过程反向生成过程,前向扩散过程是对一张图像逐渐添加高斯噪音直至变成随机噪音,而反向生成过程是去噪音过程,我们将从一个随机噪音开始逐渐去噪音直至生成一张图像,这也是我们要求解或者训练的部分。扩散模型与其它主流生成模型的对比如下所示:

目前所采用的扩散模型大都是来自于2020年的工作DDPM: Denoising Diffusion Probabilistic Models,DDPM对之前的扩散模型(具体见Deep Unsupervised Learning using Nonequilibrium Thermodynamics)进行了简化,并通过变分推断(variational inference)来进行建模,这主要是因为扩散模型也是一个隐变量模型(latent variable model),相比VAE这样的隐变量模型,扩散模型的隐变量是和原始数据是同维度的,而且推理过程(即扩散过程)往往是固定的。这篇文章将基于DDPM详细介绍扩散模型的原理,并给出具体的代码实现和分析。

扩散模型原理

扩散模型包括两个过程:前向过程(forward process)反向过程(reverse process),其中前向过程又称为为扩散过程(diffusion process),如下图所示。无论是前向过程还是反向过程都是一个参数化的马尔可夫链(Markov chain),其中反向过程可以用来生成数据,这里我们将通过变分推断来进行建模和求解。

扩散过程

扩散过程是指的对数据逐渐增加高斯噪音直至数据变成随机噪音的过程。对于原始数据

,总共包含T步的扩散过程的每一步都是对上一步得到的数据xt-1按如下方式增加高斯噪音:

这里{βt}t=1~T为每一步所采用的方差,它介于0~1之间。对于扩散模型,我们往往称不同step的方差设定为variance schedule或者noise schedule,通常情况下,越后面的step会采用更大的方差,即满足β1<β2<⋯<βT。在一个设计好的variance schedule下,的如果扩散步数T足够大,那么最终得到的xT就完全丢失了原始数据而变成了一个随机噪音。 扩散过程的每一步都生成一个带噪音的数据xt,整个扩散过程也就是一个马尔卡夫链

另外要指出的是, 扩散过程往往是固定的, 即采用一个预先定义好的variance schedule, 比 如DDPM就采用一个线性的variance schedule。扩散过程的一个重要特性是我们可以直接基 于原始数据 \(\mathbf{x}0\) 来对任意 \(t\)步的 \(\mathbf{x}_t\) 进行采样: \(\mathbf{x}_t \sim q\left(\mathbf{x}_t \mid \mathbf{x}_0\right)\) 。这里定义 \(\alpha_t=1-\beta_t\) 和 \(\bar{\alpha}_t=\prod{i=1}^t \alpha_i\) , 通过重参数技巧(和VAE类似), 那么有:

上述推到过程利用了两个方差不同的高斯分布\(\mathcal{N}\left(\mathbf{0}, \sigma_1^2 \mathbf{I}\right)\) 和 \(\mathcal{N}\left(\mathbf{0}, \sigma_2^2 \mathbf{I}\right)\) 相加等于一个新的高斯分 布 \(\mathcal{N}\left(\mathbf{0},\left(\sigma_1^2+\sigma_2^2\right) \mathbf{I}\right)\) 。反重参数化后, 我们得到:
\[
q\left(\mathbf{x}_t \mid \mathbf{x}_0\right)=\mathcal{N}\left(\mathbf{x}_t ; \sqrt{\bar{\alpha}_t} \mathbf{x}_0,\left(1-\bar{\alpha}_t\right) \mathbf{I}\right)
\]
扩散过程的这个特性很重要。首先, 我们可以看到 \(\mathbf{x}_t\) 其实可以看成是原始数据 \(\mathbf{x}_0\) 和随机噪音 \(\epsilon\) 的线性组合, 其中\(\sqrt{\bar{\alpha}_t}\) 和 \(\sqrt{1-\bar{\alpha}_t}\) 为组合系数, 它们的平方和等于 1 , 我们也可以称两者分别 为 signal_rate 和 noise_rate (见https://keras.io/examples/generative/ddim/#diffusionschedule和Variational Diffusion Models)。更近一步地,我们可以基于 \(\bar{\alpha}_t\) 而不是 \(\beta_t\) 来定义 noise schedule (见Improved Denoising Diffusion Probabilistic Models所设计的cosine schedule), 因为这样处理更直接, 比如我们直接将 \(\bar{\alpha}_T\) 设定为一个接近0的值, 那么就可以保 证最终得到的 \(\mathbf{x}_T\) 近似为一个随机噪音。其次, 后面的建模和分析过程将使用这个特性。

反向过程

扩散过程是将数据噪音化,那么反向过程就是一个去噪的过程,如果我们知道反向过程的每一步的真实分布q(xt−1|xt),那么从一个随机噪音xT∼N(0,I)开始,逐渐去噪就能生成一个真实的样本,所以反向过程也就是生成数据的过程

估计分布 \(q\left(\mathbf{x}{t-1} \mid \mathbf{x}_t\right)\) 需要用到整个训练样本, 我们可以用神经网络来估计这些分布。这里, 我们将反向过程也定义为一个马尔卡夫链, 只不过它是由一系列用神经网络参数化的高斯分布来组成:

\[p\theta\left(\mathbf{x}{0: T}\right)=p\left(\mathbf{x}_T\right) \prod{t=1}^T p_\theta\left(\mathbf{x}{t-1} \mid \mathbf{x}_t\right) \quad p\theta\left(\mathbf{x}{t-1} \mid \mathbf{x}_t\right)=\mathcal{N}\left(\mathbf{x}{t-1} ; \boldsymbol{\mu}\theta\left(\mathbf{x}_t, t\right), \mathbf{\Sigma}\theta\left(\mathbf{x}t, t\right)\right)\]

这里 \(p\left(\mathbf{x}_T\right)=\mathcal{N}\left(\mathbf{x}_T ; \mathbf{0}, \mathbf{I}\right)\), 而 \(p\theta\left(\mathbf{x}{t-1} \mid \mathbf{x}_t\right)\) 为参数化的高斯分布, 它们的均值和方差由训练的网络 \(\boldsymbol{\mu}\theta\left(\mathbf{x}t, t\right)\) 和 \(\boldsymbol{\Sigma}\theta\left(\mathbf{x}t, t\right)\) 给出。实际上, 扩散模型就是要得到这些训练好的网络, 因为它们构 成了最终的生成模型。虽然分布 \(q\left(\mathbf{x}{t-1} \mid \mathbf{x}t\right)\) 是不可直接处理的, 但是加上条件\(\mathbf{x}_0\) 的后验分布 \(q\left(\mathbf{x}{t-1} \mid \mathbf{x}t, \mathbf{x}_0\right)\) 却是可处理的, 这里有:

\[q\left(\mathbf{x}{t-1} \mid \mathbf{x}t, \mathbf{x}_0\right)=\mathcal{N}\left(\mathbf{x}{t-1} ; \tilde{\boldsymbol{\mu}}\left(\mathbf{x}_t, \mathbf{x}_0\right), \tilde{\beta}_t \mathbf{I}\right)
\]

下面我们来具体推导这个分布,首先根据贝叶斯公式,我们有:

由于扩散过程的马尔卡夫链特性,我们知道分布

,而由前面得到的扩散过程特性可知:

所以,我们有:

这里的 \(C\left(\mathbf{x}t, \mathbf{x}_0\right)\) 是一个和 \(\mathbf{x}{t-1}\) 无关的部分,所以省略。根据高斯分布的概率密度函数定义和上 述结果 (配平方),我们可以得到后验分布 \(q\left(\mathbf{x}t \mid \mathbf{x}{t-1}, \mathbf{x}0\right)\) 的均值和方差:


可以看到方差是一个定量 (扩散过程参数固定),而均值是一个依赖 \(\mathbf{x}_0\) 和 \(\mathbf{x}_t\) 的函数。这个分布将 会被用于推导扩散模型的优化目标。

优化目标

上面介绍了扩散模型的扩散过程和反向过程,现在我们来从另外一个角度来看扩散模型:如果我们把中间产生的变量看成隐变量的话,那么扩散模型其实是包含T个隐变量的隐变量模型(latent variable model),它可以看成是一个特殊的Hierarchical VAEs(见Understanding Diffusion Models: A Unified Perspective):

相比VAE来说,扩散模型的隐变量是和原始数据同维度的,而且encoder(即扩散过程)是固定的。既然扩散模型是隐变量模型,那么我们可以就可以基于变分推断来得到variational lower boundVLB,又称ELBO)作为最大化优化目标,这里有:

这里最后一步是利用了Jensen’s inequality(不采用这个不等式的推导见博客What are Diffusion Models?),对于网络训练来说,其训练目标为VLB取负

我们近一步对训练目标进行分解可得:

可以看到最终的优化目标共包含 \(T+1\) 项,其中 \(L_0\) 可以看成是原始数据重建,优化的是负对数似然, \(L_0\) 可以用估计的 \(\mathcal{N}\left(\mathbf{x}0 ; \boldsymbol{\mu}\theta\left(\mathbf{x}1, 1\right), \mathbf{\Sigma}\theta\left(\mathbf{x}1, 1\right)\right)\) 来构建一个离散化的decoder来计算(见 DDPM论文3.3部分);而 \(L_T\) 计算的是最后得到的噪音的分布和先验分布的KL散度,这个KL散度没有训练参数,近似为 0 ,因为先验 \(p\left(\mathbf{x}_T\right)=\mathcal{N}(\mathbf{0}, \mathbf{I})\) 而扩散过程最后得到的随机噪音 \(q\left(\mathbf{x}_T \mid \mathbf{x}_0\right)\) 也近似为 \(\mathcal{N}(\mathbf{0}, \mathbf{I})\) ;而 \(L{t-1}\) 则是计算的是估计分布 \(p_\theta\left(\mathbf{x}{t-1} \mid \mathbf{x}_t\right)\) 和真实后验分布 \(q\left(\mathbf{x}{t-1} \mid \mathbf{x}_t, \mathbf{x}_0\right)\) 的KL散度,这里希望䇝们估计的去噪过程和依赖真实数据的去噪过程近似一致:

之所以前面我们将 \(p_\theta\left(\mathbf{x}{t-1} \mid \mathbf{x}_t\right)\) 定义为一个用网络参数化的高斯分布 \(\mathcal{N}\left(\mathbf{x}{t-1} ; \boldsymbol{\mu}\theta\left(\mathbf{x}_t, t\right), \mathbf{\Sigma}\theta\left(\mathbf{x}t, t\right)\right)\), 是因为要匹配的后验分布 \(q\left(\mathbf{x}{t-1} \mid \mathbf{x}t, \mathbf{x}_0\right)\)也是一个高斯分布。对 于训练目标 \(L_0\) 和 \(L{t-1}\) 来说, 都是希望得到训练好的网络 \(\boldsymbol{\mu}\theta\left(\mathbf{x}_t, t\right)\) 和 \(\boldsymbol{\Sigma}\theta\left(\mathbf{x}t, t\right)\) (对于 \(L_0, t=1\) )。DDPM对 \(p\theta\left(\mathbf{x}{t-1} \mid \mathbf{x}_t\right)\) 做了近一步简化, 采用周定的方差: \(\boldsymbol{\Sigma}\theta\left(\mathbf{x}t, t\right)=\sigma_t^2 \mathbf{I}\), 这里的 \(\sigma_t^2\) 可以 设定为 \(\beta_t\) 或者 \(\tilde{\beta}_t\) (这其实是两个极端, 分别是上限和下限, 也可以采用可训练的方差, 见论文 Improved Denoising Diffusion Probabilistic Models 和Analytic-DPM: an Analytic Estimate of the Optimal Reverse Variance in Diffusion Probabilistic Models)。这里假定 \(\sigma_t^2=\tilde{\beta}_t\), 那么:

\[q\left(\mathbf{x}{t-1} \mid \mathbf{x}t, \mathbf{x}_0\right)=\mathcal{N}\left(\mathbf{x}{t-1} ; \tilde{\boldsymbol{\mu}}\left(\mathbf{x}t, \mathbf{x}_0\right), \sigma_t^2 \mathbf{I}\right) p\theta\left(\mathbf{x}{t-1} \mid \mathbf{x}_t\right)=\mathcal{N}\left(\mathbf{x}{t-1} ; \boldsymbol{\mu}_\theta\left(\mathbf{x}_t, t\right), \sigma_t^2 \mathbf{I}\right)
\]
对于两个高斯分布的KL散度, 其计算公式为(具体推导见生成模型之VAE):

那么就有:

那么优化目标即\(L{t-1}\)为:

从上述公式来看, 我们是希望网络学习到的均值 \(\boldsymbol{\mu}\theta\left(\mathbf{x}_t, t\right)\) 和后验分布的均值 \(\tilde{\boldsymbol{\mu}}\left(\mathbf{x}_t, \mathbf{x}_0\right)\) 一致。不 过DDPM发现预测均值并不是最好的选择。根据前面得到的扩散过程的特性, 我们有:

\(\mathbf{x}{\mathbf{t}}\left(\mathbf{x}_{\mathbf{0}}, \epsilon\right)=\sqrt{\bar{\alpha}_t} \mathbf{x}_0+\sqrt{1-\bar{\alpha}_t \epsilon} \quad \text { where } \epsilon \sim \mathcal{N}(\mathbf{0}, \mathbf{I})
\)

将这个公式带入上述优化目标,可以得到:

近一步地, 我们对 \(\boldsymbol{\mu}\theta\left(\mathbf{x}{\mathbf{t}}\left(\mathbf{x}0, \epsilon\right), t\right)\) 也进行重参数化, 变成:

\[\boldsymbol{\mu}\theta\left(\mathbf{x}{\mathbf{t}}\left(\mathbf{x}_0, \epsilon\right), t\right)=\frac{1}{\sqrt{\alpha_t}}\left(\mathbf{x}_t\left(\mathbf{x}_0, \epsilon\right)-\frac{\beta_t}{\sqrt{1-\bar{\alpha}_t}} \epsilon\theta\left(\mathbf{x}t\left(\mathbf{x}_0, \epsilon\right), t\right)\right)\]

这里的 \(\epsilon\theta\) 是一个基于神经网络的拟合函数, 这意味着我们由原来的预测均值而换成预测噪音 \(\epsilon\) 。我们将上述等式带入优化目标, 可以得到:

DDPM近一步对上述目标进行了简化, 即去掉了权重系数, 变成了: \(L{t-1}^{\text {simple }}=\mathbb{E}{\mathbf{x}_0, \epsilon \sim \mathcal{N}(0, \mathrm{I})}\left[\left|\epsilon-\epsilon\theta\left(\sqrt{\bar{\alpha}_t} \mathbf{x}_0+\sqrt{1-\bar{\alpha}_t} \epsilon, t\right)\right|^2\right]\) 这里的 \(t\) 在 \([1, \mathrm{~T}]\) 范围内取值(如前所述, 其中取 1 时对应 \(L_0\) )。由于去掉了不同 \(t\)的权重系数, 所以这个简化的目标其实是VLB优化 目标进行了 reweight。从DDPM的对比实验结果来看, 预测噪音比预测均值效果要好, 采用简 化版本的优化目标比VLB目标效果要好:

虽然扩散模型背后的推导比较复杂,但是我们最终得到的优化目标非常简单,就是让网络预测的噪音和真实的噪音一致。DDPM的训练过程也非常简单,如下图所示:随机选择一个训练样本->从1-T随机抽样一个t->随机产生噪音-计算当前所产生的带噪音数据(红色框所示)->输入网络预测噪音->计算产生的噪音和预测的噪音的L2损失->计算梯度并更新网络。

一旦训练完成,其采样过程也非常简单,如上所示:我们从一个随机噪音开始,并用训练好的网络预测噪音,然后计算条件分布的均值(红色框部分),然后用均值加标准差乘以一个随机噪音,直至t=0完成新样本的生成(最后一步不加噪音)。不过实际的代码实现和上述过程略有区别(见https://github.com/hojonathanho/diffusion/issues/5:先基于预测的噪音生成,并进行了clip处理(范围[-1, 1],原始数据归一化到这个范围),然后再计算均值。我个人的理解这应该算是一种约束,既然模型预测的是噪音,那么我们也希望用预测噪音重构处理的原始数据也应该满足范围要求。

模型设计

前面我们介绍了扩散模型的原理以及优化目标,那么扩散模型的核心就在于训练噪音预测模型,由于噪音和原始数据是同维度的,所以我们可以选择采用AutoEncoder架构来作为噪音预测模型。DDPM所采用的模型是一个基于residual block和attention block的U-Net模型。如下所示:

U-Net属于encoder-decoder架构,其中encoder分成不同的stages,每个stage都包含下采样模块来降低特征的空间大小(H和W),然后decoder和encoder相反,是将encoder压缩的特征逐渐恢复。U-Net在decoder模块中还引入了skip connection,即concat了encoder中间得到的同维度特征,这有利于网络优化。DDPM所采用的U-Net每个stage包含2个residual block,而且部分stage还加入了self-attention模块增加网络的全局建模能力。 另外,扩散模型其实需要的是个噪音预测模型,实际处理时,我们可以增加一个time embedding(类似transformer中的position embedding)来将timestep编码到网络中,从而只需要训练一个共享的U-Net模型。具体地,DDPM在各个residual block都引入了time embedding,如上图所示。

代码实现

最后,我们基于PyTorch框架给出DDPM的具体实现,这里主要参考了三套代码实现:

首先,是time embeding,这里是采用Attention Is All You Need中所设计的sinusoidal position embedding,只不过是用来编码timestep:

# use sinusoidal position embedding to encode time step (https://arxiv.org/abs/1706.03762)   
def timestep_embedding(timesteps, dim, max_period=10000):
    """
    Create sinusoidal timestep embeddings.
    :param timesteps: a 1-D Tensor of N indices, one per batch element.
                      These may be fractional.
    :param dim: the dimension of the output.
    :param max_period: controls the minimum frequency of the embeddings.
    :return: an [N x dim] Tensor of positional embeddings.
    """
    half = dim // 2
    freqs = torch.exp(
        -math.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32) / half
    ).to(device=timesteps.device)
    args = timesteps[:, None].float() * freqs[None]
    embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
    if dim % 2:
        embedding = torch.cat([embedding, torch.zeros_like(embedding[:, :1])], dim=-1)
    return embedding

由于只有residual block才引入time embedding,所以可以定义一些辅助模块来自动处理,如下所示:

# define TimestepEmbedSequential to support `time_emb` as extra input
class TimestepBlock(nn.Module):
    """
    Any module where forward() takes timestep embeddings as a second argument.
    """

    @abstractmethod
    def forward(self, x, emb):
        """
        Apply the module to `x` given `emb` timestep embeddings.
        """


class TimestepEmbedSequential(nn.Sequential, TimestepBlock):
    """
    A sequential module that passes timestep embeddings to the children that
    support it as an extra input.
    """

    def forward(self, x, emb):
        for layer in self:
            if isinstance(layer, TimestepBlock):
                x = layer(x, emb)
            else:
                x = layer(x)
        return x

这里所采用的U-Net采用GroupNorm进行归一化,所以这里也简单定义了一个norm layer以方便使用:

# use GN for norm layer
def norm_layer(channels):
    return nn.GroupNorm(32, channels)

U-Net的核心模块是residual block,它包含两个卷积层以及shortcut,同时也要引入time embedding,这里额外定义了一个linear层来将time embedding变换为和特征维度一致,第一conv之后通过加上time embedding来编码time:

# Residual block
class ResidualBlock(TimestepBlock):
    def __init__(self, in_channels, out_channels, time_channels, dropout):
        super().__init__()
        self.conv1 = nn.Sequential(
            norm_layer(in_channels),
            nn.SiLU(),
            nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1)
        )
        
        # pojection for time step embedding
        self.time_emb = nn.Sequential(
            nn.SiLU(),
            nn.Linear(time_channels, out_channels)
        )
        
        self.conv2 = nn.Sequential(
            norm_layer(out_channels),
            nn.SiLU(),
            nn.Dropout(p=dropout),
            nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1)
        )

        if in_channels != out_channels:
            self.shortcut = nn.Conv2d(in_channels, out_channels, kernel_size=1)
        else:
            self.shortcut = nn.Identity()


    def forward(self, x, t):
        """
        `x` has shape `[batch_size, in_dim, height, width]`
        `t` has shape `[batch_size, time_dim]`
        """
        h = self.conv1(x)
        # Add time step embeddings
        h += self.time_emb(t)[:, :, None, None]
        h = self.conv2(h)
        return h + self.shortcut(x)

这里还在部分residual block引入了attention,这里的attention和transformer的self-attention是一致的:

# Attention block with shortcut
class AttentionBlock(nn.Module):
    def __init__(self, channels, num_heads=1):
        super().__init__()
        self.num_heads = num_heads
        assert channels % num_heads == 0
        
        self.norm = norm_layer(channels)
        self.qkv = nn.Conv2d(channels, channels * 3, kernel_size=1, bias=False)
        self.proj = nn.Conv2d(channels, channels, kernel_size=1)

    def forward(self, x):
        B, C, H, W = x.shape
        qkv = self.qkv(self.norm(x))
        q, k, v = qkv.reshape(B*self.num_heads, -1, H*W).chunk(3, dim=1)
        scale = 1. / math.sqrt(math.sqrt(C // self.num_heads))
        attn = torch.einsum("bct,bcs->bts", q * scale, k * scale)
        attn = attn.softmax(dim=-1)
        h = torch.einsum("bts,bcs->bct", attn, v)
        h = h.reshape(B, -1, H, W)
        h = self.proj(h)
        return h + x

对于上采样模块和下采样模块,其分别可以采用插值和stride=2的conv或者pooling来实现:

# upsample
class Upsample(nn.Module):
    def __init__(self, channels, use_conv):
        super().__init__()
        self.use_conv = use_conv
        if use_conv:
            self.conv = nn.Conv2d(channels, channels, kernel_size=3, padding=1)

    def forward(self, x):
        x = F.interpolate(x, scale_factor=2, mode="nearest")
        if self.use_conv:
            x = self.conv(x)
        return x

# downsample
class Downsample(nn.Module):
    def __init__(self, channels, use_conv):
        super().__init__()
        self.use_conv = use_conv
        if use_conv:
            self.op = nn.Conv2d(channels, channels, kernel_size=3, stride=2, padding=1)
        else:
            self.op = nn.AvgPool2d(stride=2)

    def forward(self, x):
        return self.op(x)

上面我们实现了U-Net的所有组件,就可以进行组合来实现U-Net了:

 The full UNet model with attention and timestep embedding
class UNetModel(nn.Module):
    def __init__(
        self,
        in_channels=3,
        model_channels=128,
        out_channels=3,
        num_res_blocks=2,
        attention_resolutions=(8, 16),
        dropout=0,
        channel_mult=(1, 2, 2, 2),
        conv_resample=True,
        num_heads=4
    ):
        super().__init__()

        self.in_channels = in_channels
        self.model_channels = model_channels
        self.out_channels = out_channels
        self.num_res_blocks = num_res_blocks
        self.attention_resolutions = attention_resolutions
        self.dropout = dropout
        self.channel_mult = channel_mult
        self.conv_resample = conv_resample
        self.num_heads = num_heads
        
        # time embedding
        time_embed_dim = model_channels * 4
        self.time_embed = nn.Sequential(
            nn.Linear(model_channels, time_embed_dim),
            nn.SiLU(),
            nn.Linear(time_embed_dim, time_embed_dim),
        )
        
        # down blocks
        self.down_blocks = nn.ModuleList([
            TimestepEmbedSequential(nn.Conv2d(in_channels, model_channels, kernel_size=3, padding=1))
        ])
        down_block_chans = [model_channels]
        ch = model_channels
        ds = 1
        for level, mult in enumerate(channel_mult):
            for _ in range(num_res_blocks):
                layers = [
                    ResidualBlock(ch, mult * model_channels, time_embed_dim, dropout)
                ]
                ch = mult * model_channels
                if ds in attention_resolutions:
                    layers.append(AttentionBlock(ch, num_heads=num_heads))
                self.down_blocks.append(TimestepEmbedSequential(*layers))
                down_block_chans.append(ch)
            if level != len(channel_mult) - 1: # don't use downsample for the last stage
                self.down_blocks.append(TimestepEmbedSequential(Downsample(ch, conv_resample)))
                down_block_chans.append(ch)
                ds *= 2
        
        # middle block
        self.middle_block = TimestepEmbedSequential(
            ResidualBlock(ch, ch, time_embed_dim, dropout),
            AttentionBlock(ch, num_heads=num_heads),
            ResidualBlock(ch, ch, time_embed_dim, dropout)
        )
        
        # up blocks
        self.up_blocks = nn.ModuleList([])
        for level, mult in list(enumerate(channel_mult))[::-1]:
            for i in range(num_res_blocks + 1):
                layers = [
                    ResidualBlock(
                        ch + down_block_chans.pop(),
                        model_channels * mult,
                        time_embed_dim,
                        dropout
                    )
                ]
                ch = model_channels * mult
                if ds in attention_resolutions:
                    layers.append(AttentionBlock(ch, num_heads=num_heads))
                if level and i == num_res_blocks:
                    layers.append(Upsample(ch, conv_resample))
                    ds //= 2
                self.up_blocks.append(TimestepEmbedSequential(*layers))

        self.out = nn.Sequential(
            norm_layer(ch),
            nn.SiLU(),
            nn.Conv2d(model_channels, out_channels, kernel_size=3, padding=1),
        )

    def forward(self, x, timesteps):
        """
        Apply the model to an input batch.
        :param x: an [N x C x H x W] Tensor of inputs.
        :param timesteps: a 1-D batch of timesteps.
        :return: an [N x C x ...] Tensor of outputs.
        """
        hs = []
        # time step embedding
        emb = self.time_embed(timestep_embedding(timesteps, self.model_channels))
        
        # down stage
        h = x
        for module in self.down_blocks:
            h = module(h, emb)
            hs.append(h)
        # middle stage
        h = self.middle_block(h, emb)
        # up stage
        for module in self.up_blocks:
            cat_in = torch.cat([h, hs.pop()], dim=1)
            h = module(cat_in, emb)
        return self.out(h)

对于扩散过程,其主要的参数就是timesteps和noise schedule,DDPM采用范围为[0.0001, 0.02]的线性noise schedule,其默认采用的总扩散步数为1000

# beta schedule
def linear_beta_schedule(timesteps):
    scale = 1000 / timesteps
    beta_start = scale * 0.0001
    beta_end = scale * 0.02
    return torch.linspace(beta_start, beta_end, timesteps, dtype=torch.float64)

我们定义个扩散模型,它主要要提前根据设计的noise schedule来计算一些系数,并实现一些扩散过程和生成过程:

class GaussianDiffusion:
    def __init__(
        self,
        timesteps=1000,
        beta_schedule='linear'
    ):
        self.timesteps = timesteps
        
        if beta_schedule == 'linear':
            betas = linear_beta_schedule(timesteps)
        elif beta_schedule == 'cosine':
            betas = cosine_beta_schedule(timesteps)
        else:
            raise ValueError(f'unknown beta schedule {beta_schedule}')
        self.betas = betas
            
        self.alphas = 1. - self.betas
        self.alphas_cumprod = torch.cumprod(self.alphas, axis=0)
        self.alphas_cumprod_prev = F.pad(self.alphas_cumprod[:-1], (1, 0), value=1.)
        
        # calculations for diffusion q(x_t | x_{t-1}) and others
        self.sqrt_alphas_cumprod = torch.sqrt(self.alphas_cumprod)
        self.sqrt_one_minus_alphas_cumprod = torch.sqrt(1.0 - self.alphas_cumprod)
        self.log_one_minus_alphas_cumprod = torch.log(1.0 - self.alphas_cumprod)
        self.sqrt_recip_alphas_cumprod = torch.sqrt(1.0 / self.alphas_cumprod)
        self.sqrt_recipm1_alphas_cumprod = torch.sqrt(1.0 / self.alphas_cumprod - 1)
        
        # calculations for posterior q(x_{t-1} | x_t, x_0)
        self.posterior_variance = (
            self.betas * (1.0 - self.alphas_cumprod_prev) / (1.0 - self.alphas_cumprod)
        )
        # below: log calculation clipped because the posterior variance is 0 at the beginning
        # of the diffusion chain
        self.posterior_log_variance_clipped = torch.log(self.posterior_variance.clamp(min =1e-20))
        
        self.posterior_mean_coef1 = (
            self.betas * torch.sqrt(self.alphas_cumprod_prev) / (1.0 - self.alphas_cumprod)
        )
        self.posterior_mean_coef2 = (
            (1.0 - self.alphas_cumprod_prev)
            * torch.sqrt(self.alphas)
            / (1.0 - self.alphas_cumprod)
        )
    
    # get the param of given timestep t
    def _extract(self, a, t, x_shape):
        batch_size = t.shape[0]
        out = a.to(t.device).gather(0, t).float()
        out = out.reshape(batch_size, *((1,) * (len(x_shape) - 1)))
        return out
    
    # forward diffusion (using the nice property): q(x_t | x_0)
    def q_sample(self, x_start, t, noise=None):
        if noise is None:
            noise = torch.randn_like(x_start)

        sqrt_alphas_cumprod_t = self._extract(self.sqrt_alphas_cumprod, t, x_start.shape)
        sqrt_one_minus_alphas_cumprod_t = self._extract(self.sqrt_one_minus_alphas_cumprod, t, x_start.shape)

        return sqrt_alphas_cumprod_t * x_start + sqrt_one_minus_alphas_cumprod_t * noise
    
    # Get the mean and variance of q(x_t | x_0).
    def q_mean_variance(self, x_start, t):
        mean = self._extract(self.sqrt_alphas_cumprod, t, x_start.shape) * x_start
        variance = self._extract(1.0 - self.alphas_cumprod, t, x_start.shape)
        log_variance = self._extract(self.log_one_minus_alphas_cumprod, t, x_start.shape)
        return mean, variance, log_variance
    
    # Compute the mean and variance of the diffusion posterior: q(x_{t-1} | x_t, x_0)
    def q_posterior_mean_variance(self, x_start, x_t, t):
        posterior_mean = (
            self._extract(self.posterior_mean_coef1, t, x_t.shape) * x_start
            + self._extract(self.posterior_mean_coef2, t, x_t.shape) * x_t
        )
        posterior_variance = self._extract(self.posterior_variance, t, x_t.shape)
        posterior_log_variance_clipped = self._extract(self.posterior_log_variance_clipped, t, x_t.shape)
        return posterior_mean, posterior_variance, posterior_log_variance_clipped
    
    # compute x_0 from x_t and pred noise: the reverse of `q_sample`
    def predict_start_from_noise(self, x_t, t, noise):
        return (
            self._extract(self.sqrt_recip_alphas_cumprod, t, x_t.shape) * x_t -
            self._extract(self.sqrt_recipm1_alphas_cumprod, t, x_t.shape) * noise
        )
    
    # compute predicted mean and variance of p(x_{t-1} | x_t)
    def p_mean_variance(self, model, x_t, t, clip_denoised=True):
        # predict noise using model
        pred_noise = model(x_t, t)
        # get the predicted x_0: different from the algorithm2 in the paper
        x_recon = self.predict_start_from_noise(x_t, t, pred_noise)
        if clip_denoised:
            x_recon = torch.clamp(x_recon, min=-1., max=1.)
        model_mean, posterior_variance, posterior_log_variance = \
                    self.q_posterior_mean_variance(x_recon, x_t, t)
        return model_mean, posterior_variance, posterior_log_variance
        
    # denoise_step: sample x_{t-1} from x_t and pred_noise
    @torch.no_grad()
    def p_sample(self, model, x_t, t, clip_denoised=True):
        # predict mean and variance
        model_mean, _, model_log_variance = self.p_mean_variance(model, x_t, t,
                                                    clip_denoised=clip_denoised)
        noise = torch.randn_like(x_t)
        # no noise when t == 0
        nonzero_mask = ((t != 0).float().view(-1, *([1] * (len(x_t.shape) - 1))))
        # compute x_{t-1}
        pred_img = model_mean + nonzero_mask * (0.5 * model_log_variance).exp() * noise
        return pred_img
    
    # denoise: reverse diffusion
    @torch.no_grad()
    def p_sample_loop(self, model, shape):
        batch_size = shape[0]
        device = next(model.parameters()).device
        # start from pure noise (for each example in the batch)
        img = torch.randn(shape, device=device)
        imgs = []
        for i in tqdm(reversed(range(0, timesteps)), desc='sampling loop time step', total=timesteps):
            img = self.p_sample(model, img, torch.full((batch_size,), i, device=device, dtype=torch.long))
            imgs.append(img.cpu().numpy())
        return imgs
    
    # sample new images
    @torch.no_grad()
    def sample(self, model, image_size, batch_size=8, channels=3):
        return self.p_sample_loop(model, shape=(batch_size, channels, image_size, image_size))
    
    # compute train losses
    def train_losses(self, model, x_start, t):
        # generate random noise
        noise = torch.randn_like(x_start)
        # get x_t
        x_noisy = self.q_sample(x_start, t, noise=noise)
        predicted_noise = model(x_noisy, t)
        loss = F.mse_loss(noise, predicted_noise)
        return loss

其中几个主要的函数总结如下:

  • q_sample:实现的从x0到xt扩散过程;
  • q_posterior_mean_variance:实现的是后验分布的均值和方差的计算公式;
  • predict_start_from_noiseq_sample的逆过程,根据预测的噪音来生成x0;
  • p_mean_variance:根据预测的噪音来计算pθ(xt−1|xt)的均值和方差;
  • p_sample:单个去噪step;
  • p_sample_loop:整个去噪音过程,即生成过程。

扩散模型的训练过程非常简单,如下所示:

# train
epochs = 10

for epoch in range(epochs):
    for step, (images, labels) in enumerate(train_loader):
        optimizer.zero_grad()
        
        batch_size = images.shape[0]
        images = images.to(device)
        
        # sample t uniformally for every example in the batch
        t = torch.randint(0, timesteps, (batch_size,), device=device).long()
        
        loss = gaussian_diffusion.train_losses(model, images, t)
        
        if step % 200 == 0:
            print("Loss:", loss.item())
            
        loss.backward()
        optimizer.step()
这里我们以mnist数据简单实现了一个mnist-demo,下面是一些生成的样本:

对生成过程进行采样,如下所示展示了如何从一个随机噪音生层一个手写字体图像:

另外这里也提供了CIFAR10数据集的demo:ddpm_cifar10,不过只训练了200epochs,生成的图像只是初见成效。

小结

相比VAE和GAN,扩散模型的理论更复杂一些,不过其优化目标和具体实现却并不复杂,这其实也让人感叹:一堆复杂的数据推导,最终却得到了一个简单的结论。要深入理解扩散模型,DDPM只是起点,后面还有比较多的改进工作,比如加速采样的DDIM以及DDPM的改进版本DDPM+和DDPM++。注:本人水平有限,如有谬误,欢迎讨论交流。

参考

  • Denoising Diffusion Probabilistic Models
  • Understanding Diffusion Models: A Unified Perspective
  • https://spaces.ac.cn/archives/9119
  • https://keras.io/examples/generative/ddim/
  • What are Diffusion Models?
  • https://cvpr2022-tutorial-diffusion-models.github.io/
  • https://github.com/openai/improved-diffusion
  • https://huggingface.co/blog/annotated-diffusion
  • https://github.com/lucidrains/denoising-diffusion-pytorch
  • https://github.com/hojonathanho/diffusion

图像分割框架

Unet框架

GitHub

介绍

nnuet

https://github.com/

MIC-DKFZ/nnUNet

十项全能冠军,自动构建分割任务

虽然基于UNet的系列编解码分割网络在各类医学图像分割上取得了长足的进展,并且部分基于相关模型的应用设计已经广泛用于临床分析中。但医学影像本身的复杂性和差异性也极度影响着分割模型的泛化性和通用性,主要体现在以下几个方面:

1)各类模态的医学影像之间差异大,如研究队列的大小、图像尺寸和维度、分辨率和体素(voxel)强度等。

2)分割的语义标签的极度不平衡。相较于影像中的正常组织,病变区域一般都只占极少部分,这就造成了正常组织的体素标签与病灶组织的体素标签之间极度的类不平常。

3)不同影像数据之间的专家标注差异大,并且一些图像的标注结果会存在模棱两可的情况。

4)一些数据集在图像几何和形状等属性上差异明显,切片不对齐和各向异性的问题也非常严重。

提出一种鲁棒的基于2D UNet3D UNet的自适应框架nnUMet。作者在各种任务上拿这个框架和目前的STOA方法进行了比较,且该方法不需要手动调参。最终nnUNet得到了最高的平均dice

作者提出一种nnUNetno-new-Net)框架,基于原始的UNet(很小的修改),不去采用哪些新的结构,如相残差连接、dense连接、注意力机制等花里胡哨的东西。相反的,把重心放在:预处理(resamplingnormalization)、训练(lossoptimizer设置、数据增广)、推理(patch-based策略、test-time-augmentations集成和模型集成等)、后处理(如增强单连通域等)。并且在10种数据集上进行测试,都能够达到很好的效果,而算法不能够针对某种数据集进行人为的调整,只能自动的去适应。

 

mmsegmentation

https://github.com/open-mmlab/mmsegmentation

mmSegmentatiopenmmlab项目下开源的图像语义分割框架,目前支持pytorch,由于其拥有pipeline加速,完善的数据增强体系,完善的模型库,作为大数据语义分割训练及测试的代码框架是再好不过了。

Efficient-Segmentation-Networks

https://github.com/xiaoyufenfei/

Efficient-Segmentation-Networks

该项目旨在为使用 PyTorch 的实时语义分割模型提供易于使用、可修改的参考实现

 

Pytorch Medical Segmentation

https://github.com/MontaEllis/

Pytorch-Medical-Segmentation

基于PyTorch的专注于医学图像分割的开源库,其支持模型丰富,方便易用。其可算为torchio的一个实例,作者将其综合起来,包含众多经典算法,实用性比较强。

支持2D3D医学图像分割,可以修改hparam.py文件来确定是2D分割还是3D分割以及是否可以进行多分类。

支持绝大数主流分割模型,几乎提供了所有的2D3D分割的算法。

兼容几乎所有的医学数据格式(例如 nii.gz, nii, mhd, nrrd, …),修改hparam.pyfold_arch即可。

作者提供了训练和测试推断的代码,简单配置后训练和推断都仅需要一行命令。

TernausNet

论文地址:https://arxiv.org/abs/1801.05746

github地址:https://github.com/ternaus/TernausNet

数据集:Kaggle Carvana

像素级分割在计算机视觉中是一项艰巨的任务,经典的UNet网络结构在医学影像和卫星图像中非常流行。一般来说神经网权重由一些大型数据集如ImageNet进行初始化后会有更好的效果。在一些实际应用中,尤其是在医学和交通安全方面,模型的精确是至关重要的,本文演示如何使用预训练编码器来改善UNet网络结构。

  1. 经典的UNet网络权重采用随机初始化方式来完成,众所周知训练一个未过拟合的网络需要大量的数据来完成。因此采用经过Imagenet训练后的权重来进行初始化这一方法被广泛应用。通过这种方式来加速学习过程。
  2. 此网络编码器部分采用VGG11(VGG11包含7个3×3卷积层,每个层后加一个ReLU,同时进行5次最大池化操作,具体如下图)

为构造编码器,这里移除了全连接层替换其为一个512通道的单卷积层来分离编码器和解码器。为构造解码器这里采用转置卷积层放大特征图尺寸并且减少一半原通道数。同时将转置卷积的输出与解码器的相应部分的输出串联。特征图的结果通过卷积操作使得其通道数与对应编码器部分相同。这一上采样过程重复5次对应5次池化操作。传统全连接层可接受任意大小图片输入,但因为此处有5个池化层,每次图像缩小到原来一半,即缩小$2^5=32$倍,因此当前网络要求输入图像大小需要能被32整除。下图为本文网络结构图。

3D U-Net

论文:3D U-Net: Learning Dense Volumetric Segmentation from Sparse Annotation

github: https://github.com/wolny/pytorch-3dunet

论文最早版本arXiv上的发表时间是2016.06,本文是论文v1版本笔记 MICCAI 2016收录

本文提出了一种从稀疏注释的立体数据中学习三维分割的网络。3D U-Net这篇论文的诞生主要是为了处理一些块状图(volumetric images),基本的原理跟U-Net其实并无大差,因为3D U-Net就是用3D卷积操作替换了2D的

3D数据对于生物医学数据分析来说显得非常冗余

  • 在三维层面上标注分割label比较困难,因为电脑屏幕上只能展示2D的切片
  • 同时,逐层标注大量的切片又很繁琐,且相邻层的信息几乎是相同的
  • 因此,完整注释3D数据并不是创建大而丰富的训练数据集的有效方法,尤其是对于需要大量标签数据的学习类算法

生物医学影像(biomedical images)很多时候都是块状的,也就是说是由很多个切片构成一整张图的存在。如果是用2D的图像处理模型去处理3D本身不是不可以,但是会存在一个问题,就是不得不将生物医学影像的图片一个slice一个slice成组的(包含训练数据和标注好的数据)的送进去设计的模型进行训练,在这种情况下会存在一个效率问题,因而很多时候处理块状图的时候会让任感到不适,并且数据预处理的方式也相对比较繁琐(tedious)。

所以,论文的作者就提出来了3D -Net模型,模型不仅解决了效率的问题,并且对于块状图的切割只要求数据中部分切片被标注即可(可参考下图说明)。

模型结构(Network Architecture)

整个3D U-Net的模型是基于之前U-Net(2D)创建而来,同样包含了一个encoder部分和一个decoder部分,encoder部分是用来分析整张图片并且进行特征提取与分析,而与之相对应的decoder部分是生成一张分割好的块状图。论文中使用的输入图像的大小是132 * 132 * 116,整个网络的结构前半部分(analysis path)包含及使用如下卷积操作:

a. 每一层神经网络都包含了两个 3 * 3 * 3的卷积(convolution)

b. Batch Normalization(为了让网络能更好的收敛convergence)

c. ReLU

d. Downsampling:2 * 2 * 2的max_polling,步长stride = 2

而与之相对应的合成路径(synthesis path)则执行下面的操作:

a. upconvolution: 2 * 2 * 2,步长=2

b. 两个正常的卷积操作:3 * 3 * 3

c. Batch Normalization

d. ReLU

于此同时,需要把在analysis path上相对应的网络层的结果作为decoder的部分输入,这样子做的原因跟U-Net博文提到的一样,是为了能采集到特征分析中保留下来的高像素特征信息,以便图像可以更好的合成。

整体的一个网络结构如下图所示,其实可以看出来跟2D结构的U-Net是基本一样,唯一不同的就是全部2D操作换成了3D,这样子做了之后,对于volumetric image就不需要单独输入每个切片进行训练,而是可以采取图片整张作为输入到模型中(PS:但是当图像太大的时候,此时需要运用random crop的技巧将图片随机裁切成固定大小模块的图片放入搭建的模型进行训练,当然这是后话,之后将会在其他文章中进行介绍)。除此之外,论文中提到的一个亮点就是,3D U-Net使用了weighted softmax loss function将未标记的像素点设置为0以至于可以让网络可以更多地仅仅学习标注到的像素点,从而达到普适性地特点。

训练细节(Training)

3D U-Net同样采用了数据增强(data augmentation)地手段,主要由rotation、scaling和将图像设置为gray,于此同时在训练数据上和真实标注的数据上运用平滑的密集变形场(smooth dense deformation field),主要是通过从一个正态分布的随机向量样本中选取标准偏差为4的网格,在每个方向上具有32个体素的间距,然后应用B样条插值(B-Spline Interpolation,不知道什么是B样条插值法的可以点连接进行查看,在深度学习模型的创建中有时候也不需要那么复杂,所以这里仅限了解,除非本身数学底子很好已经有所了解),B样条插值法比较笼统地说法就是在原本地形状上找到一个类似地形状来近似(approximation)。之后就对数据开始进行训练,训练采用的是加权交叉熵损失(weighted cross-entropy loss function)以至于减少背景的权重并增加标注到的图像数据部分的权重以达到平衡的影响小管和背景体素上的损失。

实验的结果是用IoU(intersection over union)进行衡量的,即比较生成图像与真实被标注部分的重叠部分。

论文针对肾脏的生物医学影像的分割结果达到了IoU=86.3%的结果。3D U-Net的诞生在医学影像分割,特别是那些volumetric images都是由很大帮助的,因为它很大程度上解决了3D图像一个个slice送入模型进行训练的尴尬局面,也大幅度的提升训练效率,并且保留了FCN和U-Net本来具备的优秀特征。

U2-Net

论文: U2-Net: Going Deeper with Nested U-Structure for Salient Object Detection

CVPR2020

github: https://github.com/xuebinqin/U-2-Net

U²-Net给我们带来了什么?

得益于在SOTA SOD方法取得了不错的竞争力,U²-Net可以应用在很多场景。首先,U²-Net现在已经是Python的抠图工具Rembg的基础算法。抠图就是将照片的主体人或物品从图片中抠出来,以便贴到别处使用除了被用来作为抠图外,素描肖像生成(Portrait Drawing)也是其非常有趣且流行的新应用。

显着物体检测(SOD)

显着物体检测(SOD)是基于视觉注意机制的任务,其中算法旨在探索比场景或图像周围区域更专注的物体或区域,因此很适合于做抠图应用。

从自然场景中检测和分割最具视觉吸引力的对象的过程,在计算机视觉领域称为显着对象检测(SOD)。现有的大多数SOD网络都具有类似的设计,并且专注于利用由AlexNet,VGG,ResNet,ResNeXt,DenseNet等骨干网络提取的深度特征。这些骨干网络最初是为图像分类任务而构建的,因此它们提取特征代表语义含义,而不是对显着物体检测至关重要的局部细节或全局参考信息。这样的网络还倾向于在ImageNet上进行数据效率低下的预训练。

U²-Net是一种简单而强大的深度网络体系结构,具有新颖的两层嵌套U形结构,旨在解决这些问题。提出的ReSidual U (RSU)具有各种不同大小的感受野,从而使其能够更好地捕获不同规模的上下文信息。 RSU还使用池化操作来增加总体体系结构深度,而不会显着增加计算成本。

Architecture

RSU

RSU具有三个主要组成部分:输入卷积层,类似U-Net的对称编码器-解码器结构,以及通过求和融合局部和多尺度特征的残差连接。

RSU和原始残差块之间的主要区别在于,RSU用类似U-Net的结构,替换了普通的单流卷积,并用通过加权层转换的局部特征替换了原始特征。

U-2-Net

在RSU的基础上开发了U²-Net,这是用于显着物体检测的新型堆叠U形结构。 U²-Net包括一个6级编码器,一个5级解码器和一个显着度图融合模块,该模块连接到解码器级和最后一个编码器级。

总体而言,U²-Net网络结构具有丰富的多尺度特征,以及较低的计算和内存成本。 另外,由于U²-Net体系结构仅建立在RSU块上,并且不使用任何经过预训练的骨干网络进行图像分类处理,因此可以灵活,轻松地适应不同的工作环境,而性能损失最小。

Dual Attention Network for Scene Segmentation

论文地址 : https://arxiv.org/abs/1809.02983

github:https://github.com/junfu1115/DANetCVPR2019)

 为了有效地完成场景分割的任务,我们需要区分一些混淆的类别,并考虑不同外观的对象。例如,草原与牧场有时候是很难区分的,公路上的车也存在尺度、视角、遮挡与亮度等的变化。因此,像素级识别需要提高特征表示的识别能力。

创新点:

通过基于Self Attention mechanism来捕获上下文依赖,并提出了Dual Attention Networks (DANet)来自适应地整合局部特征和全局依赖。该方法能够自适应地聚合长期上下文信息,从而提高了场景分割的特征表示。

  • 提出了Dual Attention Networks (DANet)在spatial和channle维度来捕获全局特征依赖。
  • 提出position attention module去学习空间特征的相关性,提出channel attention module去建模channle的相关性。

在一贯的dilated FCN中加入两种类型地attention module。其中position attention module选择性地通过所有位置的加权求和聚集每个位置的特征,channel attention module通过所有channle的feature map中的特征选择性地强调某个特征图。最后将两种attention module的output 求和得到最后的特征表达。

采用移除down-sampling的dilated ResNet(与DeepLab相同)的预训练网络基础网络为,最后得到的feature map大小为输入图像的1/8。之后是两个并行的attention module分别捕获spatial和channel的依赖性,最后整合两个attention module的输出得到更好的特征表达。

Position Attention Module

捕获特征图的任意两个位置之间的空间依赖,对于某个特定的特征,被所有位置上的特征加权和更新。权重为相应的两个位置之间的特征相似性。因此,任何两个现有相似特征的位置可以相互贡献提升,而不管它们之间的距离。

  • 特征图A(C×H×W)首先分别通过3个卷积层(BN和ReLU)得到3个特征图{B,C,D}.shape∈(CxHxW),然后reshape为C×N,其中N=H×W。
  • 矩阵C和B的转置相乘,再通过softmax得到spatial attention map S(N×N)。
  • 矩阵D和S的转置相乘,reshape result到(CxHxW)再乘以尺度系数 α 再reshape为原来形状,,最后与A相加得到最后的输出E 其中α初始化为0,并逐渐的学习分配到更大的权重。可以看出E的每个位置的值是原始特征每个位置的加权求和得到的。

 Channel Attention Module

每个高层次特征的通道映射都可以看作是一个特定于类的响应,不同的语义响应相互关联。通过探索通道映射之间的相互依赖关系,可以强调相互依赖的特征映射,提高特定语义的特征表示。