ShuffleNet是旷世提出的高效轻量化网络,是一款很值得一提的轻量化网络,其相关论文也是很有价值的。


ShuffleNet V1

该网络提出于2017年,论文为《ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices》。

由于Xception和ResNeXt中存在大量密集的1*1卷积,导致网络十分低效。因此,旷世提出了pointwise group convolutions来减少1*1卷积的计算复杂度。但是,这样会带来副作用:通道间的信息没有得到很好的交流融合。所以,继而提出channel shuffle来帮助信息在不同特征通道中的流动。可以看出,ShuffleNet V1的主要两个创新点是pointwise group convolutions和channel shuffle。

如Fig.1所示,左图是普通的group卷积,卷积核只有相应的输入通道进行作用,不同通道之间信息没有交流。如果组数等于通道数,就可以理解成mobilenet中的depthwise convolution。(b)图是将通道进行重新打乱排列,使得不同通道信息之间能相互交流。(c)图是(b)图的等价,使用了channle shuffle进行通道重新排列。如果group卷积能够获得不同group中的输入数据,输入特征和输出特征就能很好的关联起来。通过channle shuffle操作,能构建更加强有力的网络结构。

为了使用好channel shuffle的操作,作者提出了ShuffleNet网络。首先,我们先看一下其基本单元ShuffleNet Unit。如Fig.2所示,(a)图是ResNeXT的残差模块,经过1*1的卷积来降低通道数,然后使用3*3的group卷积,最后使用1*1的卷积将通道数提升回原来。(b)图是作者提出的ShuffleNet Unit,与残差模块类似,将残差模块中的1*1卷积换成1*1的group卷积,并加入了channel shuffle操作。值得注意的是,3*3的group卷积后,没有接激活函数。(c)图是步长为2的情况,基本类似,但最后是concat操作,而不是add,这样做的目的是在很小的计算成本下,更容易扩大通道数。

接下来分析一下,ShuffleNet的FLOPs的变化。假设输出尺寸为$c*h*w$,和bottleneck中的通道数为$m$,$g$是分组的组数。

  • ResNet的FLOPs为$hwcm+9hwm^2+hwmc=9hwm^2+2hwcm$
  • ResNeXt的FLOPs为$hwcm+9hwm^2/g^2+hwcm=9hwm^2/g+2hwcm$
  • ShuffleNet的FLOPs为$9hwm+2hwcm/g$(但我自己计算出来的是$hwcm/g^2+9hwm^2/g^2+hwcm/g^2$,不知道哪里出错的)

可以看出,ShuffleNet相对的FLOPs较小。换而言之,在相同的计算资源限制下,ShuffleNet能使用更宽的特征图。这个对轻量化网络来说,是非常重要的。因为轻量化网络通常由于特征图宽度不足而无法更好处理信息。

基于提出的ShuffleNet Unit,可以构建出Shuffle网络, 如Table.1所示。在整体计算资源变化不大下(~140MFLOPs),当组数g扩大的时候,可以采用更加宽的特征图,来更好的编码信息。

为了评估pointwise group convolution的重要性,作者在上面的网络中使用了不同的g值(通道数会变化的情况),结果如Table.1所示。利用看出,当g>1时,性能会比g=1的情况好(g=1的网络类似于Xception)。所以,小网络会因为分组而得到准确率上的提升。作者认为这是因为更大的特征图宽度对特征的编码起到更多作用。但也值得注意的是,g值越大并不一定越好,网络可能会饱和或者准确率出现恶化。

最后作者在ARM平台上测试了ShuffleNet的真实速度,发现,尽管g=4或者g=8有更高的准确率,但效率却不是最高的。最终采用g=3来折中准确率和最终运行速度。作者还尝试了加入SE模块,但速度大大变慢了。


ShuffleNet V2

该网络提出于2018年,《ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design》。主要的创新点是提出了4条轻量化的原则,并基于此4条原则,在v1基础上提出了ShuffleNet V2。

首先介绍一下FLOPs,这里引用了知乎博主的介绍。

FLOPS: floating point  operations per second

FLOPs: floating point operations

FLOPS: 全大写,指每秒浮点运算次数,可以理解为计算的速度。是衡量硬件性能的一个指标。(硬件)

FLOPs: s小写,指浮点运算数,理解为计算量。可以用来衡量算法/模型的复杂度。(模型) 在论文中常用GFLOPs(1 GFLOPs = 10^9 FLOPs)

在衡量计算复杂度时,通常使用的是FLOPs(the number of float-point operations),但FLOPs是一个间接衡量的指标,它是一种近似但不等价于直接衡量指标。在实际中,我们所关心的是速度或者延时,而这些才是直接衡量的指标。因此,使用FLOPs作为唯一衡量计算复杂度的指标,是不充分的,而且容易导致次优的网络设计。

直接衡量指标(速度)和间接衡量指标(FLOPs)之间的差异,主要源于以下两个原因:

  1. 还有多个影响速度的指标,并未纳入FLOPs的考虑范围中。例如MAC(memory access cost,内存访问成本),MAC对group卷积的速度影响很大;平行度(degree of parallelism),高平行度的网络的推理速度更快。
  2. 不同平台对推理时间的影响。例如,CUDNN对3*3的卷积进行了优化,不能简单认为其是1*1卷积的9倍。

所以,接下来作者对网络的衡量指标有两点,i)使用直接衡量指标(速度);ii)在特定的同一个平台上进行衡量。

Fig.2是ShuffleNet v1和MobileNet v2的时间占比图。从图中可以看出,FLOPs仅仅是考虑了卷积部分,但其他时间同样不能忽略,例如数据的读取,Element-wise等操作。

基于上述的观察,提出了4条关于轻量化网络设计的原则:

  1. 当输入通道数和输出通道数的值接近1:1时,能减少MAC时间;
  2. 过多的group卷积,会增加MAC时间;
  3. 网络的分裂会降低平行度;
  4. Element-wise操作是不可以忽略的,包括ReLU,AddTensor,ADDBias等。

作者批判了部分轻量化网络,ShuffleNet v1过多依赖于group卷积,违反了原则2,而且使用了bottleneck模块,违反了原则1;MobileNet v2使用了倒残差模块,违反了原则1,使用了过多的深度可分离卷积核ReLU,违反了原则4;而AutoML出来的网络会存在分裂,违反了原则3。

所以,根据上述的4条原则,设计一种高效而且轻量化网络的关键是,如何保持大通道数和通道数不变的情况下,即不使用过多卷积,又不过多分组。

为了实现刚刚说的目的,引入了channel split操作,如Fig.3所示。(a)和(b)图是ShuffleNet v1中的基础单元。(c)图是引入了channel split操作的ShuffleNet v2的基本单元。(d)图是步长为2时的单元。

在该单元一开始,输入被分成两个分支,通道数分别是$c-c`$和$c`$。左边的分支保持不变,恒定变化;右边的分支会经过3个卷积,使用了相同的输入通道数和输出通道数。其中,两个1*1的卷积不再是group卷积,而是普通的卷积。当卷积完成后,两个分支会进行concat,最后使用channel shuffle来进行不同通道之间的信息交流。

基于上述的基本单元,构成ShuffleNet v2的网络结构,如Table.5所示。其中,$c`=c/2$。


综上所述,ShuffleNet v2提出的4条原则,是十分有意义的。现在很多AutoML出来的网络,其是以FLOPS作为限制条件的,所以最后出来的网络FLOPS很低,但实际进行测试时,速度缺未能达到预期效果,如EfficientNet b0,实测速度约为11ms,在resnet34的速度为6ms。

另外,在接近的计算资源下,ShuffleNet v2确实能达到较高的准确率和速度,是一个很好的网络结构。

最后,旷世在一年后,开源了ShuffleNet,有兴趣的话,开源研究一下:https://github.com/megvii-model/ShuffleNet-Series

ShuffleNet系列学习笔记的更多相关文章

  1. MVA Universal Windows Apps系列学习笔记1

    昨天晚上看了微软的Build 2015大会第一天第一场演讲,时间还挺长,足足3个小时,不过也挺震撼的.里面提到了windows 10.Microsoft edge浏览器.Azure云平台.Office ...

  2. 《Machine Learning》系列学习笔记之第一周

    <Machine Learning>系列学习笔记 第一周 第一部分 Introduction The definition of machine learning (1)older, in ...

  3. Javascript设计模式系列学习笔记

    因为是学习笔记,里面并没有很多注释和讲解,所有不太适合0基础的朋友看,只能说抱歉了. 这些笔记目前还存在很多的问题,不过我相信再今后的学习过程中会把这些问题挨个的解决. 除了前面3节后面的都不分前后顺 ...

  4. JavaScript设计模式系列学习笔记目录

    说明 本系列笔记参考书籍<JavaScript设计模式>.<JavaScript高级程序设计3> 参考博客:汤姆大叔博客:http://www.cnblogs.com/TomX ...

  5. 【学习笔记】深入理解js原型和闭包系列学习笔记——精华

    深入理解js原型和闭包笔记: 1.“一切皆是对象”,对象是属性的集合. 丨 函数也是对象,但是使用typeof时为什么函数返回function而 丨  不是object呢,js为何要对函数做这样的区分 ...

  6. NXP LPC系列学习笔记汇总(持续更新中)

    1. LPC11E68循环冗余校验CRC学习笔记 文章主要介绍了如何使用LPC11E68的CRC外设功能,并介绍了与CRC引擎相关的寄存器,然后以生成CRC-CCITT多项式校验为例进行了介绍. 2. ...

  7. Opencv2系列学习笔记10(提取连通区域轮廓)

    连通区域指的是二值图像中相连像素组成的形状.而内.外轮廓的概念及opencv1中如何提取二值图像的轮廓见我的这篇博客:http://blog.csdn.net/lu597203933/article/ ...

  8. 关于刘冬大侠Spring.NET系列学习笔记3的一点勘正

    诚如他第22楼“只因渴求等待”提出的疑问一样,他的下面那一段代码是存在一点点问题的, XElement root = XElement.Load(fileName); var objects = fr ...

  9. 开心菜鸟系列学习笔记--------初探Nodejs(了解篇)

    一Node.js开始学习了!    1) 输出hellow worlds   a.建一个js文件 hello.js 写 console.info('hellow world !!!');    进入终 ...

随机推荐

  1. [Python]切换工作目录|python将目录切换为脚本所在目录

    Python使用os.chdir命令切换python工作目录 代码示例: In []: import os In []: os.system("pwd") /home/wangju ...

  2. UML学习笔记_02_UML初识(简单的流程)

    UML建模简单流程: 分析->定义用例->定义领域模型->定义交互图->定义设计类图 1.分析: 分析需求,对项目的结构有一个大致的定义 2.定义用例: 用例是需求分析的一种工 ...

  3. CompletableFuture.allOf that doens't return Void(CompletableFuture.allOf不能返回Void的解决方法)

    import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Ti ...

  4. Python web 项目的依赖管理工具

    Poetry可以帮助你声明.管理和安装Python项目的依赖项,确保你可以在任何地方都拥有正确的堆栈. Poetry支持Python 2.7 和Python 3以上 安装 Poetry提供了一个自定义 ...

  5. HBase 参考信息

    Apache HBase Region Splitting and Merging  https://blog.cloudera.com/apache-hbase-region-splitting-a ...

  6. 【Linux开发】linux中关于dma_alloc_coherent的用法

    大家都知道,DMA的操作是需要物理地址的,但是在linux内核中使用的都是虚拟地址,如果我们想要用DMA对一段内存进行操作,我们如何得到这一段内存的物理地址和虚拟地址的映射呢?dma_alloc_co ...

  7. 前端实现app引导页面动画效果

    插件描述:jQuery引导插件TourTip 交互式可视化指南网页上的元素.使用方法 步骤1: 将以下标记添加到您的文档的<head> 你还需要复制旁边插件的css文件夹和下载的IMG文件 ...

  8. python函数 全局变量和局部变量

    li1=[1,2,3,4,5] str1='abc' def func1(): li1=[7,8,9] str1='efg' print(str1) func1() print(li1)#输出的结果为 ...

  9. axios模块封装和分类列表实现

    这个作用 主要还是为了让代码更加的,清晰. 不要全部都放到  created(){}  这个方法下面.把这些代码全部抽离出去. 这里就只是去调用方法.1. src 目录下,新建文件夹---  rest ...

  10. XPath读取xml文件

    1.创建解析工厂 2.创建解析器 3.读xml文件,生成w3c.docment对象树 4.创建XPath对象 5.通过路径查找对象 例子: import javax.xml.parsers.Docum ...