Pytorch之经典神经网络语义分割(3.1) —— 空洞卷积 Dilated conv/Atrous Conv (膨胀卷积/扩张卷积)(扩张率dilation rate) & pytorch实现

2016年提出的

空洞卷积广泛应用于语义分割与目标检测等任务中

空洞卷积(膨胀卷积/扩张卷积) Dilated/Atrous Convolution

空洞卷积是一种不增加参数量(运算量)同时增加输出单元感受野的一种方法。Atrous 卷积,就是带洞的卷积,卷积核是稀疏的

此外,空洞卷积还可以捕获多尺度上下文信息。通过设置不同的dilation rate,感受野就会不一样,也即获取了多尺度信息。多尺度信息在视觉任务中相当重要。

空洞卷积的概念是从语义分割任务中发展出来的,是为了解决基于FCN思想的语义分割中,输出图像的size要求和输入图像的size一致而需要upsample,但由于FCN中使用pooling操作来增大感受野同时降低分辨率,导致upsample无法还原由于pooling导致的一些细节信息的损失的问题而提出的。为了减小这种损失,自然需要移除pooling层,因此空洞卷积应运而生。

原先的 CNN architecture 是用一个“实心”的 kernal 去扫描 input data,然后使用 pooling 方法直接暴力的删掉其余 75% 的信息量,只留下 25% 的原汁原味,这样的做法在还没有精确到 pixel-wise 的情况时还是可以行的通的,一旦要归类到小至 pixel 等级的尺度时,pooling 对原 data 的破坏力足以让事情搞砸,试想一个原始数据被经过 Convolution 剥离出了其区域特征后,接着下一个环节被大刀阔斧般的砍去内部信息,并且永久无法复原,小物体信息无法重建 (假设有四个pooling layer 则任何小于 2^4 = 16 pixel 的物体信息在理论上将无法重建和分割)。这是在微小的 pixel 世界中无法接受的做法。

如果说 pooling 这种简单删减 data 让单位 output 中 Receptive Field 增大的方法不可行,就需要一个新的在不删减原始数据的情况下,直接让 Receptive Field 提升的办法:Dilated Convolution。简单的说,就是把原本“实心”的 kernal 元素之间按照一定规律插入 0 元素作为空格

空洞卷积向卷积层引入了一个称为 “扩张率(dilation rate)”的新参数,该参数定义了卷积核处理数据时各值的间距。

看下图可以对膨胀率有一个比较直观的理解

假设原始特征为feat0

首先使用扩张率为1的空洞卷积生成feat1,feat1上一点相对feat0感受野为3*3(如图a);

然后使用扩张率为2的空洞卷积处理feat1生成feat2(如图b),使第一次空洞卷积的卷积核大小等于第二次空洞卷积的一个像素点的感受野,图b即feat1上一个点综合了图a即feat0上3*3区域的信息,则生成的feat2感受野为7*7,即整个图b深色区域;

第三次处理同上,第二次空洞卷积的整个卷积核大小等于第三次空洞卷积的一个像素点的感受野,图c即feat2上每个点综合了feat0上7*7的信息(感受野),则采用扩张率为3的空洞卷积,生成的feat3每一个点感受野为15*15。

普通卷积的结果的size是

经过空洞卷积后的结果的size是

r是dilation

例子:7*7的feature map,kernel size = 3, padding = 0,stride = 1, dilation =2
标准卷积后大小F为(7-3+0)/1+1 = 5,Dilated卷积后大小F为[7-(3+2*1)+0]/1+1=3

空洞卷积存在的问题

潜在问题 1:The Gridding Effect

假设我们仅仅多次叠加 dilation rate 2 的 3 x 3 kernel 的话,则会出现这个问题:

我们发现我们的 kernel 并不连续,也就是并不是所有的 pixel 都用来计算了,因此这里将信息看做 checker-board 的方式会损失信息的连续性。这对 pixel-level dense prediction 的任务来说是致命的。

由于空洞卷积的计算方式类似于棋盘格式,某一层得到的卷积结果,来自上一层的独立的集合,没有相互依赖,因此该层的卷积结果之间没有相关性,即局部信息丢失

潜在问题 2:Long-ranged information might be not relevant.

我们从 dilated convolution 的设计背景来看就能推测出这样的设计是用来获取 long-ranged information。然而光采用大 dilation rate 的信息或许只对一些大物体分割有效果,而对小物体来说可能则有弊无利了。如何同时处理不同大小的物体的关系,则是设计好 dilated convolution 网络的关键。

由于空洞卷积稀疏的采样输入信号,使得远距离卷积得到的信息之间没有相关性,影响分类结果。

解决方法: Hybrid Dilated Convolution (HDC)

 总结-空洞卷积(Dilated/Atrous Convolution) - 知乎

代码实现 nn.Conv2d(dialation)

dilation convolution的操作内置在nn.Conv2d里面了

正常的紧密的kernel,dialation=1(默认)

dialation=2的情况,就不是紧凑的了

手动实现

import torch
from torch import nn
import torch.nn.functional as F
import math
 
def my_conv(input, kernel, stride=1, padding=0, bias=0, dilation=1):
    if padding > 0:
        input = F.pad(input, (padding,padding,padding,padding))
    batch_size, in_channel, input_h, input_w= input.shape
    out_channel, _, kernel_h, kernel_w = kernel.shape
    
    #本来紧凑的输入,现在相邻点之间要插入dialation-1个空洞,共插入kernel_h-1次
    kernel_h = (kernel_h-1)*(dilation-1)+kernel_h
    kernel_w = (kernel_w-1)*(dilation-1)+kernel_w
    
    output_h = math.floor((input_h - kernel_h) / stride + 1)
    output_w = math.floor((input_w - kernel_w) / stride + 1)
    output = torch.zeros(batch_size, out_channel, output_h, output_w)
    
    if bias is None:
        bias = torch.zeros(out_channel)
    
    for b in range(batch_size):
        for c in range(out_channel):
            for i in range(0, input_h - kernel_h + 1, stride):
                for j in range(0, input_w - kernel_w + 1, stride):
                    region = input[b,:,i:i+kernel_h:dilation, j:j+kernel_w:dilation]
                    output[b,c,int(i/stride), int(j/stride)] = torch.sum(region*kernel[c]) + bias[c]                
    return output
 
batch_size = 4
in_channel = 4
out_channel = 16
dilation = 2
input = torch.rand(batch_size, in_channel ,5,5)
kernel = torch.rand(out_channel, in_channel, 3,3)
bias = torch.rand(out_channel)
 
my_output = my_conv(input, kernel, padding=1, stride=2, bias=bias, dilation=dilation)
output = F.conv2d(input, kernel, padding=1, stride=2, bias=bias, dilation=dilation)
 
assert torch.allclose(my_output, output)

空洞卷积感受野的大小取决于卷积核的大小和空洞卷积。对于正常的空洞卷积,感受野尺寸可以通过以下公式计算:感受野尺寸 = (空洞卷积-1)(卷积核大小-1)+ 卷积核大小。而对于padding的空洞卷积,感受野尺寸可以通过以下公式计算:感受野尺寸 = 2(空洞卷积-1)*(卷积核大小-1)+ 卷积核大小。\[1\] 需要注意的是,有时候人们会误解空洞卷积的感受野计算公式,将其视为单独空洞卷积形成的感受野。实际上,这个计算公式是针对普通卷积和不同空洞空洞卷积级联实现的感受野。对于单独空洞卷积形成的感受野大小,可以使用简单的计算方法。\[2\] 空洞卷积是为了解决图像语义分割问题中下采样导致的图像分辨降低和信息丢失而提出的一种卷积思路。通过添加空洞来扩大感受野,使得在相同参数量和计算量下,卷积核可以拥有更大的感受野,从而无需下采样。具体来说,空洞卷积在普通卷积中间填充不参与卷积运算的空洞结构。对于特定的空洞卷积核大小,可以得到等效的卷积核大小和参与运算的点的分布。\[3\] #### 引用[.reference_title] - *1* [空洞卷积感受野大小计算](https://blog.csdn.net/weixin_42560055/article/details/83313839)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [空洞卷积感受野的正确计算方法](https://blog.csdn.net/IcdKnight/article/details/116330830)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值