小杰深度学习(sixteen)——视觉-经典神经网络——MobileNetV2

7.MobileNetV2

  1. 网络的背景

MobileNetV1 还不够轻量和高性能,为了让移动设备有更好的体验,Google 团队提出了 MobileNetV2 架构

MobileNetV2网络是由谷歌团队在2018年提出的,它相对于MobileNetV1而言,有着更高的准确率和更小的网络模型。

论文地址:https://arxiv.org/abs/1801.04381

Inverted Residuals and Linear Bottlenecks.pdf

  1. 网络的创新

在paper中的Table 2中给出了网络结构的架构表,如下图所示(网络的结构):

上表中:

Input是每一层结构的输入矩阵尺寸和channel;Operator是操作;t是拓展因子,也就是倒置残差第一个 1x1 卷积,将原来通道放大几倍;c是输出通道数channel;n是bottleneck模块重复的次数;

s是步距,如果bottleneck重复,但只针对于第一次bottleneck的DW卷积,其他为1。

由网络结构的图可以看到最后一层是卷积层,起的是全连接层的作用,k是输出的类别,如果是ImageNet数据集,那么k就是1000。

注意:在每个DW卷积之后都有batchNorm操作。

注意:在第一个bottleneck结构中,由于t=1,所以并没有进行升维操作,即没有第一个Conv2D层。

拓展因子在MobileNetV2中第一层倒残差结构中是1,其它倒残差结构采取的是6

2.1 Inverted Residuals(倒残差结构)

ResNet残差结构是先用1x1的卷积降维,再升维。而在MobileNetV2中,是先升维,再降维,所以该结构叫倒残差结构,网络结构表格中的bottleneck就是倒残差结构。

先看一下残差结构,如下图所示:

残差结构的过程是:

11x1卷积降维

23x3卷积

31x1卷积升维

对输入特征矩阵进行利用1x1卷积进行降维,减少输入特征矩阵的channel,然后通过3x3的卷积核进行处理提取特征,最后通过1x1的卷积核进行升维,它的结构为两边深,中间浅的结构。

在MobileNetV2网络结构中,采用了倒残差结构,它的结构中间深,两边浅,如下图所示:

倒残差结构的过程是:

1首先会通过一个1x1卷积层来进行升维处理,在卷积后会跟有BN和Relu6激活函数

2紧接着是一个3x3大小DW卷积,卷积后面依旧会跟有BN和Relu6激活函数

3最后一个卷积层是1x1卷积,起到降维作用,注意卷积后只跟了BN结构,并没有使用Relu6激活函数。倒残差结构的具体过程如下图所示:

在MobileNetV1中,DW卷积的个数局限于上一层的输出通道数,无法自由改变,但是加入PW卷积之后,也就是升维卷积之后,DW卷积的个数取决于PW卷积的输出通道数,而这个通道数是可以任意指定的,因此解除了3x3卷积核个数的限制。

2.2 Relu6

从上图的倒残差结构图中可以看到,卷积之后跟着的激活函数不再是MobileNetV1的Relu激活函数,而是Relu6激活函数,它的表达式是:

图像如下:

可以看到Relu6激活函数是Relu的变种,在输入小于0时,结果为0,输入大于6时:结果为6。在0到6之间时:

y=x

为什么要是用Relu6替代Relu?

主要因为在移动端设备float16的低精度的时候,也能有很好的数值分辨率,因为Relu的输出范围为0到正无穷,如果对Relu的激活范围不加限制,激活值非常大,分布在一个很大的范围内,则低精度的float16无法很好地精确描述如此大范围的数值,带来精度损失,如果进行量化,Relu6能够有更好的量化表现和更小的精度下降。

2.3 Linear Bottlenecks

在倒残差结构的最后一个1x1的卷积层,使用的激活函数为线性激活函数(即不采用非线性激活,例如Relu或者Relu6,直接输出)

2.4 Shortcut

如下图所示,左侧为有shortcut连接的倒残差结构,右侧是无shortcut连接的倒残差结构:

shortcut将输入与输出直接进行相加,可以使得网络在较深的时候依旧可以进行训练。

注意:这里只有stride=1且输入特征矩阵与输出特征矩阵shape相同时才有shortcut连接。

2.5 拓展因子

paper的Table 1给出了倒残差结构的特征矩阵,如下图所示:

上图中的h和w是输入特征矩阵的高和宽,k是channel,t是拓展因子,即升维时的比例,例如输入特征矩阵维度是32,那么升维后就是32×t,即表格中的tk,k′ 是降维时卷积核的个数。

3.2 结构组件介绍

3.2.1 卷积

输入特征矩阵是(224 x 224 x 3),本层卷积核的宽、高、通道、个数是(3 x 3 x 3 x 32),步长为2,padding方式为SAME,经过计算可知,输出特征矩阵为(112 x 112 x 32)。

本层之后要经过Relu6激活函数,如下图:

3.2.2 bottleneck结构

此层bottleneck结构无第一层卷积层,无shortcut结构。

本bottleneck结构输入特征矩阵是(112 x 112 x 32)。

本bottleneck结构第一层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 32),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(112 x 112 x 32)。

本bottleneck结构第二层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 32 x 16),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(112 x 112 x 16)。

本结构如下图:

3.2.3 bottleneck结构

此层bottleneck结构有第一层卷积层,无shortcut结构。

本bottleneck结构输入特征矩阵是(112 x 112 x 16)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 16 x 96),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(112 x 112 x 16)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 96),padding方式为SAME,步长为2,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(56 x 56 x 96)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 96 x 24),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(56 x 56 x 24)。

本结构如下图:

3.2.4 bottleneck结构

此层bottleneck结构有第一层卷积层,有shortcut结构。

本bottleneck结构输入特征矩阵是(56 x 56 x 24)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 24 x 144),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(56 x 56 x 144)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 144),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(56 x 56 x 144)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 144 x 24),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(56 x 56 x 24)。

本结构如下图:

3.2.5 bottleneck结构

此层bottleneck结构有第一层卷积层,无shortcut结构。

本bottleneck结构输入特征矩阵是(56 x 56 x 24)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 24 x 144),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(56 x 56 x 144)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 144),padding方式为SAME,步长为2,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(28 x 28 x 144)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 144 x 32),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(28 x 28 x 32)。

本结构如下图:

3.2.6 bottleneck结构

此层bottleneck结构有第一层卷积层,有shortcut结构。

本bottleneck结构输入特征矩阵是(28 x 28 x 32)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 32 x 192),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(28 x 28 x 192)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 192),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(28 x 28 x 192)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 192 x 32),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(28 x 28 x 32)。

本结构如下图:

3.2.7 bottleneck结构

此层bottleneck结构有第一层卷积层,有shortcut结构。

本bottleneck结构输入特征矩阵是(28 x 28 x 32)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 32 x 192),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(28 x 28 x 192)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 192),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(28 x 28 x 192)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 192 x 32),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(28 x 28 x 32)。

本结构如下图:

3.2.8 bottleneck结构

此层bottleneck结构有第一层卷积层,无shortcut结构。

本bottleneck结构输入特征矩阵是(28 x 28 x 32)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 32 x 192),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(28 x 28 x 192)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 192),padding方式为SAME,步长为2,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 192)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 192 x 64),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(14 x 14 x 64)。

本结构如下图:

3.2.9 bottleneck结构

此层bottleneck结构有第一层卷积层,有shortcut结构。

本bottleneck结构输入特征矩阵是(14 x 14 x 64)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 64 x 384),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 384)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 384),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 384)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 384 x 64),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(14 x 14 x 64)。

本结构如下图:

3.2.10 bottleneck结构

此层bottleneck结构有第一层卷积层,有shortcut结构。

本bottleneck结构输入特征矩阵是(14 x 14 x 64)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 64 x 384),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 384)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 384),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 384)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 384 x 64),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(14 x 14 x 64)。

本结构如下图:

3.2.11 bottleneck结构

此层bottleneck结构有第一层卷积层,有shortcut结构。

本bottleneck结构输入特征矩阵是(14 x 14 x 64)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 64 x 384),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 384)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 384),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 384)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 384 x 64),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(14 x 14 x 64)。

本结构如下图:

3.2.12 bottleneck结构

此层bottleneck结构有第一层卷积层,无shortcut结构。

本bottleneck结构输入特征矩阵是(14 x 14 x 64)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 64 x 384),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 384)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 384),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 384)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 384 x 96),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(14 x 14 x 96)。

本结构如下图:

3.2.13 bottleneck结构

此层bottleneck结构有第一层卷积层,有shortcut结构。

本bottleneck结构输入特征矩阵是(14 x 14 x 96)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 96 x 576),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 576)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 576),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 576)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 576 x 96),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(14 x 14 x 96)。

本结构如下图:

3.2.14 bottleneck结构

此层bottleneck结构有第一层卷积层,有shortcut结构。

本bottleneck结构输入特征矩阵是(14 x 14 x 96)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 96 x 576),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 576)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 576),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 576)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 576 x 96),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(14 x 14 x 96)。

本结构如下图:

3.2.15 bottleneck结构

此层bottleneck结构有第一层卷积层,无shortcut结构。

本bottleneck结构输入特征矩阵是(14 x 14 x 96)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 96 x 576),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(14 x 14 x 576)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 576),padding方式为SAME,步长为2,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(7 x 7 x 576)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 576 x 160),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(7 x 7 x 160)。

本结构如下图:

3.2.16 bottleneck结构

此层bottleneck结构有第一层卷积层,有shortcut结构。

本bottleneck结构输入特征矩阵是(7 x 7 x 160)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 160 x 960),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(7 x 7 x 960)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 960),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(7 x 7 x 960)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 960 x 160),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(7 x 7 x 160)。

本结构如下图:

3.2.17 bottleneck结构

此层bottleneck结构有第一层卷积层,有shortcut结构。

本bottleneck结构输入特征矩阵是(7 x 7 x 160)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 160 x 960),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(7 x 7 x 960)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 960),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(7 x 7 x 960)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 960 x 160),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(7 x 7 x 160)。

本结构如下图:

3.2.18 bottleneck结构

此层bottleneck结构有第一层卷积层,无shortcut结构。

本bottleneck结构输入特征矩阵是(7 x 7 x 160)。

本bottleneck结构第一层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 160 x 960),padding方式为SAME,步长为1,经过Relu6激活函数,经过计算可知,输出特征矩阵为(7 x 7 x 960)。

本bottleneck结构第二层DwiseConv2D卷积核的宽、高、个数是(3 x 3 x 960),padding方式为SAME,步长为1,经过batchNorm进行归一化,以及Relu6激活函数,经过计算可知,输出特征矩阵为(7 x 7 x 960)。

本bottleneck结构第三层Conv2D卷积核的宽、高、通道、个数是(1 x 1 x 960 x 320),padding方式为SAME,步长为1,经过计算可知,输出特征矩阵为(7 x 7 x 320)。

本结构如下图:

3.2.19 卷积

输入特征矩阵是(7 x 7 x 320),本层卷积核的宽、高、通道、个数是(1 x 1 x 320 x 1280),步长为1,padding方式为SAME,经过计算可知,输出特征矩阵为(7 x 7 x 1280)。

本层之后要经过Relu6激活函数,如下图:

3.2.20 池化-降采样

池化方式为AvgPool,输入特征矩阵是(7 x 7 x 1280),池化核大小为7,步长为1,经过计算可知,输出特征矩阵为(1 x 1 x 1280)。

如下图:

3.2.21 卷积

输入特征矩阵是(1 x 1 x 1280),本层卷积核的宽、高、通道、个数是(1 x 1 x 1280 x 1000),步长为1,padding方式为SAME,经过计算可知,输出特征矩阵为(1 x 1 x 1000)。

本层之后要Squeeze进行展平,即使输出矩阵(1 x 1 x 1000)转换成1000个节点,如下图:

3.2.22 Softmax

最后通过Softmax实现将多分类的输出值转换为范围在[0, 1]和为1的概率分布,如下图:

4 代码展示

python 复制代码
from torch import nn
import  torch

#卷积 +批归一化+激活函数的组合模块
class ConvBNRelu(nn.Module):
    def __init__(self,in_channels, out_channels, kernel_size=3, stride=1, padding=0, groups=1,
                 activation=True):
        super(ConvBNRelu,self).__init__()
        if padding=='same':
            padding=(kernel_size-1)//2
        #卷积层,groups=1为标准卷积,groups=in_channels为深度可分离卷积
        self.layers=[nn.Conv2d(in_channels=in_channels,out_channels=out_channels,
                          kernel_size=kernel_size,stride=stride,padding=padding,groups=groups,bias=False)]
        self.layers.append(nn.BatchNorm2d(out_channels))
        #激活函数层,使用relu6限制激活函数范围,适合移动端部署
        if activation:
            self.layers.append(nn.ReLU6(inplace=True))
        self.layers2=nn.Sequential(*self.layers)

    def forward(self,x):
        return self.layers2(x)

#倒残差块:MobileNetV2的核心组件,先升维再降维
class InvertedResidualBlock(nn.Module):
    def __init__(self,in_channels, t, c, s):
        """
             参数:
                 in_channels: 输入通道数
                 t: 扩展因子,决定升维倍数
                 c: 输出通道数
                 s:
        """
        super(InvertedResidualBlock,self).__init__()
        #扩展卷积:使用1x1卷积增加通道数
        self.exp=ConvBNRelu(in_channels=in_channels,out_channels=in_channels*t,kernel_size=1,stride=1)#现在设置stride为1
        #深度卷积,使用3x3深度可分离卷积进行处理空间信息
        self.depthwise=ConvBNRelu(in_channels=in_channels*t,out_channels=in_channels*t,kernel_size=3,stride=s,padding=1,groups=in_channels*t)

        #逐点卷积,使用1x1卷积降低通道数,不使用激活函数保留特征信息
        self.pointwise=ConvBNRelu(in_channels=in_channels*t,out_channels=c,kernel_size=1,activation=False)
        #是否进行残差连接:输入输出通道数相同且步长为1时,使用残差链接
        self.is_res=in_channels==c and s==1
    def forward(self,x):
        identity=x #保存输入作为残差
        x=self.exp(x)
        x=self.depthwise(x)
        x=self.pointwise(x)
        if self.is_res:
            x = identity + x  # 残差连接
        return x


class BottleneckLayer(nn.Module):
    def __init__(self,in_channels, t, c, n, s):
        """
        参数:
            in_channels: 输入通道数
            t: 扩展因子
            c: 输出通道数
            n: 堆叠的残差块数量
            s: 第一个残差块的步长,其余残差块步长为1
        """
        super(BottleneckLayer,self).__init__()
        self.stack=nn.Sequential(
            InvertedResidualBlock(in_channels,t,c,s), # 第一个残差块可能改变通道数和分辨率
            #后续残差块保持通道数和分辨率不变,仅使用步长为1
            *(InvertedResidualBlock(c,t,c,1)for _ in range(n-1))
        )
    def forward(self,x):
        return self.stack(x)

# MobileNetV2主模型
class MobileNetV2(nn.Module):
    def __init__(self,num_classes=1000):
        super(MobileNetV2,self).__init__()
        #初始化卷积层:提取基础的特征
        self.c1=ConvBNRelu(in_channels=3,out_channels=32,kernel_size=3,stride=2,padding=1)
        #7个瓶颈层模块(倒残差结构),逐步提取特征并降低空间分辨率(hxw的尺寸)
        self.bottleneck1=BottleneckLayer(32,1,16,1,1)#第一层不进行下采样
        self.bottleneck2 = BottleneckLayer(16, 6, 24, 2, 2)
        self.bottleneck3 = BottleneckLayer(24, 6, 32, 3, 2)
        self.bottleneck4 = BottleneckLayer(32, 6, 64, 4, 2)
        self.bottleneck5 = BottleneckLayer(64, 6, 96, 3, 1)  # 保持分辨率不变
        self.bottleneck6 = BottleneckLayer(96, 6, 160, 3, 2)
        self.bottleneck7 = BottleneckLayer(160, 6, 320, 1, 1)
        #最终特征提取层
        # 最终特征提取层
        self.c2 = ConvBNRelu(320, 1280, 1)
        #全局平均池化,将特征压缩为1x1
        self.avg_pool=nn.AdaptiveAvgPool2d((1,1))
        #使用普通池化转化成1x1
        # self.avg_pool2=nn.AvgPool2d((7,7))
        #输出层 分类器,使用1x1卷积直接映射为类别数
        self.c3=nn.Conv2d(in_channels=1280,out_channels=num_classes,kernel_size=1)
    def forward(self,x):
        # 特征提取路径
        x = self.c1(x)
        x = self.bottleneck1(x)
        x = self.bottleneck2(x)
        x = self.bottleneck3(x)
        x = self.bottleneck4(x)
        x = self.bottleneck5(x)
        x = self.bottleneck6(x)
        x = self.bottleneck7(x)
        x = self.c2(x)

        # 分类路径
        x = self.avg_pool(x)
        x = self.c3(x)
        out = x.view(x.size(0), -1)  # 展平为二维张量
        return out
if __name__ == '__main__':
    #模型测试 输入5张 224x224的RGB图像
    model=MobileNetV2()
    x=torch.rand(5,3,224,224)
    print(model(x).shape)  #输出形状[5,1000]
相关推荐
MYX_3093 小时前
第五章 神经网络的优化
pytorch·深度学习·神经网络·学习
TGITCIC3 小时前
有趣的机器学习-利用神经网络来模拟“古龙”写作风格的输出器
人工智能·深度学习·神经网络·ai大模型·模型训练·训练模型·手搓模型
whltaoin3 小时前
AI 超级智能体全栈项目阶段五:RAG 四大流程详解、最佳实践与调优(基于 Spring AI 实现)
java·人工智能·spring·rag·springai
Piink3 小时前
网络模型训练完整代码
人工智能·深度学习·机器学习
曾经的三心草3 小时前
OpenCV4-直方图与傅里叶变换-项目实战-信用卡数字识别
python·opencv·计算机视觉
luoganttcc3 小时前
在 orin 上 安装了 miniconda 如何使用 orin 内置的 opencv
人工智能·opencv·计算机视觉
JinchuanMaster3 小时前
cv_bridge和openCV不兼容问题
人工智能·opencv·计算机视觉
Rhys..4 小时前
python自动化中(包括UI自动化和API自动化)env的作用和使用
python·ui·自动化
心勤则明4 小时前
Spring AI 文档ETL实战:集成text-embedding-v4 与 Milvus
人工智能·spring·etl