MobileNet V1
理解 MobileNetV1的关键是理解深度可分离卷积
深度可分离卷积 Depthwise Separable Conv
深度可分离卷积=单通道卷积(提取特征)+逐点卷积(增加维度)
普通卷积
输入一个 12×12×3 的一个输入特征图,经过256 个 5×5×3 的卷积核,卷积后得到一个 8×8×256 的输出特征图。
深度卷积 Depthwise Conv
深度卷积就是将卷积核设计为单通道形式,在不改变输入特征图像的深度的情况下,对每一通道进行卷积操作,这样就得到了和输入特征图通道数一致的输出特征图。这样就能获得特征图的关键特征信息。
这样特征图少了,提取的信息也少了。下面就是要用1x1的卷积来进行升维操作。
逐点卷积 Pointwise Conv
逐点卷积就是用 1×1 卷积对特征图进行升维和降维操作。
现在我们用 256 个 1×1×3 的卷积核对 8×8×3 的输出特征图进行升维,这样经过深度卷积和逐点卷积后得到的特征图和标准的卷积操作一样都是 8×8×256 了。
计算量比较
假设
-
输入特征图为 D F × D F × M D_{F} \times D_{F} \times M DF×DF×M
-
输出特征图G为 D F × D F × N D_{F} \times D_{F} \times N DF×DF×N
-
卷积核为 D K × D K × M × N D_{K} \times D_{K} \times M \times N DK×DK×M×N
设标准卷积的stride设为1,padding使得输出特征图长宽和输入特征图一样,那么比如卷积核中红色的那个数字是要计算
D
F
⋅
D
F
D_{F} \cdot D_{F}
DF⋅DF次的,卷积核一共有
D
K
⋅
D
K
⋅
M
⋅
N
D_{K} \cdot D_{K} \cdot M \cdot N
DK⋅DK⋅M⋅N个参数。
所以标准卷积的计算量为 D K ⋅ D K ⋅ M ⋅ N ⋅ D F ⋅ D F D_{K} \cdot D_{K} \cdot M \cdot N \cdot D_{F} \cdot D_{F} DK⋅DK⋅M⋅N⋅DF⋅DF
深度可分卷积
深度卷积:卷积核为 D K × D K × 1 × M D_{K} \times D_{K} \times 1 \times M DK×DK×1×M
输出特征图大小为 D F × D F × M D_{F} \times D_{F} \times M DF×DF×M
计算量为:
D
K
⋅
D
K
⋅
M
⋅
D
F
⋅
D
F
D_{K} \cdot D_{K} \cdot M \cdot D_{F} \cdot D_{F}
DK⋅DK⋅M⋅DF⋅DF
1*1卷积:卷积核为 1 × 1 × M × N 1 \times 1 \times M \times N 1×1×M×N,最后的输出为 D F × D F × M D_{F} \times D_{F} \times M DF×DF×M
计算量: M ⋅ N ⋅ D F ⋅ D F M \cdot N \cdot D_{F} \cdot D_{F} M⋅N⋅DF⋅DF
深度可分卷积的计算量是Depthwise Conv和 Pointwise Conv 的计算量之和,为 D K ⋅ D K ⋅ M ⋅ D F ⋅ D F + M ⋅ N ⋅ D F ⋅ D F D_{K} \cdot D_{K} \cdot M \cdot D_{F} \cdot D_{F} + M \cdot N \cdot D_{F} \cdot D_{F} DK⋅DK⋅M⋅DF⋅DF+M⋅N⋅DF⋅DF
深度可分卷积 标准卷积 = D K ⋅ D K ⋅ M ⋅ D F ⋅ D F + M ⋅ N ⋅ D F ⋅ D F D K ⋅ D K ⋅ M ⋅ N ⋅ D F ⋅ D F = 1 N + 1 D K 2 \frac{深度可分卷积}{标准卷积}=\frac{D_{K} \cdot D_{K} \cdot M \cdot D_{F} \cdot D_{F} + M \cdot N \cdot D_{F} \cdot D_{F}}{D_{K} \cdot D_{K} \cdot M \cdot N \cdot D_{F} \cdot D_{F}}= \frac{1}{N} + \frac{1}{D_{K}^{2}} 标准卷积深度可分卷积=DK⋅DK⋅M⋅N⋅DF⋅DFDK⋅DK⋅M⋅DF⋅DF+M⋅N⋅DF⋅DF=N1+DK21
可以计算出深度可分卷积是标准卷积的 1 N + 1 D K 2 \frac{1}{N} + \frac{1}{D_{K}^{2}} N1+DK21
一般情况下,卷积核大小为 3 × 3 3 \times 3 3×3,为 D K 2 = 9 D_{K}^{2} = 9 DK2=9
卷积核的通道数 N N N的取值一般会大于9,那么 1 N + 1 D K 2 > 1 9 \frac{1}{N} + \frac{1}{D_{K}^{2}} > \frac{1}{9} N1+DK21>91
假设输出为一个 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
与我们所计算的九分之一到八分之一一致。
Mobilenet V1 网络结构
上图左边是标准卷积层,右边是 V1 的卷积层,虚线处是不相同点。Mobilenet V1 的卷积层,先用 3×3 的深度卷积提取特征,接着是一个 BN 层,随后是一个 ReLU6 层,然后逐点卷积,最后又是是 BN 和 ReLU 了。
这也很符合深度可分离卷积,将左边的标准卷积拆分成右边的一个深度卷积和一个逐点卷积。
ReLU6
ReLU6,当输入的值大于 6 的时候,返回 6”。作者认为 ReLU6 作为非线性激活函数,在低精度计算下具有更强的鲁棒性。
可以看到使用深度可分离卷积与标准卷积,参数和计算量能下降为后者的九分之一到八分之一左右。但是准确率只有下降极小的 1%。
MobileNet V1 首先是一个 3x3 的标准卷积,s2 进行下采样。然后是堆积深度可分离卷积,并且其中的部分深度卷积会利用 s2 进行下采样。
然后采用平均池化层将 feature 变成 1x1,根据预测类别大小加上全连接层,最后是一个 softmax 层。整个网络有 28 层,其中深度卷积层有 13 层。
实验结果
V1 论文中还有一部分对 V1 网络再进行调整,在此就不赘述了,感兴趣的同学可以去看看原论文。
V1 的效果到底好不好,作者将 V1 与大型网络 GoogleNet 和 VGG16 进行了比较:
可以发现,作为轻量级网络的 V1 在计算量小于 GoogleNet,参数量差不多是在一个数量级的基础上,在分类效果上比 GoogleNet 还要好,这就是要得益于深度可分离卷积了。VGG16 的计算量参数量比 V1 大了 30 倍,但是结果也仅仅只高了 1% 不到。
作者还在论文中分析整个了网络的参数和计算量分布,如下图所示。可以看到整个计算量基本集中在 1x1 卷积上。对于参数也主要集中在 1x1 卷积,除此之外还有就是全连接层占了一部分参数。
MobileNet V2
MobileNet V1 训完后发现深度卷积训出来的卷积核有不少是空的:
作者认为这是 ReLU 这个浓眉大眼的激活函数的锅。
ReLU 做了些啥?
MobileNet V2 的论文中,作者将低维流形的 ReLU 变换 embedded 到高维空间中的的例子。
假设在 2 维空间有一组由 m 个点组成的螺旋线 Xm 数据 (如 input),利用随机矩阵 T 映射到 n 维空间上并进行 ReLU 运算,即:
其中,
X
m
X_m
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 替换成线性激活函数。
当然不能把所有的激活层都换成线性的,而是只把最后的那个 ReLU6 换成 Linear。
倒残差 Inverted residuals Conv
ResNet中使用残差块有助于提高精度构建更深的网络,所以MobileNet V2也引入了类似的块。
经典的残差块的过程是:1x1(降维)–>3x3(卷积)–>1x1(升维)
深度可分离卷积若采用残差块,先经过1x1的逐点卷积操作将输入特征图压缩,再经过深度卷积后,提取的特征会更少。
所以mobileNetV2是先经过1x1的逐点卷积操作将特征图的通道进行扩张,丰富特征数量,进而提高精度。这一过程刚好和残差块的顺序颠倒,这也就是倒残差的由来:1x1(升维)–>3x3(dw conv+relu)–>1x1(降维+线性变换)。
MobileNet V2 的 block
瓶颈层的具体结构如下表所示。输入通过1x1的conv+ReLU层将维度从k维增加到tk维,之后通过3×3的conv+ReLU可分离卷积对图像进行降采样(stride>1时),此时特征维度已经为tk维度,最后通过1*1conv(无ReLU)进行降维,维度从tk降低到k维。
在此处着重强调一下,并不是所有的Inverted residual block都有shortcut短连接的!只有当stride=1(特征图尺寸一致)且输入特征矩阵与输出特征矩阵shape相同(也就是输入输出 通道数c 也要相同)时才有短连接。
左边是 v1 的 block,没有 Shortcut 并且带最后的 ReLU6。
右边是 v2 的加入了 1×1 升维,引入 Shortcut 并且去掉了最后的 ReLU,改为 Linear。步长为 1 时,先进行 1×1 卷积升维,再进行深度卷积提取特征,再通过 Linear 的逐点卷积降维。将 input 与 output 相加,形成残差结构。步长为 2 时,因为 input 与 output 的尺寸不符,因此不添加 shortcut 结构,其余均一致。
V2 的网络结构
如表所示,t 表示bottleneck中“胖瘦”系数,通道数变为几倍;c 表示输出通道数;n 表示bottleneck模块重复了几次;s 表示stride,步长,控制特征图尺寸大小,1的话尺寸不变,2的话,尺寸变为原来的一半,表中s为1或者2 只针对重复了n次的bottleneck 的第一个bottleneck,重复n次的剩下几个bottleneck中s均为1。
MobileNet V3
MobileNet V3的核心就是神经结构搜索(NAS)。
MobileNetV3 的相关技术
- 网络的架构基于 NAS 实现的 MnasNet(效果比 MobileNetV2 好)
- 引入 MobileNetV1 的深度可分离卷积
- 引入 MobileNetV2 的具有线性瓶颈的倒残差结构
- 引入基于 squeeze and excitation 结构的轻量级注意力模型 (SE)
- 使用了一种新的激活函数 h-swish(x)
- 网络结构搜索中,结合两种技术:资源受限的 NAS(platform-aware NAS)与 NetAdapt
- 修改了 MobileNetV2 网络端部最后阶段
激活函数 h-swish
h-swish 是基于 swish 的改进,
Swish 具备无上界有下界、平滑、非单调的特性。并且 Swish 在深层模型上的效果优于 ReLU。
但Swish 在嵌入式环境中,是有不少的成本的。而在移动设备上计算 sigmoid 函数是非常明智的选择。所以提出了 h-swish。
h-swish
作者认为几乎所有的软件和硬件框架上都可以使用 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 进行测试的结果。
为什么 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 能如此快的原因了。