MobileNet v1
论文链接:MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications
创新点
轻量化体现在:
- 深度可分离卷积(Depthwise Separable Convolution)
- 两个模型压缩参数(宽度乘数和分辨率乘数)
1、深度可分离卷积
将常规卷积分为两部分:一是深度卷积,n 个卷积核和 n 个输入特征图分别卷积,也就是分组卷积;二是 1x1 卷积,将第一步的卷积结果融合起来。之所以使用1x1卷积,是因为深度卷积导致信息流通不畅 ,即输出的 feature map 仅包含输入的 feature map 的一部分,point-wise(1x1) convolution 帮助信息在通道之间流通。深度可分离卷积好处是可以减小计算量和模型尺寸。
如何减小计算量
如下图所示。比如一个输入特征图的尺寸是,与 N 个的卷积核进行卷积,stride=1
和padding=same
,那么输出特性图尺寸为。总计算量为,每个卷积核和特征图的每个位置进行卷积;总参数量(不计偏置)。
深度可分离卷积打破输出通道数量和卷积核大小之间的相互作用。深度卷积对 M 个特征图分别进行卷积,对应的卷积核深度就变成了1,所以第一步的计算量为,参数数量为;第二步是1x1卷积,即 N 个尺寸为 1x1xM 的卷积核与第一步的 M 个特征图卷积,这步的计算量为 ,参数数量为 。总的计算量 ,总参数。计算量和参数变为原来的。当卷积核尺寸为3时,变为1/8或1/9。减小计算量的同时,准确率只会下降一点。
网络结构
除了第一个卷积层是普通卷积,后面的都是深度可分离卷积。所有层(除了最后一个全连接层)后面都是一个BN层和ReLU层,最后的全连接层后面是softmax层进行分类。此外,深度卷积和 1x1 卷积后面都分别有BN和ReLU。降采样通过stride=2
的卷积进行(常规卷积和深度可分离卷积都有)。最后在全连接层前使用平均池化层将空间分辨率降低到1,即压缩成特征向量。如果将深度卷积和1x1卷积计为单独的层,MobileNet有28层。网络总降采样倍数为32。
conv_dw
的Pytorch
实现:
import torch.nn as nn
def conv_dw(inp, oup, stride):
return nn.Sequential(
# 深度卷积,输入输出通道数相同,使用组卷积,个数等于输入通道数
nn.Conv2d(inp,inp, kernel_size=3, stride=stride, padding=1, groups=inp, bias=False),
nn.BatchNorm2d(inp),
nn.ReLU(inplace=True),
# 1x1卷积
nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
nn.ReLU(inplace=True) )
除此之外,MobileNet实现上也非常高效。1×1卷积不需要在内存中重新排序,并可以直接使用GEMM实现,GEMM是最优化的数值线性代数算法之一。 MobileNet在1×1卷积中花费95%的计算时间,其中也有75%的参数。其他参数几乎都在全连接层。
MobileNet模型在TensorFlow使用RMSprop进行训练,与训练大型模型相反,使用较少的正则化、数据增强和参数衰减(L2正则)技术,因为小型模型参数很少,在过拟合方面问题不大。
2、模型压缩系数
宽度乘数:更薄的模型
宽度乘数 α 的作用是在每层均匀地稀疏网络。对于给定层和α,输入通道的数量 M 变为 αM,输出通道的数量 N 变为 αN。总计算量变为:
α常用取值
分辨率乘数:减少分辨率
分辨率乘数 ρ 应用于输入图像,并且每个层的特征图随后被相同的乘数减少。在实践中,一般通过设置输入图片分辨率隐式设置 ρ 。ρ∈(0,1)通常隐式设置,使得网络的输入分辨率为 224、192、160 或 128。分辨率乘数具有将计算成本降低 ρ2 的效果。
现在网络核心层深度可分离卷积的计算量表示为宽度乘数 α 和分辨率乘数 ρ 的公式:
两个超参数和深度可分离卷积减小计算量对比,第一行显示完整卷积层的Mult-Adds和参数,其中输入特征映射的大小为14×14×512,卷积核 K 的大小为 3×3×512×512。下一行是在前一行的基础改动。
实验结果
- 与常规卷积相比,计算量大幅减小,准确率只略微减小
- 模型压缩系数的影响
- 与经典网络比较
MobileNet v2
论文链接:MobileNetV2: Inverted Residuals and Linear Bottlenecks
创新点
- 反残差(Inverted residuals)
- Linear bottlenecks
Inverted Residuals
MobileNet-V1 最大的特点是采用深度可分离卷积(DW)来减少运算量以及参数量,而在网络结构上,没有采用shortcut的方式。Resnet 及 Densenet 等一系列采用 shortcut 的网络的成功,表明了 shortcut 的好处,于是 MobileNet-V2 采用了 shortcut ,将输入和输出相加。
通常的 residuals block 是先经过一个 1x1 的卷积层,把特征图的通道数压缩,再通过 3x3 卷积层,最后经过一个 1x1 的卷积层将特征图通道数扩张回去。而 inverted residuals 是 先“扩张”,后“压缩”。原因是 MobileNet v2是将DW 卷积层替代 residuals block 的常规卷积,这样做会碰到如下问题:DW 卷积层提取到的特征受限于输入的通道数,若是采用以往的 residual block,先“压缩”,再卷积提特征,那么 DW 卷积层可提取得特征就太少了,因此MobileNetV2 反其道而行,一开始先“扩张”,本文实验“扩张”倍数为6。 通常residual block 里面是 “压缩”→“卷积提特征”→“扩张”,MobileNetV2 变成了 “扩张”→“卷积提特征”→ “压缩”,因此称为Inverted residuals。
与 ResNet对比:
相同点
- 借鉴 ResNet,都采用了 1x1 -> 3x3 -> 1x1的模式;
- 同样使用 Shortcut 将输出与输入相加(未在上式画出)
不同点
- ResNet 使用 标准卷积 提特征,MobileNet 使用 DW卷积 提特征;
- ResNet 先降维 (0.25倍)、卷积、再升维,而 MobileNet V2 则是 先升维 (6倍)、卷积、再降维
Linear bottlenecks
当采用“扩张”→“卷积提特征”→ “压缩”时,在“压缩”之后会碰到一个问题,那就是 Relu 会破坏特征。为什么这里的Relu会破坏特征呢?这得从 Relu 的性质说起,Relu对于负的输入,输出全为零;而本来特征就已经被“压缩”,再经过Relu的话,又要“损失”一部分特征,因此这里不采用Relu,实验结果表明这样做是正确的,这就称为 Linear bottlenecks。
与MobileNet V1对比:
相同点
- 都采用深度可分离卷积提取特征
不同点
- V2 在 DW 卷积之前新加了一个 PW 卷积“扩张”层,目的是为了提升通道数,获得更多特征;
- V2 去掉了第二个 PW 的ReLU,即 Linear Bottleneck,目的是防止Relu破坏特征
网络结构
注:文中提到共计采用19个bottleneck,但是这里只有17个。
Conv2d 和 avgpool 和传统CNN里的操作一样;最大的特点是 bottleneck,一个bottleneck由如下三个部分构成:
一个 residuals bottleneck 结构的 Multiply Add 为:
特别的,针对stride=1 和stride=2,在block上有稍微不同,主要是为了与shortcut的维度匹配,因此,stride=2时,不采用shortcut。 具体如下图:
实验结果
- MobileNet V2分类时的表现
注:这是在手机的CPU上跑出来的结果(Google pixel 1 for TF-Lite)。
- 检测时的表现
注:SSDLite是把SSD预测层中所有常规卷积用深度可分离卷替换。与常规SSD相比,SSDLite显着降低了参数量和计算成本。
SqueezeNet
论文链接:SQUEEZENET: ALEXNET-LEVEL ACCURACY WITH 50X FEWER PARAMETERS AND <0.5MB MODEL SIZE
在ImageNet上实现了和AlexNet相同的正确率,但是只使用了1/50的参数。更进一步,使用模型压缩技术,可以将SqueezeNet压缩到0.5MB,是AlexNet的1/510。
创新点
- Fire Moudle
- 使用模型压缩方法进一步压缩网络
Fire Moudle
SqueezeNet 的核心在于 Fire module,Fire module 由两层构成,分别是 squeeze 层和expand 层,如下图所示。与 inception 系列的思想非常接近,首先 squeeze 层,就是 1x1 卷积,其卷积核数要少于上一层 feature map 数,这个操作是“压缩”; Expand 层分别用 1x1 和 3x3 卷积,然后 concat,这个操作在 inception 系列里面也有。
具体操作:
首先,HxWxM 的 feature map 经过 Squeeze 层,得到 S1 个 feature map,这里的 S1 均是小于 M 的,以达到压缩的目的;然后,HxWxS1 的特征图输入到 Expand 层,分别经过 1x1 卷积层和 3x3 卷积层进行卷积,再将结果进行 concat,得到 Fire module 的输出,为 HM(e1+e3) 的 feature map。三个可调参数:S1,e1,e3,分别代表卷积核的个数,同时也表示对应输出 feature map 的维数,在文中提出的 SqueezeNet 结构中,e1=e3=4s1。
网络结构
网络结构设计思想,同样与 VGG 的类似,堆叠的使用卷积操作,只不过这里堆叠的是 Fire module(图中用红框部分)。
进一步压缩
模型压缩方法
为了得到一个参数非常少但同时保持准确性的模型,一个明智的方法是采用现有的CNN模型并以有损的方式压缩它。常用的模型压缩技术有:
- 奇异值分解(singular value decomposition (SVD))预训练模型
- 网络剪枝(Network Pruning):用零替换预训练模型低于某个阈值的参数以形成稀疏矩阵,并最终在稀疏CNN上执行一些训练迭代
- 深度压缩(Deep compression):使用网络剪枝,量化和 huffman 编码
- 使用硬件加速器(hardware accelerator)
注:标题中的0.5M参数是 Squeezenet 经过 Deep compression 后的结果。
ShuffleNet V1
论文链接:ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices
创新点
ShuffleNet 可以看作是ResNet的压缩版本,主要思想是:
- 使用 group convolution
- 使用 channel shuffle
分组卷积(group convolution)
Group convolution 自 Alexnet 就有,当时因为硬件限制而采用分组卷积;之后在 2016 年的 ResNeXt 中,表明采用 group convolution 可获得高效的网络;再有 Xception 和 MobileNet 均采用 depth-wise convolution, 这些都是最近出来的一系列轻量化网络模型。
假设有输入feature map,尺寸为 ,与 k 个 的卷积核卷积,输出尺寸为
而Group convolution的实质就是将卷积分为 g 个独立的组,分别计算。即:
- 把 input feature 分为 g 组,每组的大小为
- 把 kernel 也分为 g 组,每组有 k/g 个 的卷积核
- 按顺序,每组 input feature 和 kernel 分别做普通卷积,输出 g 组 的特征图,一共有 g 组,总输出
注:深度可分离卷积的第一步的就是分组卷积的一个特例,分组数等于输入通道数。
于是可以把 pointwise convolution(1x1)用 pointwise group convolution 代替,将卷积运算限制在每个Group内来降低计算量。
Channel Shuffle
由于采用分组卷积,group与group之间的几乎没有联系,影响了网络的准确率。因此 Xception,MobileNet等网络采用密集的 1x1 卷积,因为要保证 group convolution之后不同组的特征图之间的信息交流。但是达到上面那个目的,我们不一定非要采用 dense pointwise convolution,于是提出了 channel shuffle 来加强 group 之间的联系。同时channel shuffle是可导的,可以实现 end-to-end 一次性训练网络。
具体方法为:把各组的 channel 平均分为 g(下图 g=3)份,然后依次序的重新构成 feature map。
在程序上实现 channel shuffle 是非常容易的:假定将输入层分为 g 组,总通道数为 ,首先将总通道数那个维度拆分为 两个维度,然后将这两个维度转置变成 ,最后重新 reshape 成一个维度。
网络结构
ShuffleNet的基本单元是在一个残差单元的基础上改进而成的。如图a所示,这是一个包含3层的残差单元:首先是1x1卷积,然后是3x3的depthwise convolution(DWConv,主要是为了降低计算量),这里的3x3卷积是瓶颈层(bottleneck),紧接着是1x1卷积,最后是一个短路连接,将输入直接加到输出上。现在,进行如下的改进:将密集的1x1卷积替换成1x1的group convolution,不过在第一个1x1卷积之后增加了一个channel shuffle操作。值得注意的是3x3卷积后面没有增加channel shuffle,按paper的意思,对于这样一个残差单元,一个channel shuffle操作是足够了。还有就是3x3的depthwise convolution之后没有使用ReLU激活函数。改进之后如图b所示。对于残差单元,如果stride=1时,此时输入与输出shape一致可以直接相加,而当stride=2时,通道数增加,而特征图大小减小,此时输入与输出不匹配。一般情况下可以采用一个1x1卷积将输入映射成和输出一样的shape。但是在ShuffleNet中,却采用了不一样的策略,如图c所示:对原输入采用stride=2的3x3 avg pool,这样得到和输出一样大小的特征图,然后将得到特征图与输出进行连接(concat),而不是相加。这样做的目的主要是降低计算量与参数大小。
代码实现:https://www.jianshu.com/p/84b2a4590ec8
实验结果
注:ShuffleNet s× 表示通道数放缩到s倍。
- 与MobileNet对比
- 倍数与分组数
缺点
- Shuffle channel在实现的时候需要大量的指针跳转和Memory set,这本身就是极其耗时的;同时又特别依赖实现细节,导致实际运行速度不会那么理想。
- Shuffle channel规则是人工设计出来的,不是网络自己学出来的。这不符合网络通过负反馈自动学习特征的基本原则,又陷入人工设计特征的老路(如sift/HOG等。
ShuffleNet V2
论文链接:ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design
正如标题那样,是实验引导的高效CNN结构设计,文章的观点和实验都比较新颖。
高效CNN网络设计
时间消耗分析
目前衡量模型复杂度的一个通用指标是FLOPs,具体指的是卷积层的 multiply-add 数量,但是这却是一个间接指标,因为它不完全等同于速度。如上图中的(c)和(d),可以看到相同FLOPs的两个模型,其速度却存在差异。这种不一致主要归结为两个原因:首先影响速度的不仅仅是FLOPs,如内存使用量(memory access cost, MAC),这不能忽略,对于GPUs来说可能会是瓶颈;模型的并行程度也影响速度,并行度高的模型速度相对更快。另外一个原因,模型在不同平台上的运行速度是有差异的,如GPU和ARM,而且采用不同的库也会有影响。
下图中分析了ShuffleNet v1与MobileNet v2这两个移动端流行网络在GPU/ARM两种平台下的时间消耗分布。
![](http://img.e-com-net.com/image/info10/2cf67e77e75841b0a799d10eb197bccb.jpg)
从上图中可看出Conv等计算密集型操作占了其时间的绝大多数,但其它像Elemwise/Data IO等内存读写密集型操作也占了相当比例的时间,因此像以往那样一味以FLOPs来作为指导准则来设计CNN网络是不完备的,虽然它可以反映出占大比例时间的Conv操作。
准则一:输入输出通道数目相同时,卷积计算所需的MAC最小
假设一个1x1卷积层的输入特征通道数是c1,尺寸是h和w,输出特征通道数是c2,那么这样一个1x1卷积层的FLOPs就是下面式子所示:
。
假设内存足够大,那么内存使用量:
,
分别是输入特征图、输出特征图、卷积核权重的使用量。
根据均值不等式可以得到公式(1)。把MAC和B代入式子1,就得到(c1-c2)2 >= 0,因此等式成立的条件是 c1=c2,也就是输入特征通道数和输出特征通道数相等时,在给定FLOPs前提下,MAC取最小值。
实验也证实了这个观点,改变c1, c2的比例,固定FLOPs时,1:1时速度最快。
准则二:过多的分组卷积会加大MAC
像MobileNet、ShuffleNet、Xception其实都借鉴了卷积的group操作来加速模型,这是因为group操作可以大大减少FLOPs,因此即便适当加宽网络也不会使得FLOPs超过原来不带group的卷积操作,这样就能带来比较明显的效果提升(ResNeXt就是这样的例子)。但是,FLOPs不怎么增加并不代表速度变快,相同层数情况下,ResNeXt的速度要慢许多,差不多只有相同层数的ResNet速度的一半,但是相同层数的ResNeXt的参数量、FLOPs和ResNet是基本差不多的。这就引出了group操作所带来的速度上的影响。
和前面同理,一个带group操作的1x1卷积的FLOPs如下所示,多了一个除数g,g表示group数量。这是因为每个卷积核都只和c1/g个通道的输入特征做卷积,一共c2/g个卷积核,总输出不变:
此时MAC为:
可见,在B不变时,g越大,MAC也越大。实验也证实:c表示c1+c2的和,通过控制这个参数可以使得每个实验的FLOPs相同,可以看出随着g的不断增大,c也不断增大,这和前面说的在基本不影响FLOPs的前提下,引入group操作后可以适当增加网络宽度吻合。从速度上看,group数量的增加对速度的影响还是很大的,原因就是group数量的增加带来MAC的增加,进而带来速度的降低。
准则三:网络碎片化会降低并行度,即模型中的分支数量越多,模型速度越慢
网络结构设计上,文章用了一个词:fragment,翻译过来就是分裂的意思,可以简单理解为网络的支路数量。为了研究fragment对模型速度的影响,作者做了Table3这个实验,其中2-fragment-series表示一个block中有2个卷积层串行,也就是简单的叠加;4-fragment-parallel表示一个block中有4个卷积层并行,类似Inception的整体设计。可以看出在相同FLOPs的情况下,单卷积层(1-fragment)的速度最快。因此模型支路越多(fragment程度越高)对于并行计算越不利,这样带来的影响就是模型速度变慢,比如Inception、NASNET-A这样的网络。
准则四:Element-wise(元素级)操作会消耗较多的时间
Element-wise类型操作虽然FLOPs非常低,但是带来的时间消耗还是非常明显的。比如ReLU和Add,虽然FLOPs较小,但是却需要较大的MAC。这里实验发现如果将ResNet中残差单元中的ReLU和shortcut移除的话,速度有20%的提升。
结论
- 1x1卷积平衡输入和输出的通道数;
- 组卷积要谨慎使用,注意分组数;
- 避免网络的碎片化;
- 减少元素级运算
在ShuffleNet v1的操作中违反了四个设计准则:首先它使用了bottleneck 1x1 group conv与module最后的1x1 group conv pointwise模块,使得input channels数目与output channels数目差别较大,违反了上述规则一与规则二;其次由于它整体网络结构中过多的group conv操作的使用从而违反了上述规则三;最后类似于Residual模块中的大量Element-wise sum的使用则进而违反了上述规则四。
ShuffleNet v2中弃用了1x1的group convolution操作,而直接使用了input/output channels数目相同的1x1普通conv。它更是提出了一种ChannelSplit新的类型操作,将module的输入channels分为两部分,一部分直接向下传递,另外一部分则进行真正的向后计算。到了module的末尾,直接将两分支上的output channels数目级连起来,从而规避了原来ShuffleNet v1中Element-wise sum的操作。然后我们再对最终输出的output feature maps进行RandomShuffle操作,从而使得各channels之间的信息相互交通。
网络结构
上图是关于ShuffleNet v1和ShuffleNet v2的结构对比,其中(a)和(b)是ShuffleNet v1的两种不同block结构,同理(c)和(d)是ShuffleNet v2的两种不同block结构。从(a)和(c)的对比可以看出首先(c)在开始处增加了一个channel split操作,这个操作将输入特征的通道分成c-c’和c’,c’在文章中采用c/2,这主要是和前面第1点发现对应。然后(c)中取消了1x1卷积层中的group操作,这和前面第2点发现对应,同时前面的channel split其实已经算是变相的group操作了。其次,channel shuffle的操作移到了concat后面,和前面第3点发现对应,同时也是因为第一个1x1卷积层没有group操作,所以在其后面跟channel shuffle也没有太大必要。最后是将element-wise add操作替换成concat,这个和前面第4点发现对应。多个(c)结构连接在一起的话,channel split、concat和channel shuffle是可以合并在一起的。(b)和(d)的对比也是同理,只不过因为(d)的开始处没有channel split操作,所以最后concat后特征图通道数翻倍,可以结合后面Table5的具体网络结构来看。
Table5是ShuffleNet v2的具体网络结构示意图,不同stage的输出通道倍数关系和前面描述的吻合,每个stage都是由Figure3(c)(d)所示的block组成,block的具体数量对于Figure5中的Repeat列。
实验结果
明显看到ShuffleNet v2在精度和速度上的优势。