目前一些网络模型如MobileNet_v1, v2,ShuffleNet_v1, Xception采用了分组卷积,深度可分离卷积等操作,这些操作在一定程度上大大减少了FLOPs,但FLOPs并不是一个直接衡量模型速度或者大小的指标,它只是通过理论上的计算量来衡量模型,然而在实际设备上,由于各种各样的优化计算操作,导致计算量并不能准确地衡量模型的速度,换言之,相同的FLOPs会有不同的推理速度。
这是一篇类似于《Rethinking the Inception Architecture for Computer Vision》(即Inception_v2)的论文,在Inception_v2论文中提出了四条设计卷积网络模型的原则,Inception_v2就是基于这些原则上设计而来。同样,shuffleNet_v2(即《Pratical Guidelines for Efficient CNN Architecture Design》,一看这名字就知道很值得一读)指出了四个影响模型实际推理速度的操作,并在尽量避免这些操作的基础上提出了ShuffleNet_v2结构。
ShuffleNet v2实现了在同样的FLOPs下,速度明显快于其他类似网络。例如,在500MFLOPs,ShuffleNet v2比MobileNet v2快58%,比ShuffleNet v1快63%,比Xception快25%。
Direct metrics
前面提到FLOPs是通过理论上的计算量来衡量模型速度,这是一个indirect metrics,与direct metrics(如速度)之间是存在一些差异。主要原因一个是FLOPs忽略了一些重要的因素,一个是MAC (memory access cost),即内存访问的时间成本。例如分组卷积,其使得底层使用的一些优化实现算法由于分组后实现性能更低,从而导致,分组数越大,时间成本越高。另一个是并行度,同样FLOPs下,高并行度的模型速度快于低并行度的模型。
第二个是不同平台下,同样的FLOPs的模型运行时间不同。例如在最新的CUDNN library中,优化实现的3x3卷积所花费的时间并没有1x1卷积的9倍。
如图所示,这是一个模型在GPU上各项操作所花费的时间,FLOPs仅表示了Conv部分的计算量,而实际上Elemwise、Data相关部分也耗费相当大的时间。因此,仅仅使用FLOPs这个indirect metrics来衡量模型速度是不够的。
ShuffleNet v2使用实际运行时间来衡量模型。
高效设计CNN模型的实际指南
ShuffleNet v2进行了四项实验,得出了一些比较耗时的操作,经过原理分析,提出了四条设计原则。
1. 卷积层输入输出通道数相同时,MAC最小
2. 分组卷积的分组数越大,MAC越大
3. 网络支路会降低模型的并行度
4. Element-wise操作不可忽视
01 卷积层输入输出通道数相同时,MAC最小
为简化计算表达式,这里使用1x1卷积来进行理论上的推导。
对于空间大小为 h,w的特征图,输入和输出通道数分别为c1和c2,使用1x1卷积, 则FLOPs为B = h x w x c1 x c2。而MAC = hw(c1 + c2 ) + c1 x c2。这里hwc1为输入特征图内存访问成本,hwc2为输出特征图内存访问时间成本,c1xc2x1x1为卷积核内存访问时间成本。将B表达式代入MAC表达式中,并根据不等式定理,可有如下不等式:
由此式可知,MAC存在下限,当c1 = c2时,MAC取最小值。因此,第一组实验即为在相同的FLOPs下,取不同的输入输出通道数的比值c1/c2,查看不同c1/c2下模型运行时间。
如图所示,理论相当正确。在1:1时模型速度最快。
02 分组卷积的分组数越大,MAC越大
分组卷积在一方面,使得在相同FLOPs下,分组数越大,在通道上的密集卷积就会越稀疏,模型精度也会增加,在另一方面,更多的分组数导致MAC增加。
使用分组卷积的FLOPs表达式为B=h w c1 c2 /g , MAC表达式如下:
第二组实验是在相同的FLOPs下,查看不同的分组数对模型的运行速度:
因此,分组数需要合理的选择,需要在运行时间和精度上平衡。
03 网络支路会降低模型的并行度
在GoogLeNet(也就是Inception_v1)系列中,使用了多条支路,最后通过concat的方式拼接。这样的支路不仅提到了精度,但同时也降低了效率,这是因为支路对GPU并行运算来说是不友好的,此外,它还引入了额外的开销,如内核启动与同步。
第三组实验是在相同FLOPs情况下,设置四个支路数不同的一个网络,比较它们运行的速度。
实验证明,只有一条支路时,运行速度最快。因此,在网络结构中支路数可以提到精度,但也会降低运行速度,从而影响实时性。
04 Element-wise操作不可忽视
正如上面给的那个图,Element-wise操作在GPU上占的时间是相当多的。Element-wise操作有ReLU, AddTensor, AddBias等。它们都有比较小的FLOPs,却有比较大的MAC。特别地,depthwise conv也可以认为是一个Element-wise操作,因为它有较大的MAC/FLOPs比值。
对于第四组实验,使用ResNet中的bottleneck单元(也就是1x1卷积后接3x3卷积,再接1x1卷积,中间使用了ReLU, 另有一个shortcut连接),设置有无shortcut, ReLU四个不同的对比,得出它们的运行时间。
实验证明,ReLU,shortcut这些Element-wise会降低运行时间。
对此,shuffleNet v1使用多的分组数,违背了第二条原则,使用bottleneck相似的结构违背了第一条原则,MobileNet v2使用倒残差结构违背了第一条,且在通道数较多的feature map上使用了depthwise conv和ReLU违背了第四条,自动生成的结构有较多支路,违背了第三条。
注意:这里指的违背了这些原则,并不是说设计不好。以第二条分组数和第三条支路数为例,不能因为它们会降低模型运行时间,就再也不使用支路和分组卷积,毕竟它们对模型精度有较大提升,因此需要选择合适的分组数和支路数,以便在速度上和精度上取得权衡。
ShuffleNet v2结构
shuffleNet v2是在shuffleNet v1 unit的基础上,根据上面四组实验得出的经验,进行适当的权衡精度与速度而调整的。
图a为shuffleNet v1正常Unit, 图b为shuffleNet v1降采样Unit,图c为shuffleNet v2 正常Unit, 图d为shuffleNet v2 降采样Unit.
在shuffleNet v2中引入了Channel Split, 将通道数分为c’ 和c - c’,这里c’取c/2。一部分进行卷积操作,另一部分直接进行concat。卷积的那一路的输入和输出相等,这是考虑到第一条原则。两个1x1卷积不再进行分组,一部分原因是第二条原则,另一部分是因为Channel split就相当于是分组了。两路进行concat后,再进行Channel Shuffle,这是为了通道上的信息进行流动。否则,左端那路的一半通道信息将一直进行到后面都没有通过卷积层。
对于空间降采样层,这个Unit是没有Channel split,这样可以实现在两路concat后,通道数翻倍。其余改动具体看图更容易理解。
05 网络结构
结构跟shuffleNet v1基本一致,唯一的差别是在全局平均池化前加入了1x1卷积,以便混合特征。右边的output channels下的0.5x, 1x等,只是用来表示不同的模型尺寸,也就是通道数不一样。
06 网络精度的分析
shuffleNet v2不仅效率高,而且精度也高。这有两个主要的原因,高效率是因为使用了更多特征通道和更大的网络容量来构建Block。第二点,在每个block中,一半的通道直接进入下一个block参与下一个block,这可以认为是特征再利用(feature reuse),类似于DenseNet 和CondenseNet中的想法,特征再利用是高效高精度的设计。
Experiment
实验部分一般没有可以多说的地方。看图表更能比文字表达清晰。
如有错误或疑问,欢迎留言指出。