一、逐点卷积
当前先进的轻量化网络大都使用深度可分离卷积或组卷积,以降低网络的计算量,但这两种操作都无法改变特征图的通道数,因此需要使用1×1的卷积。总体来说,逐点的1×1卷积有如下两点特性:
-
可以促进通道之间的信息融合,改变通道至指定维度。
-
轻量化网络中1×1卷积占据了大量的计算,并且致使通道之间充满约束,一定程度上降低了模型的精度。
为了进一步降低计算量,ShuffleNet提出了通道混洗的操作,通过通道混洗也可以完成通道之间信息的融合。
二、通道混洗
1. 实现思想
图2-1中a图代表了常规的两个组卷积操作,可以看到,如果没有逐点的1×1卷积或者通道混洗,最终输出的特征仅由一部分输入通道的特征计算得出,这种操作阻碍了信息的流通,进而降低了特征的表达能力。
因此,我们希望在一个组卷积之后,能够将特征图之间的通道信息进行融合,类似于图2-1中b操作,将每一个组的特征分散到不同的组之后,再进行下一组卷积,这样输出的特征就能够包含每一个组的特征,而通道混洗恰好能够实现这个过程,如图2-1的c所示。
2. 实现过程
通道混洗可以通过几个常规的张量操作巧妙地实现,如图2-2所示。为了更好地讲解实现过程,这里对输入通道做了1-12的编号,一共包含3个组,每个组包含4个通道。
下面详细介绍混洗过程中使用到的3个操作:
- Reshape:首先将输入通道的一个维度Reshape成两个维度,一个是卷积组数,一个是每个卷积包含的通道数。
- Transpose:将扩展出的两维进行置换。
- Flatten:将置换后的通道Flatten平展后即可完成最后的通道混洗。
3. 代码示例
def channel_shuffle(x, groups):
batchsize, num_channels, height, width = x.data.size()
channels_per_groups = num_channels // groups
# Reshape操作,将通道扩展为两维
x = x.view(batchsize, groups, channels_per_group, height, width)
# Transpose操作,将组卷积两个维度进行置换
x = torch.transpose(x, 1, 2).contiguous()
# Flatten操作,两个维度平展成一个维度
x = x.view(batchsize, -1, height, width)
return x