博客专栏

EEPW首页 > 博客 > 综述:轻量级CNN架构设计(3)

综述:轻量级CNN架构设计(3)

发布人:计算机视觉工坊 时间:2021-09-14 来源:工程师 发布文章

·  ShuffleNet系列

旷视出品的ShuffleNet系列有两篇论文,且后一篇在打前一篇的脸,很有意思。

1.ShuffleNet V1是在MobileNet V1后MobileNet V2前提出的,说实话结构上和MobileNet V2还挺像,大家可以上下两张图片对比一下。两者都想到了学习ResNet的残差结构,区别在于ShuffleNet V1觉得block当中的1×1标准卷积也非常耗时,于是用1×1的分组卷积外加channel shuffle的操作给替换了,然后MobileNet V2会先升维让深度可分离卷积得到充分的学习再降维回来,ShuffleNet V1中stride为2的模块也有自己的特色,虽然看着MobileNet V2的结构更简洁一些,但ShuffleNet V1创新也是不少,尤其那个用channel shuffle增强不同组之间信息交互的操作。

19.png

ShuffleNet V1

2. ShuffleNet V2论文是一篇诚意满满之作,作者通过分析ShuffleNet v1与MobileNet v2这两个移动端网络在GPU/ARM两种平台下的时间消耗分布,看出Conv等计算密集型操作占了绝大多数时间,但其它像Elemwise和IO等内存读写密集型操作也占了相当比例的时间,因此像以往那样仅以FLOPs来作为指导准则来设计CNN网络是不完备的,虽然它可以反映出占大比例时间的Conv操作,但不够准确。于是作者提出了高效网络设计的四个指导原则:

1. 当输入和输出的通道数相同时,conv计算所需的MAC(memory access cost)最小;

2. 大量的分组卷积会增加MAC开销;

3. 网络结构的碎片化会减少其可并行优化的程度,GoogleNet系列和NASNet中很多分支进行不同的卷积/pool计算非常碎片,对硬件运行很不友好;

4. Element-wise操作不可忽视,对延时影响很大,包括ReLU,Addition,AddBias等,主要是因为这些操作计算与内存访问的占比太小;

基于此,作者提出了ShuffleNet V2的blocks,如下所示,与V1相比,去掉了分组卷积的操作,去掉了Add操作,换成了Concat,stride为2的block的旁路把平均池化换成了深度可分离卷积,为了继续延续channel shuffle的操作,作者在block进去的地方做了个split的操作,最后再concat+channel shuffle,这里是为了替换掉之前的Add,同时也可以减少计算量。

20.png

ShuffleNet V2

Shift: A Zero FLOP, Zero Parameter Alternative to Spatial Convolutions

这是一篇很有意思的论文,主要是提出了一种无参数,无计算的移位算子来代替ResNet中计算量占比很高的3×3卷积,这种算子称为shift kernel,如下图所示,只需要根据kernel上的shift信息对feature map进行位置上的上下左右偏移即可得到新的feature map,没有计算,仅仅是访存操作。详细一点说就是如下面Shift框里面的第一个卷积核,它只在黄色的区域为1,其他白色的区域为0,在做卷积计算的时候其实就相当于把输入feature map中间偏左边的那个点的值平移到输出feature map中间的地方,正如作者标注的向右的箭头所示。而且这个操作都是per-channel的,所以每个卷积核只有k×k种可能性,当通道数大于k×k时,就需要将所有通道分成iC/(k×k)组,剩下的channel设置为center,即中间为1,其余为0,然后怎么去选取每个卷积核的类型呢,论文在两个shift kernel中间夹了一个1×1的标准卷积,要保证第二次shift操作之后数据与第一次输入shift kernel之前顺序一致,并且这个shift操作可以通过SGD的方式进行端到端训练,再具体的细节论文其实也没有阐述的很清楚,而且我目前也没有看到作者公布源代码,不过这篇论文看起来还是很有意思的,论文中还分析了depthwise计算不高效的原因在于计算/IO时间导致运行更慢的问题,其实这个shift kernel的作用并没有产生新的信息或者去进行特征的学习(毕竟连参数都没有),而是对feature map空域的信息做了个混洗,使得与他相接的1×1卷积可以学到更丰富的特征,在我看来有点类似于在网络内部做数据增强的感觉。

21.png

Shift

· GhostNet

GhostNet也是一篇很有意思且简洁的架构设计的论文,作者在可视化一些训练好的神经网络中间feature map时发现它们通常会包含一些相似且冗余的特征图,使得神经网络能得到更充分的学习。基于这个想法,作者通过设定一系列廉价的线性运算操作来代替部分卷积计算,以此来产生更多的特征图,仅仅这么一个简单的操作就可以减少模型的参数量和计算量,而且在几个视觉公开数据集上取得了很不错的效果,甚至超越了MobileNet V3,感觉非常的大道至简,这也是我比较喜欢的原因。

22.png

GhostNet

基于特定硬件的神经架构搜索

基于特定硬件的神经架构搜索(MIT HAN Lab论文总结

https://zhuanlan.zhihu.com/p/320290820)

设计方法总结

接下来我将结合自己看过的论文,还有这一年多的项目比赛经历谈一谈我所理解的图像分类和目标检测相关轻量级模型设计,本文思想还比较浅薄,主要是给自己的工作做个总结,有不正确的地方希望大家能共同讨论。

设计之前

通常我们都是基于已有的硬件架构去进行模型的部署,这个时候就需要确定这个架构下能部署什么算子,可以通过已有的接口自己拓展哪些算子,并且哪些算子不是很高效。就拿我去年参加的某视觉加速比赛来说,当时初出茅庐,不太懂硬件底层,头铁要在Xilinx ultra96 V1板子 + 我们组自研的硬件架构上部署当时最新,准确率最高的EfficientNet,因为准确率确实高,老板就钦定必须使用这个模型,并且选择了比较合适的EfficientNet-B4,输入分辨率由384改成256。后来一顿开搞发现有很多swish操作,这个虽然之前还没有经验,但是还好很快想到用查找表去实现了,并且还发现我们的架构尚且不能实现全连接层(勿喷,之前都是在搞全卷积网络),所以里面的SE block还有最后一层都无法用我们的架构部署,然后博士师兄就想到了利用ultra96板子上的ARM+NEON加速技术去实现这一部分,每次PS和PL交互数据,当时只有一个月的开发时间,因为这个模型比较大且当时我们开发模式的问题,连续熬夜差点没把整个组人的命搭进去,最后上板跑帧率也只有6帧(师兄最开始预估能达到80帧,所以大家一直不停的往下做hhhhh),在ImageNet验证集上纯浮点准确率是0.805,INT8准确率是0.793,帧率低的原因有两点,一个是模型确实很大,另一个是因为SE block在每一个stride为1的module中都出现了,整个模型PS和PL交互十分频繁,而我们当时间很紧刚刚完成一版就必须提交了,所以这块也根本没有优化,导致了延时很高,并且当时我们的架构只跑了100M的频率,更高频率会有一些bug(貌似是板子的问题),所以帧率非常低,这个真的是血的教训:一定要量力而行,仔细研究评价指标,在硬件友好程度和精度上做一个trade-off,一味片面地追求精度真的要命呀。

轻量级CNN架构设计

总的思路: 选定合适结构 + 通道剪枝 + 量化

训练 :ImageNet pretrain model + Data Normalization(统计自己数据集的均值和方差) + Batch Normlization + 大batch size + 一堆数据增强tricks + 尝试各种花里胡哨的loss function和optimizer

(再次说明这部分只讨论图像分类和目标检测两种任务,目前的视觉加速比赛基本都是基于这两个任务做的,按照计算资源和内存从小到大排列,不用问,没有划分原则)

1.绝对贫穷人口

输入分辨率要小,如128,160,192或256;

下采样使用MaxPooling;

特征学习层使用Depthwise Separable Convolution,即一层3×3的Depthwise + 一层pointwise(1×1标准卷积)堆叠;

激活函数用ReLU;

另外这里推荐看看MCUNet,感觉非常呦西,MIT韩松团队yyds!

2. 相对贫穷人口

输入分辨率依旧要小,记住分辨率对计算量的影响都是翻倍的;

下采样可以使用MaxPooling或者stride为2的Depthwise Separable Convolution;

特征学习层使用Depthwise Separable Convolution,或者MobileNet V2的倒置残差结构,又或是ShuffleNet V2的unit,1×1的Group convolution能处理的比较好的话其实也推荐使用(主要是计算/访存);

激活函数用ReLU或者ReLU6;

3. 低收入人口

输入数据选用小分辨率,如果对精度要求高一些可以适当增大;

下采样可以使用MaxPooling或者stride为2的Depthwise Separable Convolution;

特征学习层可以使用MobileNet V2的倒置残差结构,又或是ShuffleNet V2的unit,也可以使用通道数小一点的3×3标准卷积;

激活函数用ReLU,ReLU6或者leaky ReLU,看效果了;

4.一般收入人口

输入数据可以稍微大一些,288,320,384啥的可以考虑上了;

下采样使用stride为2的Depthwise Separable Convolution或者stride为2的3×3卷积;

特征学习层既可以使用上述的,也可以使用3×3标准卷积 + 1×1标准卷积的堆叠形式,SE block这种硬件支持的还不错的可以尝试加上;

激活函数除了上述的可以试试H-sigmoid和H-swish,不过据我经验效果基本和ReLU差不多;

5.高收入人口

输入数据的分辨率可以往500-600靠拢了;

下采样和上述一样;

特征学习层可以上ResNet + SE block的配置,ResNet是真的牛逼,5×5的卷积啥的也可以整上,第一层直接上7×7的标准卷积也不是不可以,资源再多了可以增加通道数和深度 或者 上多核并行计算;

激活函数可以用H-swish;

番外

目标检测任务中感觉Tiny YOLO V3非常受欢迎,建议尝试!计算量太大可以换更轻量的backbone或者改输入分辨率,轻量级的backbone+FPN的结构也很棒,且推荐使用商汤开源的mmdetection,训练调参当场起飞。

另外之前阅读MIT HAN lab基于特定硬件的神经架构搜索相关文章时发现他们设计模型常用的一个子结构:MobileNetV2的倒置残差模块 + SE block + H-swish,看他们在很多算法加速比赛上拿了冠军,感觉百试不爽呀,且根据硬件资源进行拓展的灵活度也很高,具体可以参见他们今年发表的OnceForAll论文中的模型,源代码都在Github上能找到,MIT HAN lab真学术界良心,再喊一句MIT韩松团队yyds!

最后总结

过去的一年被导师安排着参加各种比赛,去年啥也不懂的时候还能拿几个不错的奖,今年感觉学了很多懂了很多,使用的模型也都对硬件比较友好,量化后几乎无损(一个点以内),反倒连连受挫,心情非常沮丧,而且总被奇奇怪怪的模型打败,总有一种自己学了一身正派功夫,最后反倒被野路子出招一击即溃的感觉,然后论文也被拒了,没心思改投,回想一下碰上疫情的这一年真的好失落,可能还是我太菜了吧。

马上也要开始投入找实习(希望老板能放我)刷题找工作的阶段了,最近也在培养下一届,把工作慢慢移交给他们,一想到找工作,整个人的心态都不一样了,无心科研,这篇文章就算是对我过去一年多的工作做个总结吧,同时也希望我们课题组能够发展的越来越好,多多拿比赛大奖,多多发论文。

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

pid控制器相关文章:pid控制器原理




关键词: AI

相关推荐

技术专区

关闭