【卷积神经网络系列】十一、MobileNetV1


参考资料:

论文:

MobileNetV1: Efficient Convolutional Neural Networks for Mobile Vision Applications

博客:

经典网络模型2——MobileNet 详解与复现

一文搞懂MobileNet v1网络


一、简介

传统卷积神经网络,内存需求大、运算量大导致无法在移动设备以及嵌入式设备上运行。MobileNet网络是由google团队在2017年提出的,专注于移动端或者嵌入式设备中的轻量级CNN网络。相比传统卷积神经网络,在准确率小幅降低的前提下大大减少模型参数与运算量。(相比VGG16准确率减少了0.9%,但模型参数只有VGG的1/32), 网络的两点主要体现下两方面:

  • Depthwise Convolution(深度可分离卷积),大大减少运算量和参数数量;
  • 增加了两个超参数 α \alpha α β \beta β ,其中 α \alpha α控制卷积核个数的超参数, β \beta β 控制输入图像大小,这两个参数是人为设定的,并不是网络学习到的;

在这里插入图片描述


二、深度可分离卷积

 它的核心思想是将一个完整的卷积运算分解为两步进行,分别为逐深度卷积(Depthwise Convolution)与逐点卷积(Pointwise Convolution)。

(1)常规卷积

 假设输入层为一个大小为64×64像素、3通道彩色图片。经过一个包含4个Filter的卷积层,最终输出4个Feature Map,且尺寸与输入层相同。整个过程可以用下图来概括:

在这里插入图片描述

 此时,卷积层共4个Filter,每个Filter包含了3个Kernel,每个Kernel的大小为3×3。因此卷积层的参数数量可以用如下公式来计算:N_std = 4 × 3 × 3 × 3 = 108

(2)逐深度卷积(Depthwise Convolution)

 同样是上述例子,一个大小为64×64像素、3通道彩色图片首先经过第一次卷积运算,不同之处在于此次的卷积完全是在二维平面内进行,且Filter的数量与上一层的Depth相同。所以一个三通道的图像经过运算后生成了3个Feature map,如下图所示。

在这里插入图片描述

 其中一个Filter只包含一个大小为3×3的Kernel,卷积部分的参数个数计算如下:N_depthwise = 3 × 3 × 3 = 27

 Depthwise Convolution完成后的Feature map数量与输入层的depth相同,但是这种运算对输入层的每个channel独立进行卷积运算后就结束了,没有有效的利用不同map在相同空间位置上的信息。因此需要增加另外一步操作来将这些map进行组合生成新的Feature map,即接下来的Pointwise Convolution。

(3)逐点卷积(Pointwise Convolution)

 Pointwise Convolution的运算与常规卷积运算非常相似,不同之处在于卷积核的尺寸为 1×1×M × NM为上一层的depth,N为新生成的Feature map的个数。所以这里的卷积运算会将上一步的map在深度方向上进行加权组合,生成新的Feature map。有几个Filter就有几个Feature map。如下图所示。

在这里插入图片描述

 由于采用的是1×1卷积的方式,此步中卷积涉及到的参数个数可以计算为:N_pointwise = 1 × 1 × 3 × 4 = 12

(4)参数数量对比

 参考<<卷积参数量计算(标准卷积,分组卷积,深度可分离开)>>

 假设输入特征图为( H × W × M H × W × M H×W×M),卷积核大小为( D K × D K × N D_K × D_K × N DK×DK×N), M M M N N N 分别为输入和输出通道数量,则对应的参数量 为:

  • 标准卷积 : D K × D K × M × N D_K × D_K × M × N DK×DK×M×N
  • 深度卷积 : D K × D K × M × 1 D_K × D_K × M × 1 DK×DK×M×1
  • 1 × 1 1×1 1×1点卷积 : 1 × 1 × M × N 1 × 1 × M × N 1×1×M×N
  • 深度可分离卷积 :( D K × D K × M × 1 D_K × D_K × M × 1 DK×DK×M×1 ) + ( 1 × 1 × M × N 1 × 1 × M × N 1×1×M×N

在这里插入图片描述

Separable Convolution的参数个数是常规卷积的约1/3。因此,在参数量相同的前提下,采用Separable Convolution的神经网络层数可以做的更深。

(5)计算量对比

 假设输入特征图为( D F × D F × M D_F × D_F × M DF×DF×M),卷积核大小为( D K × D K × N D_K × D_K × N DK×DK×N), M M M N N N 分别为输入和输出通道数量,则对应的 计算量 为:

  • 标准卷积 D F × D F × M × D K × D K × N D_F × D_F × M × D_K × D_K × N DF×DF×M×DK×DK×N
  • 深度卷积 D F × D F × M × D K × D K D_F × D_F × M × D_K × D_K DF×DF×M×DK×DK
  • 1×1点卷积 D F × D F × M × N × 1 × 1 D_F × D_F × M × N × 1 × 1 DF×DF×M×N×1×1
  • 深度可分离卷积 :( D F × D F × M × D K × D K D_F × D_F × M × D_K × D_K DF×DF×M×DK×DK ) + ($ D_F × D_F × M × N × 1 × 1 $)

 减少的 计算量 为:

在这里插入图片描述


三、网络结构

MobileNet 结构建立在深度可分离卷积基础之上,在 深度卷积逐点卷积 之后加入归一化和激活层(BN and ReLU):

在这里插入图片描述

  • 表1 Mobienet v1 网络结构中第一行Conv/s2表示普通卷积,步距为2。Filter Shape3x3x3x32表示卷积核大小为3x3,输入为彩色图片3通道,输出为32通道;
  • Conv dw/s1表示 DW卷积,步距为1Filter Shape3 x 3 x 32表示卷积核大小3x3,dw卷积的channel为1,卷积核的个数为32;
  • 由于可分离卷积是Mobienet v1基本组件,可分离卷积表示为dw +pw,因此dw 和1x1的pw是成对出现的
  • Mobienet v1的模型结构有点类似于VGG结构,简单的将一系列卷积进行串行链接。

在这里插入图片描述

训练模型过程中,与训练大型模型策略相反 :

  • 使用较少的 正则化数据增强技术,这是由于小模型出现 过拟合 现象的可能性很低 ;
  • 模型将几乎所有的计算都放在密集的 1×1卷积

在这里插入图片描述

(1)宽度倍增器

 为构造更小且计算成本更低的模型,引入了一个非常简单的参数 α(宽度倍增器 ( Width Multiplier ) );

 它可以在每一层均匀地细化网络,输入通道数 M 变为 αM,输出通道数 N 变为 αN

 基于此得到的模型计算量为( α ∈ (0,1) ):

  • 深度可分离卷积 :( D F × D F × D K × D K × α M × 1 D_F × D_F × D_K × D_K × αM × 1 DF×DF×DK×DK×αM×1 ) + ( D F × D F × 1 × 1 × α M × α N D_F × D_F × 1 × 1 × αM × αN DF×DF×1×1×αM×αN

 典型值设置为 1、0.75、0.50.25。 α=1 是基准 MobileNet 模型, α<1 是缩小版的 MobileNets宽度乘数的作用是将计算量和参数数量大约减少 α 2 α^2 α2倍,从而降低了网络计算成本( computational cost of a neural network)。 宽度乘数可以应用于任何模型结构,以定义新的较小模型,且具有合理的准确性、网络延迟 latency 和模型大小之间的权衡。 它用于定义新的精简结构,需要从头开始进行训练模型。

在这里插入图片描述

(2)分辨率倍增器

 降低神经网络计算代价的第二个超参数为 ρ (分辨率倍增器 ( Resolution Multiplier ) )

 它可以减小输入特征图的尺寸 H × W H × W H×W,由 DF 变为 ρDF

 实际上,论文通过设置输入分辨率来隐式设置 ρ 。 将网络核心层的计算成本表示为具有宽度乘数 α 和分辨率乘数 ρ 的深度可分离卷积的公式如下( α ∈ (0,1) ,ρ ∈ (0,1] ):

  • 深度可分离卷积 :( ρ D F × ρ D F × D K × D K × α M × 1 ρDF × ρDF × D_K × D_K × αM × 1 ρDF×ρDF×DK×DK×αM×1 ) + ( ρ D F × ρ D F × 1 × 1 × α M × α N ρDF × ρDF × 1 × 1 × αM × αN ρDF×ρDF×1×1×αM×αN

在这里插入图片描述

 上图为 ρ = 1,6/7,5/7,4/7 时分别对应的结果 ;通常是隐式设置的,因此网络的输入分辨率为 224、192、160128。 ρ=1 时是基准(baseline) MobilNet, ρ<1 时缩小版 MobileNets分辨率乘数的作用是将计算量减少 ρ 2 ρ^2 ρ2

 在Mobienet v1网络的实际使用中,很多人发现dw卷积,它在训练完之后部分卷积核容易废掉,即卷积核参数大部分为0。因为你观察DW卷积的参数时,你会发现它的大部分参数都是等于0的,DW卷积核是没有起到作用的。针对这个问题再我们mobienet v2中会得到改善。


四、论文复现

经典网络模型2——MobileNet 详解与复现


(1)定义带BN的卷积:卷积+BN+ReLu

class ConvBNReLU(nn.Module):
    def __init__(self, in_channels, out_channels, **kwargs):
        super(ConvBNReLU, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, **kwargs)
        self.bn = nn.BatchNorm2d(out_channels)
        self.relu = nn.ReLU6(inplace=True)

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x

(2)深度可分离卷积:

  • groups就是实现depthwise conv的关键,默认为1,意思是将输入分为一组,此时是常规卷积,当将其设为in_channels时,意思是将输入的每一个通道作为一组,然后分别对其卷积,输出通道数为k,最后再将每组的输出串联,最后通道数为K。

  • 最后总结下,要实现depthwise conv,就将groups设为in_channels,同时out_channels也设为与in_channels相同,然后再加上1X1卷积

在这里插入图片描述

class Depthwise_Separable(nn.Module):
    def __init__(self, in_channels, out_channels, stride, padding):
        super(Depthwise_Separable, self).__init__()
        self.conv = nn.Sequential(
            # 3 × 3 深度卷积
            # groups=in_channels
            ConvBNReLU(in_channels, in_channels, kernel_size=3, 
                       stride=stride, padding=padding, groups=in_channels),
            
            # 1 × 1 点卷积
            ConvBNReLU(in_channels, out_channels, kernel_size=1, stride=1, bias=False)
        )
    
    def forward(self, x):
        x = self.conv(x)
        return x

(3)主干网络:

  • 表1 Mobienet v1 网络结构中第一行Conv/s2表示普通卷积,步距为2。Filter Shape3x3x3x32表示卷积核大小为3x3,输入为彩色图片3通道,输出为32通道;

  • Conv dw/s1表示 DW卷积,步距为1Filter Shape3 x 3 x 32表示卷积核大小3x3,dw卷积的channel为1,卷积核的个数为32;

  • 由于可分离卷积是Mobienet v1基本组件,可分离卷积表示为dw +pw,因此dw 和1x1的pw是成对出现的
    在这里插入图片描述

class MobileNet(nn.Module):
    def __init__(self, num_classes=1000, width=1):
        super(MobileNet, self).__init__()

        # 第一个卷积核
        self.first_conv = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=2, padding=1, bias=False),
            nn.BatchNorm2d(32),
            nn.ReLU6(inplace=True),
        )

        # 主干网络
        self.layers = nn.Sequential(
            # width是宽度倍增器的系数α
            # 它可以在每一层均匀地细化网络,输入通道数 `M` 变为 `αM`,输出通道数 `N` 变为 `αN` ;
            Depthwise_Separable(width*32, width*64, 1, 1),
            Depthwise_Separable(width*64, width*128, 2, 1),
            Depthwise_Separable(width*128, width*128, 1, 1),
            Depthwise_Separable(width*128, width*256, 2, 1),
            Depthwise_Separable(width*256, width*256, 1, 1),
            Depthwise_Separable(width*256, width*512, 2, 1),
            Depthwise_Separable(width*512, width*512, 1, 1),
            Depthwise_Separable(width*512, width*512, 1, 1),
            Depthwise_Separable(width*512, width*512, 1, 1),
            Depthwise_Separable(width*512, width*512, 1, 1),
            Depthwise_Separable(width*512, width*512, 1, 1),
            Depthwise_Separable(width*512, width*1024, 2, 1),
            Depthwise_Separable(width*1024, width*1024, 2, 4),
        )


        self.pool = nn.AvgPool2d(kernel_size=7, stride=1)
        self.classifier = nn.Linear(width*1024, num_classes)

    def forward(self, x):
        x = self.first_conv(x)
        x = self.layers(x)
        x = self.pool(x)
        x = torch.flatten(x, 1)
        out = self.classifier(x)
        return out
def test():
    net = MobileNet()
    #创建模型,部署gpu
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    net.to(device)
    summary(net, (3, 224, 224))


if __name__ == '__main__':
    test()
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

travellerss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值