1.简介
ShuffleNetv1主要的创新点在于,虽然组卷积能够很好的减少参数和计算量,但当你连续使用几个组卷积时,每个group之间是没有任何的信息交流的,这可能导致提取出来的特征图不够准确,对于全局的关注不够,影响感受野。所以该论文用了一个shuffle的操作,将几个group之间的信息打乱,这样就能够缓解group之间信息无交流的问题。其次,由于ResNeXt网络中1x1卷积所占的计算量比重很大,所以将block中的1x1卷积也替换成了组卷积。就这两个主要改动,shuffle和1x1组卷积。
上图为ShuffleNetv1的性能展示,可以看到,与AlexNet和Mobilenet相比,同等参数量下错误率、推理时间都是最优的。
2.ShuffleNetv1 block
下图能够很好的体现该文章核心思想,将feature map打乱,促进group间的信息交流。
论文中说到,在ResNeXt中,1x1的PW卷积层占了93.4%的计算量,而group卷积占用的计算量很少,所以ShuffleNetv1 block将ResNeXt block(a图)中的1x1卷积替换成了组卷积(b图),b图是stride=1时的block,当stride=2,需要下采样时,就通过c图来进行。注意:C图中是将两个分支Concat在一起的,而不是前面的Add操作。
上图是关于这三个block参数量的对比,可以发现ShuffleNetv1的参数量是最少的。
3.ShuffleNetv1整体网络结构
下图就是ShuffleNetv1的网络结构了,
需要注意的是,每个block中,第一个1x1组卷积层和3x3DW卷积的out_channel为整个block的out_channel的四分之一。比如block输入feature map的cahnnel为256,out_channel也是256,那按顺序1x1的out_channel=64,3x3的out_channel=64,1x1的out_channel=256,最后再与shortcut的256channel相加得到block的输出。
还有一点,stage2中由于输入的feature map通道数太少,不值得第一个1x1卷积用组卷积,所以stage2的第一个1x1卷积还是普通卷积。
4.ShuffleNetv1代码
由于相较于ResNet,ShuffleNetv1只是将1x1普通卷积变为组卷积,然后多了一个Shuffle模块,所以这里就只放Shuffle模块了,其他的部分在ResNet网络上改一下就能实现。
def channel_shuffle(x: Tensor, groups: int) -> Tensor:
batch_size, num_channels, height, width = x.size()
channels_per_group = num_channels // groups
# reshape
# [batch_size, num_channels, height, width] -> [batch_size, groups, channels_per_group, height, width]
x = x.view(batch_size, groups, channels_per_group, height, width)
x = torch.transpose(x, 1, 2).contiguous()
# flatten
x = x.view(batch_size, -1, height, width)
return x