Mobile NetV2代码及总结

V1地址:https://blog.csdn.net/weixin_44543648/article/details/124417135

MobileNet V2 创新性的提出了具有线性bottleneck 的Inverted 残差块。

The Inverted residual:

  • Residual:标准的残差块先用1X1卷积降低通道数,再用3X3卷积获取特征,最后用1X1卷积恢复通道(reduce-transfer-expand)。
  • Inverted residual:为了降低计算量,引入深度可分离卷积,为了获取更多的信息,引入bottleneck结构,并为了保证数据的不丢失,在前面的1x1卷积降低通道数的位置,改为扩展通道数。即expand-transfer-reduce。
    结构如下图
    在这里插入图片描述
    不同步长的Inverted residual:
    在这里插入图片描述

Linear bottleneck

由于ReLU会使小于0的特征等于0,即不进行反馈,会造成一定的特征丢失(在缩减特征图数量的时候),因此Bottleneck在最后一个输出通道位置不加入ReLU非线性激活函数。

宽度因子和分辨率因子

宽度因子a人为设置来减少每层网络的输出通道,可以减少axa的参数量,分辨率因子p主要用来减少输入图像大小,可以减少pxp的计算量,两个一起使用,可以减少axaxpxp的计算量。

宽度因子代码:保证通道缩小后也是divisor的倍数,保持想通过倍数有利于提高网络性能。

def _make_divisible(ch,divisor,min_ch = None):
    if not min_ch:
        min_ch = divisor

    new_ch = max(min_ch,int(ch+divisor/2)//divisor*divisor)#将通道数控制在divisor的倍数。
    if new_ch<0.9*ch:
        new_ch += divisor
    return new_ch

代码:

import torch
import torch.nn as nn

def _make_divisible(ch,divisor,min_ch = None):
    if not min_ch:
        min_ch = divisor

    new_ch = max(min_ch,int(ch+divisor/2)//divisor*divisor)#将通道数控制在divisor的倍数。
    if new_ch<0.9*ch:
        new_ch += divisor
    return new_ch

class Inverted_residual_bottleneck(nn.Module):
    def __init__(self,mul_ratio,inchannels,outchannels,stride):
        super(Inverted_residual_bottleneck, self).__init__()
        self.shortcut = True if stride==1 and inchannels==outchannels else False

        layer = []
        if mul_ratio != 1:
            layer.extend([nn.Conv2d(inchannels, inchannels * mul_ratio, 1, 1),
            nn.BatchNorm2d(inchannels * mul_ratio),
            nn.ReLU6()])

        layer.extend([
            nn.Conv2d(inchannels*mul_ratio,inchannels*mul_ratio,3,stride,1,groups = inchannels*mul_ratio),
            nn.BatchNorm2d(inchannels * mul_ratio),
            nn.ReLU6(),
            nn.Conv2d(inchannels * mul_ratio, outchannels, 1, 1),
            nn.BatchNorm2d(outchannels)])

        self.conv = nn.Sequential(*layer)

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




class Mobilenet_V2(nn.Module):
    def __init__(self,inchannel,numclasses,alpha,round_nearest = 8):
        super(Mobilenet_V2, self).__init__()
        input_channel = _make_divisible(32*alpha, round_nearest)
        last_channel = _make_divisible(1280*alpha,round_nearest)

        self.conv1 = nn.Conv2d(inchannel,input_channel,3,2,1)
        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]
        ]
        self.block = Inverted_residual_bottleneck
        self.stages = nn.ModuleList([])
        for t,c,n,s in setting:
            cout = _make_divisible(c*alpha,round_nearest)
            self.stages.append(self._make_stage(t,input_channel,cout,n,s))
            input_channel = cout
        self.conv2 = nn.Sequential(nn.Conv2d(input_channel,last_channel,1,1),
                                   nn.BatchNorm2d(last_channel),
                                   nn.ReLU())
        self.pool = nn.MaxPool2d(7)
        self.fc = nn.Sequential(
            nn.Dropout(0.2),
            nn.Conv2d(last_channel,numclasses,1)
        )
        for m in self.modules():
            if isinstance(m,nn.Conv2d):
                nn.init.normal_(m.weight,0,0.01)
                if m.bias is not None:
                    nn.init.zeros_(m.bias)
            elif isinstance(m,nn.BatchNorm2d):
                nn.init.ones_(m.weight)
                nn.init.zeros_(m.bias)



    def _make_stage(self,mult,inchannel,ouchannel,repeat,stride):
        strides = [stride]+[1]*repeat
        layers = []
        for i in range(repeat):
            layers.append(self.block(mult,inchannel,ouchannel,strides[i]))
            inchannel = ouchannel
        return nn.Sequential(*layers)

    def forward(self,x):
        x = self.conv1(x)
        for stage in self.stages:
            x = stage(x)
        x = self.conv2(x)
        x = self.pool(x)

        x = self.fc(x)
        x = x.view(x.size(0), -1)
        return x

if __name__ == '__main__':
    input = torch.empty(1,3,224,224)
    m = Mobilenet_V2(3,10,0.5)
    out = m(input)
    print(out)





  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
ShuffleNetV2是一种轻量级卷积神经网络,适合用于移动设备和嵌入式设备等资源受限的场景。下面是使用ShuffleNetV2实现智能电子秤自动识别的方法和代码: 1. 数据准备:收集电子秤图片数据集,并且标注好每张图片的类别。 2. 数据预处理:将图片缩放为相同的大小,并且进行归一化处理。 3. 构建模型:使用ShuffleNetV2作为分类器模型,可以使用TensorFlow或PyTorch深度学习框架进行模型构建。 4. 模型训练:使用训练集对模型进行训练,并且使用验证集进行模型的调优。 5. 模型评估:使用测试集对模型进行评估,并且计算模型的准确率、精确率、召回率等指标。 6. 模型部署:将训练好的模型部署到电子秤上,可以使用TensorFlow Lite或PyTorch Mobile等工具对模型进行转换和优化。 下面是使用TensorFlow实现的ShuffleNetV2代码示例: ```python import tensorflow as tf from tensorflow.keras.layers import Input, Conv2D, BatchNormalization, ReLU from tensorflow.keras.layers import DepthwiseConv2D, GlobalAveragePooling2D from tensorflow.keras.layers import Dense, Dropout, Flatten from tensorflow.keras.models import Model from tensorflow.keras.optimizers import Adam def shuffle_block(x, out_channels, stride): # 定义ShuffleNetV2的基本单元:ShuffleBlock channels = x.shape[-1] if stride != 1 or channels != out_channels: # 下采样或通道数不同时,使用1x1卷积进行调整 shortcut = Conv2D(out_channels, 1)(x) shortcut = BatchNormalization()(shortcut) else: shortcut = x # 分组卷积 x = DepthwiseConv2D(3, stride, padding='same', groups=channels)(x) x = BatchNormalization()(x) x = ReLU()(x) # 通道重组 x = Conv2D(out_channels, 1)(x) x = BatchNormalization()(x) x = ReLU()(x) x = DepthwiseConv2D(3, 1, padding='same', groups=out_channels)(x) x = BatchNormalization()(x) # 通道重组 x = Conv2D(out_channels, 1)(x) x = BatchNormalization()(x) x = ReLU()(x) # 通道重组 x = tf.concat([x, shortcut], axis=-1) x = tf.nn.depth_to_space(x, 2) return x def shuffle_netv2(input_shape, num_classes): # 构建ShuffleNetV2模型 inputs = Input(shape=input_shape) x = Conv2D(24, 3, strides=2, padding='same')(inputs) x = BatchNormalization()(x) x = ReLU()(x) x = MaxPooling2D(3, strides=2, padding='same')(x) x = shuffle_block(x, 24, 1) x = shuffle_block(x, 24, 1) x = shuffle_block(x, 24, 2) x = shuffle_block(x, 48, 1) x = shuffle_block(x, 48, 1) x = shuffle_block(x, 48, 2) x = shuffle_block(x, 96, 1) x = shuffle_block(x, 96, 1) x = shuffle_block(x, 96, 2) x = GlobalAveragePooling2D()(x) x = Dropout(0.5)(x) x = Dense(num_classes, activation='softmax')(x) model = Model(inputs=inputs, outputs=x) return model # 训练模型 model = shuffle_netv2((224, 224, 3), 2) optimizer = Adam(learning_rate=0.001) model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy']) model.fit(train_data, epochs=10, validation_data=val_data) # 评估模型 test_loss, test_acc = model.evaluate(test_data) print('Test accuracy:', test_acc) # 保存模型 model.save('shuffle_netv2.h5') ``` 注意:以上代码仅供参考,具体实现需要根据数据集和场景进行调整和优化。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值