目前大部分的神经网络结构设计考虑的计算复杂度都是依据间接度量标准FLOPs (float-point operations, the number of multiply-adds),注意与FLOPS(floating-point operations per second,每秒浮点运算次数)相区别。但是FLOPs并不能真正的等价速度。见图一:
图一中(c)(d)可以清楚地看出,相同的FLOPs却有不同的速度。所以用FLOPs作为计算复杂度唯一的度量这是低效的且有可能导致次优设计。
在FLOPs和speed中的差异主要是由两个原因造成的。第一个原因是,一些重要的会对速度有重大影响的因素并没有被计算在FLOPs中去,一个例子是memeory access cost(MAC),另一个是 degree of parallelism(并行度)。在同样的FLOPs下,一个具有高并行度的模型会比一个具有低并行度的模型更快。第二个原因是,在不同的平台上,一样的FLOPs也会导致运行时间的不同。举例,tensor decomposition 被广泛的使用在早期的工作中用来加速矩阵的乘法。然而最近的工作表明虽然将FLOPs减少到了75%,但是在GPU上更慢了。发现原来是在最新的CUDNN库上对3*3卷积做了特别的优化,我们不能够再认为3*3卷积会比1*1卷积慢9倍了。
综上得到的结论有两个,第一考虑直接度量标准(speed),第二度量标准应该在指定目标平台上进行评测。
下面是具体的实验:
GPU: A single NVIDIA GTX 1080 Ti. CUDNN 7.0
ARM:A Qualcomm Snapdragon 810.
ShuffleNet v1 和 MobileNet v2是目前顶级的主流网络结构。整体的运行时间被分解成了不同的操作,如上图所示。可以清楚地看到FLOPs的度量仅算在了卷积部分。虽然卷积部分的花费在整体时间上的占比很大,但是其他操作仍占据很大的时间量。基于以上,接下来将是本文的重点,介绍4个实验。
G1) Equal channel width minimizes memory access cost (MAC).
假设一个1*1卷积层的输入特征通道数是c1,输出特征尺寸是h和w,输出特征通道数是c2,那么这样一个1*1卷积层的FLOPs就是下面式子所示,更具体的写法是B=1*1*c1*c2*h*w,这里省略了1*1。
为了简化的说明问题,我们假设计算设备上的cache足够大能够完全的存储feature maps and parameters。所以memeory access cost(MAC) = h*w(c1+c2)+c1*c2. h*w(c1+c2)是input/output feature maps, c1*c2是kernel weights。根据均值不等式可得:
因此,当给定FLOPs时,MAC能取到下界此时c1 = c2.
但在实际中cache往往不够,所以需要做实验去验证。
故就有了Table1这个实验,这些实验的网络是由10个block组成,每个block包含2个1*1卷积层,第一个卷积层的输入输出通道分别是c1和c2,第二个卷积层相反。4行结果分别表示不同的c1:c2比例,但是每种比例的FLOPs都是相同的,可以看出在c1和c2比例越接近时,速度越快,尤其是在c1:c2比例为1:1时速度最快。这和前面介绍的c1和c2相等时MAC达到最小值相对应。
(这里大家可以动手算算,FLOPs基本相等, 在h,w一致的情况下,128*128 = 16384, 90*180 = 16200, 52*312 = 16224,36*432 = 15552)
G2) Excessive group convolution increases MAC.
组卷积是现代网络结构的核心部分(MobileNetV1 V2、ShuffleNet、Xception其实都借鉴了卷积的group conv操作来加速模型)。它可以通过改变密集卷积channel的稀疏来减少计算复杂度(FLOPs)。一方面它允许使用更多的channels来得到合适的FLOPs和增加网络容量(故可以提高精度),但是另一方面,意味着增加了更多的MAC。
和上面同理,带group conv操作的1*1卷积的FLOPs如下所示,多了一个除数g,g表示group数量。这是因为每个卷积核都只和c1/g个通道的输入特征做卷积,所以多个一个除数g。
可以看出当给定合适的B(通过控制c1,c2)和hwc1时,g增大则MAC增大。
下面Table2是关于组卷积操作对速度的影响,c表示c1+c2的和,通过控制这个参数使得每个实验的FLOPs相同,可以看出随着g的不断增大,c也不断增大,这和前面说的在基本不影响FLOPs的前提下,引入group conv操作后可以适当增加网络宽度吻合。清楚地看出 group数量的增加对速度的影响很大,原因就是group数量的增加带来MAC的增加,而MAC的增加带来速度的降低。 所以结论是,对于group的数量我们应该小心选择,并不能简单的使用大的group数量。因为精度提升带来的好处很容易被快速增加的计算花费所超越。
G3) Network fragmentation reduces degree of parallelism.
在GoogLeNet系列和自动生成的结构中,一种“multi-path”的结构被广泛使用在每个网络块中。fragmentation这里就是分支的意思。虽然这种分支结构对精度有好处,但是会减少效率,原因是对像GPU这种强力的并行计算设备不够友好,而且还会增加额外的开销例如内核的启动和同步方面。
为了验证网络分支对效率的影响,做了Table3的实验,2-fragment-series表示一个block中有2个卷积层串行,也就是简单的叠加;4-fragment-parallel表示一个block中有4个卷积层并行,类似Inception的设计。可以看出在相同FLOPs的情况下,单卷积层(1-fragment)的速度最快。因此模型支路越多(fragment程度越高)对于并行计算越不利,这样带来的影响就是模型速度变慢。在GPU上分支数量对GPU速度上的减少非常显著,但是在ARM上,这种速度的减少就比较小了。
G4) Element-wise operations are non-negligible.
在之前的Figure2中就可以看到,在轻量级网络MobileNet V2和ShuffleNet中, element-wise operators占据了相当大的时间,尤其是在GPU上。这里 element-wise operators包括ReLU, AddTensor, AddBias等。常用的FLOPs指标其实主要表示的是卷积层的操作,而element-wise操作虽然基本上不增加FLOPs,但是所带来的时间消耗占比却不可忽视。特别地,depthwise convolution作为一个element-wise operator有着很高的MAC/FLOPs ratio. Table4的实验就是验证element-wise operators对模型速度的影响,实验是基于ResNet的bottleneck进行的。
基于以上4个实验,在ShuffleNet v1基础上设计出了ShuffleNet V2的结构
其中(a)和(b)是ShuffleNet v1的两种不同block结构,两者的差别在于后者对特征图尺寸做了缩小,这和ResNet中的两种block功能类似,同理(c)和(d)是ShuffleNet v2的两种不同block结构。从(a)和(c)的对比可以看出首先(c)在开始处增加了一个channel split操作,这个操作将输入特征的通道分成c-c’和c’,c’在文章中采用c/2,这主要是和前面第1点发现对应。然后(c)中取消了1*1卷积层中的group操作,这和前面第2点发现对应,同时前面的channel split其实已经算是变相的group操作了。其次,channel shuffle的操作移到了concat后面,和前面第3点发现对应,同时也是因为第一个1*1卷积层没有group操作,所以在其后面跟channel shuffle也没有太大必要。最后是将element-wise add操作替换成concat,这个和前面第4点发现对应。多个(c)结构连接在一起的话,channel split、concat和channel shuffle是可以合并在一起的。(b)和(d)的对比也是同理,只不过因为(d)的开始处没有channel split操作,所以最后concat后特征图通道数翻倍,可以结合后面Table5的具体网络结构来看。