1、常规卷积:
- 需要的参数量:Cin×K×K×Cout
2、分组卷积:
分组卷积需要的计算量 : Cin×K×K×Cout / g
3、深度可分离卷积(Depthwise Separable Convolution):
要的计算量:Cin×K×K+Cout×1×1
3.1 深度可分离卷积的过程
而应用深度可分离卷积的过程是①用16个3×3大小的卷积核(1通道)分别与输入的16通道的数据做卷积(这里使用了16个1通道的卷积核,输入数据的每个通道用1个3×3的卷积核卷积),得到了16个通道的特征图,我们说该步操作是depthwise(逐层)的,在叠加16个特征图之前,②接着用32个1×1大小的卷积核(16通道)在这16个特征图进行卷积运算,将16个通道的信息进行融合(用1×1的卷积进行不同通道间的信息融合),我们说该步操作是pointwise(逐像素)的。这样我们可以算出整个过程使用了3×3×16+(1×1×16)×32 =656个参数。
3.2 深度可分离卷积的优点
可以看出运用深度可分离卷积比普通卷积减少了所需要的参数。重要的是深度可分离卷积将以往普通卷积操作同时考虑通道和区域改变成,卷积先只考虑区域,然后再考虑通道。实现了通道和区域的分离。
4、空洞(扩张)卷积(Dilated/Atrous Convolution)
空洞卷积(dilated convolution)是针对图像语义分割问题中下采样会降低图像分辨率、丢失信息而提出的一种卷积思路。利用添加空洞扩大感受野,让原本3
x3的卷积核,在相同参数量和计算量下拥有5x5(dilated rate =2)或者更大的感受野,从而无需下采样。扩张卷积(dilated convolutions)又名空洞卷积(atrous convolutions),向卷积层引入了一个称为 “扩张率(dilation rate)”的新参数,该参数定义了卷积核处理数据时各值的间距。换句话说,相比原来的标准卷积,扩张卷积(dilated convolution) 多了一个hyper-parameter(超参数)称之为dilation rate(扩张率),指的是kernel各点之前的间隔数量,【正常的convolution 的 dilatation rate为 1】。
4.1 图说空洞卷积的概念
比如上图中(a),dilated=1,F(dilated) = 3×3;图(b)中,dilated=2,F(dilated)=7×7;图(c)中,dilated=4, F(dilated)=15×15。
dilated=2时具体的操作,即按照下图在空洞位置填入0之后,然后直接卷积就可以了
4.2 空洞卷积的动态过程
在二维图像上直观地感受一下扩张卷积的过程:
上图是一个扩张率为2的3×3卷积核,感受野与5×5的卷积核相同,而且仅需要9个参数。你可以把它想象成一个5×5的卷积核,每隔一行或一列删除一行或一列。
在相同的计算条件下,空洞卷积提供了更大的感受野。空洞卷积经常用在实时图像分割中。当网络层需要较大的感受野,但计算资源有限而无法提高卷积核数量或大小时,可以考虑空洞卷积。
5、代码实现
import torch
from torchsummary import summary
import torch.nn as nn
'''
实现分组卷积demo
'''
class CRNN(nn.Module):
def __init__(self,in_channel,out_channel,group):
super(CRNN,self).__init__()
self.conv = nn.Conv2d(in_channels=in_channel,
out_channels=out_channel,
kernel_size=3,
stride=1,
padding=1,
groups=group,
bias=False)
def forward(self,input):
out = self.conv(input)
return out
'''
深度可分离卷积demo
'''
class DEPTHWISECONV(nn.Module):
def __init__(self,in_ch,out_ch):
super(DEPTHWISECONV, self).__init__()
self.depth_conv = nn.Conv2d(in_channels=in_ch,
out_channels=in_ch,
kernel_size=3,
stride=1,
padding=1,
groups=in_ch)
self.point_conv = nn.Conv2d(in_channels=in_ch,
out_channels=out_ch,
kernel_size=1,
stride=1,
padding=0,
groups=1)
def forward(self,input):
out = self.depth_conv(input)
out = self.point_conv(out)
return out
if __name__=='__main__':
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
conv = CRNN(3,6,1).to(device)
print(summary(conv,input_size=(3,32,32)))
dp = DEPTHWISECONV(3,6).to(device)
print(summary(dp,input_size=(3,32,32)))
参考: