deeplabv3+论文笔记

一句话总结:deeplabv3+就是使用Xception作为backbone,将其最大池化(影响分辨率)去除,在深度可分离卷积上加上stride作为encoder的backbone,然后通过ASPP(不是传统的空间金字塔,而是通过11,33,5*5等不同卷积核的卷积和空洞卷积加上池化),得到五个不同的特征图再concat起来,然后送入decoder;docoder把backbone的特征和ASPP得到的特征concat,然后上采样得到我们需要的输出~~

以deeplabv3作为backbone,添加了decoder,相当于原来是上采样16倍,现在是先上采样4倍,再concat,再上采样四倍。
ASPP也有了一点变化,现在是4个空洞卷积加上池化,concate。

Deeplabv3

deeplabv3 中的DCNN 使用的是 ResNet-101的特征提取网络
deeplabv3+ 中的DCNN使用的是 Modified Aligned Xception
因为使用deeplabv3作为deeplabv3+的encoder,所以先show deeplabv3:

deeplabv3的缺点:
预测的feature map 直接双线性上采样16倍,到期望的尺寸,这样会 细节信息不够
在这里插入图片描述
所有的分支都包含256个通道和正则化,最终concat到一起,1x1卷积将通道数为256。再进行16倍上采样。

Deeplabv3+

在这里插入图片描述

使用了 【encoder-decoder】(高层特征提供语义,decoder逐步回复边界信息):提升了分割效果的同时,关注了边界的信息
encoder结构中:采用了 【Xception】 做为 DCNN、使用【ASPP】, 并将【深度可分离卷积(depthwise deparable conv)】应用在了ASPP 和 encoder 模块中,使网络更快。
decoder结构:采用一个简单的模块,用于恢复目标边界细节:原来是直接上采样16倍,现在是相当于shortcut,concat起来前面的部分之后再进行3*3卷积,再进行上采样得到期望的输出。

DCNN是Xception:此假设是Inception体系结构假设的更强版本,将提议的体系结构命名为Xception,它表示“Extreme Inception”。
Xception原图:
在这里插入图片描述
改进图
在这里插入图片描述
Sep Conv就是深度可分离卷积。所有的最大池化改为深度可分离卷积加上stride。池化之后对于恢复图像分辨率和细节有较大影响。所以标红的就是去掉Maxpooling的。

SPP融合了Atrous称为ASPP。
在这里插入图片描述
在这里插入图片描述

从backbone(Xception)出来的输出步幅为16的feature maps被送入了ASPP模块,在该模块中经过不同膨胀率的卷积块和一个全局信息提取块后,concat起来,最后经过一个1*1卷积块之后,即为ASPP模块的输出。

Encoder部分。高级特征经过ASPP的5个不同的操作得到5个输出,其中1个1×1卷积,3个不同rate的dillation conv,1个ImagePooling。这里要注意ImagePooling是全局平均池化之后再上采样到原来大小。这5个输出经过concatenate操作和1×1卷积得到output stride=16x的输出。

SPP:也就是空间金字塔池化,池化的操作如图: 256是channel, 分成了16份、4份、1份,再送入全连接层。
在这里插入图片描述
通过SPP层,特征映射被转化成了16X256+4X256+1X256 = 21X256的矩阵,在送入全连接时可以扩展成一维矩阵,即1X10752,所以第一个全连接层的参数就可以设置成10752了,这样也就解决了输入数据大小任意的问题了。

#coding=utf-8

import math
import torch
import torch.nn.functional as F

# 构建SPP层(空间金字塔池化层)
class SPPLayer(torch.nn.Module):

    def __init__(self, num_levels, pool_type='max_pool'):
        super(SPPLayer, self).__init__()

        self.num_levels = num_levels
        self.pool_type = pool_type

    def forward(self, x):
        num, c, h, w = x.size() # num:样本数量 c:通道数 h:高 w:宽
        for i in range(self.num_levels):
            level = i+1
            kernel_size = (math.ceil(h / level), math.ceil(w / level))
            stride = (math.ceil(h / level), math.ceil(w / level))
            pooling = (math.floor((kernel_size[0]*level-h+1)/2), math.floor((kernel_size[1]*level-w+1)/2))

            # 选择池化方式 
            if self.pool_type == 'max_pool':
                tensor = F.max_pool2d(x, kernel_size=kernel_size, stride=stride, padding=pooling).view(num, -1)
            else:
                tensor = F.avg_pool2d(x, kernel_size=kernel_size, stride=stride, padding=pooling).view(num, -1)

            # 展开、拼接
            if (i == 0):
                x_flatten = tensor.view(num, -1)
            else:
                x_flatten = torch.cat((x_flatten, tensor.view(num, -1)), 1)
        return x_flatten

在这里插入图片描述
采用了可分离卷积–结合空洞卷积。

猜你喜欢

转载自blog.csdn.net/caihuanqia/article/details/113883439
今日推荐