MobileNet v1 and MobileNet v2
tags: MobileNet
前言
MobileNet v2 是在v1的Depthwise Separable的基础上引入了残差结构。并发现了ReLU的在通道数较少的Feature Map上有非常严重信息损失问题,由此引入了Linear Bottlenecks和Inverted Residual。
首先在这篇文章中我们会详细介绍两个版本的MobileNet,然后我们会介绍如何使用Keras实现这两个算法。
1. MobileNet v1
1.1 回顾:传统卷积的参数量和计算量
它的一层网络的计算代价约为:
v1中介绍的Depthwise Separable Convolution就是解决了传统卷积的参数数量和计算代价过于高昂的问题。Depthwise Separable Convolution分成Depthwise Convolution和Pointwise Convolution。
1.2 Depthwise卷积
其中Depthwise卷积是指不跨通道的卷积,也就是说Feature Map的每个通道有一个独立的卷积核,并且这个卷积核作用且仅作用在这个通道之上,如图2所示。
在Keras中,我们可以使用DepthwiseConv2D
实现Depthwise卷积操作,它有几个重要的参数:
kernel_size
:卷积核的尺寸,一般设为3。strides
:卷积的步长padding
:是否加边activation
:激活函数
由于Depthwise卷积的每个通道Feature Map产生且仅产生一个与之对应的Feature Map,也就是说输出层的Feature Map的channel数量等于输入层的Feature map的数量。因此DepthwiseConv2D
不需要控制输出层的Feature Map的数量,因此并没有filters
这个参数。
1.3 Pointwise卷积
Depthwise卷积的操作虽然非常高效,但是它仅相当于对当前的Feature Map的一个通道施加了一个过滤器,并不会合并若干个特征从而生成新的特征,而且由于在Depthwise卷积中输出Feature Map的通道数等于输入Feature Map的通道数,因此它并没有升维或者降维的功能。
Pointwise的可视化如图3:
1.4 Depthwise Separable卷积
计算量为:
和普通卷积的比值为:
1.5 Mobile v1的Keras实现及实验结果分析
通过上面的分析,我们知道一个普通卷积的一组卷积操作可以拆分成了个Depthwise卷积核一个Pointwise卷积,由此而形成MobileNet v1的结构。在这个实验中我们首先会搭建一个普通卷积,然后再将其改造成v1,并在MNIST上给出实验结果,代码和实验结果见链接CPU,GPU。
首先我们搭建的传统卷积的结构如下面代码片段:
通过Summary()
函数我们可以得到每个网络的每层的参数数量,见图4,左侧是普通卷积,右侧是MobileNet v1。
接着我们在MNIST上跑一下实验,我们在CPU(Intel i7)和GPU(Nvidia 1080Ti)两个环境下运行一下,得到的收敛曲线如图5。在都训练10个epoch的情况下,我们发现MobileNet v1的结果要略差于传统卷积,这点完全可以理解,毕竟MobileNet v1的参数更少。
对比单个Epcoh的训练时间,我们发现了一个奇怪的现象,在CPU上,v1的训练时间约70秒,传统卷积训练时间为140秒,这和我们的直觉是相同的。但是在GPU环境下,传统卷积和v1的训练时间分别为40秒和50秒,v1在GPU上反而更慢了,这是什么原因呢?
问题在于cudnn对传统卷积的并行支持比较完善,而在cudnn7之前的版本并不支持depthwise卷积,现在虽然支持了,其并行性并没有做优化,依旧采用循环的形式遍历每个通道,因此在GPU环境下MobileNet v1反而要慢于传统卷积。所以说,是开源工具慢,并不是MobileNet v1的算法慢。
2. MobileNet v2 详解
在MobileNet v2中,作者将v1中加入了残差网络,同时分析了v1的几个缺点并针对性的做了改进。v2的改进策略非常简单,但是在编写论文时,缺点分析的时候涉及了流行学习等内容,将优化过程弄得非常难懂。我们在这里简单总结一下v2中给出的问题分析,希望能对论文的阅读有所帮助,对v2的motivation感兴趣的同学推荐阅读论文。
根据对上面提到的信息损耗问题分析,我们可以有两种解决方案:
既然是ReLU导致的信息损耗,那么我们就将ReLU替换成线性激活函数;
如果比较多的通道数能减少信息损耗,那么我们就使用更多的通道。
2.1 Linear Bottlenecks
我们当然不能把ReLU全部换成线性激活函数,不然网络将会退化为单层神经网络,一个折中方案是在输出Feature Map的通道数较少的时候也就是bottleneck部分使用线性激活函数,其它时候使用ReLU。代码片段如下:
这里使用了MobileNet中介绍的ReLU6激活函数,它是对ReLU在6上的截断,数学形式为:
图7便是结合了残差网络和线性激活函数的MobileNet v2的一个block,最右侧是v1。
2.2 Inverted Residual
2.3 MobileNet v2
MobileNet v2的实现可以通过堆叠bottleneck的形式实现,如下面代码片段
3. 总结
在这篇文章中,我们介绍了两个版本的MobileNet,它们和传统卷积的对比如图10。
如图(b)所示,MobileNet v1最主要的贡献是使用了Depthwise Separable Convolution,它又可以拆分成Depthwise卷积和Pointwise卷积。MobileNet v2主要是将残差网络和Depthwise Separable卷积进行了结合。通过分析单通道的流形特征对残差块进行了改进,包括对中间层的扩展(d)以及bottleneck层的线性激活(c)。Depthwise Separable Convolution的分离式设计直接将模型压缩了8倍左右,但是精度并没有损失非常严重,这一点还是非常震撼的。
Depthwise Separable卷积的设计非常精彩但遗憾的是目前cudnn对其的支持并不好,导致在使用GPU训练网络过程中我们无法从算法中获益,但是使用串行CPU并没有这个问题,这也就给了MobileNet很大的市场空间,尤其是在嵌入式平台。
最后,不得不承认v2的论文的一系列证明非常精彩,虽然没有这些证明我们也能明白v2的工作原理,但是这些证明过程还是非常值得仔细品鉴的,尤其是对于从事科研方向的工作人员。
最后更新于