计算机视觉技术 以太坊 centos7 pdf boost vue源码下载 vue教学视频 mysql小数用什么类型 js空格符 spark算法 excel被保护怎么解除 idea中svn的使用 java时间戳 python相对路径怎么写 python3文件操作 python手册 pythoninput python创建txt文件并写入 java队列 java正则 java编译环境 java编程语言 java获取现在时间 java调用方法 java创建文件夹 linux服务器 linux下载安装 html实例教程 mac地址修改器 骁龙435 华为线刷工具 快打旋风3出招表 掌门一对一下载 中维高清监控系统安装 工程html加密 绿幕抠图 小米9截图 firefox绿色版 bootskin 骰子牛牛
当前位置: 首页 > 学习教程  > 编程语言

轻量型模型之总结(mobilenet,shufflenet,ghostnet)

2020/10/8 19:09:27 文章标签:

在介绍这些模型前,首先我们了解一下分组卷积的概念。 分组卷积 上图表示普通卷积操作,即输入HWC1H\times W\times C1HWC1经过C1H1W1C2C1\times H1\times W1\times C2C1H1W1C2的卷积核,卷积成HWC2H\times W\times C2HWC2的feature map。其参数…

在介绍这些模型前,首先我们了解一下分组卷积的概念。

分组卷积

在这里插入图片描述
上图表示普通卷积操作,即输入 H × W × C 1 H\times W\times C1 H×W×C1经过 C 1 × H 1 × W 1 × C 2 C1\times H1\times W1\times C2 C1×H1×W1×C2的卷积核,卷积成 H × W × C 2 H\times W\times C2 H×W×C2的feature map。其参数量是: C 1 × H 1 × W 1 × C 2 C1\times H1\times W1\times C2 C1×H1×W1×C2;
FLOPS: H × W × C 1 × C 2 × H 1 × H 2 H\times W\times C1\times C2\times H1\times H2 H×W×C1×C2×H1×H2

下图表示分组卷积,将通道按输入分成g组,每组输入尺寸是 H × W × C 1 g H\times W\times \frac {C1}{g} H×W×gC1,对应的卷积核 H 1 × W 1 × C 1 g × C 2 g H1\times W1\times \frac {C1}{g} \times \frac {C2}{g} H1×W1×gC1×gC2,每组的输出尺寸是 H × W × C 2 g H\times W\times \frac {C2}{g} H×W×gC2,将每组输出concate就可以获得最终输出 H × W × C 2 H\times W\times C2 H×W×C2

分组卷积的参数量: H 1 × W 1 × C 1 g × C 2 g × g H1\times W1\times \frac {C1}{g} \times \frac {C2}{g} \times g H1×W1×gC1×gC2×g

Shufflenet v1

mobilenet采用了depthwise convolution以及dense pointwise convolution进行特征提取,其中depthwise是特殊的分组卷积(g=channel),为了弥补通道间交流的损失,模型中出现了大量的dense pointwise convolution,占据了大量的计算量。为了解决这个问题,shufflenet在1×1的pointwise conv中也采用了group conv的方式,对其分组来降低计算量,同时,为了弥补跨通道信息损失,shufflenet提出了channel shuffle,通过均匀打乱通道,使得信息在不同通道间流通。
在这里插入图片描述
下面是pytorch实现channel shuffle 的代码。

def shuffle_channels(x, groups):
    """shuffle channels of a 4-D Tensor"""
    batch_size, channels, height, width = x.size()
    assert channels % groups == 0
    channels_per_group = channels // groups
    # split into groups
    x = x.view(batch_size, groups, channels_per_group,
               height, width)
    # transpose 1, 2 axis
    x = x.transpose(1, 2).contiguous()
    # reshape into orignal
    x = x.view(batch_size, channels, height, width)
    return x

下图是shufflenet v1的基本单元,a是mobilenetv1,b是shufflenet采用了1×1的分组卷积降低计算量并结合channel shuffle提供跨通道信息交流的桥梁。
在这里插入图片描述

Shufflenet v2

shufflenetv2分析了flops不能作为衡量模型计算量的唯一标准,内存读写,GPU并行性,文件IO等也应该考虑进去。作者从内存访问代价(Memory Access Cost,MAC)和GPU并行性的方向分析了网络应该怎么设计才能进一步减少运行时间,直接的提高模型的效率。

总结一下,在设计高性能网络时,我们要尽可能做到:

G1). 使用输入通道和输出通道相同的卷积操作;
G2). 谨慎使用分组卷积;
G3). 减少网络分支数;
G4). 减少element-wise操作。

在这里插入图片描述

mobilenet v1

在这里插入图片描述
从上图可以看到,Mobile v1的基本模块采用了depthwise conv+pointwise conv降低计算复杂度。其重要贡献就是引入了深度可分离卷积。

mobilenet v2

经过大量实验发现,mobilenetv1容易训练出空卷积核。作者发现是relu叛变了。

作者发现将经过relu激活后的输入映射到高维,再利用逆矩阵回复,其结果发生了很大变化。
在这里插入图片描述
从上图可以看出,对低维度做ReLU运算,很容易造成信息的丢失。而在高维度进行ReLU运算的话,信息的丢失则会很少。

Linear bottleneck
为了降低relu对结果的影响,作者提出了linear bottleneck作为模型的基本模块。作者通过实验分析了低维relu回造成信息流失,所以我们首先对输入进行升维操作,即利用1×1卷积升维(激活relu6),然后再depthwise conv提取特征(激活relu6),最后pointwise conv降维(linear)。
在这里插入图片描述

mobilenetv3

mobilenetv3主要是通过NAS搜索出来的,其变化主要包括:
0.网络的架构基于NAS实现的MnasNet(效果比MobileNetV2好)
1.引入MobileNetV1的深度可分离卷积
2.引入MobileNetV2的具有线性瓶颈的倒残差结构
3.引入基于squeeze and excitation结构的轻量级注意力模型(SE)
4.使用了一种新的激活函数h-swish(x)
5.网络结构搜索中,结合两种技术:资源受限的NAS(platform-aware NAS)与NetAdapt
6.修改了MobileNetV2网络端部最后阶段

h-swish
在这里插入图片描述
在这里插入图片描述

Ghostnet

在一个训练好的深度神经网络中,通常会包含丰富甚至冗余的特征图,以保证对输入数据有全面的理解。如下图所示,在ResNet-50中,将经过第一个残差块处理后的特征图拿出来,三个相似的特征图对示例用相同颜色的框注释。 该对中的一个特征图可以通过廉价操作(用扳手表示)将另一特征图变换而获得,可以认为其中一个特征图是另一个的“幻影”。因为,本文提出并非所有特征图都要用卷积操作来得到,“幻影”特征图可以用更廉价的操作来生成。
在这里插入图片描述
ghost module
作者认为传统卷积提取的特征图中存在大量冗余特征,这些特征可以通过简单计算量低的操作获得。作者通过1×1的卷积获得primary conv features,再将primary conv features当作输入经过depthwise conv生成cheap conv features。下面给出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,:,:]

本文链接: http://www.dtmao.cc/news_show_250093.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?