最近在利用SSD检测物体时,由于实际项目要求,需要对模型进行轻量化,所以考虑利用轻量网络替换原本的骨架VGG16,查找一些资料后最终采用了google开源的mobileNetV2。这里对学习mobileNet系列的过程做一些总结。mobileNetV1是由google在2017年发布的一个轻量级深度神经网络,其主要特点是采用深度可分离卷积替换了普通卷积,2018年提出的mobileNetV2在V1的基础上引入了线性瓶颈 (Linear Bottleneck)和倒残差 (Inverted Residual)来提高网络的表征能力。

1.mobileNetV1

        mobileNet V1是一种体积较小、计算量较少、适用于移动设备的卷积神经网络。mobileNet V1的主要创新点是用深度可分离卷积(depthwise separable convolution)代替普通的卷积,并使用宽度乘数(width multiply)减少参数量,不过减少参数的数量和操作的同时也会使特征丢失导致精度下降。


   

1.1 普通卷积和深度可分离卷积

        标准的卷积过程如图1,卷积核做卷积运算时得同时考虑对应图像区域中的所有通道(channel),而深度可分离卷积对不同的通道采用不同的卷积核进行卷积,如图2所示它将普通卷积分解成了深度卷积(Depthwise Convolution)和逐点卷积(Pointwise Convolution)两个过程,这样可以将通道(channel)相关性和空间(spatial)相关性解耦。原文中给出的深度可分离卷积后面都接了一个BN和ReLU层。

rknn mobilenet rknn mobilenetv1 分类_卷积

         

rknn mobilenet rknn mobilenetv1 分类_卷积_02

      

rknn mobilenet rknn mobilenetv1 分类_ide_03

                            图1 普通卷积                                                    图2 深度可分离卷积                                                                               

1.1.1 标准卷积核

        设输入特征维度为DF*DF*M,M为通道数。标准卷积核的参数为DK*DK*M*N,DK为卷积核大小,M为输入的通道数, N为输出的通道数。卷积后输出维度为:DF*DF*N。卷积过程中每个卷积核对图像区域进行DF*DF次扫描,每次扫描的深度为M(channel),每个通道需要DK*DK次加权求和运算, 所以理论计算量(floating point operatios FLOPs)为:N*DF*DF*M*Dk*DK

rknn mobilenet rknn mobilenetv1 分类_卷积_04

rknn mobilenet rknn mobilenetv1 分类_卷积_05

rknn mobilenet rknn mobilenetv1 分类_卷积_06

1.1.2 深度可分离卷积

  • 深度卷积:设输入特征维度为DF*DF*M,M为通道数。卷积核的参数为DK*DK*1*M。输出深度卷积后的特征维度为:DF*DF*M。卷积时每个通道只对应一个卷积核(扫描深度为1),所以 FLOPs为:M*DF*DF*DK*DK
  • 逐点卷积:输入为深度卷积后的特征,维度为DF*DF*M。卷积核参数为1*1*M*N。输出维度为DF*DF*N。卷积过程中对每个特征做1*1的标准卷积, FLOPs为:N*DF*DF*M。

1.1.3 深度可分离卷积的优势

  • 参数量:关系到模型大小,通常参数用float32表示,所以模型大小一般时参数量的4倍。标准卷积的参数量为Dk*Dk*M*N(M为输入通道数, N为输出通道数),深度卷积的参数量为DK*DK*M,逐点卷积的参数量为1*1*M*N,所以深度可分离卷积相对于标准卷积的参数量为(DK*DK*M + M*N)/ DK*DK*M*N = 1/N + 1/DK*DK
  • 计算量: 可以用来衡量算法/模型的复杂度, 通常只考虑乘加操作(Multi-Adds)的数量,而且只考虑 CONV 和 FC 等参数层的计算量,忽略 BN 和PReLU 等等。一般情况,CONV 和 FC 层也会忽略仅纯加操作的计算量,如 bias 偏置加和 shotcut 残差加等。标准卷积的计算量为:N*DF*DF*M*DK*DK,深度可分离卷积的计算量为M*DF*DF*DK*DK+N*DF*DF*M。所以深度可分离卷积的计算量相比于标准卷积为(M*DF*DF*DK*DK+N*DF*DF*M)/ N*DF*DF*M*DK*DK = 1/N + 1/DK*DK。     
  • 区域和通道分离: 深度可分离卷积将以往普通卷积操作同时考虑通道和区域改变(卷积先只考虑区域,然后再考虑通道),实现了通道和区域的分离。

      举个例子

      假设输入特征的维度为224*224*3,卷积核大小为3*3,输出通道数为2,设置pad=1,stride=1,则如下图(图a)所示,标准卷积的输出维度为224*224*2。参数量为3*3*3*2=54,计算量为2*224*224*3*3*3=2709504。

     在深度卷积过程中(图b),输入为224*224*3,卷积核参数为3*3*1*3,每个通道做3*3的卷积,收集了每个通道的空间特征(Depthwise特征),输出特征维度为224*224*3。

     接着进入逐点卷积(图c),卷积核参数为1*1*3*2,对Depthwise特征做2个1*1的普通卷积,这样相当于收集了每个点的特征,输出维度为224*224*2。

     深度可分离卷积的参数量为3*3*3 + 3*2 = 33,计算量为3*224*224*3*3 + 2*224*224*3 = 1655808,33/54=1655808 / 2709504 = 0.61, 可以看出参数量和计算量减少至标准卷积的0.61倍。

rknn mobilenet rknn mobilenetv1 分类_卷积核_07

rknn mobilenet rknn mobilenetv1 分类_ide_08

rknn mobilenet rknn mobilenetv1 分类_卷积_09

   图a 标准卷积过程                                                                                     图b 深度卷积                                                                                              图c 逐点卷积

1.2 mobileNetV1网络结构

        mobileNetV1的网络结构如Table 1.前面的卷积层中除了第一层为标准卷积层外,其他都是深度可分离卷积(Conv dw + Conv/s1),卷积后接了一个7*7的平均池化层,之后通过全连接层,最后利用Softmax激活函数将全连接层输出归一化到0-1的一个概率值,根据概率值的高低可以得到图像的分类情况。

rknn mobilenet rknn mobilenetv1 分类_rknn mobilenet_10

 

1.3 超参数

宽度因子α(Width Multiplier)

        对于深度可分离卷积层,输入的通道数M乘上一个宽度因子α变为αM,输出通道数变为αN,其中α区间为(0,1],此时深度可分离卷积的参数量为:DK*DK*αN + αM*αN = α*α(1/α *DK*DK*N + M*N),计算量变为αM*DF*DF*DK*DK+αN*DF*DF*αM = α*α  (1/α*M*DF*DF*DK*DK+N*DF*DF*M),所以参数量和计算量差不多都变为原来的α*α倍。

分辨率因子ρ (Resolution Multiplier)

        ρ改变输入层的分辨率,所以深度可分离卷积的参数量不变,但计算量为M*ρDF*ρDF*DK*DK+N*ρDF*ρDF*M = ρ*ρ(M*DF*DF*DK*DK+N*DF*DF*M),即计算量变为原来的ρ*ρ倍。

1.4 mobileNetV1 实现(基于框架keras / pytorch)

  • pytorch实现: https://github.com/marvis/pytorch-mobilenet
  • keras实现: https://github.com/Hedlen/Mobilenet-Keras/blob/master/model/mobilenet.py

 

import torch
import torch.nn as nn

def conv3x3(in_planes, out_planes, stride=1, padding=1):
    return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, padding=padding, groups=in_planes, bias=False)

# why no bias: 如果卷积层之后是BN层,那么可以不用偏置参数,可以节省内存
def conv1x1(in_planes, out_planes):
    return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, bias=False)  

class DPBlock(nn.Module):
    '''
        Depthwise convolution and Pointwise convolution.
    '''
    def __init__(self, in_planes, out_planes, stride=1):
        super(DPBlock, self).__init__()  # 调用基类__init__函数初始化
        self.conv1 = conv3x3(in_planes, out_planes, stride)
        self.bn1 = nn.BatchNorm2d(in_planes)
        self.relu = nn.ReLU(inplace=True)
        self.conv2 = conv1x1(in_planes, out_planes)
        self.bn2 = nn.BatchNorm2d(out_planes)
        
    def forward(self, x):
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.relu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        out = self.relu(out)
        
        return out
        
class mobileNetV1Net(nn.Module):
    def __init__(self, block, num_class=1000):
        super(mobileNetV1Net, self).__init__()
        
        self.model = nn.Sequential(
            conv3x3(3, 32, 2),
            nn.BatchNorm2d(32),
            nn.ReLU(inplace=True)
            block(32, 64, 1),
            block(64, 128, 2),
            block(128, 128, 1),
            block(128, 256, 2),
            block(256, 256, 1),
            block(256, 512, 2),
            block(512, 512, 1),
            block(512, 512, 1),
            block(512, 512, 1),
            block(512, 512, 1),
            block(512, 512, 1),
            block(512, 1024, 2),
            block(1024, 1024, 2),
            nn.AvgPool2d(7)
        )
        self.fc = nn.Linear(1024, num_class)
        
    def forward(self, x):
        x = self.model(x)
        x = x.view(-1, 1024)  # reshape
        out = self.fc(x)
        
        return out
             
mobileNetV1 = mobileNetV1Net(DPBlock)

 

1.5 参考链接

  • 深度可分离卷积核MobileNet_v1
  • MobileNetV1 & MobileNetV2 简介
  • 从MobileNet V1到MobileNet V2
  • pytorch实现MobileNet

 

 

 

TRANSLATE with x

English

Arabic

Hebrew

Polish

Bulgarian

Hindi

Portuguese

Catalan

Hmong Daw

Romanian

Chinese Simplified

Hungarian

Russian

Chinese Traditional

Indonesian

Slovak

Czech

Italian

Slovenian

Danish

Japanese

Spanish

Dutch

Klingon

Swedish

English

Korean

Thai

Estonian

Latvian

Turkish

Finnish

Lithuanian

Ukrainian

French

Malay

Urdu

German

Maltese

Vietnamese

Greek

Norwegian

Welsh

Haitian Creole

Persian

 

 

TRANSLATE with

COPY THE URL BELOW

Back

EMBED THE SNIPPET BELOW IN YOUR SITE


Enable collaborative features and customize widget: Bing Webmaster Portal

Back

 

 

此页面的语言为中文(简体)

 

翻译为

 

 

 

 


  • 中文(简体)
  • 中文(繁体)
  • 丹麦语
  • 乌克兰语
  • 乌尔都语
  • 亚美尼亚语
  • 俄语
  • 保加利亚语
  • 克罗地亚语
  • 冰岛语
  • 加泰罗尼亚语
  • 匈牙利语
  • 卡纳达语
  • 印地语
  • 印尼语
  • 古吉拉特语
  • 哈萨克语
  • 土耳其语
  • 威尔士语
  • 孟加拉语
  • 尼泊尔语
  • 布尔语(南非荷兰语)
  • 希伯来语
  • 希腊语
  • 库尔德语
  • 德语
  • 意大利语
  • 拉脱维亚语
  • 挪威语
  • 捷克语
  • 斯洛伐克语
  • 斯洛文尼亚语
  • 旁遮普语
  • 日语
  • 普什图语
  • 毛利语
  • 法语
  • 波兰语
  • 波斯语
  • 泰卢固语
  • 泰米尔语
  • 泰语
  • 海地克里奥尔语
  • 爱沙尼亚语
  • 瑞典语
  • 立陶宛语
  • 缅甸语
  • 罗马尼亚语
  • 老挝语
  • 芬兰语
  • 英语
  • 荷兰语
  • 萨摩亚语
  • 葡萄牙语
  • 西班牙语
  • 越南语
  • 阿塞拜疆语
  • 阿姆哈拉语
  • 阿尔巴尼亚语
  • 阿拉伯语
  • 韩语
  • 马尔加什语
  • 马拉地语
  • 马拉雅拉姆语
  • 马来语
  • 马耳他语
  • 高棉语

 

随时将中文(简体)翻译为PRO
一律不翻译中文(简体)