U-Net: Convolutional Networks for Biomedical Image Segmentation

U-Net:用于生物医学图像分割的卷积网络

文章目录

  • U-Net:用于生物医学图像分割的卷积网络
  • 前言
  • 一、论文翻译
    • 1 介绍
    • 2 网络体系结构
    • 3 训练
      • 3.1 数据扩充
    • 4 实验
    • 5 结论
  • 二、补充知识
    • motivation
    • overlap-tile策略
    • unet和FCN的区别


前言

记录医学图像分割领域看的第一篇文章U-Net,包括翻译和知识点。


一、论文翻译

摘要:人们普遍认为,成功的深层网络训练需要数千个带注释的训练样本。在这篇文章中,我们提出了一个网络和训练策略,它依赖于强大的数据扩充来更有效地使用可用的注释样本。该体系结构包括一个用于捕获上下文的收缩路径(下采样)和一个支持精确定位的对称扩展路径(上采样)。我们证明这样的网络可以从很少的图像中进行端到端的训练,并且在电子显微镜堆栈中神经元结构分割的ISBI挑战方面优于先前的最佳方法(滑动窗口卷积网络)。利用同样的网络,我们在透射光显微镜图像(相衬度和DIC)上获得了2015年ISBI细胞跟踪挑战赛的冠军。而且,网络很快。在最近的GPU上,512x512图像的分割只需不到一秒钟的时间。全面实施(基于Caffe)和经过训练的网络可在原作者代码连接上获得。

(可以利用少量的数据学习到一个对边缘提取十分鲁棒的模型)

1 介绍

  在过去的两年中,深卷积网络在许多视觉识别任务中的表现都超过了现有技术,例如[7,3]。虽然卷积网络已经存在很长一段时间了[8],但由于可用训练集的大小和所考虑的网络的大小,它们的成功是有限的。Krizhevsky等人的突破[7] 这是由于在ImageNet数据集上对一个有8层和数百万个参数的大型网络的监督训练,该数据集有100万个训练图像。从那时起,甚至更大更深的网络也得到了训练[12].
  卷积网络的典型用途是分类任务,在分类任务中,图像的输出是一个单一的类标签。然而,在许多视觉任务中,特别是在生物医学图像处理中,期望的输出应该包括定位,也就是说,应该为每个像素分配一个类标签。此外,在生物医学任务中,成千上万的训练图像通常是遥不可及的。因此,Ciresan等人[1] 用滑动窗口训练网络,通过提供像素周围的局部区域(patch)来预测每个像素的类标签作为输入。首先,这个网络可以完成定位工作。其次,训练数据的patches方面远远大于训练图像的数目。由此产生的网络在2012年ISBI大会上以较大优势赢得了EM细分挑战赛。
  显然,Ciresan等人的策略[1] 有两个缺点。首先,它非常慢,因为每个patch必须单独运行网络,并且由于重叠的patches,存在大量冗余。其次,在定位精度和上下文使用之间存在一个折衷。较大的patches需要更多的最大池化层,这会降低定位精度,而小patches只允许网络看到很少的上下文。最近的方法[11,4]提出了一种考虑多层特征的分类器输出。良好的定位和上下文的同时使用是可能的。
  在本文中,我们构建了一个更优雅的体系结构,即所谓的“完全卷积网络”[9]。我们改进和扩展了这个体系结构,使得它只使用很少的训练图像,并产生更精确的分割;见图1。[9]FCN中的主要思想是用连续的层来补充通常的收缩网络,其中池操作被上采样操作符代替。因此,这些层提高了输出的分辨率。为了定位,收缩路径的高分辨率特征与上采样输出相结合。随后,一个连续的卷积层可以学习根据这些信息组装更精确的输出。
U-Net: Convolutional Networks for Biomedical Image Segmentation_第1张图片
收缩路径用于获取上下文信息(context),扩张路径用于精确的定位(localization),且两条路径相互对称。收缩路径仍然是利用传统卷积神经网络的卷积池化组件,其中经过一次下采样之后,channels变为原来的2倍。扩张路径由2 * 2的反卷积,反卷积的输出通道为原来通道数的一半,再与原来的feature map(裁剪之后)串联,得到和原来一样多的通道数的feature map,再经过2个尺寸为3 * 3的卷积和ReLU的作用。裁剪特征图是必要的,因为在卷积的过程中会有边界像素的丢失。在最后一层通过卷积核大小为1 * 1的卷积作用得到想要的目标种类。在Unet中一共有23个卷积层。但是这个网络需要谨慎的选择输入图片的尺寸,以保证所有的Max Pooling操作作用于长宽为偶数的feature map。
每经过一个池化层就一个尺度,包括原图尺度一共有5个尺度。
  我们架构中的一个重要改进是,在上采样部分,我们还有大量的特征通道,允许网络将上下文信息传播到更高分辨率的层。因此,扩展路径或多或少与收缩路径对称,并产生一个u形结构。该网络没有任何完全连接的层,只使用每个卷积的有效部分,即分割图仅包含在输入图像中可获得完整上下文信息的像素。此策略允许通过重叠-切片(overlap-tile)策略对任意大的图像进行无缝分割(参见图2)。为了预测图像边界区域的像素,通过对输入图像进行镜像操作来推断缺失的上下文信息。这种切片策略对于将网络应用于大图像非常重要,否则分辨率将受到GPU内存的限制。
U-Net: Convolutional Networks for Biomedical Image Segmentation_第2张图片
数据集可以用数据量较少 对于我们的任务来说,训练数据很少,我们通过对可用的训练图像应用弹性变形来进行数据增强。使得网络能够学习这种形变的不变性,无需提供带注释的图像语料库(the annotated image corpus)供网络学习。这在生物医学分割中尤其重要,因为变形曾经是组织中最常见的变化,并且可以有效地模拟真实的变形。Dosovitskiy等人[2]在无监督特征学习的范围内已经证明了数据增强对于学习不变性的价值。

相同物体间的间隔不容易分割出来 许多细胞分割任务中的另一个挑战是分离同一类的接触目标;请参见图3。本文提出了一种利用加权损失的方法,其中接触单元之间的分离背景标签在损失函数中获得大的权重。以此方法提升对于相互接触的相同物体之间缝隙的分割效果。
U-Net: Convolutional Networks for Biomedical Image Segmentation_第3张图片
  所得网络适用于各种生物医学分割问题。在这篇论文中,我们展示了EM堆栈中神经元结构分割的结果(ISBI 2012年开始的一项持续竞争),我们的表现超过了Ciresan等人的网络[1] 。此外,我们展示了ISBI细胞跟踪挑战赛2015的光镜图像中的细胞分割结果。在这两个最具挑战性的二维透射光数据集上,我们以较大的优势获胜。

2 网络体系结构

  网络体系结构如图1所示。它由收缩路径(左侧)和扩展路径(右侧)组成。收缩路径遵循卷积网络的典型结构。它包括重复应用两个3x3卷积(无填充卷积,unpadded convolution),每个卷积后面都有一个校正的线性单元(ReLU)和一个2x2最大池化操作,步长为2,用于下采样。在每个下采样步骤中,我们将特征通道的数量加倍。扩展路径中的每一步都包括对特征图进行上采样,然后进行2x2卷积(“上卷积”up-convolution),将特征通道数量减半,接着级联收缩路径中相应的裁剪后的特征图;再用两个3x3卷积,每个卷积后面都有一个ReLU。由于每次卷积都会丢失边界像素,因此有必要对特征图进行裁剪。在最后一层,使用1x1卷积将每个64维特征向量映射到所需数量的类。网络总共有23个卷积层。
  为了允许输出分割映射的无缝拼接(请参见图2),选择输入切片(tile)的大小非常重要,这样所有2x2最大池操作都应用于具有偶数x和y大小的层。

3 训练

  利用输入图像及其相应的分割图,利用Caffe的随机梯度下降实现训练网络[6]。由于未填充的卷积,输出图像比恒定边界宽度的输入图像小。为了最大限度地减少开销并最大限度地利用GPU内存,我们倾向于使用大的输入切片而不是大的批处理大小,从而将批处理减少到单个图像。相应地,通过使用高动量(high momentum,0.99)使得大量先前的训练样本在当前的优化步骤中更新。
  能量函数由最终特征图上的像素级soft-max结合交叉熵损失函数来计算。soft-max定义为
          在这里插入图片描述
其中ak(x)表示在第x像素点上第k个特征通道的激活函数x∈Ω,具有Ω⊂Z2。K是类的数目,pk(x)是近似的最大函数。pk(x)≈1对于具有最大活化度的ak(x),pk(x)≈0对于所有其他k。交叉熵在每个位置惩罚在这里插入图片描述与1的偏差
          :在这里插入图片描述
其中l:Ω→{1,…,K}是每个像素的真实标签,w:Ω→R是一个权重图,我们引入该图使一些像素在训练中更加重要。
  我们预先计算每个真值分割的权重图,以补偿训练数据集中每类像素的不同频率,并迫使网络学习我们在接触细胞之间引入的小分隔边界(见图3c和d)。
  分离边界的计算采用形态学运算。然后将权重计算为:
        在这里插入图片描述
  其中wc:Ω→R是平衡类频率的权重映射,d1:Ω→R表示到最近细胞边界的距离,d2:Ω→R表示到第二个最近细胞边界的距离。在我们的实验中,我们设置w0=10和σ≈5个像素。
  在有许多卷积层和不同路径的深度网络中,权值的良好初始化非常重要。否则,网络的某些部分可能会激活过多,而其他部分则不会做出贡献。理想情况下,初始权值应该调整,使得网络中的每个特征映射具有近似的单位方差。对于采用我们的体系结构(交替卷积和ReLU层)的网络,这可以通过使用有标准偏差 的标准从高斯分布中提取初始权重来实现,其中N表示一个神经元的传入节点数[5]。例如对于上一层的3x3卷积和64个特征通道,N = 9·64 = 576。

3.1 数据扩充

  在训练样本较少的情况下,数据扩充是教会网络所需的不变性和鲁棒性的关键。对于显微图像,我们主要需要位移和旋转不变性以及对变形和灰度变化的鲁棒性。特别是训练样本的随机弹性变形,似乎是训练一个只有很少注释图像的分割网络的关键概念。我们使用随机位移向量在一个粗略的3×3网格上生成平滑变形。位移从高斯分布采样,标准偏差为10像素。然后使用双三次插值计算每个像素的位移。收缩路径末端的drop-out层执行进一步的隐式数据扩充。

4 实验

  我们演示了u-net在三种不同的分割任务中的应用。第一个任务是在电子显微镜记录中分割神经元结构。图2显示了数据集和我们获得的分割的示例。我们提供完整的结果作为补充材料。数据集由ISBI2012年开始的EM细分挑战[14]提供,目前仍对新的贡献开放。训练数据是一组来自果蝇一龄幼虫腹侧神经索(VNC)的连续切片透射电镜图像(512x512像素)。每幅图像都有相应的完全注释的细胞(白色)和细胞膜(黑色)的真实分割图。测试集是公开的,但是它的分割图是保密的。通过将预测的膜概率图发送给组织者,可以得到评估。评估是通过在10个不同级别上对地图进行阈值化,并计算“扭曲误差”、“随机误差”和“像素误差”[14]。
  u-net(在输入数据的7个旋转版本上的平均值)在没有任何进一步的预处理或后处理的情况下实现了0.0003529的翘曲误差(新的最佳分数,见表1)和0.0382的随机误差。
  这明显优于Ciresan等人的滑动窗卷积网络结果[1] ,其最佳提交结果的翘曲误差为0.000420,随机误差为0.0504。就随机误差而言,在该数据集上唯一表现更好的算法是将高度数据集特定的后处理方法1应用于Ciresan等人的概率图[1]。
U-Net: Convolutional Networks for Biomedical Image Segmentation_第4张图片
U-Net: Convolutional Networks for Biomedical Image Segmentation_第5张图片
  我们还将u-net应用于光镜图像中的细胞分割任务。这个分割任务是2014年和2015年ISBI细胞追踪挑战赛的一部分[10,13]。第一个数据集“PhC-U373”包含由相差显微镜记录的聚丙烯腈基片上的胶质母细胞瘤星形细胞瘤U373细胞(见图4a、b和补充资料)。它包含35个部分注释的训练图像。在这里,我们实现了92%的平均IOU(“交集对联合”),这明显优于第二最佳算法83%(见表2)。第二个数据集“DIC HeLa”是用差分干涉对比(DIC)显微镜记录在平板玻璃上的HeLa细胞(见图3、图4c、d和补充材料)。它包含20个部分注释的训练图像。在这里,我们实现了77.5%的平均IOU,明显优于46%的次优算法。

5 结论

u-net体系结构在非常不同的生物医学分割应用程序上取得了非常好的性能。由于弹性变形的数据增强,它只需要很少的注释图像,并且在NVidia Titan GPU(6gb)上只需要10个小时的合理训练时间。我们提供完整的基于Caffe[6]的实现和经过训练的网络。我们确信u-net架构可以很容易地应用到更多的任务中。

二、补充知识

motivation

已有网络需要大量标注训练样本,生物医学任务中没有数千个标注的数据集,所以需要对数据进行数据扩张。
经典卷积网络大部分都是针对图像分类任务的,但是在一些特定场景,如医疗图像处理领域,应是pixel-wise像素级的处理,也就是图像分割。图像分割指进行端对端操作,输入和输出应保持同一维度,输入一张待分割图像,输出应该是分割好的图像。Ciresan用滑窗法来解决该问题。sliding-window 算法提出预测patch的类别(patch指像素周围的局部区域) 该算法有两个主要问题:一、由于每个patch都需要训练导致这个算法很慢。二、分割准确率和上下文关系需要平衡的,平衡取决于patch的大小,patch越大需要pooling越多准确率越低,patch越小则不具备上下文联系。也就是说滑窗法的感受野(有效视野)大小和分割精度呈负相关关系。

overlap-tile策略

对图像的某一块像素点(黄框内部分)进行预测时,需要该图像块周围的像素点(蓝色框内)提供上下文信息(context),以获得更准确的预测。简单地说,就是在预处理中,对输入图像进行padding,通过padding扩大输入图像的尺寸,使得最后输出的结果正好是原始图像的尺寸, 同时, 输入图像块(黄框)的边界也获得了上下文信息从而提高预测的精度,本文用的是mirror padding。overlap部分可以为分割区域边缘部分提供文理等信息, 并且分割结果并没有受到切成小patch而造成分割情况不好。
U-Net: Convolutional Networks for Biomedical Image Segmentation_第6张图片

unet和FCN的区别

Unet++作者分享
和FCN相比,U-Net的第一个特点是完全对称,也就是左边和右边是很类似的,而FCN的decoder相对简单,只用了一个deconvolution的操作,之后并没有跟上卷积结构。第二个区别就是skip connection,FCN用的是加操作(summation),U-Net用的是叠操作(concatenation)。这些都是细节,重点是它们的结构用了一个比较经典的思路,也就是编码和解码(encoder-decoder),早在2006年就被Hinton大神提出来发表在了nature上。
降采样可以增加对输入图像的一些小扰动的鲁棒性,比如图像平移,旋转等,减少过拟合的风险,降低运算量,和增加感受野的大小。升采样的最大的作用其实就是把抽象的特征再还原解码到原图的尺寸,最终得到分割结果。

关于裁剪以及滑动窗卷积介绍比较好:Unet概要以及优点分析
个人感觉写的非常详细非常好的博文,程序也很清晰明了:精读U-Net
pytorch代码:
添加链接描述
添加链接描述

import torch.nn as nn
import torch
from torch import autograd

#把常用的2个卷积操作简单封装下
class DoubleConv(nn.Module):
    def __init__(self, in_ch, out_ch):
        super(DoubleConv, self).__init__()
        self.conv = nn.Sequential(
            nn.Conv2d(in_ch, out_ch, 3, padding=1),
            nn.BatchNorm2d(out_ch), #添加了BN层
            nn.ReLU(inplace=True),
            nn.Conv2d(out_ch, out_ch, 3, padding=1),
            nn.BatchNorm2d(out_ch),
            nn.ReLU(inplace=True)
        )

    def forward(self, input):
        return self.conv(input)

class Unet(nn.Module):
    def __init__(self, in_ch, out_ch):
        super(Unet, self).__init__()
        self.conv1 = DoubleConv(in_ch, 64)
        self.pool1 = nn.MaxPool2d(2)
        self.conv2 = DoubleConv(64, 128)
        self.pool2 = nn.MaxPool2d(2)
        self.conv3 = DoubleConv(128, 256)
        self.pool3 = nn.MaxPool2d(2)
        self.conv4 = DoubleConv(256, 512)
        self.pool4 = nn.MaxPool2d(2)
        self.conv5 = DoubleConv(512, 1024)
        # 逆卷积,也可以使用上采样(保证k=stride,stride即上采样倍数)
        self.up6 = nn.ConvTranspose2d(1024, 512, 2, stride=2)
        self.conv6 = DoubleConv(1024, 512)
        self.up7 = nn.ConvTranspose2d(512, 256, 2, stride=2)
        self.conv7 = DoubleConv(512, 256)
        self.up8 = nn.ConvTranspose2d(256, 128, 2, stride=2)
        self.conv8 = DoubleConv(256, 128)
        self.up9 = nn.ConvTranspose2d(128, 64, 2, stride=2)
        self.conv9 = DoubleConv(128, 64)
        self.conv10 = nn.Conv2d(64, out_ch, 1)

    def forward(self, x):
        c1 = self.conv1(x)
        p1 = self.pool1(c1)
        c2 = self.conv2(p1)
        p2 = self.pool2(c2)
        c3 = self.conv3(p2)
        p3 = self.pool3(c3)
        c4 = self.conv4(p3)
        p4 = self.pool4(c4)
        c5 = self.conv5(p4)
        up_6 = self.up6(c5)
        merge6 = torch.cat([up_6, c4], dim=1)
        c6 = self.conv6(merge6)
        up_7 = self.up7(c6)
        merge7 = torch.cat([up_7, c3], dim=1)
        c7 = self.conv7(merge7)
        up_8 = self.up8(c7)
        merge8 = torch.cat([up_8, c2], dim=1)
        c8 = self.conv8(merge8)
        up_9 = self.up9(c8)
        merge9 = torch.cat([up_9, c1], dim=1)
        c9 = self.conv9(merge9)
        c10 = self.conv10(c9)
        out = nn.Sigmoid()(c10)
        return out


你可能感兴趣的:(图像分割目标检测)