ShuffleNet网络模型学习笔记
ShuffleNet网络模型的Motivation和之前的MobileNet基本是一致的,都是构建一个轻量级的网络构架,针对现有网络模型普遍依赖于高参数,高深度,高计算量的现状,提出一种能够适应于嵌入式设备或者移动端设备的深度学习网络框架,作者在测试阶段,也与MobileNet V1的测试结果进行了对比,在ImageNet Top-1错误率上取得了更好的结果。
ShuffleNet的核心是两个点,pointwise group convolution(逐点分组卷积)和channel shuffle(通道洗牌),前者主要负责减少网络的操作量,后者则是针对逐点分组卷积存在的缺点所提出的改进方法。
Group convolution,分组卷积,最早在AlexNet网络中被提出,受限于当时的硬件计算资源,在卷积层的计算不能完全依赖于一个Gpu,于是便提出了分组卷积,将feature map分给两个Gpu进行处理。而现在的分组卷积,主要是为了减少卷积操作的操作量。
上图是一张普通的卷积层操作,黄色的blocks代表着学习的参数,灰色的blocks代表着feature map,对于一个尺寸为的输入,卷积层的参数为
,最后得到的输出是
,在这个过程中需要的计算量是
,非常大的计算量,于是我们产生了一种想法,能不能把输入以及卷积层都进行切割,分组,一组一组进行卷积操作,最后concat,并联到一起,就能减少很多计算量,基于这种想法,便有了group convolution:
分组卷积的思想中,我们有一个可以调整的超参数,代表着分组的组数,对于同样一个尺寸为
的输入,我们将它按照通道分成
组,分辨率不变,每一组的尺寸为
,我们对卷积层进行同样的操作,卷积核的尺寸不变,卷积核的数目(通道数)分成
,每一组的尺寸为
,然后每一组进行组内卷积,得到
个结果
,然后将这
组结果按照通道进行concat,并联操作,最后得到最终输出
,与普通卷积层的输出尺寸相同,但这整个过程的计算量仅仅是
,分子是普通卷积层的计算量,分母是分组数目,计算量比原本减少了
倍。纵观整个过程,可以发现,并联操作是减少计算量的核心步骤。
但是这样的分组卷积有一个非常明显的问题,因为分组后,只进行组内卷积,组与组之间完全没有联系,它明显降低了信息之间的流通,影响信息的表达能力,为了解决这个问题,作者提出了使用channel shuffle操作,这个操作的核心思想,是对于输入,进行分组的时候,由于分成组会得到
个输入,对于这每一个输入,我们再度按照通道分成
组,然后feed给卷积层的每一个组,从而让卷积层的每一组都能得到全部组的部分输入:
如作者在论文中给出的图解,(a)图是普通的,不带channel shuffle操作的group convolution,可以看见,组与组之间不存在信息流通,信息表达能力低下,(b)图则是对(a)图存在问题的一个解决,经过GConv1(Group Convolution1)的输出Feature,一共有三组(红绿蓝),这三组的每一组,我们再分成三组,一共九组,三红,三绿,三蓝,然后按照一红一绿一蓝为一组,输入到GConv2中去,这样GConv2就能接收到来自所有组的部分信息,(c)图则是一个Channel Shuffle的比较优雅,直观的解释。
上图是借鉴一个****博主的对channel shuffle的解释,非常简洁易懂。对于再分组后得到的组通道,使用reshape指令变成一个
的矩阵,这个矩阵的每一行都是来自某一组全部的信息(上图的橘色,绿色,蓝色),然后我们对这个矩阵进行转置,转置后每一层则包含了来自各个组的信息(上图的一橘一绿一蓝),再将这个矩阵flatten,输入下一个卷积层中。
之后作者就提出了一个ShuffleNet Unit,分为两种,都是在深度残差网络的基础上,改进而来:
上面是论文中给出的图解,(a)图是一个将普通的卷积层替换成DepthWise Convolution后的bottleneck block,这里的DepthWise Convolution来自于MobileNet中,主要进行特征提取,变换分辨率,不改变通道数,最后一个
的卷积层得到的输出经过BN后与原始输入进行Add元素相加操作,通过ReLU,输入下一层。(b)和(c)两图都是ShuffleNet Unit,(b)在(a)的基础上,将
的卷积层,替换成了
的分组卷积层,并在第一个GConv1的后面加入了Channel Shuffle操作,(b)的步长是1,不进行feature map的分辨率变换,而(c)的步长是2,进行变换,同时,(c)还加入了一个
,步长为2的平均池进行辅分支操作,同时将原本的Add,元素相加操作变成了Concat,将主副分支得到的两个输出进行通道并联操作,通道数翻倍,然后通过ReLU,输入下一层。
可以看出来,两个ShuffleNet Unit负责不同的功用,(c)会把feature map的分辨率降低一倍,而通道数提高一倍,(b)则是两者都不变,使用的时候,多先使用(c),然后反复使用(b),提取特征。值得注意的是,和深度残差网络一样,主分支的两个的分组卷积层还兼有降维和升维的任务,GConv1降低维度,GConv2将维度恢复,存在一个超参数bottleneck_channels,它一般是输入通道数的几分之一,可以根据需求自我调整,作者在代码中取值为4:
第一行代码表示输入的通道数将会被降低为原本的四分之一,第二行代码则是第一个的分组卷积层,它的输出通道数为输入的四分之一。
最后是这个单元的计算量,得益于逐点分组卷积的使用,以及channel shuffle的采用,ShuffleNet Unit的计算量非常小,ResNet Unit需要FLOPs,ResNeXt需要
,但ShuffleNet Unit只需要
。
根据上述的内容,作者最后提出了ShuffleNet的网络结构:
输入图像首先经过一个步长为2的卷积层,降低分辨率后,经过最大池池化后,然后连续通过三个Stage,这里每个Stage都是有两种ShuffleNet Unit组成,比如Stage2,首先是一个步长为2,(c)型ShuffleNet Unit后,再经过三个同样的(b)型ShuffleNet Unit,注意,一个Stage里面,(c)型和(b)型ShuffleNet Unit的参数是一致的。经过三个Stage后,通过一个全局池后,将分辨率降为,最后通过全连接层。最后一行给出了对应不同的分组数,整体网络的计算复杂程度。
值得注意的是,右图中,从Stage2开始,对于每个不同的分组数,给出了不同数值的输出通道数,这里的数值是作者人为根据情况设置的,可以从源代码中看出来:
一开始的条件语句中,根据分组参数的不同,设定不同的全局输出通道数,之后则是Stage内的操作,先是通过一个(c)型的ShuffleNet Unit,改变通道数和分辨率,然后反复通过相同的(b)型ShuffleNet Unit,最后返回输出。
最后是关于这个网络模型的参数调整,主要是三个超参数:
第一个是bottleneck_channels,用于ShuffleNet Unit内部降维幅度的调整,作者在代码中设为与ReeNet一致的四分之一。
第二个是分组数目,这个参数控制逐点卷积的链接稀疏度,在给定限制下,这个数值越大,通道数越多,有助于编码信息。
最后一个是作者给出的参数,用于控制通道数,ShuffleNet
代表将通道数放缩到
倍:
这里,bottleneck_channels设置为输入通道的四分之一,可以看见,越小,计算复杂度越小,但相对的精确度越低,而
则是一个不宜取大也不宜取小的参数,在第二行的测试中,过低或者过高的
值都会造成精确度的损失。