推荐词
概念讲得很清晰
原文链接
本文由 简悦 SimpRead 转码, 原文地址 zhuanlan.zhihu.com
正文
自从 2017 年由谷歌公司提出,MobileNet 可谓是轻量级网络中的 Inception,经历了一代又一代的更新。成为了学习轻量级网络的必经之路。
MobileNet V1
![]()
MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications 论文地址:https://arxiv.org/abs/1704.04861 收录:CVPR2017
2017 年 4 月,谷歌提出 MobileNetV1,这一专注于在移动设备上的轻量级神经网络。一直都有一个争议,说 MobileNetV1 怎么和 Xception 的网络 block 结构一样,都大量用到了深度可分离?
其实这里有个小插曲: MobileNetV1 在 http://arxiv.org 上的介绍是:
![]()
可以看到 MobileNetV1 是在 2017 年 4 月才提交的 v1 版本,但是
![]()
Xception 是早在 2016 年 10 月 v1 版本就提出来了。那么,真的是 MobileNet“抄袭” 了 Xception 吗?其实并不是的,在 Xception v1 版本论文当中有这样的一句话:
![]()
而这个 Andew Howard 是谁呢?没错,就是 MobileNetV1 的作者。而在 Xception v3 论文版本中,一句话就变成了:
![]()
真相只有一个: 2016 年 6 月,谷歌提出了 MobileNetV1,由于各种原因当时没有挂上 arxiv,一直到 2017 年 4 月才提交。好巧不巧,谷歌的另一团队,同时提出了 Xception。所有才有了两个结构都是基于深度可分离卷积的相似争论。
好了,键盘党们可以擦擦键盘休息休息了。
废话说完,开始正文(好像每篇文章都有开头废话啊喂!!!)
其实介绍 MobileNetV1(以下简称 V1)只有一句话,MobileNetV1 就是把 VGG 中的标准卷积层换成深度可分离卷积就可以了。
那么,这个深度可分离卷积是什么?
深度可分离卷积
深度可分离卷积(depthwise separable convolution),根据史料记载,可追溯到 2012 年的论文 Simplifying ConvNets for Fast Learning,作者提出了可分离卷积的概念(下图(a)):
![]()
Laurent Sifre 博士 2013 年在谷歌实习期间,将可分离卷积拓展到了深度(depth),并且在他的博士论文 Rigid-motion scattering for image classification 中有详细的描写,感兴趣的同学可以去看看论文
可分离卷积主要有两种类型:空间可分离卷积和深度可分离卷积。
空间可分离
顾名思义,空间可分离就是将一个大的卷积核变成两个小的卷积核,比如将一个 3×3 的核分成一个 3×1 和一个 1×3 的核:
![]()
由于空间可分离卷积不在 MobileNet 的范围内,就不说了。
深度可分离卷积
![]()
深度可分离卷积就是将普通卷积拆分成为一个深度卷积和一个逐点卷积。
我们先来看一下标准的卷积操作:
![]()
输入一个 12×12×3 的一个输入特征图,经过 5×5×3 的卷积核卷积得到一个 8×8×1 的输出特征图。如果此时我们有 256 个特征图,我们将会得到一个 8×8×256 的输出特征图。
以上就是标准卷积做干的活。那深度卷积和逐点卷积呢?
深度卷积
![]()
与标准卷积网络不一样的是,我们将卷积核拆分成为但单通道形式,在不改变输入特征图像的深度的情况下,对每一通道进行卷积操作,这样就得到了和输入特征图通道数一致的输出特征图。如上图:输入 12×12×3 的特征图,经过 5×5×1×3 的深度卷积之后,得到了 8×8×3 的输出特征图。输入个输出的维度是不变的 3。这样就会有一个问题,通道数太少,特征图的维度太少,能获取到足够的有效信息吗?
逐点卷积
逐点卷积就是 1×1 卷积。主要作用就是对特征图进行升维和降维,如下图:
![]()
在深度卷积的过程中,我们得到了 8×8×3 的输出特征图,我们用 256 个 1×1×3 的卷积核对输入特征图进行卷积操作,输出的特征图和标准的卷积操作一样都是 8×8×256 了。
标准卷积与深度可分离卷积的过程对比如下:
![]()
为什么要深度可分离卷积?
这个问题很好回答,如果有一个方法能让你用更少的参数,更少的运算,但是能达到差的不是很多的结果,你会使用吗?
深度可分离卷积就是这样的一个方法。我们首先来计算一下标准卷积的参数量与计算量(只考虑 MAdd):
![]()
标准卷积的参数量
卷积核的尺寸是 Dk×Dk×M,一共有 N 个,所以标准卷积的参数量是:
![]()
标准卷积的计算量
卷积核的尺寸是 Dk×Dk×M,一共有 N 个,每一个都要进行 Dw×Dh 次运算,所以标准卷积的计算量是:
![]()
标准卷积算完了,我们接下来计算深度可分离卷积的参数量和计算量:
![]()
深度可分离卷积的参数量
深度可分离卷积的参数量由深度卷积和逐点卷积两部分组成:
深度卷积的卷积核尺寸 Dk×Dk×M;逐点卷积的卷积核尺寸为 1×1×M,一共有 N 个,所以深度可分离卷积的参数量是:
![]()
深度可分离卷积的计算量
深度可分离卷积的计算量也是由深度卷积和逐点卷积两部分组成:
深度卷积的卷积核尺寸 Dk×Dk×M,一共要做 Dw×Dh 次乘加运算;逐点卷积的卷积核尺寸为 1×1×M,有 N 个,一共要做 Dw×Dh 次乘加运算,所以深度可分离卷积的计算量是:
![]()
总的来说:
![]()
可以参数数量和乘加操作的运算量均下降为原来的
![]()
我们通常所使用的是 3×3 的卷积核,也就是会下降到原来的九分之一到八分之一。
假设
输出为一个 224×224×3 的图像,VGG 网络某层卷积输入的尺寸是 112×112×64 的特征图,卷积核为 3×3×128,标准卷积的运算量是:
3×3×128×64×112×112 = 924844032
深度可分离卷积的运算量是:
3×3×64×112×112+128×64×112×112 = 109985792
这一层,MobileNetV1 所采用的深度可分离卷积计算量与标准卷积计算量的比值为:
109985792 /924844032 = 0.1189
与我们所计算的九分之一到八分之一一致。
V1 卷积层
![]()
上图左边是标准卷积层,右边是 V1 的卷积层,虚线处是不相同点。V1 的卷积层,首先使用 3×3 的深度卷积提取特征,接着是一个 BN 层,随后是一个 ReLU 层,在之后就会逐点卷积,最后就是 BN 和 ReLU 了。这也很符合深度可分离卷积,将左边的标准卷积拆分成右边的一个深度卷积和一个逐点卷积。
等等,我们发现有什么东西混了进来???ReLU6 是什么?
ReLU6
![]()
上图左边是普通的 ReLU,对于大于 0 的值不进行处理,右边是 ReLU6,当输入的值大于 6 的时候,返回 6,relu6“具有一个边界”。作者认为 ReLU6 作为非线性激活函数,在低精度计算下具有更强的鲁棒性。(这里所说的 “低精度”,我看到有人说不是指的 float16,而是指的定点运算 (fixed-point arithmetic))
现在就有一个问题,标准卷积核深度可分离卷积层到底对结果有什么样的影响呢?
上实验。
![]()
可以看到使用深度可分离卷积与标准卷积,参数和计算量能下降为后者的九分之一到八分之一左右。但是准确率只有下降极小的 1%。
V1 网络结构
![]()
MobileNet 的网络结构如上图所示。首先是一个 3x3 的标准卷积,s2 进行下采样。然后就是堆积深度可分离卷积,并且其中的部分深度卷积会利用 s2 进行下采样。然后采用平均池化层将 feature 变成 1x1,根据预测类别大小加上全连接层,最后是一个 softmax 层。整个网络有 28 层,其中深度卷积层有 13 层。
实验结果
V1 论文中还有一部分对 V1 网络再进行调整,在此就不赘述了,感兴趣的同学可以去看看原论文。
V1 的效果到底好不好,作者将 V1 与大型网络 GoogleNet 和 VGG16 进行了比较:
![]()
可以发现,作为轻量级网络的 V1 在计算量小于 GoogleNet,参数量差不多是在一个数量级的基础上,在分类效果上比 GoogleNet 还要好,这就是要得益于深度可分离卷积了。VGG16 的计算量参数量比 V1 大了 30 倍,但是结果也仅仅只高了 1% 不到。
目标检测,在 COCO 数据集上的结果:
![]()
对了,作者还在论文中分析整个了网络的参数和计算量分布,如下图所示。可以看到整个计算量基本集中在 1x1 卷积上。对于参数也主要集中在 1x1 卷积,除此之外还有就是全连接层占了一部分参数。
![]()
MobileNet V2
![]()
MobileNetV2: Inverted Residuals and Linear Bottlenecks 论文地址:https://arxiv.org/abs/1704.04861 收录:CVPR2018
MobileNetV1(以下简称:V1)过后,我们就要讨论讨论 MobileNetV2(以下简称:V2)了。为了能更好地讨论 V2,我们首先再回顾一下 V1:
回顾 MobileNet V1
V1 核心思想是采用 深度可分离卷积 操作。在相同的权值参数数量的情况下,相较标准卷积操作,可以减少数倍的计算量,从而达到提升网络运算速度的目的。
V1 的 block 如下图所示:
![]()
首先利用 3×3 的深度可分离卷积提取特征,然后利用 1×1 的卷积来扩张通道。用这样的 block 堆叠起来的 MobileNetV1 既能较少不小的参数量、计算量,提高网络运算速度,又能的得到一个接近于标准卷积的还不错的结果,看起来是很美好的。
但是!
有人在实际使用的时候, 发现深度卷积部分的卷积核比较容易训废掉:训完之后发现深度卷积训出来的卷积核有不少是空的:
![]()
这是为什么?
作者认为这是 ReLU 这个浓眉大眼的激活函数的锅。(没想到你个浓眉大眼的 ReLU 激活函数也叛变革命了???)
ReLU 做了些啥?
V2 的论文中,作者也有这样的一个解释。(论文中的实在不是很好懂,我就根据一些解读结合我的想法简单说说吧。有说的不正确的地方,还请各位大佬指出,感谢!)
这是将低维流形的 ReLU 变换 embedded 到高维空间中的的例子。
![]()
我们在这里抛弃掉流形这个概念,通俗理解一下。
假设在 2 维空间有一组由 m 个点组成的螺旋线 Xm 数据 (如 input),利用随机矩阵 T 映射到 n 维空间上并进行 ReLU 运算,即:
![]()
其中,Xm 被随机矩阵 T 映射到了 n 维空间:
![]()
再利用随机矩阵 T 的逆矩阵 T-1,将 y 映射回 2 维空间当中:
![]()
全过程如下表示:
![]()
换句话说,就是对一个 n 维空间中的一个 “东西” 做 ReLU 运算,然后(利用 T 的逆矩阵 T-1 恢复)对比 ReLU 之后的结果与 Input 的结果相差有多大。
可以看到:
![]()
当 n = 2,3 时,与 Input 相比有很大一部分的信息已经丢失了。而当 n = 15 到 30,还是有相当多的地方被保留了下来。
也就是说,对低维度做 ReLU 运算,很容易造成信息的丢失。而在高维度进行 ReLU 运算的话,信息的丢失则会很少。
这就解释了为什么深度卷积的卷积核有不少是空。发现了问题,我们就能更好地解决问题。针对这个问题,可以这样解决:既然是 ReLU 导致的信息损耗,将 ReLU 替换成线性激活函数。
Linear bottleneck
我们当然不能把所有的激活层都换成线性的啊,所以我们就悄咪咪的把最后的那个 ReLU6 换成 Linear。(至于为什么换最后一个 ReLU6 而不换第一个和第二个 ReLU6,看到后面就知道了。)
![]()
Separable with linear bottleneck
作者将这个部分称之为 linear bottleneck。对,就是论文名中的那个 linear bottleneck。
Expansion layer
现在还有个问题是,深度卷积本身没有改变通道的能力,来的是多少通道输出就是多少通道。如果来的通道很少的话,DW 深度卷积只能在低维度上工作,这样效果并不会很好,所以我们要 “扩张” 通道。既然我们已经知道 PW 逐点卷积也就是 1×1 卷积可以用来升维和降维,那就可以在 DW 深度卷积之前使用 PW 卷积进行升维(升维倍数为 t,t=6),再在一个更高维的空间中进行卷积操作来提取特征:
![]()
也就是说,不管输入通道数是多少,经过第一个 PW 逐点卷积升维之后,深度卷积都是在相对的更高 6 倍维度上进行工作。
![]()
Inverted residuals
回顾 V1 的网络结构,我们发现 V1 很像是一个直筒型的 VGG 网络。我们想像 Resnet 一样复用我们的特征,所以我们引入了 shortcut 结构,这样 V2 的 block 就是如下图形式:
![]()
对比一下 V1 和 V2:
![]()
可以发现,都采用了 1×1 → 3 ×3 → 1 × 1 的模式,以及都使用 Shortcut 结构。但是不同点呢:
- ResNet 先降维 (0.25 倍)、卷积、再升维。
- MobileNetV2 则是 先升维 (6 倍)、卷积、再降维。
刚好 V2 的 block 刚好与 Resnet 的 block 相反,作者将其命名为 Inverted residuals。就是论文名中的 Inverted residuals。
V2 的 block
至此,V2 的最大的创新点就结束了,我们再总结一下 V2 的 block:
![]()
我们将 V1 和 V2 的 block 进行一下对比:
![]()
左边是 v1 的 block,没有 Shortcut 并且带最后的 ReLU6。
右边是 v2 的加入了 1×1 升维,引入 Shortcut 并且去掉了最后的 ReLU,改为 Linear。步长为 1 时,先进行 1×1 卷积升维,再进行深度卷积提取特征,再通过 Linear 的逐点卷积降维。将 input 与 output 相加,形成残差结构。步长为 2 时,因为 input 与 output 的尺寸不符,因此不添加 shortcut 结构,其余均一致。
V2 的网络结构
![]()
28×28×32 那一层的步长为 2 的话,输出应该是 14×14,应该是一处错误。按照作者论文里的说法,自己修改了一下:
![]()
实验结果
Image Classification
![]()
图像分类的实验,主要是在以上的网络上进行的,ShuffleNet 是 V1 的版本使用了分组卷积和 shuffling, 也使用了类似的残差结构(c)中的(b)。
结果如下:
![]()
详细对比如下:
![]()
Object Detection
SSDLite
目标检测方面,作者首先提出了 SSDLite。就是对 SSD 结构做了修改,将 SSD 的预测层中所有标准卷积替换为深度可分离卷积。作者说这样参数量和计算成本大大降低,计算更高效。SSD 与 SSDLite 对比:
![]()
应用在物体检测任务上,V1 与常用检测网络的对比:
![]()
可以看到,基于 MobileNetV2 的 SSDLite 在 COCO 数据集上超过了 YOLOv2,并且大小小 10 倍速度快 20 倍。
Semantic Segmentation
![]()
分割效果如下:
![]()
V1 VS V2
![]()
可以看到,虽然 V2 的层数比 V1 的要多很多,但是 FLOPs,参数以及 CPU 耗时都是比 V1 要好的。
V1V2 在 google Pixel 1 手机上在 Image Classification 任务的对比:
![]()
MobileNetV2 模型在整体速度范围内可以更快实现相同的准确性。
目标检测和语义分割的结果:
![]()
综上,MobileNetV2 提供了一个非常高效的面向移动设备的模型,可以用作许多视觉识别任务的基础。
但是!
在我实际应用 V1V2 时,V1 的效果都要稍微好一点。上一张 gluonCV 的结果图,和我的实现也差不多:
![]()
不知道为什么。
MobileNet V3
V1,V2 都看完了,现在就来到了 MobileNetV3(以下简称 V3)。
![]()
Searching for MobileNetV3 论文地址:https://arxiv.org/pdf/1905.02244.pdf
MobileNetV3,是谷歌在 2019 年 3 月 21 日提出的网络架构。首先,引入眼帘的是这篇文章的标题,“searching” 一词就把 V3 的论文的核心观点展示了出来——用**神经结构搜索(NAS)**来完成 V3。虽然本人没有接触过 NAS,但是我已经闻到了金钱的味道。
“抱歉,有钱真的可以为…”
由于真的没有接触过 NAS,所以 V3 就讲讲其他的,除 NAS 之外的东西吧。
先上结果:
![]()
可以看到,在同一大小的计算量下,V3 在 ImageNet 上的结果都是最好的。
我们先来看看 V3 做了什么?
MobileNetV3 的相关技术
-
- 网络的架构基于 NAS 实现的 MnasNet(效果比 MobileNetV2 好)
-
- 引入 MobileNetV1 的深度可分离卷积
-
- 引入 MobileNetV2 的具有线性瓶颈的倒残差结构
-
- 引入基于 squeeze and excitation 结构的轻量级注意力模型 (SE)
-
- 使用了一种新的激活函数 h-swish(x)
-
- 网络结构搜索中,结合两种技术:资源受限的 NAS(platform-aware NAS)与 NetAdapt
-
- 修改了 MobileNetV2 网络端部最后阶段
第 0 点,关于 MnasNet 也是基于 NAS 的,也不是很了解。大家感兴趣的话,可以参考曲晓峰老师的这个回答如何评价 Google 最新的模型 MnasNet? - 曲晓峰的回答 - 知乎,写的很棒!所以我们只要认为 MnasNet 是一个比 MobileNet 精度和实时性更高的模型就行了。
第 1,2 点在前面的 MobileNetV1 和 V2 上有讨论,在这里就不赘述了。
第 3 点引入 SE 模块,主要为了利用结合特征通道的关系来加强网络的学习能力。先不仔细讨论,之后在【深度回顾经典网络】系列的时候再详细讨论吧,感兴趣的同学,可以看看这一篇文章。
激活函数 h-swish
swish
h-swish 是基于 swish 的改进,swish 最早是在谷歌大脑 2017 的论文 Searching for Activation functions 所提出(又是 Searching for!!!)。
![]()
swish 论文的作者认为,Swish 具备无上界有下界、平滑、非单调的特性。并且 Swish 在深层模型上的效果优于 ReLU。仅仅使用 Swish 单元替换 ReLU 就能把 MobileNet,NASNetA 在 ImageNet 上的 top-1 分类准确率提高 0.9%,Inception-ResNet-v 的分类准确率提高 0.6%。
V3 也利用 swish 当作为 ReLU 的替代时,它可以显著提高神经网络的精度。但是呢,作者认为这种非线性激活函数虽然提高了精度,但在嵌入式环境中,是有不少的成本的。原因就是在移动设备上计算 sigmoid 函数是非常明智的选择。所以提出了 h-swish。
h-swish
可以用一个近似函数来逼急这个 swish,让 swish 变得硬 (hard)。作者选择的是基于 ReLU6,作者认为几乎所有的软件和硬件框架上都可以使用 ReLU6 的优化实现。其次,它能在特定模式下消除了由于近似 sigmoid 的不同实现而带来的潜在的数值精度损失。
![]()
下图是 Sigmoid 和 swish 的 hard、soft 形式:
![]()
我们可以简单的认为,hard 形式是 soft 形式的低精度化。作者认为 swish 的表现和其他非线性相比,能够将过滤器的数量减少到 16 个的同时保持与使用 ReLU 或 swish 的 32 个过滤器相同的精度,这节省了 3 毫秒的时间和 1000 万 MAdds 的计算量。
并且同时,作者认为随着网络的深入,应用非线性激活函数的成本会降低,能够更好的减少参数量。作者发现 swish 的大多数好处都是通过在更深的层中使用它们实现的。因此,在 V3 的架构中,只在模型的后半部分使用 h-swish(HS)。
网络结构搜索 NAS
由于不熟,就简单写一点吧。
主要结合两种技术:**资源受限的 NAS(platform-aware NAS)**与 NetAdapt。
资源受限的 NAS,用于在计算和参数量受限的前提下搜索网络来优化各个块(block),所以称之为模块级搜索(Block-wise Search) 。
NetAdapt,用于对各个模块确定之后网络层的微调每一层的卷积核数量,所以称之为层级搜索(Layer-wise Search)。
一旦通过体系结构搜索找到模型,我们就会发现最后一些层以及一些早期层计算代价比较高昂。于是作者决定对这些架构进行一些修改,以减少这些慢层 (slow layers) 的延迟,同时保持准确性。这些修改显然超出了当前搜索的范围。
对 V2 最后阶段的修改
作者认为,当前模型是基于 V2 模型中的倒残差结构和相应的变体(如下图)。使用 1×1 卷积来构建最后层,这样可以便于拓展到更高维的特征空间。这样做的好处是,在预测时,有更多更丰富的特征来满足预测,但是同时也引入了额外的计算成本与延时。
![]()
所以,需要改进的地方就是要保留高维特征的前提下减小延时。首先,还是将 1×1 层放在到最终平均池之后。这样的话最后一组特征现在不是 7x7(下图 V2 结构红框),而是以 1x1 计算(下图 V3 结构黄框)。
![]()
![]()
这样的好处是,在计算和延迟方面,特征的计算几乎是免费的。最终,重新设计完的结构如下:
![]()
在不会造成精度损失的同时,减少 10ms 耗时,提速 15%,减小了 30m 的 MAdd 操作。
V3 的 block
综合以上,V3 的 block 结构如下所示:
![]()
与 V2 的 block 相比较:
![]()
MobileNetV3 的网络结构
MobileNetV3 定义了两个模型: MobileNetV3-Large 和 MobileNetV3-Small。V3-Large 是针对高资源情况下的使用,相应的,V3-small 就是针对低资源情况下的使用。两者都是基于之前的简单讨论的 NAS。
MobileNetV3-Large
![]()
MobileNetV3-Small
![]()
就像之前所说的:只有在更深层次使用 h-swish 才能得到比较大的好处。所以在上面的网络模型中,不论大小,作者只在模型的后半部分使用 h-swish。
用谷歌 pixel 1/2/3 来对大小 V3 进行测试的结果。
![]()
实验结果
Image Classification
![]()
Detection
![]()
Semantic Segmentation
![]()
![]()
感觉实验结果没什么好说的。
对了,有一点值得说一下,训练 V3 用的是 4x4 TPU Pod,batch size 409…(留下了贫穷的泪水)
为什么 MobileNet 会这么快?
在写这篇文章的时候看到了一篇文章 Why MobileNet and Its Variants (e.g. ShuffleNet) Are Fast?,这也让我有了一样的一个问题,这篇文章主要是从结构方面进行了讨论,从深度可分离卷积到组卷积的参数计算量等,因为之前的文章都有写过,在这里就不赘述了,感兴趣的同学可以翻阅下之前的文章。
在这里换一个的角度。我们直接从用时多少的角度去讨论下这个问题。
下图来自 Caffe 作者贾扬清的博士论文:
![]()
该图是 AlexNet 网络中不同层的 GPU 和 CPU 的时间消耗,我们可以清晰的看到,不管是在 GPU 还是在 CPU 运行,最重要的 “耗时杀手” 就是 conv,卷积层。也就是说,想要提高网络的运行速度,就得到提高卷积层的计算效率。
我们以 MobileNetV1 为主,看看 MobileNet 的资源分布情况:
![]()
可以看到,MobileNet 的 95% 的计算都花费在了 1×1 的卷积上,那 1×1 卷积有什么好处吗?
我们都知道,卷积操作就是如下图所示的乘加运算:
![]()
在计算机操作时,需要将其存入内存当中再操作(按照 “行先序”):
![]()
这样一来,特征图 y11,y12,y21,y22 的计算如下所示:
![]()
按照卷积计算,实线标注出卷积计算中的访存过程(对应数据相乘),我们可以看到这一过程是非常散乱和混乱的。直接用卷积的计算方式是比较愚蠢的。
这时候就要用到 im2col 操作。
im2col
一句话来介绍 im2col 操作的话,就是通过牺牲空间的手段(约扩增 K×K 倍),将特征图转换成庞大的矩阵来进行卷积计算。
![]()
其实思路非常简单:
把每一次循环所需要的数据都排列成列向量,然后逐一堆叠起来形成矩阵(按通道顺序在列方向上拼接矩阵)。
比如 Ci×Wi×Hi 大小的输入特征图,K×K 大小的卷积核,输出大小为 Co×Wo×Ho,
输入特征图将按需求被转换成 (K∗K)×(Ci∗Wo∗Ho) 的矩阵,卷积核将被转换成 Co×(K∗K)的矩阵,
![]()
然后调用 GEMM(矩阵乘矩阵)库加速两矩阵相乘也就完成了卷积计算。由于按照计算需求排布了数据顺序,每次计算过程中总是能够依次访问特征图数据,极大地提高了计算卷积的速度。 (不光有 GEMM,还有 FFt(快速傅氏变换))
![]()
换一种表示方法能更好地理解,图片来自 High Performance Convolutional Neural Networks for Document Processing:
![]()
这样可以更清楚的看到卷积的定义进行卷积操作(上图上半部分),内存访问会非常不规律,以至于性能会非常糟糕。而 Im2col() 以一种内存访问规则的方式排列数据,虽然 Im2col 操作增加了很多数据冗余,但使用 Gemm 的性能优势超过了这个数据冗余的劣势。
所以标准卷积运算大概就是这样的一个过程:
![]()
那我们现在回到 1×1 的卷积上来,有点特殊。按照我们之前所说的,1×1 的卷积的原始储存结构和进行 im2col 的结构如下图所示:
![]()
可以看到矩阵是完全相同的。标准卷积运算和 1×1 卷积运算对比如下图:
![]()
也就是说,1x1 卷积不需要 im2col 的过程,所以底层可以有更快的实现,拿起来就能直接算,大大节省了数据重排列的时间和空间。
当然,这些也不是那么绝对的,因为毕竟 MobileNet 速度快不快,与 CONV1x1 运算的优化程度密切相关。如果使用了定制化的硬件(比如用 FPGA 直接实现 3x3 的卷积运算单元),那么 im2col 就失去了意义而且反而增加了开销。
回到之前的 MobileNet 的资源分布,95% 的 1×1 卷积和优化的网络结构就是 MobileNet 能如此快的原因了。
![]()
Reference
MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications
MobileNetV2: Inverted Residuals and Linear Bottlenecks
Xception: Deep Learning with Depthwise Separable Convolutions
Simplifying ConvNets for Fast Learning
a-basic-introduction-to-separable-convolution
https://mp.weixin.qq.com/s/O2Bhn66cWCN_87P52jj8hQ
http://machinethink.net/blog/mobilenet-v2/
如何评价 Google 最新的模型 MnasNet? - 曲晓峰的回答 - 知乎
Learning Semantic Image Representations at a Large Scale 贾扬清博士论文
在 Caffe 中如何计算卷积? - 贾扬清的回答 - 知乎
High Performance Convolutional Neural Networks for Document Processing