淘先锋技术网

首页 1 2 3 4 5 6 7


标准二维卷积、转置卷积等详见上篇: https://blog.csdn.net/qq_43665602/article/details/126668764

一、膨胀卷积

1.介绍

膨胀卷积也称为扩张卷积或空洞卷积,一般可通过对标准二维卷积的卷积核设置合适的膨胀率(具体地指卷积核元素之间的距离)实现。合理利用膨胀卷积可在不引入其他参数的同时,扩大输出中元素的感受野,提高特征的全局表示能力
下面通过展示几个不同膨胀率下的卷积核大小以及感受野变化情况,可以更直观的理解:
图中灰色为输入,蓝色为卷积核,黄色为输出
1)dilation=1:表示卷积核元素之间距离为1,使用0进行大小为dilation-1=0的填充(这是默认情况),因此卷积核大小保持不变,依然是(2,2),输出中的每个元素映射回原始输入的大小为(2,2),既此时输出中元素的感受野大小为(2,2)
在这里插入图片描述
2)dilation=2:表示卷积核元素之间距离为2,使用0进行大小为dilation-1=1的填充,此时卷积核大小变为(3,3),输出中的每个元素映射回原始输入的大小为(3,3),既此时输出中元素的感受野大小为(3,3)
在这里插入图片描述
3)dilation=3:表示卷积核元素之间距离为3,使用0进行大小为dilation-1=2的填充,此时卷积核大小变为(4,4),输出中的每个元素映射回原始输入的大小为(4,4),既此时输出中元素的感受野大小为(4,4)
在这里插入图片描述
通过图示,可观察到当膨胀率变大时,输出特征元素对应的感受野随之变大,意味着输出特征更能体现原始输入的全局信息。

2.调用方式

torch.nn.Conv2d(
	in_channels, 
	out_channels, 
	kernel_size, 
	stride=1, 
	padding=0, 
	dilation=1, 
	groups=1, 
	bias=True, 
	padding_mode='zeros', 
	device=None, 
	dtype=None)

在调用时,通过设置合适的dilation(膨胀率,默认为1)即可实现不同的膨胀卷积。卷积核通过设置的膨胀率更改元素之间的距离,使用0填充这些间隔元素。

3.实例

inp=torch.tensor([[[[8., 8., 7., 4.],
          [4., 4., 8., 3.],
          [3., 9., 4., 1.],
          [7., 7., 9., 5.]]]])
# torch.Size([1, 1, 4, 4])
# print(inp)
# print(inp.shape)
print("-"*25)
dilation_conv2d=nn.Conv2d(
    in_channels=1,
    out_channels=1,
    kernel_size=2,
    stride=1,
    dilation=2
)
out=dilation_conv2d(inp)
print(out)
print(out.shape)
print("-"*25)
print(dilation_conv2d.weight)
print(dilation_conv2d.weight.shape)
print("-"*25)
print(dilation_conv2d.bias)
print(dilation_conv2d.bias.shape)
print("-"*25)

1)dilation=1:卷积核大小不变;
在这里插入图片描述
2)dilation=2:使用0对卷积核进行填充,使得卷积核元素之间距离为dilation-1=1,卷积核大小变为(3,3);
在这里插入图片描述
3)dilation=3:使用0对卷积核进行填充,使得卷积核元素之间距离为dilation-1=2,卷积核大小变为(4,4);
在这里插入图片描述

4.缺点

  • 卷积核元素不连续(因为元素之间按照膨胀率对卷积核进行0填充,所以原始元素被间隔开了,对应原始输入的元素也就被间隔开了),导致提取特征不连续;
  • 对于小目标而言,本身需要的感受野就不是很大,因此膨胀卷积在这种情况下不太适用;

二、可分离卷积

可分离卷积分为空间可分离卷积(spatially separable convolution)和深度可分离卷积(depthwise separable convolution)。对于类似多通道图像这样的三维数据而言,空间维度指高和宽维度,而深度指通道构成的维度。标准二维卷积通常利用大小为(kernel_size_h,kernel_size_w)的卷积核在高、宽方向的移动,实现特征提取。

1.空间可分离卷积

1)介绍

空间可分离卷积是在空间维度进行,首先将(kernel_size_h,kernel_size_w)=(M,M)的卷积核拆分为两个更小的(1,M)、(M,1)卷积核,然后依次使用(M,1)、(1,M)卷积核进行特征提取,达到标准卷积同样的效果。这样做可以很大程度降低卷积核需要学习的参数量,并且降低卷积过程中乘法运算的次数,网络运行速度更快。
下面通过实例及图示对此进行详细解释:
(1)比较经典的空间可分离卷积核,Sobel算子:将3×3卷积核拆为3×1,1×3的两个更小的卷积核,此时卷积核需要学习的参数从3×3=9个减少为3×1+1×3=6个参数。
在这里插入图片描述
(2)图中灰色为(5,5)输入,蓝色卷积核大小为(3,3),其他参数保持默认,黄色为输出,分别展示标准卷积与空间可分离卷积的卷积过程,以及卷积过程中涉及的乘法运算次数、参数量:
标准卷积情况下,卷积核沿着输入的高、宽方向均可移动三次,共移动3×3=9次,而每次要进行3×3=9次乘法运算,故乘法运算总次数为:9×9=81,参数量为卷积核大小:3×3=9
在这里插入图片描述
深度可分离卷积情况下,将卷积核拆分为大小为3×1,1×3的两个卷积核,然后分两步进行特征提取:①先使用3×1卷积核对输入进行特征提取;②然后使用1×3卷积核对第一步的卷积结果进行特征提取得到最终的卷积结果。在第一步卷积过程中,卷积核沿着输入的高、宽方向分别移动五、三次,共移动5×3=15次,而每次要进行3×1=3次乘法运算,故第一步乘法运算总次数为:15×3=45,参数量为卷积核大小:3×1=3;而第二步卷积过程中,卷积核沿着输入的高、宽方向均移动三次,共移动3×3=9次,而每次要进行1×3=3次乘法运算,故第二步乘法运算总次数为:9×3=27,参数量为卷积核大小:1×3=3;所以就最终的输出结果而言,乘法运算总次数为:45+27=72,参数量为:3+3=6,可看到相比标准卷积,空间可分离卷积降低了网络学习的参数量以及计算复杂性。
在这里插入图片描述
(3)推广验证
假设输入大小为:(N,N),卷积核大小为(M,M),其他参数保持默认,分别计算标准卷积和空间可分离卷积过程中涉及到的乘法运算次数:
标准卷积进行的过程中,卷积核在高、宽方向均可移动N-M+1次,故一共移动(N-M+1)×(N-M+1)次,每次移动执行M×M次乘法运算,因此乘法运算总次数为:(N-M+1)×(N-M+1)×M×M
在这里插入图片描述
空间可分离卷积进行的过程中,先将M×M卷积核拆分为大小为M×1,1×M的两个卷积核,然后分两步进行特征提取:①先使用M×1卷积核对输入进行特征提取;②然后使用1×M卷积核对第一步的卷积结果进行特征提取得到最终的卷积结果。在第一步卷积过程中,卷积核沿着输入的高、宽方向分别移动N、N-M+1次,共移动(N-M+1)×N次,而每次要进行M×1=M次乘法运算,故第一步乘法运算总次数为:(N-M+1)×N×M;而第二步卷积过程中,卷积核沿着输入的高、宽方向均移动(N-M+1)次,共移动(N-M+1)×(N-M+1)次,而每次要进行1×M=M次乘法运算,故第二步乘法运算总次数为:(N-M+1)×(N-M+1)×M;所以就最终的输出结果而言,乘法运算总次数为:(N-M+1)×(2N-M+1)×M。
在这里插入图片描述
现在我对,二者涉及的乘法次数进行比较,观察以下结果,通常输入大小N远大于卷积核大小M,
在这里插入图片描述
因此二者之比为:当M>=3时很明显看到空间可分离卷积可以大幅降低计算复杂度。在这里插入图片描述

2)优点及缺点

优点:

  • 降低卷积过程中的乘法运算的次数;
  • 降低网络需要学习的参数量(体现在卷积核拆成两个更小的卷积核,而这两个小卷积核的总元素数量小于原卷积核);

缺点:

  • 并非所有的卷积核都可以合理拆分为两个更小的卷积核,因此如果在神经网络中使用大量的深度可分离卷积去替换常用的标准卷积,则会降低卷积核参数的搜索空间,进而造成网络表示能力的下降。因此空间可分离卷积并不常用,局限性较大。

3)实例

此处实例将使用卷积核大小分别为(3,1)和(1,3)的连续卷积替代卷积核为(3,3)的标准卷积,依次展示空间可分离卷积实现的过程。

inp=torch.randint(10,size=(1,3,7,7),dtype=torch.float32)
conv0=nn.Conv2d(in_channels=3,out_channels=2,kernel_size=(3,3))
out0=conv0(inp)
print(out0.shape)
print('--'*10)
# 可分离卷积第一阶段
conv1=nn.Conv2d(in_channels=3,out_channels=2,kernel_size=(3,1))
out1=conv1(inp)
print(out1.shape)
print('--'*10)
# 可分离卷积第二阶段
conv2=nn.Conv2d(in_channels=2,out_channels=2,kernel_size=(1,3))
out2=conv2(out1)
print(out2.shape)
print('--'*10)
标准卷积输出:
torch.Size([1, 2, 5, 5])
--------------------
空间可分离卷积中间输出:
torch.Size([1, 2, 5, 7])
--------------------
空间可分离卷积最终输出:
torch.Size([1, 2, 5, 5])
--------------------

2.深度可分离卷积

1)介绍

相比空间可分离卷积而言,深度可分离卷积的应用更为普遍,深度可分离卷积同样可以大幅降低网络学习的计算复杂性,降低参数量,提高网络效率!深度可分离卷积分以下两阶段实现:

  • 利用深度卷积得到与输入通道数一致的特征;
  • 利用多组由1×1卷积核构成的过滤器扩展输入特征的深度;
    在这里插入图片描述

此处利用到的深度卷积是一种特殊的分组卷积方式,详见https://blog.csdn.net/qq_43665602/article/details/126750410

下面通过一系列图示及实例进行详细说明,此处实例的原始输入为(3,7,7),期望输出为(128,5,5)
(1)标准卷积:采用128组过滤器对输入进行特征提取,每个过滤器由3个(3,3)卷积核叠加而成。以此方式每个过滤器分别可在高、宽方向移动5次,共移动5×5=25次,每次移动所需乘法运算为3×3×3=27次,故乘法运算总次数为:25×27=675次,整个卷积过程中乘法运算总次数为:675×128=86400次,涉及到的参数量为:128×(3×3×3)=3456
在这里插入图片描述
(2)深度可分离卷积,分为深度卷积和1×1卷积两步完成
深度卷积:对于深度卷积来说,采用三组过滤器进行特征提取。每个滤波器的大小为(1,3,3),各自对应输入的一个通道进行特征提取得到各自大小为(1,5,5)的特征,再将得到的所有特征级联获得深度卷积的(3,5,5)输出结果。在此过程中,每个过滤器分别可在高、宽方向移动5次,共移动5×5=25次,每次移动所需乘法运算为3×3=9次,故乘法运算总次数为:25×9=225次,整个卷积过程中乘法运算总次数为:225×3=675次,涉及到的参数量为:3×3×3=27
在这里插入图片描述
1×1卷积:通过利用多组过滤器进行对深度卷积的输出结果进行特征提取,扩展其深度得到期望的结果。在这里,采用128组过滤器进行特征提取。每个滤波器的大小为(3,1,1),以此方式得到(128,5,5)的最终结果。此过程中,每个过滤器分别可在高、宽方向移动5次,共移动5×5=25次,每次移动所需乘法运算为3×1×1=3次,故乘法运算总次数为:25×3=75次,整个卷积过程中乘法运算总次数为:75×128=9600次,涉及到的参数量为:128×(3×1×1)=384在这里插入图片描述
结合深度卷积和1×1卷积两个步骤,在深度可分离卷积整个过程中涉及的乘法运算总次数为:675+9600=10275次,涉及到的参数量为:27+384=411。与标准卷积比较,深度可分离卷积大大降低了网络学习的参数量和计算复杂性。

2)优点及缺点

优点:

  • 可在不显著损失性能的前提下,提高网络效率;
  • 大幅降低网络学习的参数量和计算复杂性;
    缺点:
  • 对于小模型而言,由于参数量大幅下降,可能会严重损失模型性能;

3)实例

inp=torch.randint(10,size=(1,3,7,7),dtype=torch.float32)
conv0=nn.Conv2d(in_channels=3,out_channels=64,kernel_size=(3,3))
out0=conv0(inp)
print(out0.shape)
print('--'*10)
# 深度可分离卷积:通过设置groups沿着深度进行分组
conv1=nn.Conv2d(in_channels=3,out_channels=3,kernel_size=(3,3),groups=3)  # 深度卷积
out1=conv1(inp)
print(out1.shape)
print('--'*10)
conv2=nn.Conv2d(in_channels=3,out_channels=64,kernel_size=(1,1))  # 1*1卷积
out2=conv2(out1)
print(out2.shape)
print('--'*10)
标准卷积输出:
torch.Size([1, 64, 5, 5])
--------------------
深度可分离卷积中间输出(深度卷积):
torch.Size([1, 3, 5, 5])
--------------------
深度可分离卷积最终输出(1×1卷积):
torch.Size([1, 64, 5, 5])
--------------------

三、分组卷积

1.介绍

分组卷积的提出是为了解决当时硬件设备的限制问题,作者在《ImageNet Classification with Deep Convolutional Neural Networks》一文中引入分组卷积,利用多个GPU对输入进行并行处理,最后将各个GPU的处理结果融合在一起,完成特征提取工作。
在这里插入图片描述
图中网络的多数中间层均分两条支路进行多GPU并行学习,直观地体现了分组卷积的工作方式。

2.调用方式以及nn.Conv2d的groups参数详解

分组卷积是通过对标准卷积的in_channels, out_channels以及groups参数进行合适的设置实现,下面对groups参数做一个详细介绍:

torch.nn.Conv2d(
	in_channels, 
	out_channels, 
	kernel_size, 
	stride=1, 
	padding=0, 
	dilation=1, 
	groups=1, 
	bias=True, 
	padding_mode='zeros', 
	device=None, 
	dtype=None)

groups:这是分组的意思,控制对于卷积层的输入特征和输出特征之间的联系,表示在进行卷积处理时,将整个输入特征沿着通道的方向划分为多少组进行各自的处理。需要注意,该卷积层in_channels和out_channels均可被设置的groups整除,默认groups=1

这里我通过不同groups下,输入、卷积核、输出之间的关系对此进行直观的展示:
图中蓝色为输入特征,绿色为卷积核,输出为黄色
1)首先复习以下标准卷积在卷积过程中的一个通用情况:对于标准卷积而言,采用C_out组过滤器进行特征提取。每个过滤器由C_in个卷积核叠加而成,每个过滤器沿着输入的高、宽方向移动,实现卷积过程,得到一个单通道的输出,所有过滤器的卷积结果最后级联在一起构成最终的卷积结果。
在这里插入图片描述
2)对于分组卷积而言,设置不同的groups可控制不同的卷积过程:
(1)groups=1,此时和标准卷积等价,所有的输入特征一起进行卷积得到最后的输出结果;
(2)groups=2,此时将输入特征沿着通道分为2组分别进行卷积,卷积通过两个分支进行,最后将各自的结果级联构成最后的输出。此时每个过滤器均由C_in/groups=C_in/2个卷积核叠加构成,而每个分支中均有C_out/groups=C_out/2个过滤器,因此各个分支中卷积核的大小为(C_in/2,K_h,K_w),输出结果为(C_out/2,H_out,W_out),然后将两个分支的结果级联构成(C_out,H_out,W_out)的输出。
在这里插入图片描述
(3)同理,当groups=C_in,此时将输入特征沿着通道分为C_in组分别进行卷积,卷积通过两个分支进行,最后将各自的结果级联构成最后的输出。此时每个过滤器均由C_in/groups=C_in/C_in=1个卷积核叠加构成,而每个分支中均有C_out/groups=C_out/C_in个过滤器,因此各个分支中卷积核的大小为(1,K_h,K_w),输出结果为(C_out/C_in,H_out,W_out),然后将C_in个分支的结果级联构成(C_out,H_out,W_out)的输出。
从以上不同的分组卷积的输入、输出结果来看,其实最终完成的任务与标准卷积一样,区别只是在分组卷积中我们通过设置groups将卷积过程分为多个分支进行,而标准卷积由一个分支完成(下面代码测试结果也可以说明这一点)

3.实例

import torch
import torch.nn as nn


inp=torch.randint(10,size=(1,10,4,4),dtype=torch.float32)
print("-"*25)
conv2d=nn.Conv2d(
    in_channels=10,
    out_channels=8,
    kernel_size=2,
    stride=1,
)
out=conv2d(inp)
print(out.shape)
print("-"*25)
groups_conv2d=nn.Conv2d(
    in_channels=10,
    out_channels=8,
    kernel_size=2,
    stride=1,
    groups=2
)
out1=groups_conv2d(inp)
print(out1.shape)
print("-"*25)
-------------------------
torch.Size([1, 8, 3, 3])
-------------------------
torch.Size([1, 8, 3, 3])
-------------------------

4.优点

先看以下分组卷积与标准卷积各自需要学习的参数量:
标准卷积:过滤器形状为(C_out,C_in,K_h,K_w),则参数量为:C_out×C_in×K_h×K_w
分组卷积(以groups=2为例):过滤器分两组,每组过滤器形状为(C_out/2,C_in/2,K_h,K_w),则参数量为:(C_out/2×C_in/2×K_h×K_w)×2=(C_out×C_in×K_h×K_w)/2。推广,通用情况下参数量为:(C_out×C_in×K_h×K_w)/groups。很明显看到分组卷积使用更小的参数量实现了与标准卷积相同的结果

优点:
(1)降低网络学习的参数量,缓解过拟合,提高网络训练速度;
(2)在多GPU上的多分支模型并行学习的方式使模型训练更高效;
(3)采用分组卷积通常可以比标准卷积提供更好的模型;

四、可变形卷积

关于可变形卷积有机会我会单独写一篇文章来说明。

参考资料

1.部分图来源:
(1)
https://towardsdatascience.com/intuitively-understanding-convolutions-for-deep-learning-1f6f42faee1
(2)https://www.163.com/dy/article/E8F50CLJ05118HA4.html
(3)https://proceedings.neurips.cc/paper/2012/file/c399862d3b9d6b76c8436e924a68c45b-Paper.pdf
2.参考:
https://www.163.com/dy/article/E8F50CLJ05118HA4.html
文章通过参考及自己理解汇总,如有错误,欢迎大家评论探讨!我会及时更正,谢谢。