DeepLab系列总结
文章目录
- 转载
- DeepLab系列总结
- DeepLab V1
- DeepLab V2
- DeepLab V3
- DeepLab V3+
- 转载
DeepLab网络是由Liang-Chieh Chen(下文以大神指代)与google团队提出来的,是一个专门用来处理语义分割的模型。目前推出了4个(或者说3.5个)版本。最近把四个版本从头撸了一遍,做一个简单的总结。
DeepLab V1
原文:Semantic image segmentation with deep convolutional nets and fully connected CRFs
收录:ICLR 2015 (International Conference on Learning Representations)
Backbone:VGG16
Contributions:
Atrous convolution
CRF
DeepLab V1是基于VGG16网络改写的,一共做了三件事。
首先,去掉了最后的全连接层。做语义分割使用全卷积网络是大势所趋,DeepLab当然也不能例外。
然后,去掉了最后两个池化层。池化层是神经网络中的一个经典结构,没记错的话,BP解决了神经网络训练的软件问题(权重更新),pooling解决了训练的硬件问题(对计算资源的需求)。这就是池化层的第一个作用,缩小特征层的尺寸。池化层还有另一个重要作用,快速扩大感受野。为什么要扩大感受野呢?为了利用更多的上下文信息进行分析。
既然pooling这么好用,为什么要去掉俩呢?这个问题需要从头捋。先说传统(早期)DCNN,主要用来解决图片的分类问题,举个栗子,对于下边这张语义分割的图,传统模型只需要指出图片中有没有小轿车,至于小轿车在哪儿,不care。这就需要网络网络具有平移不变性。我们都知道,卷积本身就具有平移不变性,而pooling可以进一步增强网络的这一特性,因为pooling本身就是一个模糊位置的过程。所以pooling对于传统DCNN可以说非常nice了。
再来说语义分割。语义分割是一个end-to-end的问题,需要对每个像素进行精确的分类,对像素的位置很敏感,是个精细活儿。这就很尴尬了,pooling是一个不断丢失位置信息的过程,而语义分割又需要这些信息,矛盾就产生了。没办法,只好去掉pooling喽。全去掉行不行,理论上是可行的,实际使用嘛,一来显卡没那么大的内存,二来费时间。所以只去掉了两层。
(PS:在DeepLab V1原文中,作者还指出一个问题,使用太多的pooling,特征层尺寸太小,包含的特征太稀疏了,不利于语义分割。)
矛盾解决了,喜大普奔。
em……等等,好像忘了点儿啥。
哦,去了两个pooling,感受野又不够了怎么办?没关系,大神想了个办法,把atrous convolution借来用一下,这也是对VGG16的最后一个修改。atrous convolution人称空洞卷积(好像多称为dilation convolution,不过这是DeepLab的总结,那就得按DeepLab的来啊),相比于传统卷积,可以在不增加计算量的情况下扩大感受野,厉害了(?)。先上张图
空洞卷积与传统卷积的区别在于,传统卷积是三连抽,感受野是3,空洞卷积是跳着抽,也就是使用图中的rate,感受野一下扩大到了5(rate=2),相当于两个传统卷积,而通过调整rate可以自由选择感受野。这样感受野的问题就解决了。
另外,原文指出,空洞卷积的优势在于增加了特征的密度。盯着上边这张图我想了很久这个问题,虽然你画的密,但是卷积都是一对一的输入多大输出多大,怎么空洞卷积的特征就密了呢。~~一道闪电划过后,~~我终于想明白了,这张图你不能单独看,上边的传统卷积是经过pooling以后的第一个卷积层,而下边卷积输入的浅粉色三角正是被pooling掉的像素。所以,下边的输出是上边的两倍,特征多出了一倍当然密啦(?♂️)。
DeepLab V1的另一个贡献是使用条件随机场CRF提高分类精度。效果如下图,可以看到提升是非常明显的。具体CRF是什么原理呢?没有去研究,因为懒到了V3就舍弃了CRF。
最后来张DeepLab V1的全流程图,其中上采样直接使用了双线性采样。
DeepLab V2
原文:DeepLab: Semantic Image Segmentation with Deep Convolutional Nets, Atrous Convolution, and Fully Connected CRFs
收录:TPAMI2017 (IEEE Transactions on Pattern Analysis and Machine Intelligence, 2017)
Backbone:ResNet-101
Contributions:ASPP
在DeepLab V2中,可能是觉得VGG16表达能力有限,于是大神换用了更复杂,表达能力更强的ResNet-101。ResNet是由另一位大神Kaiming He 何恺明提出的。
在V2中,大神同样对ResNet动了刀,刀法和V1相同。V2的贡献在于更加灵活的使用了atrous convolution,提出了空洞空间金字塔池化ASPP。还是先给图
虽然名字挺复杂,但是看图就能轻易理解ASPP作用,说白了就是利用空洞卷积的优势,从不同的尺度上提取特征。这么做的原因也很简单,因为相同的事物在同一张图或不同图像中存在尺度上的差异。还是以这张图为例,图中的树存在多种尺寸,使用ASPP就能更好的对这些树进行分类。
至于ASPP如何融合到ResNet中,看图说话。将VGG16的conv6,换成不同rate的空洞卷积,再跟上conv7,8,最后做个大融合(对应相加或1*1卷积)就OK了。
DeepLab V3
原文:Rethinking Atrous Convolution for Semantic Image Segmentation
Backbone:ResNet-101
Contributions:
ASPP
Going deeper with atrous convolution
Remove CRF
说是三个贡献也不准确,姑且这么说吧。先来说最后一个,舍弃了CRF,因为分类结果精度已经提高到不需要CRF了(也可能是CRF不起作用了,谁知道呢)。
另外两个贡献,一个是改进了ASPP,另一个是使用空洞卷积加深网络,这两者算是一个二选一吧,是拓展网络的宽度,还是增加网络的深度。一般说起DeepLab V3模型指的是前者,因为从大神给出的结果和后续发展来看,明显前者效果更好一些。
对于ASPP,大神在V3中做了两点改进。一是在空洞卷积之后使用batch normalization,大神说BN对训练很有帮助。理由嘛,没有。第二点是增加了11卷积分支和image pooling分支。增加这两个分支是为了解决使用空洞卷积带来的问题,随着rate的增大,一次空洞卷积覆盖到的有效像素(特征层本身的像素,相应的补零像素为非有效像素)会逐渐减小到1(这里没有图全靠脑补)。这就与我们的初衷(获取更大范围的特征)相背离了。所以为了解决这个问题,一是使用11的卷积,也就是当rate增大以后33卷积的退化形式,替代33卷积,减少参数个数;另一点就是增加image pooling,可以叫做全局池化,来补充全局特征。具体做法是对每一个通道的像素取平均,之后再上采样到原来的分辨率。
ASPP的变化就这么多,再来简单说说另一种思路Going deeper with atrous convolution。为什么要加深网络呢,我理解的是为了获取更大的感受野。提到感受野自然离不开空洞卷积。还是看图说话,很显然pooling用多了特征层都快小的看不见了,所以大神给出了使用空洞卷积不断加深网络的一种思路。就这么回事儿,没啥可说的了。
DeepLab V3+
原文:Encoder-Decoder with Atrous Separable Convolution for Semantic Image Segmentation
Backbone:Xception
Contributions:
Xception
Encoder-decoder structure
DeepLab V3+再次修改了主网络,将ResNet-101升级到了Xception。在原始的Xception的基础上,大神进行了三点修改:1)使用更深的网络;2)将所有的卷积层和池化层用深度分离卷积Depthwise separable convolution进行替代,也就是下图中的Sep Conv;3)在每一次3*3 depthwise convolution之后使用BN和ReLU。
因为V3+使用深度分离卷积替代了pooling,那么为了缩小特征层尺寸,有几个block的最后一层的stride就必须为2,也就是下图中标红的层。具体有几个取决于输出output stride(下采样的大小)的设置。
Xception的核心是使用了Depthwise separable convolution。Depthwise separable convolution的思想来自inception结构,是inception结构的一种极限情况。Inception 首先给出了一种假设:卷积层通道间的相关性和空间相关性是可以退耦合的,将它们分开映射,能达到更好的效果。在inception结构中,先对输入进行11的卷积,之后将通道分组,分别使用不同的33卷积提取特征,最后将各组结果串联在一起作为输出。
Depthwise separable convolution是将这种分组演化到了极致,即把每一个通道作为一组。先对输入的每一个通道做33的卷积,将各个通道的结果串联后,再通过11的卷积调整到目标通道数。
说了这么多,好像还没说到使用depthwise separable convolution的好处。好处也很简单,大幅缩减参数个数。幅度有多大呢?举个简单的栗子,假设输入输出都是64通道,卷积核采用3*3,那么传统卷积的参数个数为
3∗3∗64∗64=36864
而Depthwise separable convolution为
3∗3∗64+1∗1∗64∗64=4672
只有前者的八分之一多点儿,而且通道数越多,节省的参数越多。em……很逆天。
说完了backbone,再来说说V3+的整体结构。前三个版本都是backbone(ASPP)输出的结果直接双线性上采样到原始分辨率,非常简单粗暴的方法,下图中的(a)。用了三个版本,大神也觉得这样做太粗糙了,于是吸取Encoder-Deconder的结构,下图中的(b),增加了一个浅层到输出的skip层,下图中的©。
下面说说具体的skip方法。首先,选取block2中的第二个卷积输出(看代码这个是固定的),使用11卷积调整通道数到48(减小通道数是为了降低其在最终结果中的比重),然后resize到指定的尺寸,也就是output stride。然后,将ASPP的输出resize到output stride。最后将两部分串联起来做两次33的卷积。最后的最后再做一次1*1的卷积,得到分类结果。最后的最后的最后将分类结果resize到原来的分辨率,嗯,还是熟悉的双线性采样。
写不动了,最后来张完整的流程图吧。