深度可分离卷积(Depthwise Separable Convolution)是一种卷积神经网络中常用的卷积操作,它在减少计算量的同时保持了较好的特征提取能力,因此被广泛用于轻量化的模型设计中。深度可分离卷积将标准卷积操作分解为两步:深度卷积(Depthwise Convolution)和逐点卷积(Pointwise Convolution)。
这种分解带来了以下几个优点:
1. 减少参数量: 标准卷积使用一个卷积核对输入数据进行卷积,而深度可分离卷积将卷积操作分解为深度卷积和逐点卷积,从而显著减少了参数量。深度卷积只使用一个卷积核对输入通道逐通道进行卷积,逐点卷积使用1x1的卷积核进行通道之间的混合。
2. 降低计算复杂度: 由于减少了参数量,深度可分离卷积在计算上更加高效,适合在资源有限的环境下使用,如移动设备或嵌入式系统。
3. 提升特征提取能力: 尽管参数量减少了,但深度可分离卷积通过逐点卷积将不同通道的信息进行了组合,从而保持了一定的特征提取能力。
下面是深度可分离卷积的两个主要步骤:
1. 深度卷积(Depthwise Convolution):
深度卷积是在输入的每个通道上分别应用卷积核,生成相同数量的通道,然后将这些通道按通道维度进行堆叠。它只关注输入的空间维度,不考虑通道之间的信息。深度卷积的计算公式如下:
对于输入特征图
X
X
X,输出特征图
Y
Y
Y 的深度卷积可以表示为:
Y
i
,
j
,
k
=
∑
m
,
n
X
i
+
m
,
j
+
n
,
k
⋅
K
m
,
n
Y_{i,j,k} = \sum_{m,n} X_{i+m,j+n,k} \cdot K_{m,n}
Yi,j,k=m,n∑Xi+m,j+n,k⋅Km,n
其中,
i
,
j
i, j
i,j 是输出特征图的空间位置,
k
k
k 是通道索引,
m
,
n
m, n
m,n 是卷积核的空间位置,
K
m
,
n
K_{m,n}
Km,n 是卷积核的权重。
2. 逐点卷积(Pointwise Convolution):
逐点卷积是应用1x1的卷积核在不同通道之间进行卷积,用于将通道之间的信息进行混合。它不改变特征图的空间维度,只改变通道数。逐点卷积的计算公式如下:
对于输入特征图
X
X
X,输出特征图
Y
Y
Y 的逐点卷积可以表示为:
Y
i
,
j
,
k
′
=
∑
k
X
i
,
j
,
k
⋅
K
k
,
k
′
Y_{i,j,k'} = \sum_{k} X_{i,j,k} \cdot K_{k,k'}
Yi,j,k′=k∑Xi,j,k⋅Kk,k′
其中,
i
,
j
i, j
i,j 是输出特征图的空间位置,
k
′
k'
k′ 是逐点卷积后的通道索引,
k
k
k 是逐点卷积前的通道索引,
K
k
,
k
′
K_{k,k'}
Kk,k′ 是卷积核的权重。
下面是使用 PyTorch 实现深度可分离卷积和标准卷积,并使用 torchsummary
输出它们的模型参数量的代码:
import torch
import torch.nn as nn
from torchsummary import summary
#1、深度可分离卷积
class DepthwiseSeparableConv(nn.Module):
def __init__(self,in_channels,out_channels):
super(DepthwiseSeparableConv,self).__init__()
#深度卷积
self.depthwise=nn.Conv2d(in_channels,in_channels,kernel_size=3,padding=1,groups=in_channels)
#逐点卷积
self.pointwise=nn.Conv2d(in_channels,out_channels,kernel_size=3)
def forward(self,x):
x=self.depthwise(x)
x=self.pointwise(x)
return x
#2、普通卷积
class NormalConv(nn.Module):
def __init__(self,in_channels,out_channels):
super(NormalConv,self).__init__()
self.conv=nn.Conv2d(in_channels,out_channels,kernel_size=3,padding=1)
def forward(self,x):
x=self.conv(x)
return x
# 创建深度可分离卷积模型和普通卷积模型,并输出参数量
depthwise_model=DepthwiseSeparableConv(3,64)
normal_model=NormalConv(3,64)
# 将模型加载到设备上(CPU或GPU)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
depthwise_model.to(device)
normal_model.to(device)
input_tensor=(3,224,224)
print("Depthwise Separable Convolution:")
summary(depthwise_model, input_tensor) # 输入尺寸为(3, 224, 224)
print("\nNormal Convolution:")
summary(normal_model, input_tensor) # 输入尺寸为(3, 224, 224)