论文:ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices
论文链接:https://arxiv.org/abs/1707.01083
参考博客:@Thaurun https://www.cnblogs.com/heguanyou/p/8087422.html
目前许多CNNs模型往深度更深的方向发展,但是这类深度网络模型难以运行在移动设备上。针对上述问题,部分研究集中在对现有预训练模型的修剪、压缩或使用低精度数据表示。
在2017年末,Face++发了一篇论文ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices讨论了一个极有效率且可以运行在手机等移动设备上的网络结构——ShuffleNet。ShuffleNet的工作专注于设计更好的模型,直接提高性能,而不是加速或转换现有模型。
ShuffleNet通过在残差模块上添加分组卷积与1×1的卷积核来降低计算量,通过重组通道来丰富各个通道的信息。这个论文的mxnet源码的开源地址为:MXShuffleNet。
文章创造思路:最先进的网络例如Xception和ResNeXt将有效的深度可分离卷积或群卷积引入构建block中,在表示能力和计算消耗之间取得很好的折中。但是,我们注意到这两个设计都没有充分采用1×1的逐点卷积,因为这需要很大的计算复杂度。在小型网络中,昂贵的逐点卷积造成有限的通道之间充满约束,这会显著的降低精度。为了解决这个问题,一个直接的方法是应用通道稀疏连接,例如组卷积(group convolutions)。通过确保每个卷积操作仅在对应的输入通道组上,组卷积可以显著的降低计算损失。然而,如果多个组卷积堆叠在一起,会有一个副作用: 某个通道输出仅从一小部分输入通道中导出。交叉连接或者shuffle的形式便应用到分组卷积之中以进行组别之间的信息交互。shuffle 具体来说是 channel shuffle,是将各部分的 feature map 的 channel 进行有序的打乱,构成新的 feature map,以解决 group convolution 带来的 信息流通不畅 问题。(MobileNet 是用 point-wise convolution 解决的这个问题)。ShuffleNet将输入的group进行打散,从而保证每个卷积核的感受野能够分散到不同group的输入中,增加了模型的学习能力。
讨论分组卷积与卷积核大小对计算量的影响
为什么用分组卷积与小的卷积核会减少计算的复杂度呢?
不分组且只有一个样本
在不分组与输入的样本量为1(batch_size=1)的条件下,输出一个通道上的一个点是卷积核会与所有的通道卷积之积,如图1所示:
图1 输入层(第一层)只有一个通道,那个第二层一个通道上的点是第一层通道相应区域与相应卷积核的卷积,第三层一个通道上的点是与第二层所有通道上相应区域与相应卷积核的卷积,而且对于输出通道每个输入通道对应的卷积核是不一样的,不同的输出通道也有不同的卷积核,所以说卷积核的参数量是Cout×Cin×Kh×Kw
图2 输入的所有通道按卷积核的大小提取出来排列成一行,要注意的是在这只是示意图,在实际的程序中,一般会排成一列,因为在防问数据时会一个通道一个通道地访问的。输出一个点要输出的数据有Cin×Kh×Kw个。
图3 输出一个通道就有Hout×Wout个点,而且在程序中同一个通道(图中的同一个颜色)的内容是按行排列的,所以说转换出来的的矩阵是图中(Cin×Kh×Kw)×(Hout×Wout)矩阵的转置。
图4 同样卷积核(Filter)也要Reshape成(Cin×Kh×Kw)×(Hout×Wout) 的矩阵
得到的两个矩阵Feature与Filter相乘得到输出矩阵Output:
从式(1.2)中可以看出来,卷积核的大小对计算量影响是很大的,3×3的卷积核比1×1的计算量要大3**4=81倍。
分组且只有一个样本
什么叫做分组,就是将输入与输出的通道分成几组,比如输出与输入的通道数都是4个且分成2组,那第1、2通道的输出只使用第1、2通道的输入,同样那第3、4通道的输出只使用第1、2通道的输入。也就是说,不同组的输出与输入没有关系了,减少联系必然会使计算量减小,但同时也会导致信息的丢失。
当分成g组后,一层参数量的大小由变成。Feature Matrix的大小虽然没发生变化,但是每一组的使用量是原来的1/g,Filter也只用到所有参数的1/g。然后再循环计算。然后再循环计算g次(同时FeatureMatrix与FilterMatrix要有地址偏移),那么计算公式与计算量的大小为:
所以,分成g组可以使参数量变成原来的1/g,计算量是原来的1/(g**2)。
多个样本输入
为了节省内存,多个样本输入的时候,上述的所有过程都不会改变,而是每一个样本都运行一次上述的过程。
以上只是最简单、粗略的分析,实际上计算效率的提升并不会有上述这么多,一方面因为im2col会消耗与矩阵运算差不多的时间,另一方面因为现代的blas库优化了矩阵运算,复杂度并没有上述分析的那么多,还有计算过程for循环是比较耗时的指令,即使用openmp也不能优化卷积的计算过程。
交换通道(Shuffle Channels)
在上面我提到过,分组会导致信息的丢失,那么有没有办法来解决这个问题呢?这个论文给出的方法就是交换通道,因为在同一组中不同的通道蕴含的信息可能是相同的,如果在不同的组之后交换一些通道,那么就能交换信息,使得各个组的信息更丰富,能提取到的特征自然就更多,这样是有利于得到更好的结果。
图5 分组交换通道的示意图,a)是不交换通道但是分成3组了,要吧看到,不同的组是完全独立的;b)每组内又分成3组,不分别交换到其它组中,这样信息就发生了交换,c)这个是与b)是等价的。
ShuffleUnit
ShuffleUnit的设计参考了ResNet,总有两个基本单元,两人个基本单元功能不一样,将他们组合起来就可以得到ShuffleNet。这样的设计可以在增加网络的深度(比mobilenet深约一倍)的同时,减少参数总量与计算量(本人运行Cifar10时,速度大约是molibenet的10倍)。
图6 b)与c)是两人个ShuffleNet的基本单元,这两个单元是参考了a)的设计,单元b)输出与输入的Shape一致,只是丰富了每个通道的信息,单元c)增加了一倍的通道数且输出的Hou、Wout 比Hin、Win减少了一倍。
至此论文的核心思想:分组卷积+Shuffle已经介绍完毕,有兴趣的读者可以阅读源码MXShuffleNet。