移动端轻量级卷积网络近三年进展(MobileNet V3, Blaze, GhostNet)- 附源码讲解

CNN 在图像分类,分割检测等领域获得广泛应用,在 PC 端运行模型虽然精度高,但参数量和算力都不是移动端的设备可以承受的,为了让深度学习模型可以在移动端高效的运行,目前业界主流的解决手段有三种。

  1. 网络架构设计:思想在于设计能在移动端高效运行的轻量化网络架构(本文讲的算法都属于此手段)

  2. 通道剪枝:对网络中的通道层进行重要性分析,裁剪重要程度低的层来降低网络的计算量

  3. 模型搜索:给定搜索空间,使用强化,遗传等算法在搜索空间中找到满足给定计算量的模型架构(这里跳转了解 NAS 中的 OFA 算法)

这里主要介绍近三年比较出名的移动端轻量级网络,都是属于网络架构设计这条分支,分别是

  • MobileNet V3 - ICCV 2019
  • BlazeFace - CVPR 2019
  • GhostNet - CVPR 2020

不过最近新出的文章已经从网络结构化设计转向网络搜索这个方向了。

在开始之前,为了让本文阅读起来更加的流畅,这里普及两个定义(可能不严谨,但能看懂其含义即可),分别是层(Layer) 和块(Block),它不管在论文中还是在源码中都非常的常见

层(Layer): 泛指卷积层,激活函数层,Pooling 层等算子,一层一般情况下只对应一个算子

块(Block): 一般块由多个层构成,一个网络架构一般是由几种块重复堆砌而构成的

本文介绍的三种算法主要都是聚焦在如何设计高效的块这个层面上的,当然也会对整体网络架构有调整,那现在我们开始吧。


MobileNet V3

发表于 ICCV 2019,MobileNet 系列的最新作,先来看看效果,论文中拿了 ImageNet 分类来做栗子,对比 MobileNet V2,其精度表现如下:

在这里插入图片描述

从图中可以看出,相比 MobileNet V2,同等计算量下,Top-1 的 Acc 大概是有 2~3% 的提升。

MobileNet V3 网络中的 block 具备以下几个特点

  1. 集合了 V1, V2 的深度可分离卷积和倒残差结构
  2. 引入了基于 squeeze-and-excitation 结构的轻量级注意力组件
  3. 激活函数上使用了一种全新的 h-swish(x) 激活函数
  4. 优化了 V1,V2 上一些冗余的组件,降低了耗时且没有损失太多的精度

在这里插入图片描述

除了在 block 层面上的改动,谷歌在重新审视了 MobileNet V1, V2 的整个网络架构时,发现网络在手机端运行时,有三个地方比较耗时:

  1. 网络开始的第一个卷积
  2. 网络末端的 1x1 卷积
  3. 激活函数的计算

然后作者开始了实验之旅,首先是网络开始的部分,也就是图片输入网络后,经过的第一个卷积,输出是 32 个通道的特征图,这很耗时,且这个卷积的作用仅仅是提取边缘,那么砍成 16 个通道行不行呢?作者实验后 say yes,精度也没啥变化,速度还快了 2ms。

接着是网络的最后几层,一般都会使用 1x1 的卷积来扩大通道数达到提取高位特征的目的,这对预测精度的确是有提高,但是也带来了不少额外的耗时,对此,论文中直接把 960 后面的两个卷积模块砍掉,直接拼接上 Avg Pool 后再接一个 H-Swish 激活层,由此耗时降低了 7ms 且精度也没有太大的变化(文中并没有讲这样做的原由,感觉是拍脑袋得出来的?)

在这里插入图片描述

这两个操作一来一去就快了接近 10ms,Strong。

虽然作者这里实验是在 ImageNet 的分类任务上做的,但是对于其他任务,这里的经验也具备一定的迁移性

最后则是优化 swish 激活函数在移动端运行耗时过大的问题

在这里插入图片描述

其实这里开销大的原因主要是在 Sigmoid 计算这一块,因此,论文中提出使用 ReLU6(x+3)/6 来替代 Sigmoid 的计算,使用 ReLU6 的另外两个优点是大部分硬件都支持,并且量化的时候不会因为不同平台的实现而损失精度,文中把这个替换后的激活函数取名为 h-swish

在这里插入图片描述

为了对比,文章还对是否加入 h-swish 和 se 组件对耗时以及精度的影响做了消融实验,如下图所示:

在这里插入图片描述

加入了 se 对模型的耗时几乎没有影响,但是加入 h-swish 激活函数对耗时是有影响的,因此,文章中还提到使用了分段函数来降低 h-swish 的内存访问从而降低延迟,从实验图表中不难看出,优化后不管是精度上还是耗时上表现都是不错的。

最后,MobileNet V3 中的 Block 对应的伪代码如下

class Block(nn.Module):
    '''
    expand + depthwise + pointwise
    '''
    def __init__(self, kernel_size, in_size, expand_size, out_size, nolinear, semodule, stride):
        super(Block, self).__init__()
        ......

    def forward(self, x):
        out = self.nolinear1(self.bn1(self.conv1(x)))
        out = self.nolinear2(self.bn2(self.conv2(out)))
        out = self.bn3(self.conv3(out))
        if self.se != None:
            out = self.se(out)
        out = out + self.shortcut(x) if self.stride==1 else out
        return out

BlazeFace

发表于 CVPR 2019,同为谷歌团队出品,文章提出了高效的移动端实时人脸检测,旗舰机型上 FPS 达到了 200~1000 FPS,同时提出了紧凑轻量的卷积神经网络用作特征提取器,且放出了移动端相关的 Demo。

在这里插入图片描述

体验了谷歌放出的移动端 Demo 来看,速度和效果都很不错,但作者只公开了预训练好的模型,并未公布网络源码和对应的训练代码。

论文中有详细提到了网络架构上的设计,那我们就一起来看看吧。

BlazeFace 是应用在人脸检测(也就是目标检测)任务上,而不是 ImageNet 分类任务,因此整个网络架构与分类模型在后半段会有差异。

同样的,论文也对网络中的 Block 进行了一番设计

  • BlazeBlock,作者发现深度可分离卷积计算量主要集中在点卷积的部分,通过加大卷积核来扩大感受野,也就是说通过设置大一些的卷积核来提升感受野的性价比更高(因为之前的方案都是通过加深网络来达到的),从论文中给出的 BlazeBlock 也可以看出,Kernel Size 从 3 变成了 5

在这里插入图片描述

另外,文章中还提到移动端的 GPU 在处理小 Feature Map 的时候,耗时是不划算的,经过实验,最好 feature map 的尺寸可以被 4 整除,且不要小于 8。

BlazeFace 中对应的 Block 实现的伪代码如下

class BlazeBlock(nn.Module):
    def __init__(self, inp, oup1, oup2=None, stride=1, kernel_size=5):
        super(BlazeBlock, self).__init__()
        ......

    def forward(self, x):
        h = self.conv1(x)
        if self.use_double_block:
            h = self.conv2(h)

        # skip connection
        if self.use_pooling:
            x = self.mp(x)
        if self.channel_pad > 0:
            x = F.pad(x, (0, 0, 0, 0, 0, self.channel_pad), 'constant', 0)
        return self.act(h + x)
  • 基于上述的 block 模块,文章中还放出了适合在移动端运行的特征提取器,结果如下图所示:

在这里插入图片描述

也就是说如果我们像对一个模型做压缩或者说轻量化,我们便可以将特征提取这部分替换成上述的结构,把卷积换成 BlazeBlock,谷歌基于此也衍生出了一系列的 Blaze 模型,BlazePose,BlazeHand


GhostNet

发表于 CVPR 2020, 华为团队出品,提出了一种新型的轻量级卷积运算组件,且在传统的 CV 任务上精度有所提升。

文章通过可视化中间特征图,发现训练好的网络里是存在大量的冗余的 feature map,而这些 feature map 都非常的相似,像鬼影(Ghost)一样,如下图所示:

在这里插入图片描述

所以作者认为并非所有的 Feature Map 都需要用计算量大的卷积来生成,可以使用廉价的的操作来生成

在这里插入图片描述

但论文中所述的廉价的操作是分组卷积,也就是 depthwise 卷积,论文中也尝试了其他的仿射变换,但最后基于兼容性考虑还是选择了卷积

所以,又一个新的块诞生了,官方放出的 GhostBlock 的 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, :, :]

同时源码中还包含了加入了 skip-gate 和 se 的组件(GhostBottleneck)

最后,来看一下作者在 ImageNet 上精度的对比,对比 MobileNet V3,Top 1 Acc 有 1% 左右的提升,是目前的 SOTA。

在这里插入图片描述

参考

1. Searching for mobilenetv3.
2. BlazeFace: Sub-millisecond Neural Face Detection on Mobile GPUs.
3. GhostNet: More Features From Cheap Operations.

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值