定义
-
空间可分离卷积:是因为它主要处理图像和卷积核(kernel)的空间维度:宽度和高度。空间可分离卷积简单地将卷积核划分为两个较小的卷积核。 最常见的情况是将3x3的卷积核划分为3x1和1x3的卷积 核,如下所示:
现在,我们不是用9次乘法进行一次卷积,而是进行两次卷积,每次3次乘法(总共6次),以达到相同的效果。 乘法较少,计算复杂性下降,网络运行速度更快。 -
深度可分离卷积:对输入图像的每个通道分别设置一个卷积核,卷积出的结果通道数与原图保持一致,后使用point-wise 1*1卷积调成需要的通道数。
具体代码分析
import torch.nn as nn
from Module.activation import act_layers
class ConvBNReLU(nn.Sequential):
def __init__(self,i,o,k,s,p,dilation=(1,1),groups=1,bias=False,activation='ReLU'):
super(ConvBNReLU, self).__init__()
self.CBA = nn.Sequential(
nn.Conv2d(i,o,kernel_size=k,stride=s,padding=p,dilation=dilation,groups=groups,bias=bias),
nn.BatchNorm2d(o),
act_layers(activation)
)
def forward(self, input):
x = self.CBA(input)
return x
class Param(nn.Module):
def __init__(self,activation='ReLU'):
super(Param, self).__init__()
self.conv1 = nn.Sequential(
nn.Conv2d(3, 24, kernel_size=3, stride=2, padding=1, bias=False),
nn.BatchNorm2d(24),
act_layers(activation)
)
# 普通卷积
self.conv2 = nn.Sequential(
nn.Conv2d(24, 24, kernel_size=3, stride=1, padding=1, bias=False),
nn.BatchNorm2d(24),
act_layers(activation)
)
# 深度可分离
self.conv3 = nn.Sequential(
self.depthwise_conv(24, 24, kernel_s=3, stride=1, padding=1),
nn.Conv2d(24, 24, 1),
nn.BatchNorm2d(24),
act_layers(activation)
)
# 空间可分离
self.D3x1_D1x3 = nn.Sequential(
ConvBNReLU(24,24,(3,1),1,p=(1,0),dilation=(1,1),groups=1),
ConvBNReLU(24,24,(1,3),1,p=(0,1),dilation=(1,1),groups=1)
)
@staticmethod
def depthwise_conv(input_c: int,
output_c: int,
kernel_s: int,
stride: int = 1,
padding: int = 0,
bias: bool = False) -> nn.Conv2d:
return nn.Conv2d(in_channels=input_c, out_channels=output_c, kernel_size=kernel_s,
stride=stride, padding=padding, bias=bias, groups=input_c)
def forward(self, x):
x = self.conv1(x)
# 普通卷积 258.55M 5.93k
x = self.conv2(x)
# 深度可分离 69.57M 1.56K
x = self.conv3(x)
# 空间可分离 186.9M 4.25K
x = self.D3x1_D1x3(x)
return x
很明显深度可分离卷积参数量和计算复杂度都最小。