Hi,我们是 MobileNet 家族!

Date: 2020/02/07

Author: CW

Foreword:

轻量化网络是深度学习领域的研究热点之一,其目标是在网络的参数量少、训练和预测速度快的情况下又能够保持一定的准确率,以下是一些常用的减少网络计算量的方法:

i). 网络模型设计:使用组卷积(Group Conv)、1x1 卷积(Ponit-Wise Conv)等在达到相同(或近似)效果的同时减少计算量,类似的案例如 Inception、Xception、ShuffleNet 以及本文的主角MobileNet等;

ii). 剪枝: 通过剪去网络中的冗余部分来减少网络计算量;

iii). 知识蒸馏:利用大模型(Teacher-Model)来辅助小模型(Student-Model)学习,从而在小模型上达到目标效果。

MobileNet是Google的作品,能够将模型部署应用于移动端,同时又保证良好的效果,目前Google Pixel 系列的手机就是用的MobileNet。MobileNet目前更新到了v3版本,CW参考和收集了网上的资料及博文,在本文中会从入门到放弃...哦不,是会从v1到v3都进行解读,供广大帅哥靓女们参考学习。如有不当之处,尽管反馈,大家一起学习与进步,欢迎交流,谢谢!


Outline

1、MobileNetv1

     i). 对标准卷积层进行改进

     ii). 使用2个超参数构建更小的模型

2、MobileNetv2

     i). 扩展层:Expansion Layer

     ii). 线性瓶颈:Linear Bottleneck

     iii). “倒”残差结构:Inverted Residual

3、MobileNetv3

     i). 新的非线性激活函数:h-swish

     ii). 基于Squeeze & Excitation(SE)的轻量级注意力结构

     iii). 修改了部分v2的结构:头部卷积核的通道数及最后的尾部结构

     iv). 网络结构搜索:资源受限的NAS(Platform-Aware NAS)与 NetAdapt

4、MobileNet为何这么快?


MobileNetv1

v1的主要工作是将标准的卷积过程拆为两个步骤 —— Depth-Wise Conv 和 Point-Wise Conv,并且引入2个超参,减少了计算量并且模型也更小,从而可以轻松地匹配移动和嵌入式视觉应用的设计要求。

i). 对标准卷积层的改进 —— Depth-Wise Conv 和 Point-Wise Conv

Depth-Wise Conv(简称dw),也称深度可分离卷积,它将卷积核的每个通道分别应用于输入特征图的每个通道(这样,输入和输出的通道数维持一致),而非如标准卷积般将输入特征图的所有通道加权组合在一起。

Point-Wise Conv(简称pw), 也称逐点卷积,它使用1x1大小的卷积核,用于组合深度可分离卷积的输出结果(将深度可分离卷积的输出通道数映射到目标通道数)。

标准卷积将提取空间特征和通道之间的相关性组合在一起,而MobileNet将其分解为Depth-Wise + Point-Wise,这样的效果是先基于各个通道提取空间特征(空间相关性),之后再组合通道之间的相关性,这种因式分解操作具有大幅度减少计算和模型大小的效果。

标准卷积=dw+pw卷积

为何说这样能够减少计算量?根据上图,举个例子动手计算下才有说服力(下文均使用 channel first 惯例,所谓的计算量指乘法次数):

(a) 表示标准卷积的过程:有N个卷积核,每个卷积核维度是M xx,输入特征图的通道数是M,输出特征图维度为N x  x ,计算量为;

(b) 表示dw的过程:用M个维度为1 x  x 的卷积核去卷积对应输入特征图的M个通道,得到M个输出结果,注意这M个结果不会进行相加(相比标准卷积是卷积输入特征图的所有通道,并累加这M个结果),输出结果的维度是,这时计算量为 x ;

(c) 表示pw的过程:用N个维度为的卷积核卷积上述(b)的输出结果,最终得到维度为的 feature map。这个过程和普通卷积无异,只是卷积核大小为1 x 1,此时计算量是。

(b) + (c) 总共的计算量是+,我们拿它除以标准卷积 (a)的计算量,来看看缩减了多少:

=

也就是说,如果使用将我们最常使用的3x3标准卷积分解为dw+pw,那么计算量将缩减为原来的有多!

根据paper原文的意思,有些点还需要提下:

MobileNet在每一层均使用BN和ReLU两种非线性变换;

与标准卷积相比,dw非常有效。然而,它只会滤除输入通道,不会将它们组合起来以创建新功能。因此,需要通过pw来计算深度卷积输出的线性组合的附加层来生成这些新特征

标准卷积层 vs MobileNet的dw+pw卷积层

ii). 使用2个超参数构建更小的模型

(1) 宽度乘数(mulitiplier)

记宽度乘数为α,其作用是在每层均匀地减薄网络。对于给定的层和宽度乘数α,输入通道M的数量变为αM,输出通道数量N变为αN。

再拿上述例子来说,使用了宽度乘数后,dw+pw的计算量为:,通常设置为0.75。

(2) 分辨率乘数

这个超参通常隐式设置,应用于输入图像,以降低分辨率,记其为。

同样地,拿上述例子来说,在使用了宽度乘数的基础上,进一步使用分辨率乘数后,dw+pw的计算量为:

最后来看下MobileNetv1的整体架构,总共28个卷积层(conv+bn+relu),第1个和最后1个都是标准卷积层,中间13个是dw+pw卷积层(dw+pw算作1个卷积层

MobileNetv1架构和计算量
MobileNetv1各参数设置对比实验结果

附:MobileNetv1 paper


MobileNetv2

MobileNetv1的dw+pw卷积层

回顾下MobileNetv1的骚操作——首先利用3×3的深度可分离卷积提取空间特征,然后利用1×1的逐点卷积来组合通道特征,同时映射到目标通道数。这样既减少了参数量、计算量,同时又提高了网络运算速度,还能得到一个接近于标准卷积的不错的结果,看起来十分美好。

然而,现实是残酷的!

不少炼丹者在实际使用过程中, 发现深度卷积部分的卷积核被废掉了——训练完之后发现深度卷积核有不少是空的!

“废掉”的dw

于是,作者赶紧再发一篇paper(心想:本来想坑你们一把,没想到这么快就被识破了,不好玩   !),把锅甩给了ReLU(ReLU内心独白:我太难了!),同时,MobileNetv2也诞生了(此刻脑补众炼丹者们内心:也不知道是不是新挖的坑...)。

在MobileNetv2的paper中,作者举出一个充分必要条件将锅“合乎所以然”地甩给了ReLU——将低维流形映射到高维空间后使用ReLU变换再复原的例子:

低维流形在不同维度下的映射与复原对比

如上图,在2维空间有一组由m个点组成的螺旋线Xm数据(上图input),利用随机矩阵T映射到n维空间上并进行ReLU运算:

矩阵映射+ReLU的“拥抱”

这时,再利用随机矩阵T的逆矩阵,将y映射回2维空间中:

逆映射

最后,根据映射到不同维度空间的情况,对比下逆映射后的结果与原始输入:

可以看到,当映射到2、3维空间(n = 2, 3)时,与原始输入input相比有很大一部分的信息已经丢失了;而映射到15、30维空间(n = 15, 30)时,还有许多信息能被保留下来。

这就是说,在低维度空间下与ReLU拥抱(做ReLU运算),很容易造成信息丢失;而在高维度的情况下,信息丢失则相对没那么严重。

这就解释了为什么dw的卷积核有不少是空,因为dw本身不会改变通道数,如果输入通道本来就少的话,经过ReLU后信息丢失就会比较严重。

咦...说了那么久,怎么好像都没有提到MobileNetv2呀?是不是跑题了?矣?对耶!

哦,不不不,以上铺垫的这个问题很重要,因为针对这个问题的解决手段正是MobileNetv2最重要的骚操作,好了,接下来进入正题。

i). Expansion Layer

对于深度可分离卷积,其本身没有改变通道的能力,输入通道多少输出就是多少。有上述可知,这样的话,若输入通道很少,经过深度可分离卷积后再接ReLU,效果便不是很好,那怎么办呢?

我们可以在深度可分离卷积前先扩展通道数,也称作Expansion Layer(扩展层)。OK,那具体如何扩展呢?

既然在深度可分离卷积后我们使用了逐点卷积来将feature map的通道数映射到目标通道数,那么同样地,我们也可以在深度可分离卷积之前先使用逐点卷积进行升维(paper原文是升6倍)。

先使用逐点卷积升维,接着进行深度可分离卷积,最后再使用逐点卷积降维。

ii). Linear Bottleneck

相对于上述方式,这是一个比较“暴力”的手段,干脆把ReLU换掉,使用线性激活层替代。不过,我们可不能把所有的激活函数都换成线性的,这样整张网络就相当于一个线性操作了(别忘记使用激活函数的一个原因之一就是引入非线性变换),那么应该替换掉哪里的ReLU呢?

仔细看上图,第1个pw已将通道数扩展,中间的pw不会改变通道数,那么这两层后面使用ReLU通常较为“安全”,而最后1个pw通常是压缩通道,如果后面接ReLU,效果可能就相对没那么好了,因此可以将最后1个pw后的ReLU替换为线性激活函数,这样的结构也称作Linear Bottleneck

iii). Inverted Residual

还记得ResNet那货不?哦,这肯定是废话了,对于众炼丹者来说,它也算得上是个全明星了。

残差结构(通常也称作shortcut)能够其起到特征复用和避免梯度消失的作用,于是在MobileNetv2里也引入这一骚操作。

ResNet's residual vs MobileNetv2's Inverted-Residual

根据上图,对比下可以发现,两者都采用了 1×1 -> 3 ×3 -> 1 × 1 的卷积模式以及shortcut,不同点在于ResNet先使用pw降维,后使用pw升维,而MobileNetV2“反其道而行之”——先使用pw升维,后使用pw降维

这样一来,MobileNetv2的block形状看起来就刚好与ResNet的block相反,因此作者给了它一个网红名字——Inverted-Residual。

综合以上,我们来看下MobileNetv2的block:

MobileNetv2 block

再来对比下v1和v2的block:

MobileNetv1 vs MobileNetv2

上图左边是v1的block,没有shortcut并且最后的pw后面接了ReLU6;

右边的是v2的block,加入了Expansion Layer(使用1×1 pw 升维),引入shortcut,同时去掉了最后pw后的ReLU,改为线性激活函数。注意,v2的block有2种,当dw的步长(stride)为1时,使用了shortcut,形成残差结构;而dw的步长(stride)为2时,由于input与output的尺寸不同,因此没有使用shortcut结构。

最后,附上MobileNetv2的网络结构:

MobileNetv2 结构

附:MobileNetv2 paper


MobileNetv3

本以为v2能成为网红,没想到一下子被v3干掉了...好吧,我们先来回顾下v1和v2都做了哪些骚操作。

v1将标准卷积分解为dw+pw,同时使用2个超参进一步构建小模型和降低计算量;

v2在v1基础上,在dw前加入 Expansion Layer 进行通道数的扩展,将dw后的pw接的ReLU6替换为线性激活层,并且引入了shortcut,最终形成 inverted-residual(“倒残差”) 这样的结构。

简单精炼,OK!那么v3在以上的基础上又有哪些骚操作呢?

i). 新的非线性激活函数 —— h-swish

在介绍h-swish先来认识一个家伙——swish,它一次是在谷歌大脑2017的论文 Searching for Activation functions 种亮相,其具备无上界有下界、平滑以及非单调的特性,并且在深层模型上的效果优于ReLU,并且作者通过实验进行了验证。

 ()

这好东西v3当然也尝试使用过,但是作者又认为这家伙虽然提高了精度,但在嵌入式环境中,还是有不少计算成本,原因是在移动设备上计算sigmoid 函数成本不小,因此把sigmoid这部分替换掉,改为ReLU6,并且将这整个激活函数命名为h-swish

为啥叫h-siwsh?h代表什么呢?h其实是单词hard的第一个字母,h-swish的意思就是这个近似的函数可以逼近swish,让swish硬(hard)起来(别想歪呀...)。那为啥使用ReLU6呢?作者认为几乎所有的软硬件框架上都可以方便计算ReLU6,同时它能在特定模式下消除由于近似sigmoid的不同实现而带来的潜在数值精度损失。

sigmoid的“软”、“硬”模式以及swish和h-swish

下图展示了使用h-swish对于时间以及精度的影响,可以发现,使用h-swish@16可以提高大约0.2%的精度,但是持剑延长了大约20%。因此,总的来说,在更深的层中使用h-swish好处更大,于是建议通常在模型的后半部分使用。

h-swish对于时间以及精度的影响

ii). 基于Squeeze & Excitation(SE)的轻量级注意力结构

在bottleneck中加入了SE结构,并且放在了dw之后。另外,由于SE部分的计算会消耗一定的时间,因此在SE结构的第1个FC层中,压缩了通道数(paper原文是变为原来的1/4),在最后的FC层再复原,通过实验证明,这样在减少时耗的同时也提高了精度,这是属于MobileNet的轻量级SE结构。

MobileNetv3中的轻量级SE结构

关于这里的SE,有几点提醒下:

(1). 这里的Pool指的是GAP(Global Average Pooling),即全局平均池化,经过它的“沐浴”后,feature map的大小变为1 x 1,通道数维持不变;

(2). 第1个FC后的激活函数是ReLU,最后1个FC后的激活函数是h-sigmoid(注意不是 h-swish,相比 h-swish 少乘了1个 x,即)

iii). 修改了部分v2的结构 —— 头部卷积核的通道数 和 尾部结构

(1). 修改头部卷积核的通道数

v2中的头部卷积核是 32 x 3 x 3,v3中改成了 16 x 3 x 3,作者发现这样在保证了精度的前提下还降低了3ms的时耗。

(2). 修改尾部结构

v2中,在最后的 Avg-Pooling 之前,使用了1个pw来升维,有利于结构的预测,但这同时引入了一定的计算量,于是作者在v3中作了修改:

先去掉这个 pw 前的 bottleneck 中的 dw 和后面的 pw,然后将原本位于 Avg-Pooling 前的 pw 放置于 Avg-Pooling 后,这样就变为先用 Avg-Pooling 将feature map大小由 7 x 7 降到了 1 x 1(Avg-Pooling 的 kernel size 是 7 x 7),然后再使用 pw 升维度,减少了计算量和时耗,同时发现精度并没有得到损失,最终变为如下所示的结构:

MobileNetv3尾部结构

相比于v2:

MobileNetv2尾部结构

iv). 网络结构搜索 —— 资源受限的NAS(Platform-Aware NAS)与 NetAdapt

通过上述,可以发现v3相比于v2并没有做太多创新,其实重头之戏在于这部分。但是CW对这部分没有深入了解,参考了一些博文,在这里简单介绍一下。

总体过程就是先用资源受限的NAS,在计算和参数量受限的前提下搜索网络来优化各个块(block),称之为模块级搜索(Block-wise Search)。然后再使用 NetAdapt 算法对各个模块确定每一层的卷积核数量,称之为层级搜索(Layer-wise Search)


MobileNet为何这么快?

看到这里,你有没有认真想过其实为何MobileNet会这么快呢?它是闪电侠吗,sorry跑题...

或许你会说因为它将标准卷积分解为dw+pw、使用了宽度乘数和分辨率乘数缩减计算量、使用了h-swish...blablabla等等,嗯,也没错,但是这里可以尝试从另一个视角去理解。

以v1为例,来看看计算资源分布情况:

MobileNetv1 计算资源统计

可以看到,大部分计算都分布在了pw也就是1 x 1卷积上,这么看来,快就快在1 × 1卷积了。咦,难道1 x 1卷积才是闪电侠?(⊙o⊙)…又跑题,sorry...

我们知道,卷积实质是矩阵之间的加乘运算,而在计算机进行操作时,需要将其先存入内存再操作,按照 “行先序”:

卷积运算与计算机“行先序”

再来一张图,你会发现这是有点“辛苦”的:

卷积在内存中的运算,实线标注出卷积计算中的访存过程(对应数据相乘)

于是,通常都会使用到一个叫im2col的骚操作,其实质是通过牺牲空间的手段(约扩增K×K倍),将特征图转换成更大的矩阵来进行卷积计算,具体为:

把在特征图中每一次循环所需的数据排列成列向量,然后逐一堆叠起来形成矩阵(按通道顺序在列方向上拼接),比如输入特征图维度为 Ci × Wi × Hi ,卷积核尺寸为 K × K ,输出维度为Co×Wo×Ho,那么卷积核转换为 Co x ( K x K) 的矩阵,同时输入特征图转换为(K x K) × (Ci x Wo x Ho)的矩阵,如下所示。

im2col“骚操作”

然后调用诸如 GEMM(矩阵乘矩阵)这样的库加速两矩阵的相乘计算。由于这过程按照计算需求排布了数据顺序,使得计算机每次计算过程中能够依次访问到特征图中所需的数据,因此极大地提高了运算速度。

im2col后GEMM

OK,现在回来看看MobileNet的宝贝1×1卷积,根据上述,1×1卷积的“行先序”储存结构以及使用im2col后的结构分别如下图所示:

1x1卷积在计算机内存中使用“行先序”的存储结构以及使用im2col骚操作后的存储结构

咦,这是...一样哒!也就是说,1x1卷积根本不需要im2col的过程,“即插即用”!大大节省了数据重排列的时间和空间,因此在底层计算中相对更快。

附:MobileNetv3 paper


#最后

若你认真看完了本文,那么CW真心感谢你!与此同时,如果你觉得本文给予了你帮助或者让你有了新的认知,那我就更开心了,CW期待与大家共同成长!


参考:

https://cloud.tencent.com/developer/article/1467101

https://blog.csdn.net/u010712012/article/details/95922901

https://blog.csdn.net/qq_38807688/article/details/84590717

https://blog.csdn.net/Chunfengyanyulove/article/details/91358187

你可能感兴趣的:(Hi,我们是 MobileNet 家族!)