小白学PyTorch | 11 MobileNet详解及PyTorch实现

╄→гoц情女王★ 提交于 2021-02-07 00:18:35
【机器学习炼丹术】的学习笔记分享
<<小白学PyTorch>>

小白学PyTorch | 10 pytorch常见运算详解

小白学PyTorch | 9 tensor数据结构与存储结构

小白学PyTorch | 8 实战之MNIST小试牛刀

小白学PyTorch | 7 最新版本torchvision.transforms常用API翻译与讲解

小白学PyTorch | 6 模型的构建访问遍历存储(附代码)

小白学PyTorch | 5 torchvision预训练模型与数据集全览

小白学PyTorch | 4 构建模型三要素与权重初始化

小白学PyTorch | 3 浅谈Dataset和Dataloader

小白学PyTorch | 2 浅谈训练集验证集和测试集

小白学PyTorch | 1 搭建一个超简单的网络

小白学PyTorch | 动态图与静态图的浅显理解


参考目录:

  • 1 背景

  • 2 深度可分离卷积

    • 2.2 一般卷积计算量

    • 2.2 深度可分离卷积计算量

    • 2.3 网络结构

  • 3 PyTorch实现


本来计划是想在今天讲EfficientNet PyTorch的,但是发现EfficientNet是依赖于SENet和MobileNet两个网络结构,所以本着本系列是给“小白”初学者学习的,所以这一课先讲解MobileNet,然后下一课讲解SENet,然后再下一课讲解EfficientNet,当然,每一节课都是由PyTorch实现的。

这个系列《小白学PyTorch》的所有代码和数据集放在了公众号【机器学习炼丹术】后台,回复【pytorch】获取(还在更新的呢):

当然有什么问题、有事没事都可以找炼丹兄交流哈哈,炼丹兄就是一个非Top学校的跨专业应届研究生。

↑↑↑扫码加炼丹兄好友↑↑↑

1 背景

Mobile是移动、手机的概念,MobileNet是Google在2017年提出的轻量级深度神经网络,专门用于移动端、嵌入式这种计算力不高、要求速度、实时性的设备。

2 深度可分离卷积

主要应用了深度可分离卷积来代替传统的卷积操作,并且放弃pooling层。把标准卷积分解成:

  • 深度卷积(depthwise convolution)
  • 逐点卷积(pointwise convolution)。这么做的好处是可以 大幅度降低参数量和计算量。

2.2 一般卷积计算量

我们先来回顾一下什么是一般的卷积:先说一下题目:特征图尺寸是H(高)和W(宽),尺寸(边长)为K,M是输入特征图的通道数,N是输出特征图的通道数。

现在简化问题,如上图所示,输入单通道特征图,输出特征图也是单通道的, 我们知道每一个卷积结果为一个标量,从输出特征图来看,总共进行了9次卷积。每一次卷积计算了9次,因为每一次卷积都需要让卷积核上的每一个数字与原来特征图上对应的数字相乘(这里只算乘法不用考虑加法)。所以图6.18所示,总共计算了:

如果输入特征图是一个2通道的 ,那么意味着卷积核也是要2通道的卷积核才行,此时输出特征图还是单通道的。这样计算量就变成:

原本单通道特征图每一次卷积只用计算9次乘法,现在因为输入通道数变成2,要计算18次乘法才能得到输出中的1个数字。现在假设输出特征图要输出3通道的特征图。 那么就要准备3个不同的卷积核,重复上述全部操作3次才能拿的到3个特征图。所以计算量就是:

现在解决原来的问题:特征图尺寸是H(高)和W(宽),卷积核是正方形的,尺寸(边长)为K,M是输入特征图的通道数,N是输出特征图的通道数。 那么这样卷积的计算量为:

这个就是卷积的计算量的公式。

2.2 深度可分离卷积计算量

  • 深度可分离卷积(Depthwise Separable Convolution,DSC)

假设在一次一般的卷积中,需要将一个输入特征图64×7×7,经过3×3的卷积核,变成128×7×7的输出特征图。计算一下这个过程需要多少的计算量:

如果用了深度可分离卷积,就是把这个卷积变成两个步骤:

  1. Depthwise:先用64×7×7经过3×3的卷积核得到一个64×7×7的特征图。注意注意!这里是64×7×7的特征图经过3×3的卷积核,不是64×3×3的卷积核!这里将64×7×7的特征图看成64张7×7的图片,然后依次与3×3的卷积核进行卷积;
  2. Pointwise:在Depthwise的操作中,不难发现,这样的计算根本无法整合不同通道的信息,因为上一步把所有通道都拆开了,所以在这一步要用64×1×1的卷积核去整合不同通道上的信息,用128个64×1×1的卷积核,产生128×7×7的特征图。

最后的计算量就是:

计算量减少了百分之80以上。

分解过程示意图如下:

在图中可以看到:

  • (a)表示一般卷积过程, 卷积核都是M个通道,然后总共有N和卷积核,意味着输入特征图有M个通道,然后输出特征图有N个通道。
  • (b)表示depthwise过程, 总共有M个卷积核,这里是对输入特征图的M个通道分别做一个卷积,输出的特征图也是M个通道的;
  • (c)表示pointwise过程,总共有N个 的卷积核,这样来整合不同通道的信息,输出特征图有N个通道数。

2.3 网络结构

左图表示的是一般卷积过程,卷积之后跟上BN和ReLU激活层,因为DBC将分成了两个卷积过程,所以就变成了图右这种结构,Depthwise之后加上BN和ReLU,然后Pointwise之后再加上Bn和ReLU。

从整个网络结构可以看出来:

  • 除了第一层为标准的卷积层之外,其他的层都为深度可分离卷积。
  • 整个网络没有使用Pooling层。

3 PyTorch实现

import torch
import torch.nn as nn
import torch.nn.functional as F


class Block(nn.Module):
    '''Depthwise conv + Pointwise conv'''
    def __init__(self, in_planes, out_planes, stride=1):
        super(Block, self).__init__()
        self.conv1 = nn.Conv2d\
            (in_planes, in_planes, kernel_size=3, stride=stride, 
             padding=1, groups=in_planes, bias=False)
        self.bn1 = nn.BatchNorm2d(in_planes)
        self.conv2 = nn.Conv2d\
            (in_planes, out_planes, kernel_size=1
            stride=1, padding=0, bias=False)
        self.bn2 = nn.BatchNorm2d(out_planes)

    def forward(self, x):
        out = F.relu(self.bn1(self.conv1(x)))
        out = F.relu(self.bn2(self.conv2(out)))
        return out


class MobileNet(nn.Module):
    # (128,2) means conv planes=128, conv stride=2, 
    # by default conv stride=1
    cfg = [64, (128,2), 128, (256,2), 256, (512,2), 
           512512512512512, (1024,2), 1024]

    def __init__(self, num_classes=10):
        super(MobileNet, self).__init__()
        self.conv1 = nn.Conv2d(332, kernel_size=3
         stride=1, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(32)
        self.layers = self._make_layers(in_planes=32)
        self.linear = nn.Linear(1024, num_classes)

    def _make_layers(self, in_planes):
        layers = []
        for x in self.cfg:
            out_planes = x if isinstance(x, int) else x[0]
            stride = 1 if isinstance(x, int) else x[1]
            layers.append(Block(in_planes, out_planes, stride))
            in_planes = out_planes
        return nn.Sequential(*layers)

    def forward(self, x):
        out = F.relu(self.bn1(self.conv1(x)))
        out = self.layers(out)
        out = F.avg_pool2d(out, 2)
        out = out.view(out.size(0), -1)
        out = self.linear(out)
        return out

net = MobileNet()
x = torch.randn(1,3,32,32)
y = net(x)
print(y.size())
> torch.Size([110])

正常情况下这个预训练模型都会输出1024个线性节点,然后这里我自己加上了一个1024->10的一个全连接层。

我们来看一下这个网络结构:

print(net)

输出结果:

然后代码中:

关于模型通道数的设置部分:

MobileNet就差不多完事了,下一节课为SENet的PyTorch实现和详解。

- END -


<<小白学图像>>

小白学论文 | EfficientNet强在哪里

小白学论文 | 神经网络初始化Xavier

小白学论文 | 端侧神经网络GhostNet(2019)

小白学目标检测 | RCNN, SPPNet, Fast, Faster

小白学图像 | BatchNormalization详解与比较

小白学图像 | Group Normalization详解+PyTorch代码

小白学图像 | 八篇经典CNN论文串讲

图像增强 | CLAHE 限制对比度自适应直方图均衡化

小白学卷积 | 深入浅出卷积网络的平移不变性

小白学卷积 | (反)卷积输出尺寸计算

损失函数 | 焦点损失函数 FocalLoss 与 GHM

<<小白学机器学习>>

小白学ML | 随机森林 全解 (全网最全)

小白学SVM | SVM优化推导 + 拉格朗日 + hingeLoss

小白学LGB | LightGBM = GOSS + histogram + EFB

小白学LGB | LightGBM的调参与并行

小白学XGB | XGBoost推导与牛顿法

评价指标 | 详解F1-score与多分类F1

小白学ML | Adaboost及手推算法案例

小白学ML | GBDT梯度提升树

小白学优化 | 最小二乘法与岭回归&Lasso回归

小白学排序 | 十大经典排序算法(动图)

杂谈 | 正态分布为什么如此常见

Adam优化器为什么被人吐槽?

机器学习不得不知道的提升技巧:SWA与pseudo-label

<<小白面经>>

小白面经 | 快手 AI算法岗 附答案解析

小白面经 | 拼多多 AI算法岗 附带解析

【小白面经】八种应对样本不均衡的策略

【小白面经】之防止过拟合的所有方法

【小白面经】梯度消失爆炸及其解决方法

【小白面经】 判别模型&生成模型

<<小白健身>>

【小白健身】徒手健身40个动作(gif)

【小白健身】弹力带轻度健身gif动图









本文分享自微信公众号 - 机器学习炼丹术(liandanshu)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!