文章目录
- 1 原理浅析
- 1.1 背景简介
- 1.2 标准卷积
- 1.3 深度可分离卷积
- 1.3.1 逐通道卷积
- 1.3.2 逐点卷积
- 1.4 综合比较
- 2 代码实现 - pytorch
1 原理浅析
1.1 背景简介
2017 年 4 月,谷歌提出 MobileNetV1 这一专注于移动设备的轻量级神经网络。MobileNetV1 运用深度可分离卷积(Depthwise separable convolution)构建轻量级网络,在准确率没有大幅下降的情况下,显著降低参数量和计算量,这在实际应用中意义非凡。MobileNetV1 论文相关信息如下:
论文:《MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications》
作者:Andrew G. Howard et al. (谷歌)
年份:2017 年
关于 MobileNetV1 的可用一句话概括,即 MobileNetV1 就是把 VGG 中的标准卷积层替换为深度可分离卷积。因此,本文将对深度可分离卷积进行详细介绍。
1.2 标准卷积
标准卷积过程如上图所示。因为标准卷积并非本文重点,故而不在此次对其展开讲解。作为下文深度可分离卷积的对照组,按此方式设置标准卷积相关参数:输入为 5 x 5 x 3,卷积核组为 3 x 3 x 3 x 4,padding 为 1,stride 为 1,故而输出为 5 x 5 x 4。在此基础上,计算标准卷积的参数量和计算量:
- 参数量(卷积核参数量):3 x 3 x 3 x 4 = 108;
- 计算量(卷积操作计算量):3 x 3 x 3 x 3 x 3 x 4 = 972;
其中,关于参数量的计算可参考本人之前的博客 (神经网络参数量的计算),计算量的计算公式则为计算量 = 卷积核W x 卷积核H x (图片W - 卷积核W + 1) x (图片H - 卷积核H + 1) x 输入通道数 x 输出通道数
。
1.3 深度可分离卷积
深度可分离卷积可分为逐通道卷积(Depthwise Convolution)和逐点卷积(Pointwise Convolution)两个过程,如上图所示。下面将对这两个过程展开详细的讲解。
1.3.1 逐通道卷积
逐通道卷积的过程如上图所示,一个卷积核作用于一个通道,因此有卷积核通道数 = 输入通道数 = 输出通道数
。此外,也可借助分组卷积进行理解,即逐通道卷积可看作是一个组数为输入通道数的标准卷积,通过设置nn.Conv2d()
函数中 groups 参数为输入通道数加以实现。对比标准卷积设置相关参数:输入为 5 x 5 x 3,卷积核组为 3 x 3 x 3,padding 为 1,stride 为 1,故而输出为 5 x 5 x 3。在此基础上,计算其参数量和计算量:
- 参数量:3 x 3 x 3 = 27;
- 计算量:3 x 3 x 3 x 3 x 3 = 243;
1.3.2 逐点卷积
逐点卷积的过程如上图所示,其可被看作是标准卷积的特殊形式,即卷积核尺寸变为 1 x 1 的标准卷积。同样对逐点卷积相关参数进行设置:输入为 5 x 5 x 3,卷积核组为 1 x 1 x 3 x 4,padding 为 0,stride 为 1,故而输出为 5 x 5 x 4。在此基础上,计算其参数量和计算量:
- 参数量:1 x 1 x 3 x 4 = 12;
- 计算量:1 x 1 x 5 x 5 x 3 x 4 = 300;
需要注意的是,为保证在比较标准卷积和深度可分离卷积时的一致性,即保证二者的输入和输出完全一致,标准卷积、逐通道卷积核逐点卷积的padding
被设置为 1、1 和 0。
1.4 综合比较
为直观展示标准卷积与深度可分离卷积在参数量核计算量上的差距,将前文所得结果汇总至下表:
结果对比
卷积操作 | 参数量 | 计算量 | |
标准卷积 | 108 | 972 | |
深度可分离卷积 | 逐通道卷积 | 27 | 243 |
逐点卷积 | 12 | 300 | |
合计 | 39 | 543 |
由上表可知,在参数量和计算量方面,深度可分离卷积优势巨大。
2 代码实现 - pytorch
# _*_coding:utf-8_*_
import torch
import torch.nn as nn
class DSC(nn.Module):
def __init__(self, in_channel, out_channel):
super(DSC, self).__init__()
self.dsc_module = nn.Sequential(
nn.Conv2d(in_channel, in_channel, kernel_size=3, padding=1, groups=in_channel),
nn.Conv2d(in_channel, out_channel, kernel_size=1)
)
def forward(self, x):
return self.dsc_module(x)
if __name__ == "__main__":
inputs = torch.rand((8, 3, 5, 5))
dsc = DSC(3, 4)
outputs = dsc(inputs)
# outputs: (B=8, C=4, H=5, W=5)
print("Outputs shape: ", outputs.size())
【参考】