创建日期: 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实现:

class GhostModule(nn.Module):
def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True):
super(GhostModule, self).__init__()
self.oup = oup
init_channels = math.ceil(oup / ratio)
new_channels = init_channels*(ratio-1) self.primary_conv = nn.Sequential(
nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size//2, bias=False),
nn.BatchNorm2d(init_channels),
nn.ReLU(inplace=True) if relu else nn.Sequential(),
) self.cheap_operation = nn.Sequential(
nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size//2, groups=init_channels, bias=False),
nn.BatchNorm2d(new_channels),
nn.ReLU(inplace=True) if relu else nn.Sequential(),
) def forward(self, x):
x1 = self.primary_conv(x)
x2 = self.cheap_operation(x1)
out = torch.cat([x1,x2], dim=1)
return out[:,:self.oup,:,:]

Ghost BottleNeck的pytorch实现:

class GhostBottleneck(nn.Module):
def __init__(self, inp, hidden_dim, oup, kernel_size, stride, use_se):
super(GhostBottleneck, self).__init__()
assert stride in [1, 2] self.conv = nn.Sequential(
# pw
GhostModule(inp, hidden_dim, kernel_size=1, relu=True),
# dw
depthwise_conv(hidden_dim, hidden_dim, kernel_size, stride, relu=False) if stride==2 else nn.Sequential(),
# Squeeze-and-Excite
SELayer(hidden_dim) if use_se else nn.Sequential(),
# pw-linear
GhostModule(hidden_dim, oup, kernel_size=1, relu=False),
) if stride == 1 and inp == oup:
self.shortcut = nn.Sequential()
else:
self.shortcut = nn.Sequential(
depthwise_conv(inp, inp, 3, stride, relu=True),
nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
nn.BatchNorm2d(oup),
) def forward(self, x):
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. .NET面试经典三问:什么是.NET?什么是.NET Framework?什么是.NET Core?

    什么是.NET?什么是.NET Framework? 本文将从上往下,循序渐进的介绍一系列相关.NET的概念,先从类型系统开始讲起,我将通过跨语言操作这个例子来逐渐引入一系列.NET的相关概念,这主要 ...

  2. printf()函数压栈a++与++a的输出

    printf()中a++与++a的输出问题 在C语言中有个很常用的函数printf(),使用时从右向左压栈,也就是说在printf("%d %d %d %d\n",a,a++,++ ...

  3. [译]HTML&CSS Lesson5: 定位

    CSS最大的用处之一就是可以将内容和元素定位到任何我们想要的位置,使我们的设计具有结构,使内容更加易懂. CSS有好几种不同的定位属性,每种都有自己的使用场景.在这节课中我们会通过不同的案例--可复用 ...

  4. 聊聊 DisplayObject 的x/y/regX/regY/rotation/scale/skew 属性

    首先要指出的是:DisplayObject 实例的属性<x, y> 与 graphics.draw*(x, y, ...) 的参数<x, y>没有关系. 在原生的 Canvas ...

  5. VISIO下载+安装+第一个数据流图

    一. 下载地址 Visio2021 (64bit).zip_免费高速下载|百度网盘-分享无限制 (baidu.com) 码3333 二. 安装步骤 Visio2021安装教程 (qq.com) 三. ...

  6. number(10,6)正则表达式

    /**     * 判断number(10,6)     * @param dateStr     * @return     */    public boolean isNumJW(String ...

  7. 简单的axios请求返回数据解构赋值

    本地  data.json 文件 { "name": "大熊", "age": 18, "fnc": [ 1, 2, 3 ...

  8. Python IDLE清屏

    在学习和使用Python的过程中,少不了要与Python IDLE打交道.但使用 Python IDLE 都会遇到一个常见而又懊恼的问题--要怎么清屏? 答案是为IDLE增加一个清屏的扩展ClearW ...

  9. js 生成 pdf 文件

    话不多说好吧, 直接上demo图: 直接上代码好吧:(要引入的两个js  链接我放最后) <!DOCTYPE html> <html> <head> <met ...

  10. 在Wireshark中使用过滤器——显示过滤器

    在Wireshark运行过程中选择搜索(Ctrl-F),第一个默认的搜索选项就是显示过滤器. 显示过滤器用于捕获文件,用来告诉Wireshark只显示那些符合过滤条件的数据包. 显示过滤器比捕获过滤器 ...