Mobile Net 与深度可分离卷积层
1. 深度可分离卷积层
基本概念
深度可分离卷积 (Depthwise Separable Convolution) 本质是一种分解卷积,它把一个标准的卷积操作分解成下面两个操作:
- 深度卷积 (Depthwise Convolution):负责卷积。
- 逐点卷积 (Pointwise Convolution):一个1x1的卷积,负责组合前面卷积的结果。
原论文推到了这种做法可以减少 8~9 倍的计算量,这里就不推了。
这里的逐渐卷积正是我们在 NiN 网络章节中介绍过的。它可以把不同通道的结果进行线性组合,以此“整合”所有通道的信息。
对 CNN 池化层的替代
由于我们使用了可分离卷积模块,在 MobileNet 中我们不使用传统池化层来做降采样,而是使用 stride 为 2 的可分离卷积层。这个卷积层在执行卷积操作提取特征的同时,也完成了对特征图的降维(尺寸减半了)。
同时,传统池化层的采样方式都是固定的、非学习性的,而使用可分离卷积层进行下采样可以让卷积层自己学习如何更好地提取特征。
2. 网络架构
Mobile Net 的总体架构包括了:
- 第一层的标准卷积层。
- 之后的深度可分离卷积层模块。
- 将最后一个深度可分离卷积层的输出结果进行全局平均池化,将特征图空间分辨率压缩至 1x1。然后把这个结果送到线性层去分类。
其中深度可分离卷积层这个核心组件架构如下:
3.简单实现
我们依然在 CIFAR-10 数据集上搭建一个简单的 MobileNet。深度可分离卷积模块如下:
self.depthwise = nn.Conv2d(
in_channels,
in_channels,
kernel_size=3,
stride=stride,
padding=1,
groups=in_channels,
bias=False
)
self.bn1 = nn.BatchNorm2d(in_channels)
self.relu1 = nn.ReLU(inplace=True)
self.pointwise = nn.Conv2d(
in_channels,
out_channels,
kernel_size=1,
stride=1,
padding=0,
bias=False
)
self.bn2 = nn.BatchNorm2d(out_channels)
self.relu2 = nn.ReLU(inplace=True)
由于 CIFAR-10 数据集比较小,我们不需要搭建很深的网络,经过测试,搭建两个“深度卷积+下采样”模块,然后在 512x512 特征图上应用两次 1x1 卷积进行进一步信息整合提取效果不错:
self.features = nn.Sequential(
DepthwiseSeparableConv(32, 64, stride=1), # 32x32
DepthwiseSeparableConv(64, 128, stride=2), # 16x16
DepthwiseSeparableConv(128, 128, stride=1), # 16x16
DepthwiseSeparableConv(128, 256, stride=2), # 8x8
DepthwiseSeparableConv(256, 256, stride=1), # 8x8
DepthwiseSeparableConv(256, 512, stride=2), # 4x4
DepthwiseSeparableConv(512, 512, stride=1), # 4x4
DepthwiseSeparableConv(512, 512, stride=1), # 4x4
DepthwiseSeparableConv(512, 512, stride=1), # 4x4
)
完整实现如下: