《简记ShuffleNetV1&V2》
组卷积和深度可分离卷积其实是一个思想,都可以减少模型的参数量,那么如何合理的利用这个思想来设计模型,既要使用又不能无所顾忌的使用。ShuffleNetv1和v2从两个角度给出了很好的阐述。ShuffleNetv2提出了提高网络速度设计的4个准则,并基于此设计了网络,这些结论是很值得学习和深思的。
Key Words:GConv、DWConv、
Beijing, 2020
ShuffleNet作者:Face++
文章目录
ShuffleNet V1
核心思想
利用如下trick修改原来的ResNet单元,使得运算更高效:
- PointWise Group Convolution
- Channel Shuffle
- DepthWise Separable Convolution
DepthWise卷积就是group卷积,而卷积的group操作从AlexNet就已经有了,当时主要是解决模型在双GPU上的训练。ResNeXt借鉴了这种group操作改进了原本的ResNet。MobileNet则是采用了depthwise separable convolution代替传统的卷积操作,在几乎不影响准确率的前提下大大降低计算量。
连续的 group 卷积会产生边界效应,即某个输出channel仅仅来自输入channel的一小部分。这样学出来的特征会非常局限。于是就有了channel shuffle来解决这个问题如图 b 所示,在第二个 group 之前,将一个组内分成不同的子组,然后让子组分别与各组进行卷积。或者像图 c 所示,在进入第二个 group 卷积之前先对目前的组进行重组,即channel shuffle。这样每次组卷积对应的channel就不再局限了。
![](https://i-blog.csdnimg.cn/blog_migrate/bf0ef65ababb1d268ceeb6d1ada714d7.jpeg)
作者认为1*1的卷积操作的计算量不可忽视,所以对1x1的卷积进行了分组,然后利用channel shuffle操作来让通道间信息能够通过 点组卷积 进行有效编码,shuffleNet 的 unit 设计如下:
![](https://i-blog.csdnimg.cn/blog_migrate/ef990e687d1c2476a5f64cde147bbaef.jpeg)
ShuffleNet的核心就是用 PointWise Group Convolution,Channel Shuffle和DepthWise Separable Convolution代替ResNet block的相应层构成了ShuffleNet uint,达到了减少计算量和提高准确率的目的。channel shuffle解决了多个group convolution叠加出现的边界效应,PointWise Group Convolution和Depthwise Separable Convolution主要减少了计算量。
Channel Shuffle 的实现
def channel_shuffle(x, groups):
batchsize, num_channels, height, width = x.data.size()
channels_per_group = 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
# 例子,抽象理解
# b, c, h, w
# 1,2,3,4,5,6 表示c这个维度的数据
# b, g, cpg, h, w
# 1,2,3
# 4,5,6
# transpose
# 1,4
# 2,5
# 3,6
# flatten
# 1, 4, 2, 5, 3, 6
ShuffleNet V2
模型执行效率的准则不能完全取决于FLOPs,经常发现FLOPs差不多的两个模型的运算速度却不一样,因为FLOPs仅仅反映了模型的乘加次数,这种评价往往是片面的。影响模型运行速度的另一个指标也很重要,那就是MAC(memory access cost)内存访问成本。shuffleNetv2充分考虑了不同结构的MAC,从而设计了更加高效的网络模型shuffleNetV2。
以输入为 c 1 c_1 c1 的输出为 c 2 c_2 c2 的 1 x 1 1x1 1x1 的卷积为例,计算MAC:
M A C = h w ( c 1 + c 2 ) + c 1 c 2 MAC = hw(c_1 + c_2) + c_1c_2 MAC=hw(c1+c2)+c1c2
即输入 h w c 1 hwc_1 hwc1 和输出 h w c 2 hw_c2 hwc2 以及卷积核 c 1 c 2 c_1c_2 c1c2 所占用的memory。
核心思想
作者根据四条Guidelines,设计了一个有效的网络模型,
通道 组 分支 element-wise
-
G1:输入输出具有相同channel的时候,内存消耗是最小的
-
G2:过多的使用组卷积,会增加MAC
-
G3:网络分支数量虽然增加了模型的模型的性能,但对模型速度的有影响,网络的分支减少了并行度,模型的分支数量越少,模型的速度越快
-
G4:Element-wise 操作对模型速度的影响,element-wise所带来的时间消耗远比FLOPs上体现的数值要多,因此需要尽可能的减少element-wise操作 (ReLU,AddTensor,AddBias等)
G1 的推导
同样的,以输入为 c 1 c_1 c1 的输出为 c 2 c_2 c2 的 1 x 1 1x1 1x1 的卷积为例:
F L O P s = h w c 1 c 2 FLOPs = hwc_1c_2 FLOPs=hwc1c2
M A C = h w ( c 1 + c 2 ) + c 1 c 2 MAC = hw(c_1 + c_2) + c_1c_2 MAC=hw(c1+c2)+c1c2
利用均值不等式 a + b ≥ 2 a b a+b \ge 2\sqrt{ab} a+b≥2ab,令 FLOPs 为 B 则
M A C ≥ 2 h w B + B h w MAC \ge 2 \sqrt{hwB} + \frac{B}{hw} MAC≥2hwB+hwB
当且仅当 c1 == c2的时候MAC取得最小值,所以使用卷积要尽可能的平衡(c1 == c2),才会更高效.
G2 的推导
当使用组卷积的时候,FLOPs 和 MAC的计算如下:
F L O P s = c 1 / g ∗ c 2 / g ∗ g ∗ h ∗ w = h w c 1 c 2 / g FLOPs = c_1/g * c_2/g * g * h * w = hwc_1c_2/g FLOPs=c1/g∗c2/g∗g∗h∗w=hwc1c2/g
M A C = h w ( c 1 + c 2 ) + c 1 c 2 g MAC = hw(c_1 + c_2) + \frac{c_1c_2}{g} MAC=hw(c1+c2)+gc1c2
令 FLOPs 为 B 则
M A C = h w c 1 + B g c 1 + B h w MAC = hwc_1 + \frac{Bg}{c_1} + \frac{B}{hw} MAC=hwc1+c1Bg+hwB
其中 g g g 表示分组数,上式中很容易发现,当我们固定 c 1 × h × w c_1 \times h \times w c1×h×w 和 B B B MAC就随着g的增加而增加了,虽然B是关于g的反比例函数,但是如果B不变,那么随着g增加 c 2 c_2 c2也跟着增加。
模型结构
一个结构在考虑 FLOPs 的同时也要考虑其 MAC,对于一个结构也可以综合考虑 MAC/FLOPs
Depthwise Convolution 也同样具有低FLOPs高MAC的特点,Depthwise Convolution(group数等于通道数,每个卷积核只卷积一个channel)也认为是一种element-wise操作。
![](https://i-blog.csdnimg.cn/blog_migrate/637d105a65b2b66a548d5cc9001b2393.jpeg)
Channel split是将channel 分成了 c ′ c' c′ 和 c − c ′ c - c' c−c′,本文中 c ′ = c / 2 c' = c / 2 c′=c/2,根据(G3),让其中一个分支保持不变,另一个分支有相同的channel的输入和输出(G1),而且其中的1x1卷积不再是GC Conv了(G2),因为Channel Split 已经分成了两个组,然后将两个结果concat,然后再利用 “channel shuffle” 来让两个分支的通道信息进行融合。根据(G4)之前shuffleNet之后的Add操作去掉了,像ReLU和DepthWise Conv只存在一个分支中,另一个分支的特征不变,可以被看做是一种特征复用。
与shuffleNet V1不同的是在global pooling的前面增加了Conv5(1*1的卷积层),来进行特征的融合。
总结
shuffleNet V2不仅仅efficient同时具有很高的精度,这主要有如下两个原因:
- 第一个原因是:由于高效,可以增加更多的channel,增加网络的容量。
- 另外采用split使得一部分特征直接与下面block相连,这可以被看做是一种特征复用
shuffleNet V2在相同FLOPs下,其精度最高,同时作者也指出:
- 分类精度:ShuffleNet v2 > MobileNet V2 > ShuffleNet v1 > Xception
- 检测的结果是:ShuffleNet v2 > Xception > ShuffleNet v1 > MobileNet v2
Q&A:
Q1: ShuffleNet 的channel shuffle操作是怎么做的?
A1: 1. 先 reshape 类似于分组操作;然后transpose,类似于shuffle;最后再reshape回到原来的shape(对channel部分的两个变量flatten)即可。
Q2: 一个高效的网络应该具备哪些条件?
A2:
- use ”balanced“ convolutions (equal channel width);
- be aware of the cost of using group convolution;
- reduce the degree of fragmentation;
- reduce element-wise operations.
They should be taken into accout for practical network design.
- 使用平衡卷积,即 input channel == output channel
- 组卷积数量的考虑
- 减少模型的分支
- 减少模型的element-wise 操作