U-Net: Convolutional Networks for Biomedical Image Segmentation
引用:Ronneberger O , Fischer P , Brox T . U-Net: Convolutional Networks for Biomedical Image Segmentation[J]. 2015.
U-Net:用于生物医学图像分割的卷积网络
论文地址:https://arxiv.org/pdf/1505.04597v1.pdf
GitHub源码地址:
https://lmb.informatik.uni-freiburg.de/people/ronneber/u-net/
https://github.com/zhixuhao/unet
https://github.com/yihui-he/u-net
http://blog.leanote.com/post/zongwei/Pa
http://blog.csdn.net/hjimce/article/details/50268555
一、摘要
人们普遍认为,成功地训练深度网络需要数千个带注释的训练样本。在本文中,我们提出了一种网络和培训策略,该策略依赖于数据增强的强大使用来更有效地使用可用的带注释的样本。该体系结构包括一个用于捕获上下文的收缩路径和一个能够实现精确定位的对称扩展路径。我们展示了这样的网络可以从很少的图像进行端到端训练,并且在ISBI挑战方面优于现有的最佳方法(滑动窗口卷积网络),用于在电子显微镜堆栈中分割神经元结构。使用在透射光显微镜图像(相差和DIC)上训练过的同一网络,我们在这些类别中赢得了2015年ISBI细胞跟踪挑战赛的冠军。而且,网络速度很快。在最新的GPU上,对512x512图像进行分割所需的时间不到一秒钟。完整的实现(基于Caffe)和受过培训的网络可在
http://lmb.informatik.uni-freiburg.de/people/ronneber/u-net上获得。
二、相关工作
在过去的两年中,深度卷积网络在许多视觉识别任务中的表现都超过了当前的技术水平,例如[7,3]。虽然卷积网络已经存在很长时间了,但是由于可用训练集的大小和考虑的网络的大小,它们的成功是有限的。Krizhevsky et al.[7]的突破是由于在ImageNet数据集上对一个具有8层和数百万参数的大型网络进行监督训练100万张训练图像。从那时起,甚至更大更深的网络被训练[12]。
卷积网络的典型用途是用于分类任务,其中图像的输出是单个类别标签。 然而,在许多视觉任务中,特别是在生物医学图像处理中,期望的输出应包括定位,即,应该将类别标签分配给每个像素。 此外,在生物医学任务中通常无法获得数千个训练图像。 因此,Ciresan等。 [1]在滑动窗口设置中训练了一个网络,以通过提供围绕该像素的局部区域(补丁)来预测每个像素的类别标签。 首先,该网络可以本地化。 其次,就补丁而言,训练数据远大于训练图像的数量。 最终的网络在ISBI 2012上大幅度赢得了EM细分挑战。
显然,Ciresan等人的策略。 [1]有两个缺点。 首先,它很慢,因为每个补丁程序都必须单独运行网络,而且由于补丁程序重叠,因此存在很多冗余。 其次,在定位精度和上下文使用之间需要权衡。 较大的修补程序需要更多的最大池化层,这会降低定位精度,而较小的修补程序使网络只能看到很少的上下文。 最近的方法[11,4]提出了一种分类器输出,该输出考虑了来自多层的特征。 良好的本地化和上下文的使用是可能的。
在本文中,我们基于更好的架构,即所谓的“全卷积网络” [9]。 我们修改并扩展了此架构,使其可以使用很少的训练图像并产生更精确的分割。 参见图1。[9]中的主要思想是通过连续的层来补充通常的合同网络,其中合并池运算符被上采样运算符代替。 因此,这些层提高了输出的分辨率。 为了定位,将收缩路径中的高分辨率特征与上采样的输出结合在一起。 然后,连续的卷积层可以根据此信息学习组装更精确的输出。
图1: U-net架构(例如最低分辨率为32x32像素)。每个蓝色框对应一个多通道特征映射。通道的数量显示在盒子的顶部。x-y尺寸在框的左下角提供。白框表示复制的功能映射。箭头表示不同的操作。
我们架构的一项重要修改是,在上采样部分中,我们还拥有大量特征通道,这些特征通道使网络可以将上下文信息传播到更高分辨率的层。 结果,扩展路径或多或少地相对于收缩路径对称,并且产生u形结构。 网络没有任何完全连接的层,仅使用每个卷积的有效部分,即,分割图仅包含像素,在输入图像中可以使用其完整上下文。 这种策略允许通过重叠拼贴策略对任意大图像进行无缝分割(参见图2)。 为了预测图像边界区域中的像素,可通过镜像输入图像来推断缺失的上下文。 这种平铺策略对于将网络应用于大图像非常重要,因为否则分辨率会受到GPU内存的限制。
图2:用于任意大图像的无缝分割(此处为EM堆栈中的神经元结构的分割)的重叠拼贴策略。 对黄色区域中的分割的预测需要蓝色区域内的图像数据作为输入。 丢失的输入数据通过镜像推断 。
至于我们的任务,几乎没有可用的训练数据,我们通过对可用的训练图像应用弹性变形来使用过多的数据增强。 这允许网络学习此类变形的不变性,而无需在带注释的图像语料库中查看这些转换。 这在生物医学分割中尤其重要,因为变形曾经是组织中最常见的变化,并且可以有效地模拟实际变形。 Dosovitskiy等人已经证明了数据增强对于学习不变性的价值。 [2]在无监督特征学习的范围内。
许多细胞分割任务的另一个挑战是分离相同类的触摸对象;参见图3。为此,我们建议使用加权损失,即接触细胞之间的分离背景标签在损失函数中获得较大的权重。
图3: 玻璃上的HeLa细胞通过DIC(差示干涉对比)显微镜观察记录。(一)原始图像。(b)与地面真相分割重叠。不同的颜色表示HeLa细胞的不同实例。(c)生成的分割蒙版(白色:前景,黑色:背景)。(d)地图用像素方式减重,迫使网络学习边界像素。
所得的网络适用于各种生物医学分割问题。 在本文中,我们显示了关于EM堆栈中神经元结构分割的结果(一场持续的竞争始于ISBI 2012),在此我们胜过了Ciresan等人的网络。 [1]。 此外,我们在2015年ISBI细胞追踪挑战赛的光学显微镜图像中显示了细胞分割的结果。在这里,我们在两个最具挑战性的2D透射光数据集上大获全胜。
三、网络结构
网络架构如图1所示。它由一个收缩路径(左侧)和一个扩展路径(右侧)组成。收缩路径遵循卷积网络的典型架构。它由两个3x3卷积(未填充卷积)的重复应用组成,每个卷积后跟一个整流线性单位(ReLU)和一个2x2最大合并运算,步长为2用于下采样。在每个降采样步骤中,我们将特征通道的数量增加一倍。扩展路径中的每个步骤都包括对特征图进行升采样,然后是将特征通道数量减半的2x2卷积(“向上卷积”),与来自收缩路径的相应裁剪的特征图的串联以及两个3x3卷积,每个后跟一个ReLU。由于每次卷积中都会丢失边界像素,因此有必要进行裁剪。在最后一层,使用1x1卷积将每个64分量特征向量映射到所需的类数。该网络总共有23个卷积层。
为了无缝拼接输出分割图(请参见图2),重要的是选择输入图块大小,以便将所有2x2最大合并操作应用于x和y大小均等的图层。
四、U-Net网络
参考链接:https://blog.csdn.net/maliang_1993/article/details/82084983
参考链接:https://blog.csdn.net/xxiaozr/article/details/81191890
参考链接:https://blog.csdn.net/hduxiejun/article/details/71107285
参考链接:https://blog.csdn.net/mieleizhi0522/article/details/82025509
参考链接:https://www.cnblogs.com/ys99/p/10889695.html
参考链接:https://www.jianshu.com/p/7db4c8f8113a
参考链接:https://www.zhihu.com/question/268331470/answer/762639159
参考链接:https://blog.csdn.net/fabulousli/article/details/78633531
1. U-Net网络大体是什么
大意上可以理解为:普遍认为深度网络需要大量已标签数据集,这个网络(U-Net)可以依靠数据增强来事先少量数据集训练网络。而且,这个网络训练得很快,运用GPU运行,512*512的图片只需要不用一秒即可。并且该网络属于端对端网络,即输入图片,输出分割开的图片。
而U-Net提出的原因主要是:
卷积神经网络已经存在很久了,但因为缺少可用的训练数据集而没被大量使用,直到ImageNet数据集(百万张图片)的出现,传统的卷积网络的目标是分类,即对每个图片给予一个标签。但是对于很多视觉任务,特别是医疗图像方向,目标应该包括定位,以及对每个像素块给予一个标签。而且,医疗图像的训练集都不大。
2. 语义分割
对图片的每个像素都做分类。较为重要的语义分割数据集有:VOC2012 以及 MSCOCO。
深度学习最初流行的分割方法是,打补丁式的分类方法 ( patch classification ) 。逐像素地抽取周围像素对中心像素进行分类。由于当时的卷积网络末端都使用全连接层 ( full connected layers ) ,所以只能使用这种逐像素的分割方法。
关于语义分割:https://blog.csdn.net/yql_617540298/article/details/83143182
3. U-Net网络
参考链接:https://www.cnblogs.com/ChinaField-blog/p/10672648.html
参考链接:https://www.lizenghai.com/archives/27533.html
contracting path是典型的卷积网络架构:
- 架构中含有着一种重复结构,每次重复中都有2个33卷积层(无padding)、非线性ReLu层和一个22 max pooling层(stride为2)。(图中的蓝箭头、红箭头、没画ReLu)
- 每一次下采样后我们都把特征通道的数量加倍
expansive path也使用了一种相同的排列模式:
- 每一步都首先使用反卷积(up-convolution),每次使用反卷积都将特征通道数量减半,特征图大小加倍。
- 反卷积过后,将反卷积的结果与contracting path中对应步骤的特征图拼接起来。
- contracting path中的特征图尺寸稍大,将其修建过后进行拼接。
- 对拼接后的map再进行2次3*3的卷积。
- 最后一层的卷积核大小为1*1,将64通道的特征图转化为特定类别数量(分类数量,二分类为2)的结果。
为了允许输出分割图的无缝拼接(上图),重要的是要选择输入块大小,以便将所有2*2最大池化操作应用到具有对应x和y大小的层。
4. Pytorch实现U-Net
如何在本机上安装Pytorch环境
目前大部分都有anaconda,所以直接通过anaconda建立一个虚拟环境即可。
详细参考:https://www.cnblogs.com/zhouzhiyao/p/11784055.html
安装环境:win10+python3.6.2
在cmd中输入:
conda create -n pytorch python=3.6
直接选择输入Y
之后安静的等待安装
安装成功后,可以查看虚拟环境
conda info --envs
进入pytorch虚拟环境中
conda activate pytorch
之后,pytorch官方网站:http://pytorch.org/
根据自己的环境选择如何安装pytorch
或者:只用采用pip安装。
pip install torch==1.4.0+cpu torchvision==0.5.0+cpu -f https://download.pytorch.org/whl/torch_stable.html
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchsummary import summary
class unetConv2(nn.Module):
def __init__(self,in_size,out_size,is_batchnorm):
super(unetConv2,self).__init__()
if is_batchnorm:
self.conv1=nn.Sequential(
nn.Conv2d(in_size,out_size,kernel_size=3,stride=1,padding=0),
nn.BatchNorm2d(out_size),
nn.ReLU(inplace=True),
)
self.conv2=nn.Sequential(
nn.Conv2d(out_size,out_size,kernel_size=3,stride=1,padding=0),
nn.BatchNorm2d(out_size),
nn.ReLU(inplace=True),
)
else:
self.conv1=nn.Sequential(
nn.Conv2d(in_size,out_size,kernel_size=3,stride=1,padding=0),
nn.ReLU(inplace=True),
)
self.conv2=nn.Sequential(
nn.Conv2d(out_size,out_size,kernel_size=3,stride=1,padding=0),
nn.ReLU(inplace=True)
)
def forward(self, inputs):
outputs=self.conv1(inputs)
outputs=self.conv2(outputs)
return outputs
class unetUp(nn.Module):
def __init__(self,in_size,out_size,is_deconv):
super(unetUp,self).__init__()
self.conv=unetConv2(in_size,out_size,False)
if is_deconv:
self.up=nn.ConvTranspose2d(in_size,out_size,kernel_size=2,stride=2)
else:
self.up=nn.UpsamplingBilinear2d(scale_factor=2)
def forward(self, inputs1,inputs2):
outputs2=self.up(inputs2)
offset=outputs2.size()[2]-inputs1.size()[2]
padding=2*[offset//2,offset//2]
outputs1=F.pad(inputs1,padding) #padding is negative, size become smaller
return self.conv(torch.cat([outputs1,outputs2],1))
class unet(nn.Module):
def __init__(self,feature_scale=4,n_classes=21,is_deconv=True,in_channels=3,is_batchnorm=True):
super(unet,self).__init__()
self.is_deconv=is_deconv
self.in_channels=in_channels
self.is_batchnorm=is_batchnorm
self.feature_scale=feature_scale
filters=[64,128,256,512,1024]
filters=[int(x/self.feature_scale) for x in filters]
#downsample
self.conv1=unetConv2(self.in_channels,filters[0],self.is_batchnorm)
self.maxpool1=nn.MaxPool2d(kernel_size=2)
self.conv2=unetConv2(filters[0],filters[1],self.is_batchnorm)
self.maxpool2=nn.MaxPool2d(kernel_size=2)
self.conv3=unetConv2(filters[1],filters[2],self.is_batchnorm)
self.maxpool3=nn.MaxPool2d(kernel_size=2)
self.conv4=unetConv2(filters[2],filters[3],self.is_batchnorm)
self.maxpool4=nn.MaxPool2d(kernel_size=2)
self.center=unetConv2(filters[3],filters[4],self.is_batchnorm)
#umsampling
self.up_concat4=unetUp(filters[4],filters[3],self.is_deconv)
self.up_concat3=unetUp(filters[3],filters[2],self.is_deconv)
self.up_concat2=unetUp(filters[2],filters[1],self.is_deconv)
self.up_concat1=unetUp(filters[1],filters[0],self.is_deconv)
#final conv (without and concat)
self.final=nn.Conv2d(filters[0],n_classes,kernel_size=1)
def forward(self, inputs):
conv1=self.conv1(inputs)
maxpool1=self.maxpool1(conv1)
conv2=self.conv2(maxpool1)
maxpool2=self.maxpool2(conv2)
conv3=self.conv3(maxpool2)
maxpool3=self.maxpool3(conv3)
conv4=self.conv4(maxpool3)
maxpool4=self.maxpool4(conv4)
center=self.center(maxpool4)
up4=self.up_concat4(conv4,center)
up3=self.up_concat3(conv3,up4)
up2=self.up_concat2(conv2,up3)
up1=self.up_concat1(conv1,up2)
final=self.final(up1)
return final
if __name__=="__main__":
model=unet(feature_scale=1)
print(summary(model,(3,572,572)))
来源:CSDN
作者:蹦跶的小羊羔
链接:https://blog.csdn.net/yql_617540298/article/details/104495662