行为分析(八):姿态估计部分(五):ShuffleNet的基本原理

答疑的名义

行为分析(五)那篇文章中有位同学提问:ShuffleNet有两个版本,Lite-HRNet是基于哪个版本的ShuffleNet做出改进的?答案是ShuffleNetv2版本,其实很容易判断的,下图给出了两个版本的ShuffleNet Block的对比。

左边的(a)和(b)图是v1版本,右边的(c)和(d)图是v2版本,只要观察Channel Shuffle在哪里就可以分辨,在下面就是v2版本,在分支内就是v1版本。

借着这个机会我们就来聊聊ShuffleNet的两个版本
ShuffleNetv1论文:https://arxiv.org/abs/1707.01083
ShuffleNetv2论文:https://arxiv.org/abs/1807.11164

Shuffle Block原理

下面的两端是从参考链接1中直接搬运过来的,在此感谢。
直接搬运是因为大佬写的实在是太清晰了。

算法详解

ShuffleNet是Face++的一篇关于降低深度网络计算量的论文,号称是可以在移动设备上运行的深度网络。这篇文章可以和MobileNet、Xception和ResNeXt结合来看,因为有类似的思想。卷积的group操作从AlexNet就已经有了,当时主要是解决模型在双GPU上的训练。ResNeXt借鉴了这种group操作改进了原本的ResNet。MobileNet则是采用了depthwise separable convolution代替传统的卷积操作,在几乎不影响准确率的前提下大大降低计算量,具体可以参考MobileNets-深度学习模型的加速。Xception主要也是采用depthwise separable convolution改进Inception v3的结构。

该文章主要采用channel shuffle、pointwise group convolutions和depthwise separable convolution来修改原来的ResNet单元,接下来依次讲解。

channel shuffle

channel shuffle的思想可以看下面的Figure 1。这就要先从group操作说起,一般卷积操作中比如输入feature map的数量是N,该卷积层的filter数量是M,那么M个filter中的每一个filter都要和N个feature map的某个区域做卷积,然后相加作为一个卷积的结果。假设你引入group操作,设group为g,那么N个输入feature map就被分成g个group,M个filter就被分成g个group,然后在做卷积操作的时候,第一个group的M/g个filter中的每一个都和第一个group的N/g个输入feature map做卷积得到结果,第二个group同理,直到最后一个group,如Figure1(a)。不同的颜色代表不同的group,图中有三个group。这种操作可以大大减少计算量,因为你每个filter不再是和输入的全部feature map做卷积,而是和一个group的feature map做卷积。但是如果多个group操作叠加在一起,如Figure1(a)的两个卷积层都有group操作,显然就会产生边界效应,什么意思呢?就是某个输出channel仅仅来自输入channel的一小部分。这样肯定是不行的的,学出来的特征会非常局限。于是就有了channel shuffle来解决这个问题,先看Figure1(b),在进行GConv2之前,对其输入feature map做一个分配,也就是每个group分成几个subgroup,然后将不同group的subgroup作为GConv2的一个group的输入,使得GConv2的每一个group都能卷积输入的所有group的feature map,这和Figure1(c)的channel shuffle的思想是一样的。

pointwise group convolutions

其实就是带group的卷积核为1*1的卷积,也就是说pointwise convolution是卷积核为1*1的卷积。在ResNeXt中主要是对3*3的卷积做group操作,但是在ShuffleNet中,作者是对1*1的卷积做group的操作,因为作者认为1*1的卷积操作的计算量不可忽视。可以看Figure2(b)中的第一个1*1卷积是GConv,表示group convolution。Figure2(a)是ResNet中的bottleneck unit,不过将原来的3*3 Conv改成3*3 DWConv,作者的ShuffleNet主要也是在这基础上做改动。首先用带group的1*1卷积代替原来的1*1卷积,同时跟一个channel shuffle操作,这个前面也介绍过了。然后是3*3 DWConv表示depthwise separable convolution。depthwise separable convolution可以参考MobileNet,下面贴出depthwise separable convolution的示意图。Figure2(c)添加了一个Average pooling和设置了stride=2,另外原来Resnet最后是一个Add操作,也就是元素值相加,而在(c)中是采用concat的操作,也就是按channel合并,类似googleNet的Inception操作。

ShuffleNetv2版本优化了哪些部分

先看一下ShuffleNetv2论文中原图

论文中提出了FLOPs不能作为衡量目标检测模型运行速度的标准,因为MAC(Memory access cost)也是影响模型运行速度的一大因素。(我觉的就算不提出ShuffleNetv2,仅凭借揭示MAC的产生原因及其影响就足够发一篇论文了)

总之就是既然已经发现了MAC的影响,下一步就是确定如何降低MAC。方法有以下四点:

(1)相同的输入输出通道可最大限度地降低存储器访问成本(MAC)
(2)过多地使用组卷积会导致MAC增加
(3)分支数量越少,模型速度越快
(4)element-wise操作导致速度的消耗,远比FLOPs上体现的多

 还是拿出这张图,按照上面的结论可见,ShuffleNet v1在很大程度上依赖于组卷积,这违背了第(2)条。bottleneck-like building blocks设计显然违背了第(1)条。MobileNetv2使用了违反(1)的反向瓶颈结构。它在“很厚的”特征图上使用深度卷积和ReLU,这违反了第(4)条(这里的意思是说很厚的特征图的计算量会急剧的增加)。自动生成的结构(auto-generated structures)是高度碎片化的(分支巨多的意思),违反了第(3)条。

那么v2版本具体是怎么减少MAC的

重点来了

1.引入channel split操作
2.根据(3),其中一条分支保持不变
3.根据(1),另一个分支由三个具有相同输入输出通道的卷积组成
4.遵循(2),注意右分支的1x1卷积不再是分组的,这里可以理解为channel split操作已经进行了分组。
5.两个分支拼接在一起后仍然可以保持输入输出通道不变,遵循(1)
6.将channel shuffle操作移到后部分操作,不影响前几步优化的实施,同时保证v1版本的shuffle操作

后记

这一波操作,太牛了,值得反复琢磨

参考

链接1:https://blog.csdn.net/u014380165/article/details/75137111
链接2:https://blog.csdn.net/huang_nansen/article/details/84075030

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白 AI 日记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值