语义分割算法之DeepLabV3+论文理解及代码分析

前言

之前讲了DeepLabV1,V2,V3三个算法,DeepLab系列语义分割还剩下最后一个DeepLabV3+,以后有没有++,+++现在还不清楚,我们先来解读一下这篇论文并分析一下源码吧。论文地址:https://arxiv.org/pdf/1802.02611.pdf

背景

语义分割主要面临两个问题,第一是物体的多尺度问题,第二是DCNN的多次下采样会造成特征图分辨率变小,导致预测精度降低,边界信息丢失。DeepLab V3设计的ASPP模块较好的解决了第一个问题,而这里要介绍的DeepLabv3+则主要是为了解决第2个问题的。
我们知道从DeepLabV1系列引入空洞卷积开始,我们就一直在解决第2个问题呀,为什么现在还有问题呢?
我们考虑一下前面的代码解析推文的DeepLab系列网络的代码实现,地址如下:https://mp.weixin.qq.com/s/0dS0Isj2oCo_CF7p4riSCA 。对于DeepLabV3,如果Backbone为ResNet101,Stride=16将造成后面9层的特征图变大,后面9层的计算量变为原来的4倍大。而如果采用Stride=8,则后面78层的计算量都会变得很大。这就造成了DeepLabV3如果应用在大分辨率图像时非常耗时。所以为了改善这个缺点,DeepLabV3+来了。

算法原理

DeepLabV3+主要有两个创新点。

编解码器

为了解决上面提到的DeepLabV3在分辨率图像的耗时过多的问题,DeepLabV3+在DeepLabV3的基础上加入了编码器。具体操作见论文中的下图:
在这里插入图片描述其中,(a)代表SPP结构,其中的8x是直接双线性插值操作,不用参与训练。(b)是编解码器,融集合了高层和低层信息。©是DeepLabv3+采取的结构。

我们来看一下DeepLabV3+的完整网络结构来更好的理解这点:

在这里插入图片描述
对于编码器部分,实际上就是DeepLabV3网络。首先选一个低层级的feature用1 * 1的卷积进行通道压缩(原本为256通道,或者512通道),目的是减少低层级的比重。论文认为编码器得到的feature具有更丰富的信息,所以编码器的feature应该有更高的比重。 这样做有利于训练。
对于解码器部分,直接将编码器的输出上采样4倍,使其分辨率和低层级的feature一致。举个例子,如果采用resnet conv2 输出的feature,则这里要 × 4 \times 4 ×4上采样。将两种feature连接后,再进行一次 3 × 3 3 \times 3 3×3的卷积(细化作用),然后再次上采样就得到了像素级的预测。

实验结果表明,这种结构在Stride=16时有很高的精度速度又很快。stride=8相对来说只获得了一点点精度的提升,但增加了很多的计算量。

更改主干网络

论文受到近期MSRA组在Xception上改进工作可变形卷积(Deformable-ConvNets)启发,Deformable-ConvNets对Xception做了改进,能够进一步提升模型学习能力,新的结构如下:
在这里插入图片描述
最终,论文使用了如下的改进:

  • 更深的Xception结构,不同的地方在于不修改entry flow network的结构,为了快速计算和有效的使用内存
  • 所有的max pooling结构被stride=2的深度可分离卷积代替
  • 每个3x3的depthwise convolution都跟BN和Relu

最后将改进后的Xception作为encodet主干网络,替换原本DeepLabv3的ResNet101。

实验

论文使用modified aligned Xception改进后的ResNet-101,在ImageNet-1K上做预训练,通过扩张卷积做密集的特征提取。采用DeepLabv3的训练方式(poly学习策略,crop 513 × 513 513\times 513 513×513)。注意在decoder模块同样包含BN层。

使用1*1卷积少来自低级feature的通道数

上面提到过,为了评估在低级特征使用1*1卷积降维到固定维度的性能,做了如下对比实验:
在这里插入图片描述
实验中取了 C o n v 2 Conv2 Conv2尺度为 [ 3 × 3 , 256 ] [3\times3,256] [3×3,256]的输出,降维后的通道数在32和48之间最佳,最终选择了48。

使用3*3卷积逐步获取分割结果

编解码特征图融合后经过了 3 × 3 3\times 3 3×3卷积,论文探索了这个卷积的不同结构对结果的影响:
在这里插入图片描述

最终,选择了使用两组 3 × 3 3\times 3 3×3卷积。这个表格的最后一项代表实验了如果使用 C o n v 2 Conv2 Conv2 C o n v 3 Conv3 Conv3同时预测, C o n v 2 Conv2 Conv2上采样2倍后与 C o n v 3 Conv3 Conv3结合,再上采样2倍的结果对比,这并没有提升显著的提升性能,考虑到计算资源的限制,论文最终采样简单的decoder方案,即我们看到的DeepLabV+的网络结构图。

Backbone为ResNet101

在这里插入图片描述

Backbone为Xception

在这里插入图片描述
这里可以看到使用深度分离卷积可以显著降低计算消耗。

与其他先进模型在VOC12的测试集上对比:

在这里插入图片描述在目标边界上的提升,使用trimap实验模型在分割边界的准确度。计算边界周围扩展频带(称为trimap)内的mIoU。结果如下:

在这里插入图片描述
与双线性上采样相比,加decoder的有明显的提升。trimap越小效果越明显。Fig5右图可视化了结果。

结论

论文提出的DeepLabv3+是encoder-decoder架构,其中encoder架构采用Deeplabv3,decoder采用一个简单却有效的模块用于恢复目标边界细节。并可使用空洞卷积在指定计算资源下控制feature的分辨率。论文探索了Xception和深度分离卷积在模型上的使用,进一步提高模型的速度和性能。模型在VOC2012上获得了SOAT。Google出品,必出精品,这网络真的牛。

代码实现

结合一下网络结构图还有我上次的代码解析点这里 看,就很容易了。


from __future__ import absolute_import, print_function

from collections import OrderedDict

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

from .deeplabv3 import _ASPP
from .resnet import _ConvBnReLU, _ResLayer, _Stem


class DeepLabV3Plus(nn.Module):
    """
    DeepLab v3+: Dilated ResNet with multi-grid + improved ASPP + decoder
    """

    def __init__(self, n_classes, n_blocks, atrous_rates, multi_grids, output_stride):
        super(DeepLabV3Plus, self).__init__()

        # Stride and dilation
        if output_stride == 8:
            s = [1, 2, 1, 1]
            d = [1, 1, 2, 4]
        elif output_stride == 16:
            s = [1, 2, 2, 1]
            d = [1, 1, 1, 2]

        # Encoder
        ch = [64 * 2 ** p for p in range(6)]
        self.layer1 = _Stem(ch[0])
        self.layer2 = _ResLayer(n_blocks[0], ch[0], ch[2], s[0], d[0])
        self.layer3 = _ResLayer(n_blocks[1], ch[2], ch[3], s[1], d[1])
        self.layer4 = _ResLayer(n_blocks[2], ch[3], ch[4], s[2], d[2])
        self.layer5 = _ResLayer(n_blocks[3], ch[4], ch[5], s[3], d[3], multi_grids)
        self.aspp = _ASPP(ch[5], 256, atrous_rates)
        concat_ch = 256 * (len(atrous_rates) + 2)
        self.add_module("fc1", _ConvBnReLU(concat_ch, 256, 1, 1, 0, 1))

        # Decoder
        self.reduce = _ConvBnReLU(256, 48, 1, 1, 0, 1)
        self.fc2 = nn.Sequential(
            OrderedDict(
                [
                    ("conv1", _ConvBnReLU(304, 256, 3, 1, 1, 1)),
                    ("conv2", _ConvBnReLU(256, 256, 3, 1, 1, 1)),
                    ("conv3", nn.Conv2d(256, n_classes, kernel_size=1)),
                ]
            )
        )

    def forward(self, x):
        h = self.layer1(x)
        h = self.layer2(h)
        h_ = self.reduce(h)
        h = self.layer3(h)
        h = self.layer4(h)
        h = self.layer5(h)
        h = self.aspp(h)
        h = self.fc1(h)
        h = F.interpolate(h, size=h_.shape[2:], mode="bilinear", align_corners=False)
        h = torch.cat((h, h_), dim=1)
        h = self.fc2(h)
        h = F.interpolate(h, size=x.shape[2:], mode="bilinear", align_corners=False)
        return h


if __name__ == "__main__":
    model = DeepLabV3Plus(
        n_classes=21,
        n_blocks=[3, 4, 23, 3],
        atrous_rates=[6, 12, 18],
        multi_grids=[1, 2, 4],
        output_stride=16,
    )
    model.eval()
    image = torch.randn(1, 3, 513, 513)

    print(model)
    print("input:", image.shape)
print("output:", model(image).shape)

参考文章

https://blog.youkuaiyun.com/u011974639/article/details/79518175


欢迎关注我的微信公众号GiantPadaCV,期待和你一起交流机器学习,深度学习,图像算法,优化技术,比赛及日常生活等。
图片.png

### DeepLabV3 语义分割使用教程和实现方法 #### 实现框架选择 对于构建语义分割平台,可以选择PyTorch或TensorFlow作为开发环境。前者提供了简洁易懂的API接口,后者则拥有更广泛的社区支持和技术文档[^2]。 #### DeeplabV3+架构详解 DeeplabV3+是一种先进的语义分割网络结构,在保持高分辨率的同时能够捕捉图像中的细节特征。其核心组件为空洞卷积(也称为膨胀卷积),这使得模型可以在不增加参数量的情况下扩大感受野范围;另外还引入了ASPP模块来增强多尺度上下文信息的学习能力[^1]。 #### 数据准备与预处理 为了训练有效的语义分割模型,高质量的数据集至关重要。可以采用`labelme`这样的工具来进行自定义类别的标注工作,并将其转化为适合输入给定神经网络的形式。如果需要调整图片大小,则可以通过编写简单的脚本来完成这一操作[^4]: ```python import cv2 from pathlib import Path def resize_images(input_dir, output_dir, target_size=(395, 700)): input_path = Path(input_dir) output_path = Path(output_dir) if not output_path.exists(): output_path.mkdir(parents=True) for img_file in input_path.glob('*.jpg'): img = cv2.imread(str(img_file)) resized_img = cv2.resize(img, dsize=target_size) save_path = str(output_path / img_file.name) cv2.imwrite(save_path, resized_img) resize_images('./input_images', './output_resized') ``` 此代码片段展示了如何利用Python库OpenCV批量改变指定文件夹内所有JPEG格式照片的尺寸并保存至另一位置。 #### 训练过程概述 当准备好数据后便可以着手于实际的模型训练阶段。以PyTorch为例,整个流程大致如下所示: - 加载已有的预训练权重(如ResNet),以便加速收敛速度; - 定义损失函数(通常是交叉熵损失)以及优化器; - 将训练样本送入GPU/CPU设备中进行前向传播计算预测结果; - 反馈误差信号更新权值直至满足停止条件为止。 #### 测试评估环节 经过充分迭代后的模型应当能够在验证集上取得较好的表现。此时可进一步测试未知样例的效果并通过可视化手段直观展示出来。常用的性能度量标准包括但不限于平均交并比(mean Intersection over Union)[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值