[语义分割]SPP、空洞卷积与ASPP总结

ASPP全称:Atrous Spatial Pyramid Pooling,中文可以理解为空洞空间卷积池化金字塔或者多孔空间金字塔池化。在这其中,要理解两个概念:一个是SPP,池化金字塔结构或者叫空间金字塔池化层,都是一个东西;另一个是Atrous,空洞卷积,两个概念加在一起产生了ASPP。

首先说一下SPP:Spatial Pyramid Pooling。这个结构出自于论文《Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition》,原文连接:https://arxiv.org/pdf/1406.4729.pdf

一、SPP

1.问题的产生

这里问了让逻辑更通顺,多讲一些,大佬们请跳到2

通常在神经网络的训练过程中,我们都需要保证数据集图片大小的一致性,可这是为什么呢?我们知道一个神经网络通常包含三个部分:卷积、池化、全连接。

假设给定一个30*30大小的输入图片,通过一个3*3的卷积核得到大小为29*29的输出和给定一个40*40大小的输入图片,得到大小为39*39的输出之间有区别吗?其实是没有区别的,因为在这里我们要训练的是卷积核的参数,与输入的图片大小无关。

再来看池化层,池化层其实可以理解成一个压缩的过程,无论是AVE还是MAX其实也输入都没啥关系,输出大小直接变为输出一半就完了(参数为2)。

所以问题出现在全连接层上,假设同一个池化层的输出分别是32*32*1和64*64*1,这就出问题了,因为全连接层的权重矩阵W是一个固定值,池化层的不同尺寸的输出会导致全连接层无法进行训练。

针对这个问题,原有的解决思路是通过拉伸或者裁剪去统一图片的尺寸,但是会造成信息丢失,失真等等众多问题。

                                                                                图1.图片变换后失去了原有的样子

所以大佬们就想了个办法,将原有的神经网络处理流程从图2改变为了图3,提出了SPP结构,也就是池化金字塔,利用多尺度解决这个问题。

                                                                                   图2.原有神经网络处理流程

                                                                         图3.带有SPP结构的神经网络处理流程

 

2.解决方案-SPP

                                                                                    图4.SPP模块示意图

SPP的思想就是利用多个不同尺度的池化层进行特征的提取,融合成一个21维的向量输入至全连接层。

如图4所示,从下往上看,输入图片的大小可以是任意的,经过卷积层卷积之后获取特征图的channels数量为256,将其输入到SPP结构中。图中从左往右看,分别将特征图分成了16个格子,4个格子和1个格子。

假设特征图大小是:width*height,这里蓝色格子的大小就是width/4*height/4,绿色格子的大小就是width/2*height/2,灰色格子的大小就是width*height。对每个格子分别进行池化,一般是采用MAX pooling,这样子我们分别可以得到16*256、4*256、1*256的向量,将其叠加就是21维向量,这样子就保证了无论输入图片尺寸是多少,最终经过SPP输出的尺度都是一致的,也就可以顺利地输入到全连接层。

这就是SPP层的处理过程,思路和结构都很巧妙。

 

二、空洞卷积

再一个就是空洞卷积,这里直接丢个连接:https://blog.csdn.net/lipengfei0427/article/details/108968914

 

三、ASPP

ASPP一开始在DeepLabv2中提出,DeepLab系列也是语义分割效果很棒的一个系列,丢个原文链接:https://arxiv.org/pdf/1606.00915.pdf

其实在理解了SPP模块和空洞卷积之后再来看ASPP就十分简单了。

                                                                                  图5.ASPP模块示意图

图5就是ASPP模块示意,对于给定的输入以不同采样率的空洞卷积并行采样,将得到的结果concat到一起,扩大通道数,然后再通过1*1的卷积将通道数降低到预期的数值。相当于以多个比例捕捉图像的上下文。

                                                                            图6.添加ASPP模块网络示意图

添加ASPP模块后的网络如图6所示,将Block4的输出输入到ASPP,经过多尺度的空洞卷积采样后经过池化操作,然后由1*1卷积将通道数降低至预期值。

在DeepLabv3中,在ASPP中加入了BN层,再丢一个DeepLabv3原文链接:https://arxiv.org/pdf/1706.05587.pdf

最后附一个没有BN层的ASPP代码(PyTorch)

#without bn version
class ASPP(nn.Module):
    def __init__(self, in_channel=512, depth=256):
        super(ASPP,self).__init__()
        self.mean = nn.AdaptiveAvgPool2d((1, 1)) #(1,1)means ouput_dim
        self.conv = nn.Conv2d(in_channel, depth, 1, 1)
        self.atrous_block1 = nn.Conv2d(in_channel, depth, 1, 1)
        self.atrous_block6 = nn.Conv2d(in_channel, depth, 3, 1, padding=6, dilation=6)
        self.atrous_block12 = nn.Conv2d(in_channel, depth, 3, 1, padding=12, dilation=12)
        self.atrous_block18 = nn.Conv2d(in_channel, depth, 3, 1, padding=18, dilation=18)
        self.conv_1x1_output = nn.Conv2d(depth * 5, depth, 1, 1)
 
    def forward(self, x):
        size = x.shape[2:]
 
        image_features = self.mean(x)
        image_features = self.conv(image_features)
        image_features = F.upsample(image_features, size=size, mode='bilinear')
 
        atrous_block1 = self.atrous_block1(x)
        atrous_block6 = self.atrous_block6(x)
        atrous_block12 = self.atrous_block12(x)
        atrous_block18 = self.atrous_block18(x)
 
        net = self.conv_1x1_output(torch.cat([image_features, atrous_block1, atrous_block6,
                                              atrous_block12, atrous_block18], dim=1))
        return net

参考连接:

https://www.cnblogs.com/zongfa/p/9076311.html

https://blog.csdn.net/qq_26898461/article/details/50424240

https://zhuanlan.zhihu.com/p/27485018

https://blog.csdn.net/qq_36530992/article/details/102628455

https://blog.csdn.net/qq_21997625/article/details/87080576

https://www.pianshen.com/article/5912309758/

猜你喜欢

转载自blog.csdn.net/lipengfei0427/article/details/109368471