MobileNet-v2网络框架

一、MobileNet-v2

MobileNetV2: Inverted Residuals and Linear Bottlenecks

二、MobileNet算法

1、线性瓶颈层(linear bottlenecks)

MobileNet-v2使用了线性瓶颈层。因为当使用ReLU等激活函数时,会导致信息丢失。如下图所示,低维(2维)的信息嵌入到n维的空间中,并通过随机矩阵T对特征进行变换,之后再加上ReLU激活函数,之后在通过T-1进行反变换。当n=2,3时,会导致比较严重的信息丢失,部分特征重叠到一起了;当n=15到30时,信息丢失程度降低,但是变换矩阵已经是高度非凸的了。
在这里插入图片描述
由于非线性层会毁掉一部分信息,因而非常有必要使用线性瓶颈层。且线性瓶颈层包含所有的必要信息,扩张层则是供非线性层丰富信息使用。

在这里插入图片描述
上图对比了不同的卷积方式:

  • (a),传统卷积方式,输入和输出维度不一样,且卷积核直接对输入的红色立方体进行滤波;
  • (b)为可分离卷积,左侧3×3卷积的每个卷积核只对输入的对应层进行滤波,此时特征维度不变;右边的1*1的卷积对特征进行升维或者降维(图中为升维)。
  • (c)图中为带线性瓶颈层的可分离卷积,输入通过3×3 depthwise卷积+ReLU6,得到中间相同维度的特征。之后在通过1×1conv+ReLU6,得到降维后的特征(带斜线立方体)。之后在通过1×1卷积(无ReLU)进行升维。
  • (d)图中则是维度比较低的特征,先通过1×1conv(无ReLU)升维,而后通过3×3 depthwise卷积+ReLU6保持特征数量不变,再通过1×1conv+ReLU6得到降维后的下一层特征;

2、Inverted residual block
在这里插入图片描述
上图为反转残差块(inverted residual block)。显示了传统的残差块和反转残差块的区别:

  • 传统的残差块如(a)将高维特征先使用1×1conv降维,然后在使用3×3conv进行滤波,并使用1×1conv进行升维(这些卷积中均包含ReLU),得到输出特征(下一层的输入),并进行element wise的相加。
  • 反转残差块则是将低维特征使用1×1conv升维(不含ReLU),而后使用3×3conv+ReLU对特征进行滤波,并使用1×1conv+ReLU对特征再降维,得到本层特征的输出,并进行element wise的相加。

反转的原因:瓶颈层的输入包含了所有的必要信息,因而右侧最左边的层后面不加ReLU,防止信息丢失。升维后,信息更加丰富,此时加上ReLU,之后在降维,理论上可以保持所有的必要信息不丢失。

为何使用ReLU? 使用ReLU可以增加模型的稀疏性。过于稀疏了,信息就丢失了。。。

那瓶颈层内部为何需要升维呢? 原因是为了增加模型的表达能力:当使用ReLU对某通道的信息进行处理后,该通道会不可避免的丢失信息;然而如果有足够多的通道的话,某通道丢失的信息,可能仍旧保留在其他通道中,因而才会在瓶颈层内部对特征进行升维。文中附录证明了,瓶颈层内部升维足够大时,能够抵消ReLU造成的信息丢失(如文中将特征维度扩大了6倍)。

在这里插入图片描述
瓶颈层的具体结构如上表所示。输入通过1×1的conv+ReLU层将维度从k维增加到tk维,之后通过3×3conv+ReLU可分离卷积对图像进行降采样(stride>1时),此时特征维度已经为tk维度,最后通过1×1conv(无ReLU)进行降维,维度从tk降低到k’维。

需要注意的是,除了整个模型中的第一个瓶颈层的t=1之外,其他瓶颈层t=6(论文中Table 2),即第一个瓶颈层内部并不对特征进行升维。

在这里插入图片描述
另外,对于瓶颈层,当stride=1时,才会使用elementwise 的sum将输入和输出特征连接(如上图左侧);stride=2时,无short cut连接输入和输出特征(上图右侧)。

3、网络模型

MobileNetV2的模型如下图所示,其中t为瓶颈层内部升维的倍数,c为特征的维数,n为该瓶颈层重复的次数,s为瓶颈层第一个conv的步幅。

需要注意的是:

  • 当n>1时(即该瓶颈层重复的次数>1),只在第一个瓶颈层stride为对应的s,其他重复的瓶颈层stride均为1
  • 只在stride=1时,输出特征尺寸和输入特征尺寸一致,才会使用elementwise sum将输出与输入相加
  • 当n>1时,只在第一个瓶颈层特征维度为c,其他时候channel不变。

例如,对于该图中56²×24的那层,共有3个该瓶颈层,只在第一个瓶颈层使用stride=2,后两个瓶颈层stride=1;第一个瓶颈层由于输入和输出尺寸不一致,因而无short cut连接,后两个由于stride=1,输入输出特征尺寸一致,会使用short cut将输入和输出特征进行elementwise的sum;只在第一个瓶颈层最后的1×1conv对特征进行升维,后两个瓶颈层输出维度不变(不要和瓶颈层内部的升维弄混了)。

该层输入特征为56×56×24,第一个瓶颈层输出为28×28×32(特征尺寸降低,特征维度增加,无short cut),第二个、第三个瓶颈层输入和输出均为28×28×32(此时c=32,s=1,有short cut)。

另外,下表中还有一个k。MobileNetV1中提出了宽度缩放因子,其作用是在整体上对网络的每一层维度(特征数量)进行瘦身。MobileNetV2中,当该因子<1时,最后的那个1×1conv不进行宽度缩放;否则进行宽度缩放。

在这里插入图片描述

4、pytorch代码

import torch.nn as nn
import math


def conv_bn(inp, oup, stride):
    return nn.Sequential(
        nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
        nn.BatchNorm2d(oup),
        nn.ReLU6(inplace=True)
    )


def conv_1x1_bn(inp, oup):
    return nn.Sequential(
        nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
        nn.BatchNorm2d(oup),
        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]

        self.use_res_connect = self.stride == 1 and inp == oup

        self.conv = nn.Sequential(
            # pw
            nn.Conv2d(inp, inp * expand_ratio, 1, 1, 0, bias=False),
            nn.BatchNorm2d(inp * expand_ratio),
            nn.ReLU6(inplace=True),
            # dw
            nn.Conv2d(inp * expand_ratio, inp * expand_ratio, 3, stride, 1, groups=inp * expand_ratio, bias=False),
            nn.BatchNorm2d(inp * expand_ratio),
            nn.ReLU6(inplace=True),
            # pw-linear
            nn.Conv2d(inp * expand_ratio, oup, 1, 1, 0, bias=False),
            nn.BatchNorm2d(oup),
        )

    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, n_class=1000, input_size=224, width_mult=1.):
        super(MobileNetV2, self).__init__()
        # setting of inverted residual blocks
        self.interverted_residual_setting = [
            # t, c, n, s
            [1, 16, 1, 1],
            [6, 24, 2, 2],
            [6, 32, 3, 2],
            [6, 64, 4, 2],
            [6, 96, 3, 1],
            [6, 160, 3, 2],
            [6, 320, 1, 1],
        ]

        # building first layer
        assert input_size % 32 == 0
        input_channel = int(32 * width_mult)
        self.last_channel = int(1280 * width_mult) if width_mult > 1.0 else 1280
        self.features = [conv_bn(3, input_channel, 2)]
        # building inverted residual blocks
        for t, c, n, s in self.interverted_residual_setting:
            output_channel = int(c * width_mult)
            for i in range(n):
                if i == 0:
                    self.features.append(InvertedResidual(input_channel, output_channel, s, t))
                else:
                    self.features.append(InvertedResidual(input_channel, output_channel, 1, t))
                input_channel = output_channel
        # building last several layers
        self.features.append(conv_1x1_bn(input_channel, self.last_channel))
        self.features.append(nn.AvgPool2d(input_size/32))
        # make it nn.Sequential
        self.features = nn.Sequential(*self.features)

        # building classifier
        self.classifier = nn.Sequential(
            nn.Dropout(),
            nn.Linear(self.last_channel, n_class),
        )

        self._initialize_weights()

    def forward(self, x):
        x = self.features(x)
        x = x.view(-1, self.last_channel)
        x = self.classifier(x)
        return x

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, math.sqrt(2. / n))
                if m.bias is not None:
                    m.bias.data.zero_()
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()
            elif isinstance(m, nn.Linear):
                n = m.weight.size(1)
                m.weight.data.normal_(0, 0.01)
                m.bias.data.zero_()
  • 9
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: MobileNetV2-6a65762b.pth是一个用于深度学习的预训练模型。MobileNetV2是一种轻量级的卷积神经网络结构,适用于在移动设备和嵌入式设备上部署。 模型文件的后缀.pth表示它是由PyTorch框架保存的模型权重文件。PyTorch是一个广泛使用的开源深度学习框架,可用于构建、训练和部署各种深度学习模型。 在MobileNetV2模型中,6a65762b是一个唯一的标识符,可能代表了该模型的某个版本或者某个训练实例的标识符。 使用这个预训练模型可以帮助开发者更快速地构建和训练自己的深度学习模型。通过加载这个预训练模型的权重,我们可以利用该模型在大规模数据集上的预训练结果,从而使得我们在更小规模的数据集上能够更好地实现迁移学习和快速训练。 通过加载这个.pth文件,我们可以使用它提供的模型架构和训练好的权重参数来进行图像分类、目标检测或其他相关任务。这个预训练模型具有较高的准确度和较低的模型复杂度,适用于资源受限的设备上的深度学习应用。 总结来说,mobilenet_v2-6a65762b.pth是一个用于深度学习任务的预训练模型文件,结合MobileNetV2网络架构和训练好的权重参数,可以帮助我们在移动设备和嵌入式设备上构建高效、准确的深度学习模型。 ### 回答2: mobilenet_v2-6a65762b.pth是一个模型文件,它是移动网络(MobileNet)v2模型的一个版本。MobileNet是一种轻量级的卷积神经网络,特别适用于移动设备和嵌入式系统上的计算资源受限环境。MobileNet v2是MobileNet的改进版本,通过引入轻量级的残差连接和线性瓶颈结构,在保持模型大小和计算性能的同时,提高了准确度。 mobilenet_v2-6a65762b.pth是训练好的MobileNet v2模型的权重文件。通过使用这个权重文件,可以加载预训练好的MobileNet v2模型,从而进行图像分类、目标检测或特征提取等任务。 在深度学习中,预训练的模型权重文件将模型的参数保存在了.pth文件中,以便在需要的时候直接加载使用。这样做的好处是可以避免重新训练模型,节省时间和计算资源。这个权重文件是由在大规模图像数据集上训练得到的,所以模型已经具有较好的泛化能力,可以在各种图像数据上进行有效的预测。 加载mobilenet_v2-6a65762b.pth文件,可以实现快速且准确的图像识别和分类,广泛应用于计算机视觉领域。在图像分类任务中,该模型可以识别不同物体的类别,例如识别猫、狗、汽车等。在目标检测任务中,该模型可以检测图像中的物体位置和边界框信息。而在特征提取任务中,该模型可以提取出图像的高层语义特征,作为其他任务的输入或用于图像相似度比较等用途。 总之,mobilenet_v2-6a65762b.pth是一个预训练好的MobileNet v2模型权重文件,使用它可以方便地加载MobileNet v2模型,实现高效准确的图像分类、目标检测和特征提取等任务。 ### 回答3: mobilenet_v2-6a65762b.pth是一个预训练的模型文件,用于MobileNetV2模型的权重初始化。MobileNetV2是一种轻量级的卷积神经网络架构,用于图像分类和目标检测任务。该模型文件包含了已经在大规模数据集上训练好的权重参数,可以直接加载到相应的模型中进行使用。 mobilenet_v2-6a65762b.pth文件的命名规则通常以模型名称和一串唯一的标识符组成,用于区分不同版本或训练过程中的不同阶段。其中,6a65762b是一个标识符,用于确保文件的唯一性。 通过加载mobilenet_v2-6a65762b.pth文件,我们可以利用预训练的权重参数来加速模型的训练过程,并提高模型的性能表现。这是因为预训练权重已经在大规模数据集上进行了充分的训练,具有良好的特征提取能力和泛化能力。在加载预训练权重后,我们可以在较小的数据集上进行微调或进行迁移学习,从而在更小的计算成本内获取较好的结果。 总之,mobilenet_v2-6a65762b.pth是MobileNetV2模型的预训练权重文件,使用它可以帮助我们快速构建和训练具有强大特征提取能力的轻量级卷积神经网络

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值