ghostnet论文解析:ghost
创建日期: 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生成和特征图拼接三步(如下图所示):
- 首先用常规卷积得到本征特征图(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的更多相关文章
- [Network Architecture]Mask R-CNN论文解析(转)
前言 最近有一个idea需要去验证,比较忙,看完Mask R-CNN论文了,最近会去研究Mask R-CNN的代码,论文解析转载网上的两篇博客 技术挖掘者 remanented 文章1 论文题目:Ma ...
- LTMU论文解析
LTMU 第零部分:前景提要 一般来说,单目标跟踪任务可以从以下三个角度解读: A matching/correspondence problem.把其视为前后两帧物体匹配的任务(而不考虑在跟踪过程中 ...
- CVPR2020论文解析:实例分割算法
CVPR2020论文解析:实例分割算法 BlendMask: Top-Down Meets Bottom-Up for Instance Segmentation 论文链接:https://arxiv ...
- 人脸真伪验证与识别:ICCV2019论文解析
人脸真伪验证与识别:ICCV2019论文解析 Face Forensics++: Learning to Detect Manipulated Facial Images 论文链接: http://o ...
- 人体姿态和形状估计的视频推理:CVPR2020论文解析
人体姿态和形状估计的视频推理:CVPR2020论文解析 VIBE: Video Inference for Human Body Pose and Shape Estimation 论文链接:http ...
- 视频教学动作修饰语:CVPR2020论文解析
视频教学动作修饰语:CVPR2020论文解析 Action Modifiers: Learning from Adverbs in Instructional Videos 论文链接:https://a ...
- 分层条件关系网络在视频问答VideoQA中的应用:CVPR2020论文解析
分层条件关系网络在视频问答VideoQA中的应用:CVPR2020论文解析 Hierarchical Conditional Relation Networks for Video Question ...
- 慢镜头变焦:视频超分辨率:CVPR2020论文解析
慢镜头变焦:视频超分辨率:CVPR2020论文解析 Zooming Slow-Mo: Fast and Accurate One-Stage Space-Time Video Super-Resol ...
- CVPR2020论文解析:视觉算法加速
CVPR2020论文解析:视觉算法加速 GPU-Accelerated Mobile Multi-view Style Transfer 论文链接:https://arxiv.org/pdf/2003 ...
随机推荐
- 使用过 Redis 分布式锁么,它是什么回事?
先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了 释放. 这时候对方会告诉你说你回答得不错,然后接着问如果在 setnx 之后执行 expire 之前进程意外 ...
- Linux用户身份与文件权限学习笔记
用户身份 管理员UID为0:系统的管理员用户 系统用户UID为1~999:服务程序会有独立的系统用户负责运行:防止被黑客入侵进行提权,并有效控制被破坏的范围 普通用户UID从1000开始:是由管理员创 ...
- C++ | 动多态 | 虚函数表
多态机制 C++语言有三大特性:封装.继承.多态. 其中所谓的多态,即 "同一接口,不同形态".接口在我们 C/C++ 语言中可以理解为函数名,不同形态可以理解为函数执行的功能不同 ...
- ZEGO音视频服务的高可用架构设计与运营
前言: ZEGO 即构科技作为一家实时音视频的提供商,系统稳定性直接影响用户的主观体验,如何保障服务高可用且用户体验最优是行业面临的挑战,本文结合实际业务场景进行思考,介绍 ZEGO 即构在高可用架构 ...
- 一个看一次就永远不会忘的windows环境开发小技巧
前言:本人前端开发,在日常开发中需要打开多个窗口进行开发,如:本地服务窗口,ide工具,设计图,prd文档,浏览器,浏览器调试工具: 如此多的窗口同时打开并且时常需要查看的情况下,遗憾的是,即使我是双 ...
- 从零开始开发一款H5小游戏(三) 攻守阵营,赋予粒子新的生命
本系列文章对应游戏代码已开源 Sinuous game. 每个游戏都会包含场景和角色.要实现一个游戏角色,就要清楚角色在场景中的位置,以及它的运动规律,并能通过数学表达式表现出来. 场景坐标 canv ...
- 小程序wx.createInnerAudioContext()获取不到时长问题
最近在开发小程序中,需要用到音频播放功能.但在初始化时,使用InnerAudioContext.duration获取不到音频的时长. Page({ /** * 生命周期函数--监听页面初次渲染完成 * ...
- 剖析虚幻渲染体系(14)- 延展篇:现代渲染引擎演变史Part 1(萌芽期)
目录 14.1 本篇概述 14.1.1 游戏引擎简介 14.1.2 游戏引擎模块 14.1.3 游戏引擎列表 14.1.3.1 Unreal Engine 14.1.3.2 Unity 14.1.3. ...
- 分库分表实现方式Client和Proxy,性能和维护性该怎么选?
大家好,我是[架构摆渡人],一只十年的程序猿.这是分库分表系列的第一篇文章,这个系列会给大家分享很多在实际工作中有用的经验,如果有收获,还请分享给更多的朋友. 其实这个系列有录过视频给大家学习,但很多 ...
- JdGrid排序问题
JdGrid排序问题 js代码 function gridList() { var $gridList = $("#gridList"); $gridList.dataGrid({ ...