GhostNet

欢迎访问我的个人博客,查看更多文章:https://www.wanglichun.tech/2020/03/08/ghostnet/

本篇论文是发表于CVPR2020的一篇轻量级网络的论文,作者是华为诺亚方舟实验室,文章的总体思路比较清晰,为了减少网络计算量,作者将传统的卷积分成两步进行,首先利用较少的计算量通过传统的卷积生成channel较小的特征图,然后在此特征图的基础上,通过cheap operation(depthwise conv)再进一步利用较少的计算量,生成新的特征图,最后将两组特征图拼接到一起,得到最终的output,最终实验效果还不错,相同计算量的情况下比MobileNet- V3的效果还要更好一些。


作者:华为诺亚方舟实验室
论文链接:https://arxiv.org/abs/1911.11907
作者解读:https://zhuanlan.zhihu.com/p/109325275
开源代码tensorflow:https://github.com/huawei-noah/ghostnet
开源代码:pytorch : https://github.com/iamhankai/ghostnet.pytorch/blob/master/ghost_net.py


虽然说mobileNet或者是shuffleNet提出了使用depthwise或者是shuffle等操作,但是引入的1x1卷积依然会产生一定的计算量。

为什么1x1依然会产生较大的计算量?看卷积计算量的计算公式 n ∗ h ∗ w ∗ c ∗ k ∗ k n*h*w*c*k*k nhwckk,可以发现,由于c和n都是比较大的,所以会导致这个计算量也是比较大的,但是作者在分析输出的特征图的时候发现,其实有些特征图是比较相似的,如下所示,作者认为可以通过简单的变换得到。

在这里插入图片描述

基于此,作者得到启发,是不是每张图都需要用这么大的计算量去得到?是否可以通过cheap transformation得到这些相似的特征图?

于是乎,就诞生了GhostNet。Ghost就是说相似的特征图,犹如另一个的幽灵,可以通过简单的线性变换得到。

在这里插入图片描述

Ghost module结构图

上图完美的解释了Ghost究竟做了什么。

Ghost module介绍

相比于传统的卷积,GhostNet分两步走,首先GhostNet采用正常的卷积计算,得到channel较少的特征图,然后利用cheap operation得到更多的特征图,然后将不同的特征图concat到一起,组合成新的output.

那么这么处理,到底节省了多少计算量呢?下面我们分析一下。

首先,假设我们输入特征图的尺寸是h*w*c,输出特征图的尺寸是h’*w’*n,卷积核大小为k*k。

在cheap operation变换中,我们假设特征图的channel是m,变换的数量是s,最终得到的新的特征图的数量是n,那么我们可以得到等式:

n = m ∗ s n = m * s n=ms

由于Ghost的变换过程中最后存在一个恒等变换(Identity),所以实际有效的变换数量是s-1,所以上式可以得到如下公式:

m ∗ ( s − 1 ) = n / s ∗ ( s − 1 ) m * (s-1) = n/s * (s-1) m(s1)=n/s(s1)

所以我们便可以计算得到如下结果:

在这里插入图片描述

当然这里还有一个条件:m << n

通过这么分析,可以体会到,其实GhostNet的方法也很简单,无外乎就是将原本的乘法变成了两个乘法相加,然后在代码实现中,其实第二个变换是用depthwise conv实现的。作者在文中也提到,前面的卷积使用pointwise效率比较高,所以网络嫣然类似一个mobilenet的反过来的版本,只不过GhostNet采用了拼接的方式,进一步减少了计算量

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,:,:]

Difference from existing methods
  • 在MobileNet等网络中,基本都会使用1x1的卷积,而在GhostNet中,可以使用任何尺寸的卷积。
  • 在MobileNet中,使用了pointwise+depthwise,但是在GhostNet中,可以使用正常的卷积。
  • Ghost使用了更多的线性变换。
GhostNet结构

下图是Ghost bottleneck结构图,很类似resnet结构,不同的是channel是先升维再降维。

在这里插入图片描述

Ghost bottleneck

下面是GhostNet的网络结构图,可以看到channel控制的比较小,并且引入了SE结构。

在这里插入图片描述

GhostNet 细节
实验

作者首先采用控制变量法,测试不同的s以及d的效果。经过测试发现在s=2,d=3的情况下模型表现较好。

在这里插入图片描述

下表为在resnet50实验的不同网络的压缩比例以及精度对比

在这里插入图片描述

ImageNet效果对比

在这里插入图片描述
在这里插入图片描述

目标检测的效果

在这里插入图片描述

  • 22
    点赞
  • 164
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值