轻量级网络mobilenetv1 and v2 v3网络结构详解

mobilenet结构详解

mobilenet简介

mobilenet网路是一种轻量级网络,专门给嵌入式设备而设计,它可以稍微降低准确率的情况下大大缩减模型的参数量。因为现在很多网络的参数量巨大,比如resnet152模型参数量就有600多兆,无法使用到嵌入式设备。

mobilenetv1

模型亮点

mobilenetv1网络是由谷歌团队在2017年提出的,这个网络有两个亮点:
1、使用了depthwise conv(dw)和pointwise conv(pw)两个卷积结构
2、使用了两个超参数(α和β)α:控制卷积核个数 β:控制输入图像分辨率

dw和pw

1.什么是dw卷积呢?
看下图 此图片是 霹雳吧啦Wz up主视频中的图片,如果不让使用请联系删除
霹雳吧啦Wz
如图所示,其采用卷积核的通道数是1,卷积核的个数=输入图片的通道数=输出特征图的通道数

2.pw卷积是什么呢?
霹雳吧啦Wz
如图就是pw卷积,它和普通的卷积操作相同,只不过其卷积核的大小是11,
dw卷积核pw卷积就组合成了我们的深度可分离卷积,下面我们看看两个操作所的参数量对比。
大家都知道,参数和输入输出特征图的大小是没有关系的,只和其特征图的深度,和卷积核的大小和深度有关,比如一个普通卷积,
在这里插入图片描述
到这里,基础不是很好的同学要拿出你的笔,稍微记录画一下我下面叙述的内容,这样你就便于理解了,想象力非常强可以忽略哦,比如:
输入特征图是28
283
卷积核个数:4
卷积核大小:3
33
则在此层的参数量是3
334=108
如果采用深度可分离卷积:
首先dw卷积:输入图像28283
卷积核:331
卷积核个数:3
输出特征图:28283
首先dw卷积的参数量:1333=9
然后是pw卷积:
输入特征图:28
283
卷积核:1
13
卷积核个数:4
pw卷积的参数量1
134=12
dw+pw=9+12=21
大致是3-4倍左右,我这里是简单的举了一个例子,在真实情况中比这个要大,因为我这里数值太小,影响了

α和β

第二个亮点就是设置了α和β两个参数,第一个是卷积核个数,第二个是输入图片大小。
在这里插入图片描述
这里给出v1网络的性能对比,

模型整体结构

这个是mobilenetv1的网络结构图了,一个conv dw和一个conv组成了一个深度可分离卷积
在研究过程中呢?很多的dw卷积的卷积核很多的参数接近于0,直接就废掉了,为了解决这个问题,我们产生了mobilenetv2版本

mobilenetv2

它是谷歌团队在2018年提出的,

模型亮点

他的亮点主要有两个:1.提出了inverted residual block(倒残差结构)和bottleneck

inverted residual block

在这里插入图片描述
直接上图,如图所示,第一个是残差结构,两边大中间小的一种瓶颈结构,在resnet中提出,我们这里不做详细介绍,第二个是到残差结构,两边小中间大,其先使用11的卷积核对特征图进行升维,然后用33的卷积核对特征图进行卷积提取特征,这里用到的卷积是dw卷积,我们在上边已经提到过,最后再使用1*1的卷积核进行降维,其中升维和降维的意思就是特征图的深度。

激活函数

在一般的卷积中使用的是relu激活函数,但是在mobilenetv2中提出,relu激活函数会对低维特征造成巨大的信息损失,所以本文提出了使用relu6激活函数。
在这里插入图片描述

bottlenect

下面这三个图显示了mobilenetv2的网络结构,下面我们进行分析
图1
上面这个图和下面这个图是配套的,首先我们先用11的卷积进行升维,卷积得到特征图的深度是由t 这个系数进行控制,在总的结构图中也给出了t在各个层的取值,然后再进行33的dw卷积操作来提取特征, 这个图片上标的s=s,s就是步长的意思,所以其将特征图大小压缩了S,因为是dw卷积,所以其特征图的维度没有发生改变,最后一个是1*1卷积,对特征图进行降维操作,最后使用的是线性激活,不是relu激活,这三步就组成了我们mobilenet网络的基础bottlenect,这个还不是完全的,还差残差连接。
下边这个图片就是一个bottlenect,bottlenect中是有残差结构的,其实残差结构就是将卷积结果和输入直接相加,而不是堆叠,如果是直接相加的话,需要满足一定的条件才能相加,你想:如果两个特征图相加,是不是特征图的大小和维度相同才能让两个特征图中的数据对位相加,如果大小,或者维度有一个不是相等的,计算机就无法运算了,这里就是这个道理,进行卷积后必须要特征图大小和通道数相等才能相加。
在这里插入图片描述

网络的整体架构

下表就是mobilenetv2的网络结构图,都是由很多个bottlenect组成,
在这里插入图片描述
这里就详细叙述一下这个表:表中的t:就是我们刚才那个bottlenect表中的
t,就是卷积核个数(输出特征图深度)的扩增倍数,
c:就是卷积出来的特征图的通道数,或者该层卷积核的个数,
n:bottlenect的重复次数,
s:string,卷积核移动的步长,
还有需要提醒的s步长只针对第一层,其他的均为1,因为只在第一层会改变特征图的大小
在pytorch的torchvision中实现了mobilenetv2版本,有兴趣的同学可以看一下,

import torchvision.models.mobilenet

我下载的是torchvision比较老的版本了,不知道那些版本对这个为了完善,有看了的小伙伴可以跟我说一下,顺便告诉我你下载的是torchvision的版本,我也该一下,哈h
在这里插入图片描述
最后贴出来mobilenetv2的性能对比图,第一个是在分类中的性能,第二个是在目标检测领域中的性能。

代码

from torch import nn
import torch
from torchsummary import summary


__all__ = ['MobileNetV2', 'mobilenet_v2']


model_urls = {
   
    'mobilenet_v2': 'https://download.pytorch.org/models/mobilenet_v2-b0353104.pth',
}


def _make_divisible(v, divisor, min_value=None):
    """
    This function is taken from the original tf repo.
    It ensures that all layers have a channel number that is divisible by 8
    It can be seen here:
    https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet/mobilenet.py
    :param v:
    :param divisor:
    :param min_value:
    :return:
    """
    if min_value is None:
        min_value = divisor
    new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
    # Make sure that round down does not go down by more than 10%.
    if new_v < 0.9 * v:
        new_v += divisor
    return new_v


class ConvBNReLU(nn.Sequential):
    def __init__(self, in_planes, out_planes, kernel_size=3, stride=1, groups=1):
        padding = (kernel_size - 1) // 2
        super(ConvBNReLU, self).__init__(
            nn.Conv2d(in_planes, out_planes, kernel_size, stride, padding, groups=groups, bias=False),
            nn.BatchNorm2d(out_planes),
            nn.ReLU6(inplace=True)
        )


class InvertedResidual(nn.Module):
    def __init__(self, inp, oup, stride, expand_ratio):
        super(InvertedResidual, self).__init__()
        self.stride = stride
        assert stride in [1, 2]

        hidden_dim = int(round(inp * expand_ratio))
        self.use_res_connect = self.stride == 1 and inp == oup

        layers = []
        if expand_ratio != 1:
            # pw
            layers.append(ConvBNReLU(inp, hidden_dim, kernel_size=1))
        layers.extend([
            # dw
            ConvBNReLU(hidden_dim, hidden_dim, stride=stride, groups=hidden_dim),
            # pw-linear
            nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False),
            nn.BatchNorm2d(oup),
        ])
        self.conv = nn.Sequential(*layers)

    def forward(self, x):
        if self.use_res_connect:
            return x + self.conv(x)
        else:
            return self.conv(x)


class MobileNetV2(nn.Module):
    def __init__(self, num_classes=1000, width_mult=1.0, inverted_residual_setting=None, round_nearest=8):
        """
        MobileNet V2 main class

        Args:
            num_classes (int): Number of classes
            width_mult (float): Width multiplier - adjusts number of channels in each layer by this amount
            inverted_residual_setting: Network structure
            round_nearest (int): Round the number of channels in each layer to be a multiple of this number
            Set to 1 to turn off rounding
        """
        super(MobileNetV2, self).__init__()
        block = InvertedResidual
        input_channel = 32
        last_channel = 1280

        
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值