创建日期: 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. 为什么 wait()方法和 notify()/notifyAll()方法要在同步块 中被调用 ?

    这是 JDK 强制的,wait()方法和 notify()/notifyAll()方法在调用前都必须先获得对 象的锁

  2. kafka-linux-install

    linux按照kafka 必须先按照java jdk包!!!!!!!!!!!! 先安装zookeeper 下载:http://mirrors.hust.edu.cn/apache/zookeeper/ ...

  3. JS的箭头函数this作用域

    name="小刚"; let student={ name:"小明", printLog:function(){ // 这里绑定了顶层作用域,可以使用变量与方法 ...

  4. Netty学习摘记 —— 初识编解码器

    本文参考 本篇文章是对<Netty In Action>一书第十章"编解码器框架"的学习摘记,主要内容为解码器和编码器 编解码器实际上是一种特殊的ChannelHand ...

  5. (2)_引言Introduction【论文写作】

  6. onsubmit阻止表单提交

    在实际开发中往往会遇到检查表单数据的合法性,如果数据不合法,就不让其提交. <!DOCTYPE html> <html> <head> <meta chars ...

  7. 小小标签,强大功能——深藏不露的 <input>

    <input> 虽只是一个看似简单的 HTML 表单元素,但它这么一个单一的元素,就有多达 30 多个属性(attribute),相信无论你是个小菜鸟还是像我一样写了 15 年 HTML ...

  8. 手把手教你从零写一个简单的 VUE--模板篇

    教程目录1.手把手教你从零写一个简单的 VUE2.手把手教你从零写一个简单的 VUE--模板篇 Hello,我又回来了,上一次的文章教会了大家如何书写一个简单 VUE,里面实现了VUE 的数据驱动视图 ...

  9. 动态div点击事件传递对象参数格式-草稿889

    <button type='button' style='border: 1px solid #eeeeee;color: #717070;height: 20px;border-radius: ...

  10. EMS查看及修改邮箱发送和接受邮件大小的方法

    默认情况下,新建用户邮箱没有进行单独设置,故用户邮箱默认值为"Unlimited"(未限制),即遵从全局设置(继承邮箱数据库策略).通过EMS查看用户邮箱发送和接受邮件大小的默认值 ...