创建日期: 2020-03-02 17:02:54

简介:

GhostNet是2020CVPR录用的一篇对卷积操作进行改进的论文。文章的核心内容是Ghost模块(Ghost Module),可以用来替换任何经典CNN网络中的卷积操作,突出优势是轻量高效,实验证明使用了Ghost Module的MobileNetV3的效果,要比原始的MobileNetV3要好。贴出paper和code地址:

https://arxiv.org/abs/1911.11907huawei-noah/ghostnet

本文不包含GhostNet的实验分析部分,主要介绍核心内容Ghost module的原理,以及在Ghost Module基础上搭建的Ghost BottleNeck的原理,还有在实践过程中部署/移植到其他CNN网络的方法

1. Ghost Module原理

出发点:通过对比分析ResNet-50网络第一个残差组(Residual group)输出的特征图可视化结果,发现一些特征图高度相似(如Ghost一般,下图中的三组box内的图像对)。如果按照传统的思考方式,可能认为这些相似的特征图存在冗余,是多余信息,想办法避免产生这些高度相似的特征图。

但本文思路清奇,推测CNN的强大特征提取能力和这些相似的特征图(Ghost对)正相关,不去刻意的避免产生这种Ghost对,而是尝试利用简单的线性操作来获得更多的Ghost对。

常规卷积:我们通常使用的卷积是下图这种,运算量约等于 hwcnw'*h' (忽略偏置计算)

Ghost Module分为常规卷积、Ghost生成和特征图拼接三步(如下图所示):

  1. 首先用常规卷积得到本征特征图(intrinsic feature maps Y_{w'h'm} ,这部分的运算量约等于 hwcmw'*h' (忽略偏置项)。

\2. 然后将 Y’ 每一个通道的特征图 y^{'}i ,用 \Phi{i,j} 操作来产生Ghost特征图 y_{ij} 。

\3. 最后将第一步得到的本征特征图和第二步得到的Ghost特征图拼接(identity连接)得到最终结果OutPut。

(PS: 当然也可以认为(论文中的思路),第2步中的 \Phi_{i,j} 中包含一个单位/恒等映射,即将本征特征图直接输出,则不需用第三部,例如:对于Y’(m通道)中的每一个特征图,对其进行s次映射,s次中包含一次恒等映射,其余s-1次为cheap operate来得到Ghost特征图。所以最终得到m*s通道的输出结果。理论上完全一致。)

对线性操作 \Phi_{i,j} 的理解:论文中表示,可以探索仿射变换和小波变换等其他低成本的线性运算来构建Ghost模块。但是,卷积是当前硬件已经很好支持的高效运算,它可以涵盖许多广泛使用的线性运算,例如平滑、模糊等。 此外,线性运算 \Phi_{i,j} 的滤波器的大小不一致将降低计算单元(例如CPU和GPU)的效率,所以论文中实验中让Ghost模块中的滤波器size取固定值,并利用Depthwise卷积实现 \Phi_{i,j} ,以构建高效的深度神经网络。

所以说,论文中使用的线性操作并不是常见的旋转、平移、仿射变换、小波变换等,而是用的Depthwise卷积。个人猜测可能是传统的线性操作效果没有Depthwise效果好,毕竟CNN可以自动调整filter的权值。那么Ghost Module和深度分离卷积就很类似了,不同之处在于先进行PointwiseConv,后进行DepthwiseConv,另外增加了DepthwiseConv的数量,包括一个恒定映射。

小结:很明显,相比于直接用常规卷积,Ghost Module的计算量大幅度降低。个人认为从另一个角度可以看做是对卷积得到的特征图做了增强/增广,和数据增广似乎有点相似。

2. Ghost BottleNeck原理

Ghost BottleNeck整体架构和Residual Block非常相似,也可以直接认为是将Residual Block中的卷积操作用Ghost Module(GM)替换得到。

上图基本上对Ghost描述的很清楚,第一张图(左,stride=1)主干通路用两个Ghost Module(GM)串联组成,其中第一个GM扩大通道数,第二个GM将通道数降低到与输入通道数一致;跳跃连接通路与ResNet使用方法一样。这样一来,Ghost BottleNeck输入输出维度也一致了,可以和ResBlock一样,很方便地嵌入到其他CNN网络中。

第二张图(右,stride=2)和第一张图的不同之处在于,主干通路的两个GM之间加入了一个stride=2的Deepwise卷积,可以将特征图大小降为输入的1/2,同样跳跃连接通路也需要同样的降采样,以保证Add操作可以对齐。这个模块可以用来替换其他CNN中的降采样层(1/2)。

PS:Ghost BottleNeck的Add操作前主干通路不进行ReLU激活(参考了MobileNetV2);

实际应用中,为了进一步提高效率,GhostModule中的所有常规卷积都用pointwise卷积代替。

3. Ghost部署/移植

这部分对官方代码进行分析,并讨论一下如何对Ghost Module进行移植的方法。

(2020.07.04更新)

Ghost Module的pytorch实现:

  1. class GhostModule(nn.Module):
  2. def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True):
  3. super(GhostModule, self).__init__()
  4. self.oup = oup
  5. init_channels = math.ceil(oup / ratio)
  6. new_channels = init_channels*(ratio-1)
  7. self.primary_conv = nn.Sequential(
  8. nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False),
  9. nn.BatchNorm2d(init_channels),
  10. nn.ReLU(inplace=True) if relu else nn.Sequential(),
  11. )
  12. self.cheap_operation = nn.Sequential(
  13. nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False),
  14. nn.BatchNorm2d(new_channels),
  15. nn.ReLU(inplace=True) if relu else nn.Sequential(),
  16. )
  17. def forward(self, x):
  18. x1 = self.primary_conv(x)
  19. x2 = self.cheap_operation(x1)
  20. out = torch.cat([x1,x2], dim=1)
  21. return out[:,:self.oup,:,:]

Ghost BottleNeck的pytorch实现:

  1. class GhostBottleneck(nn.Module):
  2. def __init__(self, inp, hidden_dim, oup, kernel_size, stride, use_se):
  3. super(GhostBottleneck, self).__init__()
  4. assert stride in [1, 2]
  5. self.conv = nn.Sequential(
  6. # pw
  7. GhostModule(inp, hidden_dim, kernel_size=1, relu=True),
  8. # dw
  9. depthwise_conv(hidden_dim, hidden_dim, kernel_size, stride, relu=False) if stride==2 else nn.Sequential(),
  10. # Squeeze-and-Excite
  11. SELayer(hidden_dim) if use_se else nn.Sequential(),
  12. # pw-linear
  13. GhostModule(hidden_dim, oup, kernel_size=1, relu=False),
  14. )
  15. if stride == 1 and inp == oup:
  16. self.shortcut = nn.Sequential()
  17. else:
  18. self.shortcut = nn.Sequential(
  19. depthwise_conv(inp, inp, 3, stride, relu=True),
  20. nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
  21. nn.BatchNorm2d(oup),
  22. )
  23. def forward(self, x):
  24. return self.conv(x) + self.shortcut(x)

Ghost BottleNeck结构类似于MobileNetV2的模块,可以很方便的嵌入到模型的任何地方,我在下面这个github项目里面调用了GhostNet网络在Cifar10数据集上进行分类测试。

https://github.com/lee-zq/CNN-Backbone

ghostnet论文解析:ghost的更多相关文章

  1. [Network Architecture]Mask R-CNN论文解析(转)

    前言 最近有一个idea需要去验证,比较忙,看完Mask R-CNN论文了,最近会去研究Mask R-CNN的代码,论文解析转载网上的两篇博客 技术挖掘者 remanented 文章1 论文题目:Ma ...

  2. LTMU论文解析

    LTMU 第零部分:前景提要 一般来说,单目标跟踪任务可以从以下三个角度解读: A matching/correspondence problem.把其视为前后两帧物体匹配的任务(而不考虑在跟踪过程中 ...

  3. CVPR2020论文解析:实例分割算法

    CVPR2020论文解析:实例分割算法 BlendMask: Top-Down Meets Bottom-Up for Instance Segmentation 论文链接:https://arxiv ...

  4. 人脸真伪验证与识别:ICCV2019论文解析

    人脸真伪验证与识别:ICCV2019论文解析 Face Forensics++: Learning to Detect Manipulated Facial Images 论文链接: http://o ...

  5. 人体姿态和形状估计的视频推理:CVPR2020论文解析

    人体姿态和形状估计的视频推理:CVPR2020论文解析 VIBE: Video Inference for Human Body Pose and Shape Estimation 论文链接:http ...

  6. 视频教学动作修饰语:CVPR2020论文解析

    视频教学动作修饰语:CVPR2020论文解析 Action Modifiers: Learning from Adverbs in Instructional Videos 论文链接:https://a ...

  7. 分层条件关系网络在视频问答VideoQA中的应用:CVPR2020论文解析

    分层条件关系网络在视频问答VideoQA中的应用:CVPR2020论文解析 Hierarchical Conditional Relation Networks for Video Question ...

  8. 慢镜头变焦:视频超分辨率:CVPR2020论文解析

    慢镜头变焦:视频超分辨率:CVPR2020论文解析 Zooming Slow-Mo:  Fast and Accurate One-Stage Space-Time Video Super-Resol ...

  9. CVPR2020论文解析:视觉算法加速

    CVPR2020论文解析:视觉算法加速 GPU-Accelerated Mobile Multi-view Style Transfer 论文链接:https://arxiv.org/pdf/2003 ...

随机推荐

  1. Java 中的同步集合与并发集合有什么区别?

    同步集合与并发集合都为多线程和并发提供了合适的线程安全的集合,不过并发 集合的可扩展性更高.在 Java1.5 之前程序员们只有同步集合来用且在多线程并发 的时候会导致争用,阻碍了系统的扩展性.Jav ...

  2. jQuery--事件绑定|委派|切换

    一.事件的绑定 1.事件的绑定介绍 事件绑定: bind(type,fn) 给当前对象绑定一个事件.例如:A.bind("click",fn);类似A.click(fn) unbi ...

  3. JVM-learning

    JVM是什么?? Java Virtual Mechine JRE(JavaRuntimeEnvironment,Java运行环境),也就是Java平台.所有的Java 程序都要在JRE下才能运行. ...

  4. ROS环境变量的设置

    一.前言(大神可以直接跳过) 本博客主要就是为了介绍ROS中环境变量的设置过程,还不是很了解ROS的可以去看一下我的博客,ROS简介-从零开始讲解ROS(适合超零基础阅读) ROS为什么需要设置环境变 ...

  5. Android普通工具类获取Context

    在普通工具类中定义一个构造方法,类成员context,用于接收传过来的context 在activity中定义: 将context传过去. 在工具类中也可以使用SharePreferences,get ...

  6. 【Android开发】jarsigner重新打包apk

    签名(sign):在应用程序的特定字段写入特定的标记信息,表示该软件已经通过了签署者的审核. 过程:使用私有密钥数字地签署一个给定的应用程序. 作用: 识别应用程序作者: 检測应用程序是否发生改变: ...

  7. audio小记

    写H5活动页的需要音频,图标旋转停止保持当时的旋转角度,这样视觉体验效果好: 之前写法是点击pause()就直接停止动画,后来发现了animation有个比较好的属性animation-play-st ...

  8. 微信小程序常用表单校验方法(手机号校验、身份证号(严格和非严格校验、验证码六位数字校验))

    util.js function isPhone(value) { if (!/^1(3|4|5|7|8)\d{9}$/.test(value)) { return false } else { re ...

  9. MySQL---drop, delete, truncate的区别

    drop, delete, truncate的区别 删除内容 drop直接删除整个表, 包含表结构和数据; truncate删除表中数据, 表结构及其列, 约束, 索引等不变, 再插入时自增id又从1 ...

  10. 动态代理-JDK

    代理模式:假设一个场景,你的公司是一位软件公司,你是一位软件工程师,显然客户带着需求不会去找你谈,而是去找商务谈,此时商务就代表公司. 商务的作用:商务可以谈判:也有可能在开发软件之前就谈失败,此时商 ...