CV学习笔记-MobileNet

news/2024/4/16 19:13:06/文章来源:https://blog.csdn.net/qq_38853759/article/details/129230192

MobileNet

文章目录

  • MobileNet
    • 1. MobileNet概述
    • 2. 深度可分离卷积(depthwise separable convolution)
      • 2.1 深度可分离卷积通俗理解
      • 2.2 深度可分离卷积对于参数的优化
    • 3. MobileNet网络结构
    • 4. 代码实现
      • 4.1 卷积块
      • 4.2 深度可分离卷积块
      • 4.3 MobileNet定义
      • 4.4 完整代码

1. MobileNet概述

  网络专注于移动端或者嵌入式设备中的轻量级CNN,相比于传统卷积神经网络,在准确率小幅度降低的前提下大大减少模型参数与运算量。

  传统卷积与DW卷积(Depthwise Conv)的差异,在传统卷积中,每个卷积核的channel与输入特征矩阵的channel相等(每个卷积核都会与输入特征矩阵的每一个维度进行卷积运算),输出特征矩阵channel等于卷积核的个数。而在DW卷积中,每个卷积核的channel都是等于1的(每个卷积核只负责输入特征矩阵的一个channel,卷积核的个数=输入特征矩阵的channel数=输出特征矩阵的channel数)

  MobileNet模型是Google针对手机等嵌入式设备提出的一种轻量级的深层神经网络,其使用的核心思想便是深度可分离卷积 depthwise separable convolution

2. 深度可分离卷积(depthwise separable convolution)

2.1 深度可分离卷积通俗理解

  传统的三通道卷积过程如下:

三通道卷积

  那么深度可分离卷积能用到轻量级的网络中,保证效率减少参数量,其具体是如何巧妙设计优化的,下图为深度可分离卷积的运作过程。

点卷积和深度卷积

  深度可分离卷积分为两个部分,Depthwise Convolution (深度卷积)、Pointwise Convolution(点卷积),这是两个不同的卷积过程,传统三通道卷积的过程是一个卷积核的厚度有三层,每一层与输入的feature map的每一层做加权求和,从而生成输出的一个通道,故输出通道数取决于卷积核的数量,卷积核的通道数等同于输入feature map的通道数(对齐)

传统卷积卷积核与输入矩阵的对应关系

  而Depthwise Convolution不同,其卷积核的厚度只有1,对于输入的feature map(特征图谱)的每一个通道,都有一个不同的厚度为1的卷积核相对应(卷积核数量与输入通道数对应),每个卷积核都只对对应通道的feature map做卷积操作,这样得到的每一个通道的卷积操作得到一个1通道的feature map,这样深度卷积之后的输出通道数与输入通道数一致。下图中绿色、红色、黄色表示的不同的通道数为1的卷积核。

深度卷积

  点卷积(Pointwise Convolution)是采用1×11\times11×1大小的卷积核(此时的卷积核是传统卷积核,其通道数与输入通道数相同)分别遍历输入的所有通道,得到的输出通道取决于卷积核的个数,点卷积与传统卷积方式相同,只是卷积核使用1×11\times11×1,起到一个改变通道数的作用,直观意义上讲就是加厚输出的feature map,其实际的意义在于由于深度卷积的方式对于特征提取不够明显,再通过点卷积进行一些信息补偿,在保证参数量减少的情况下,尽可能的让网络的效果保持一个可观的水平。

点卷积

2.2 深度可分离卷积对于参数的优化

  举例说明优化的效果,由于MobileNet是用于嵌入式设备等受限的设备上的网络,其参数肯定是大幅度降低的。

  有下列场景:
  使用3×33\times33×3大小的卷积层,输入通道数为16,输出通道数为32.

  使用传统卷积的方式,需要32个3×33\times33×3的卷积核对16个通道中的每一层数据进行卷积计算,最后得到32个输出通道的feature map,所需要的参数量为:
16×32×3×3=460816\times 32\times 3\times 3=4608 16×32×3×3=4608
  采用深度可分离卷积,由于输入的通道数为16,那么采用16个3×33\times33×3大小的卷积核对16个通道的feature map分别卷积,得到一个16通道的输出feature map,为了得到所需要的32通道的输出,采用点卷积的方式,使用32个1×11\times11×1大小的卷积核遍历16个通道的输入feature map,那么参数量为:
16×3×3+16×32×1×1=65616\times 3\times 3+16\times 32\times 1\times 1=656 16×3×3+16×32×1×1=656
  通过上述实验对比,参数量确实大大减少。

注意:深度可分离卷积指的是深度卷积(Depthwise Conv)+点卷积(Pointwise Conv),而并不是一个dw(Depthwise的缩写)就是一个深度可分离卷积,这个概念混淆度很高

3. MobileNet网络结构

一个深度可分离卷积的结构如下所示:

深度可分离卷积

  首先对输入做深度卷积(Depthwise Conv),深度卷积的特点是是卷积核的个数与处理的输入通道数一致同时每个卷积核通道数都是1,每个1通道卷积核去卷积输入feature map里的一个通道的数据,导致深度卷积处理之后输入与输出的通道数总是不变的。

  深度卷积之后就是BN层,BN层为Batch Normalization,对数据做归一化处理,再通过激活函数,接下来是一个1×11\times11×1的Conv层,其就是点卷积的层,使用1×11\times11×1的卷积核进行卷积操作,改变通道数,再进行归一化和激活输出。

BN的作用以及应用过程已经在笔者的博文《CV学习笔记-Inception》中详细介绍,不再赘述。

MobileNet的网络结构图如下所示

MobileNet

  在此不进行逐层分析,仅对初始几层进行分析,后面的读者可以自行推导,计算过程一致。

  首先输入为224×224×3224\times 224\times 3224×224×3,卷积核的shape为3×3×3×323\times 3\times 3\times 323×3×3×32,通过卷积核的shape,能够看出本次卷积操作采用的是一个传统的卷积计算,卷积核的通道数为3,个数为32,那么得到的输出为112×112×32112\times 112\times 32112×112×32(stride步长为2),此处的通道数32与卷积采用的卷积核个数32对应,之后经过Conv dw层,这个是深度卷积层,dw即Depthwise,输入feature map为112×112×32112\times 112\times 32112×112×32,所用卷积核shape为3×3×323\times 3\times 323×3×32注意与上面一层的卷积层相区别,少了一个维度,因为每一个卷积核的通道数为1,每个1通道卷积核只需要卷积feature map中的一个通道的数据,故经过深度卷积之后的输出通道数不变,输出的feature map为112×112×32112\times 112\times 32112×112×32,然后通过一个点卷积层,卷积核shape为1×1×32×641\times 1\times 32\times 641×1×32×64,即使用64个1×1×1×321\times 1\times 1 \times 321×1×1×32的卷积核进行卷积操作,点卷积卷积的方式与传统的卷积相同,只是在尺寸上采用的1×11\times 11×1的卷积核,用点卷积的方式改变通道数,输出的feature map shape为112×112×64112\times 112\times 64112×112×64,接下来就可以留给读者推算了,深度可分离卷积部分已经作出了分析。

4. 代码实现

4.1 卷积块

  代码按照传统的Conv-BN-Relu组合拳,进行卷积块的定义padding采用same方式

def _conv_block(inputs, filters, kernel=(3, 3), strides=(1, 1)):x = Conv2D(filters, kernel,padding='same',use_bias=False,strides=strides,name='conv1')(inputs)x = BatchNormalization(name='conv1_bn')(x)return Activation(relu6, name='conv1_relu')(x)

4.2 深度可分离卷积块

  深度可分离卷积分为深度卷积和点卷积,x = DepthwiseConv2D([params])即为深度卷积块的定义,使用的是DepthwiseConv2D(),在深度卷积完成BN+Relu后,紧接着接上了一个点卷积模块,x = Conv2D(pointwise_conv_filters,(1, 1)),使用1×11\times 11×1卷积核来改变通道数。

def _depthwise_conv_block(inputs, pointwise_conv_filters,depth_multiplier=1, strides=(1, 1), block_id=1):x = DepthwiseConv2D((3, 3),padding='same',depth_multiplier=depth_multiplier,strides=strides,use_bias=False,name='conv_dw_%d' % block_id)(inputs)x = BatchNormalization(name='conv_dw_%d_bn' % block_id)(x)x = Activation(relu6, name='conv_dw_%d_relu' % block_id)(x)x = Conv2D(pointwise_conv_filters, (1, 1),padding='same',use_bias=False,strides=(1, 1),name='conv_pw_%d' % block_id)(x)x = BatchNormalization(name='conv_pw_%d_bn' % block_id)(x)return Activation(relu6, name='conv_pw_%d_relu' % block_id)(x)

4.3 MobileNet定义

  按照MobileNet的网络结构,将其复现成python程序,整合的就是上面定义的卷积模块和深度可分离卷积模块。(预训练权重文件可以在网络上下载)

def MobileNet(input_shape=[224,224,3],depth_multiplier=1,dropout=1e-3,classes=1000):img_input = Input(shape=input_shape)# 224,224,3 -> 112,112,32x = _conv_block(img_input, 32, strides=(2, 2))# 112,112,32 -> 112,112,64x = _depthwise_conv_block(x, 64, depth_multiplier, block_id=1)# 112,112,64 -> 56,56,128x = _depthwise_conv_block(x, 128, depth_multiplier,strides=(2, 2), block_id=2)# 56,56,128 -> 56,56,128x = _depthwise_conv_block(x, 128, depth_multiplier, block_id=3)# 56,56,128 -> 28,28,256x = _depthwise_conv_block(x, 256, depth_multiplier,strides=(2, 2), block_id=4)# 28,28,256 -> 28,28,256x = _depthwise_conv_block(x, 256, depth_multiplier, block_id=5)# 28,28,256 -> 14,14,512x = _depthwise_conv_block(x, 512, depth_multiplier,strides=(2, 2), block_id=6)# 14,14,512 -> 14,14,512x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=7)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=8)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=9)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=10)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=11)# 14,14,512 -> 7,7,1024x = _depthwise_conv_block(x, 1024, depth_multiplier,strides=(2, 2), block_id=12)x = _depthwise_conv_block(x, 1024, depth_multiplier, block_id=13)# 7,7,1024 -> 1,1,1024x = GlobalAveragePooling2D()(x)x = Reshape((1, 1, 1024), name='reshape_1')(x)x = Dropout(dropout, name='dropout')(x)x = Conv2D(classes, (1, 1),padding='same', name='conv_preds')(x)x = Activation('softmax', name='act_softmax')(x)x = Reshape((classes,), name='reshape_2')(x)inputs = img_inputmodel = Model(inputs, x, name='mobilenet_1_0_224_tf')model_name = 'mobilenet_1_0_224_tf.h5'model.load_weights(model_name)return model

4.4 完整代码

  本代码完成了一个图片的识别,图片如下,可以重命名为elephant.jpg输入网络运行。

美洲象

#-------------------------------------------------------------#
#   MobileNet的网络部分
#-------------------------------------------------------------#
import warnings
import numpy as np# from keras.preprocessing import imagefrom keras.models import Model
from keras.layers import DepthwiseConv2D,Input,Activation,Dropout,Reshape,BatchNormalization,GlobalAveragePooling2D,GlobalMaxPooling2D,Conv2D
from keras.applications.imagenet_utils import decode_predictions
from keras.utils import image_utils as image
from keras import backend as Kdef MobileNet(input_shape=[224,224,3],depth_multiplier=1,dropout=1e-3,classes=1000):img_input = Input(shape=input_shape)# 224,224,3 -> 112,112,32x = _conv_block(img_input, 32, strides=(2, 2))# 112,112,32 -> 112,112,64x = _depthwise_conv_block(x, 64, depth_multiplier, block_id=1)# 112,112,64 -> 56,56,128x = _depthwise_conv_block(x, 128, depth_multiplier,strides=(2, 2), block_id=2)# 56,56,128 -> 56,56,128x = _depthwise_conv_block(x, 128, depth_multiplier, block_id=3)# 56,56,128 -> 28,28,256x = _depthwise_conv_block(x, 256, depth_multiplier,strides=(2, 2), block_id=4)# 28,28,256 -> 28,28,256x = _depthwise_conv_block(x, 256, depth_multiplier, block_id=5)# 28,28,256 -> 14,14,512x = _depthwise_conv_block(x, 512, depth_multiplier,strides=(2, 2), block_id=6)# 14,14,512 -> 14,14,512x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=7)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=8)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=9)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=10)x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=11)# 14,14,512 -> 7,7,1024x = _depthwise_conv_block(x, 1024, depth_multiplier,strides=(2, 2), block_id=12)x = _depthwise_conv_block(x, 1024, depth_multiplier, block_id=13)# 7,7,1024 -> 1,1,1024x = GlobalAveragePooling2D()(x)x = Reshape((1, 1, 1024), name='reshape_1')(x)x = Dropout(dropout, name='dropout')(x)x = Conv2D(classes, (1, 1),padding='same', name='conv_preds')(x)x = Activation('softmax', name='act_softmax')(x)x = Reshape((classes,), name='reshape_2')(x)inputs = img_inputmodel = Model(inputs, x, name='mobilenet_1_0_224_tf')model_name = 'mobilenet_1_0_224_tf.h5'model.load_weights(model_name)return modeldef _conv_block(inputs, filters, kernel=(3, 3), strides=(1, 1)):x = Conv2D(filters, kernel,padding='same',use_bias=False,strides=strides,name='conv1')(inputs)x = BatchNormalization(name='conv1_bn')(x)return Activation(relu6, name='conv1_relu')(x)def _depthwise_conv_block(inputs, pointwise_conv_filters,depth_multiplier=1, strides=(1, 1), block_id=1):x = DepthwiseConv2D((3, 3),padding='same',depth_multiplier=depth_multiplier,strides=strides,use_bias=False,name='conv_dw_%d' % block_id)(inputs)x = BatchNormalization(name='conv_dw_%d_bn' % block_id)(x)x = Activation(relu6, name='conv_dw_%d_relu' % block_id)(x)x = Conv2D(pointwise_conv_filters, (1, 1),padding='same',use_bias=False,strides=(1, 1),name='conv_pw_%d' % block_id)(x)x = BatchNormalization(name='conv_pw_%d_bn' % block_id)(x)return Activation(relu6, name='conv_pw_%d_relu' % block_id)(x)def relu6(x):return K.relu(x, max_value=6)def preprocess_input(x):x /= 255.x -= 0.5x *= 2.return xif __name__ == '__main__':model = MobileNet(input_shape=(224, 224, 3))img_path = 'elephant.jpg'img = image.load_img(img_path, target_size=(224, 224))x = image.img_to_array(img)x = np.expand_dims(x, axis=0)x = preprocess_input(x)print('Input image shape:', x.shape)preds = model.predict(x)print(np.argmax(preds))print('Predicted:', decode_predictions(preds,1))  # 只显示top1

实验输出:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_74390.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一步步教你电脑变成服务器,tomcat的花生壳设置(原创)

1,首先你去https://console.oray.com/这网站注册个帐号,如果注册成功它会送你一个免费域名,当然不记得也没关系,你记住你注册的 帐号跟密码,然后下载它的软件(花生壳动态域名6.0正式版)有xp跟li…

java基础系列(六) sleep()和wait() 区别

一.前言 关于并发编程这块, 线程的一些基础知识我们得搞明白, 本篇文章来说一下这两个方法的区别,对Android中的HandlerThread机制原理可以有更深的理解, HandlerThread源码理解,请查看笔者的这篇博客: HandlerThread源码理解_handlerthread 源码_broadview_java的博客-CSDN博…

安装kibana 报错/访问不了

安装kibana 报错1,elasticsearch.yaml 和kibana.yaml 配置问题2,elasticsearch 和kibana版本不一致3,索引问题1,elasticsearch.yaml 和kibana.yaml 配置问题 我的RPM安装的,配置文件都在/etc/ vim /etc/elasticsearc…

【Python基础】类

面向对象编程 面向对象编程是最有效的软件编写方法之一。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。 面向对象和面向过程的区别 比如我想吃西红柿炒蛋,怎么运用面向过程的方法来解决这个问题呢?…

《高性能MySQL》——MySQL基准测试(笔记)

文章目录二、MySQL基准测试2.1 为什么需要基准测试2.2 基准测试的策略2.2.1 测试何种指标2.3 基准测试方法2.3.1设计和规划基准测试2.3.2 基准测试应该运行多长时间2.3.3 获取系统性能和状态2.3.4 获得准确的测试结果2.3.5 运行基准测试并分析结果2.3.6 绘图的重要性2.4 基准测…

yii-shopwind商城多数页面报错,修改mysql一个配置就解决!

解决办法打开mysql配置文件,在[mysqld]下添加如下一行:sql_modeNO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES成功解决!还以为是网站的代码问题, 惊讶到我了. 开源网站下载下来就报错 多不可思议. 终于是配置的问题!加油报错信息如下是其中一个界面的&…

[MySQL]MySQL数据类型

文章目录数据类型分类数值类型tinyint类型bit类型float类型decimal类型字符串类型char类型varchar类型char和varchar对比日期和时间类型enum和set类型数据类型分类 MySQL中,支持各种各样的类型,比如表示数值的整型浮点型,文本、二进制类型、…

RK3568镜像的拆包和打包

文章目录 前言一、window上分包和打包分包打包二、Linux上分包和打包分包打包总结前言 本文记录在win10上利用瑞芯微提供的工具进行分包和打包,同样也有Linux教程 提示:以下是本篇文章正文内容,下面案例可供参考 一、window上分包和打包 分包 window下一般直接利用工具即…

[oeasy]python0094_视频游戏_双人网球_pong_atari_mos_6502_雅达利_米洛华

编码进化 回忆上次内容 上次 我们回顾了 微软之前的 比尔盖茨和保罗艾伦 mits 迎来的 是帮手还是隐患? intel-8080 遇到了 mos-6502 底层硬件 驱动 游戏行业进化 不光是扑克牌和柏青哥了出现了双人网球 不过 目前的游戏 PDP-1 上的《太空大战》Donner Model 30 上…

信号类型(雷达)——脉冲雷达(三)

系列文章目录 《信号类型(雷达通信)》 《信号类型(雷达)——雷达波形认识(一)》 《信号类型(雷达)——连续波雷达(二)》 文章目录 前言 一、相参雷达 1…

从中国文化看面试挑人标准

文章目录标准一、面相1. 1 四白眼1.2 浓眉二、讲话2.1 言多与气虚总结本文结合中国面相,是个概率性问题,对于个体无效。 标准 正直,三观正,沟通好,技术。从概率上讲: 正直且三观正的人----有恒心&#x…

Android OTA 相关工具(四) 查看 payload 文件信息

文章目录1. payload_info.py 的使用1. 环境2. 帮助信息2. 查看 payload 文件信息1. 不带选项查看2. 使用 stats 选项查看3. 使用 signagures 选项4. 使用 list_ops 选项查看3. 其它一直以来,很多人都表达过很想去研究一下 Android OTA 的 payload 文件,看…

Guna Charts WinForm 1.0.8 Crack

Guna Charts 16 图表 在 16 种不同的图表类型中可视化您的数据。 Guna Charts 反应灵敏 轻松响应屏幕尺寸的变化。 Guna Charts 实时图表 创建实时数据仪表板现在非常容易。 Guna Charts 混合图表类型 混合多种图表类型,例如条形图和折线图/面积图。 Guna Charts…

26 openEuler管理网络-使用ip命令配置网络

文章目录26 openEuler管理网络-使用ip命令配置网络26.1 配置IP地址26.1.1 配置静态地址26.1.2 配置多个地址26.2 配置静态路由26 openEuler管理网络-使用ip命令配置网络 说明: 使用ip命令配置的网络配置可以立即生效但系统重启后配置会丢失。 26.1 配置IP地址 使用…

基于stm32电梯管理系统设计

基于stm32电梯管理系统设计这里记录一下以前自己做的嵌入式课程设计,报告中的图片和文字太多了,全部一个一个把搬过来太麻烦了,需要完整文本和代码自行q我963160156,也可在微信公众号 *高级嵌入式软件* 里回复 *电梯* 查看完整版文章摘要关键…

Redis 之企业级解决方案

文章目录一、缓存预热二、缓存雪崩三、缓存击穿四、缓存穿透五、性能指标监控5.1 监控指标5.2 监控方式🍌benchmark🍌monitor🍌slowlog提示:以下是本篇文章正文内容,Redis系列学习将会持续更新 一、缓存预热 1.1 现象…

ctf pwn基础-4

今天是学pwn的第四天,去接触了pwn的整数溢出。 目录 基础 实例讲解 实例讲解2 基础 关于整数溢出,这里以int为例,因为我php之前搞的比较多,以为这个int也是想php一样是64,最大值是9开头的那个,闹了不少笑…

QML Animation动画详解

1.Animation简介 Animation类型提供了四个属性: alwaysRunToEnd:该属性接收布尔类型的参数。该属性保存动画是否运行到完成才停止。当loops属性被设置时,这个属性是最有用的,因为动画将正常播放结束,但不会重新启动。…

算法进阶-动态规划

经典例题 大家肯定想用递归做 思路大概就是这样 递归到最后一行就是对应的D(i,j) 然后往上推 但是这样会超时,因为存在大量的重复计算 比如调用第一行MasSum(7)需要调用MaxSum(3)和MaxSum(8) 但是调用第二行MaxSum(3)还要调用3行的MaxSum(8)和3行的MaxSum(1) 第二行…

人工智能-机器视觉篇搞定(笔记)

考书目《人工智能之机器视觉》–程晨 1.从计算机读取一张图片显示 ##获取图片 import cv2 imcv2.imread("im.jpg") cv2.imshow("my",im) cv2.waitKey() cv2.destroyAllWindows()2.显示视频帧 import cv2 #cap cv2.VideoCapture("video.mp4")获…