之前介绍了 MobileNets,MobileNets 主要通过 Depthwise Convolution 和 Pointwise Convolution 替代传统卷积操作提高模型效率,使模型更容易用在移动端。本文介绍旷视科技提出的 ShuffleNet,ShuffleNet 对分组卷积进行 Channel Shuffle 操作,融合各个分组的特征,在降低计算量的同时保持了模型的精度。在shuffleNet中全都是使用的组卷积&DW卷积。
V1版本的核心部分:
1 shuffle channel
2 1x1普通卷积换成1x1的组卷积
shuffleNet网络指标
网络结构:group(g)=3的比较经典
1 为什么要channel Shuffle:组卷积中虽然能够减少参数,但是不同组之间的信息没有交流。
对于分组卷积来讲,如图红绿蓝,他们只能在各自的channel中提取特征信息,所以我们要考虑让不同channel之间特征融合起来,以便达到普通卷积的特征提取效果。
我们可以先将组卷积中的channel,堆叠在一起,然后进行转置(向量转置)操作,然后在展平。
具体操作可以为:假设原来包含 G 个分组,每个分组 N 个 channel,则先把 channel 的维度转为 2 维 (G, N),然后转置 (N, G),最后 reshape 回 1 维即可。过程如下图所示。
2 其次作者发现,在resnext网络中占用计算量绝大多数的操作是1x1的普通卷积操作,大约占到了总操作的93%。因此,在shuffulenet网络中,我们将所有的1x1卷积换成1x1的组卷积。(a->b)
图b对应stride=1的情况,图c对应stride=2的情况。在之前ResNet网络中shortcut结构是直接通过卷积来进行下采样操作,但是shufflenet中我们使用平均池化操作来进行下采样。
ResNet、ResNext、ShuffleNet网络参数对比:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
V2版本的核心部分:
1 计算复杂度不能只看FLOPs
2 提出4条设计高效网络准则
3 提出新的Block设计
1 FLOPs只是间接指标,速度是最直接的评价指标,除了FLOPs以外,还应该考虑memory access cost (MAC)、并行等级(degree of parallelism),在相同的FLOPs下,并行度高的模型比并行度低的模型速度快,所以一味加宽网络宽度也是不行的,比如残差网络。另外,相同的FLOPs在不同的平台上执行时间也不一样。
卷积占了模型推理的大部分时间,但其他的操作也占据了相当一部分的时间
2 四条设计高效网络准则
(1)当卷积层的in与out的channel相等时MAC最小(保持FLOPs不变时)
论文探究了当FLOPs不变的情况下,in-channel与out-channel之间的比值对于速度的影响,可以看到两者相差越大,计算时间越长。
(2)关注组卷积的计算成本
虽然组卷积可以减少参数,但是组数越多,你得内存占用也越多,对于速度的影响是不能忽略的。
作者在FLOPs保持不变的前提下改变g的数值,可以看出随着g的增多,在GPU上速度下降明显,但在CPU上不明显。
(3) 降低我们网络的碎片化程度
其实就是减少分支,因为他就像总线一样,一个程序的执行要等待所有数据指令都到站之后在进行下一步操作。
论文说:虽然这种碎片化结构会提升我们的准确率,但它会降低我们模型的一个效率。因为对于GPU这种具有很强的并行计算的能力的设备是不友好的。并且在多分支情况下要考虑kernel的启动和同步的的时间parallel。
(4) 关注卷积之后的处理操作 (element-wise Operation是不可忽视的)
卷积后操作包括,relu,add,concat类等操作。
3 提出新的Block设计
V1---->V2
Channel Split 是对于考虑到in-c和out-c比例为1:1。包括后面的concat拼接操作也是1:1。
考虑到上面刚讲的关注组卷积计算成本,我们不在使用V1中的组卷积。
考虑到要关注到卷积后操作,ShuffleNet v1中的“Add”操作不再存在。像relu和深度卷积这样的Element-wise运算只存在于一个分支中
三个连续的Element-wise操作,即“CONAT”、“Channel Shuffle”和“Channel Split”,被合并成一个单元级的操作(对应第四条)。
v2网络结构:
与v1的不同在于多了一个1*1的卷积(conv5)。注意:对于Stage2的第一个block,它的两个分支输出的channel并不等于输入channel,而是直接设置为指定输出的一半,比如2x版本,则指定为out-channel=122。这样做我认为是为了对于探索不同channel所对应的特征信息。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------以下是原笔记剩下的一部分内容------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Shuffle模块
实现的内容如下图所示:
lass InvertedResidual(nn.Module):
def __init__(self, input_c: int, output_c: int, stride: int):
super(InvertedResidual, self).__init__()
assert output_c % 2 == 0
branch_features = output_c // 2
# 当stride为1时,input_channel应该是branch_features的两倍
# python中 '<<' 是位运算,可理解为计算×2的快速方法
assert (self.stride != 1) or (input_c == branch_features << 1)
Branch1对应的左边分支
Branch2
如果不想载入权重,把default=删‘’掉,就重新开始训练了
像这样
Tensorflow中如果不使用权重,可以自己训练权重了
把前面三行注释掉