概述

在FCN网络在2104年提出后,越来越多的关于图像分割的深度学习网络被提出,相比传统方法,这些网络效果更好,运算速度更快,已经能成熟的运用在自然图像上。语义分割显然已经是计算机视觉领域的一个热门研究领域,也是通往实现完全场景理解的道路之一,被广泛应用于无人驾驶、人机交互、医疗图像、计算摄影、图像搜索引擎、增强现实等应用领域。语义分割是像素级分类问题,将同一类物体像素点归为一类,如图所示。

主要挑战

  • 池化或者卷积步长造成的特征图分辨率减小,不利于pixel-level的预测任务
  • 图像中存在多尺度的目标
  • 需要利用上下文的关系(高层特征)提高预测精度

不清楚的问题:

  • 错误匹配关系;
  • 类别混淆;
  • 类别不明显。

解决方法

  • dilated convolution;

    不降低特征分辨率的同时增大感受野

  • 图像金字塔;

  • 编码解码结构;

    多尺度特征

  • 级联结构;

  • 空间金字塔池化

    不同大小的感受野的卷积核 捕捉多尺度的对象

FCN

https://blog.csdn.net/qq_37274615/article/details/73251503

传统的基于 CNN 的分割方法缺点

传统基于CNN的图像分割方法:为了对每一个像素点分类,将该像素点周围的一个图像块裁剪,输入到CNN进行分类

缺点:

  • 存储开销大 因为有大量重复的存储
  • 效率低,含有大量重复计算
  • 裁剪像素块的大小限制了感受野大小,利用不到全局信息

FCN 的新思路:从抽象的全d局特征中恢复出每一个像素所属的类别。

解决了之前的效率低下和没有使用全局信息的缺点

https://blog.csdn.net/u011974639/article/details/79148719

DeepLab V1

  • 网络最后两个池化层替换成d=2的卷积
  • encoder高层使用空洞卷积 不可以少下采样一次 输出更加清晰
  • backbone: vgg16
  • 使用CRF 调整
  • 使用MLP 结合多尺度特征解决 多尺度物体的问题

DeepLab v2

  • 提出ASPP 解决多尺度物体的问题
  • backbone: resnet
  • 使用CRF调整

DeepLab v3

  • 提出通用框架 可以使用任意backbone

  • 复制resnet的block4 整出block5,6,7

    • 每一个block里面三个卷积
    • block5,6 stride=2
  • BN加入到 ASPP

  • 串行并行结构的区别?

    • 并行结构 承接v2的ASPP

      空洞卷积的d越大,padding的zero也就越多

  • 砍掉CRF

DeepLab v3 +

  • encoder = deeplab v2
  • decoder部分使用了encoder中stride=4的低层特征

代码学习

ASPP模块

某一个aspp支路

self.aspp4 = _ASPPModule(inplanes, 256, 3, padding=dilations[3], dilation=dilations[3], BatchNorm=BatchNorm)

细节: 为啥padding = dilation?

首先应该明确aspp模块的输入输出size不变,现在的卷积核大小是3,stride=1,对于大dilation的卷积核如果不padding是不可能滑行输入size那么多次的,需要padding的大小是k-1/2 这里的k指的是空洞卷积填充0之后的大小,不难看出恰好等于dilation

多支路并行

def forward(self, x):
    x1 = self.aspp1(x)
    x2 = self.aspp2(x)
    x3 = self.aspp3(x)
    x4 = self.aspp4(x)
    x5 = self.global_avg_pool(x) # 强行获得全局信息
    x5 = F.upsample(x5, size=x4.size()[2:], mode='bilinear')
    x = torch.cat((x1, x2, x3, x4, x5), dim=1)

    x = self.conv1(x)
    x = self.bn1(x)
    x = self.relu(x)

DeepLab整体框架

def forward(self, input):
    x, low_level_feat = self.backbone(input)
    x = self.aspp(x)
    x = self.decoder(x, low_level_feat)
    x = F.upsample(x, size=input.size()[2:], mode='bilinear', align_corners=True)

    return x

可以看出 真个流程是 backbone+ASPP+decoder