【pytorch】轻量级网络MobileNetv2完整实现,对照结构图手动编写

89 篇文章 11 订阅
65 篇文章 3 订阅

1.Inverted Residual Block结构
利用深度可分离卷积天生计算量少的特点,区别于以往卷积先降维计算再升维的特点,先升维获得更好的性能,再进行降维计算。
在这里插入图片描述

2.MobileNet v2的单个模块的结构图如下图所示:
在这里插入图片描述
如上图所示,经历了先升维,再降维的过程。
网络整体结构图如下:
在这里插入图片描述
其中包含:Stride为1及Stride为2时BottolNeck结构的区分,当Stride为1时,输入输出不改变特征图大小,此时有图中SUM层将前一层输出及本层输入相加,即为代码中的shortCut。
其次,由于本身所得特征较小,去掉MobileNet v1模型最后的ReLu层。使特征不被非线性破坏。
在这里插入图片描述
pytorch实现深度可分离卷积分为两步:
第一部分:分组卷积,且groups和输出通道数皆为输入通道数。
第二部分:利用1×1的卷积将输入通道数变更为输出通道数。
其单个BottolNeck的实现代码为:(综合stride1及stride2)

import os.path
from typing import Iterator
import numpy as np
import torch
import cv2
from PIL import Image
from torch.utils.data import Dataset, DataLoader, Subset, random_split
import re
from functools import reduce
from torch.utils.tensorboard import SummaryWriter as Writer
from torchvision import transforms, datasets
import torchvision as tv
from torch import nn
import torch.nn.functional as F
import time
class DSCWithBNAndRelu(nn.Module):
    def __init__(self,indim,hidden,outdim,ksize,stride,padding,hasShortCut=False):
        super().__init__()
        self.hasShortCut=hasShortCut
        # 带BN及Relu的深度可分离卷积
        self.baseNet=nn.Sequential(nn.Conv2d(indim, hidden, kernel_size=1,bias=False),
                              nn.BatchNorm2d(hidden),
                              nn.ReLU(True),
                              nn.Conv2d(hidden, hidden, kernel_size=ksize, stride=stride,
                                        padding=padding,groups=hidden,bias=False),
                              nn.BatchNorm2d(hidden),
                              nn.ReLU(True),
                              nn.Conv2d(hidden, outdim, kernel_size=1,bias=False),
                              nn.BatchNorm2d(outdim),
                              )
    def forward(self,x):
        x1 =self.baseNet(x)
        if self.hasShortCut:
           return x1+x
        else:
           return x1

完整的网络代码如下:

import os.path
from typing import Iterator
import numpy as np
import torch
import cv2
from PIL import Image
from torch.utils.data import Dataset, DataLoader, Subset, random_split
import re
from functools import reduce
from torch.utils.tensorboard import SummaryWriter as Writer
from torchvision import transforms, datasets
import torchvision as tv
from torch import nn
import torch.nn.functional as F
import time
from collections import OrderedDict
class DSCWithBNAndRelu(nn.Module):
    def __init__(self,indim,hidden,outdim,ksize,stride,padding,hasShortCut=False):
        super().__init__()
        self.hasShortCut=hasShortCut
        # 带BN及Relu的深度可分离卷积
        self.baseNet=nn.Sequential(nn.Conv2d(indim, hidden, kernel_size=1,bias=False),
                              nn.BatchNorm2d(hidden),
                              nn.ReLU(True),
                              nn.Conv2d(hidden, hidden, kernel_size=ksize, stride=stride,
                                        padding=padding,groups=hidden,bias=False),
                              nn.BatchNorm2d(hidden),
                              nn.ReLU(True),
                              nn.Conv2d(hidden, outdim, kernel_size=1,bias=False),
                              nn.BatchNorm2d(outdim),
                              )
    def forward(self,x):
        x1 =self.baseNet(x)
        if self.hasShortCut:
           return x1+x
        else:
           return x1
class myCustomerMobileNetv2(nn.Module):
    #参数为分类数:
    def __init__(self,classNum=20):
        super().__init__()
        # 带BN及Relu的深度可分离卷积
        self.features=nn.Sequential(OrderedDict([
            ('C1',nn.Sequential(nn.Conv2d(3, 32, kernel_size=3, stride=2, padding=1),nn.BatchNorm2d(32),nn.ReLU(True))),

            ('Bottleneck_1',DSCWithBNAndRelu(indim=32, hidden=32, outdim=16, ksize=3, stride=1, padding=1, hasShortCut=False)),
            ('Bottleneck_2',DSCWithBNAndRelu(indim=16, hidden=96, outdim=24, ksize=3, stride=2, padding=1, hasShortCut=False)),
            ('Bottleneck_3',DSCWithBNAndRelu(indim=24, hidden=144, outdim=24, ksize=3, stride=1, padding=1, hasShortCut=True)),

            ('Bottleneck_4',DSCWithBNAndRelu(indim=24, hidden=144, outdim=32, ksize=3, stride=2, padding=1, hasShortCut=False)),
            ('Bottleneck_5',DSCWithBNAndRelu(indim=32, hidden=192, outdim=32, ksize=3, stride=1, padding=1, hasShortCut=True)),

            ('Bottleneck_6',DSCWithBNAndRelu(indim=32, hidden=192, outdim=32, ksize=3, stride=1, padding=1, hasShortCut=True)),

            ('Bottleneck_7',DSCWithBNAndRelu(indim=32, hidden=192, outdim=64, ksize=3, stride=1, padding=1, hasShortCut=False)),
            ('Bottleneck_8',DSCWithBNAndRelu(indim=64, hidden=384, outdim=64, ksize=3, stride=1, padding=1, hasShortCut=True)),

            ('Bottleneck_9',DSCWithBNAndRelu(indim=64, hidden=384, outdim=64, ksize=3, stride=1, padding=1, hasShortCut=True)),

            ('Bottleneck_10',DSCWithBNAndRelu(indim=64, hidden=384, outdim=64, ksize=3, stride=1, padding=1, hasShortCut=True)),

            ('Bottleneck_11',DSCWithBNAndRelu(indim=64, hidden=384, outdim=96, ksize=3, stride=2, padding=1, hasShortCut=False)),
            ('Bottleneck_12',DSCWithBNAndRelu(indim=96, hidden=576, outdim=96, ksize=3, stride=1, padding=1, hasShortCut=True)),

            ('Bottleneck_13',DSCWithBNAndRelu(indim=96, hidden=576, outdim=96, ksize=3, stride=1, padding=1, hasShortCut=True)),

            ('Bottleneck_14',DSCWithBNAndRelu(indim=96, hidden=576, outdim=160, ksize=3, stride=2, padding=1, hasShortCut=False)),
            ('Bottleneck_15',DSCWithBNAndRelu(indim=160, hidden=960, outdim=160, ksize=3, stride=1, padding=1, hasShortCut=True)),

            ('Bottleneck_16',DSCWithBNAndRelu(indim=160, hidden=960, outdim=160, ksize=3, stride=1, padding=1, hasShortCut=True)),

            ('Bottleneck_17',DSCWithBNAndRelu(indim=160, hidden=960, outdim=320, ksize=3, stride=1, padding=1, hasShortCut=False)),
            ('C2',nn.Sequential(nn.Conv2d(320, 1280, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(1280),nn.ReLU(True))),
            ('GP',nn.AdaptiveAvgPool2d(1)),
            ('C3', nn.Sequential(nn.Conv2d(1280, classNum, kernel_size=1, stride=1, padding=0), nn.BatchNorm2d(classNum),nn.ReLU(True)))
        ])
        )
    def forward(self,x):
        return self.features(x)

#进行测试
myNet=myCustomerMobileNetv2()
myNet.eval()
#测试模式时nn.BatchNorm2d的batchsize可以为1
k = torch.rand(1, 3, 224, 224)
print(myNet(k).shape)

输出结果:

torch.Size([1, 20, 1, 1])
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

颢师傅

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

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

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

打赏作者

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

抵扣说明:

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

余额充值