博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
深度可分离卷积结构(depthwise separable convolution)计算复杂度分析
阅读量:6298 次
发布时间:2019-06-22

本文共 4219 字,大约阅读时间需要 14 分钟。

这个例子说明了什么叫做空间可分离卷积,这种方法并不应用在深度学习中,只是用来帮你理解这种结构。

在神经网络中,我们通常会使用深度可分离卷积结构(depthwise separable convolution)。

这种方法在保持通道分离的前提下,接上一个深度卷积结构,即可实现空间卷积。接下来通过一个例子让大家更好地理解。

假设有一个3×3大小的卷积层,其输入通道为16、输出通道为32。具体为,32个3×3大小的卷积核会遍历16个通道中的每个数据,从而产生16×32=512个特征图谱。进而通过叠加每个输入通道对应的特征图谱后融合得到1个特征图谱。最后可得到所需的32个输出通道。

针对这个例子应用深度可分离卷积,用16个3×3大小的卷积核分别遍历16通道的数据,得到了16个特征图谱。在融合操作之前,接着用32个1×1大小的卷积核遍历这16个特征图谱,进行相加融合。这个过程使用了16×3×3+16×32×1×1=656个参数,远少于上面的16×32×3×3=4608个参数。

这个例子就是深度可分离卷积的具体操作,其中上面的深度乘数(depth multiplier)设为1,这也是目前这类网络层的通用参数。

这么做是为了对空间信息和深度信息进行去耦。从Xception模型的效果可以看出,这种方法是比较有效的。由于能够有效利用参数,因此深度可分离卷积也可以用于移动设备中。

 

src convolution

  input                              output

M*N*Cin                      M*N*Cout

             16*3*3*32

depthwise separable convolution

  input                       output1                          output2

M*N*Cin                 M*N*Cin                       M*N*Cout

               16*3*3                       16*32*1*1

 

另外一个地方看到的解释:

MobileNet-v1:

MobileNet主要用于移动端计算模型,是将传统的卷积操作改为两层的卷积操作,在保证准确率的条件下,计算时间减少为原来的1/9,计算参数减少为原来的1/7.

MobileNet模型的核心就是将原本标准的卷积操作因式分解成一个depthwise convolution和一个1*1的pointwise convolution操作。简单讲就是将原来一个卷积层分成两个卷积层,其中前面一个卷积层的每个filter都只跟input的每个channel进行卷积,然后后面一个卷积层则负责combining,即将上一层卷积的结果进行合并。 

depthwise convolution:

比如输入的图片是Dk*Dk*M(Dk是图片大小,M是输入的渠道数),那么有M个Dw*Dw的卷积核,分别去跟M个渠道进行卷积,输出Df*Df*M结果

pointwise convolution:

对Df*Df*M进行卷积合并,有1*1*N的卷积,进行合并常规的卷积,输出Df*Df*N的结果

上面经过这两个卷积操作,从一个Dk*Dk*M=>Df*Df*N,相当于用Dw*Dw*N的卷积核进行常规卷积的结果,但计算量从原来的DF*DF*DK*DK*M*N减少为DF*DF*DK*DK*M+DF*DF*M*N.

 

第一层为常规卷积,后面接着都为depthwise convolution+pointwise convolution,最后两层为Pool层和全连接层,总共28层.

下面的代码是mobilenet的一个参数列表,计算的普通卷积与深度分离卷积的计算复杂程度比较

# Tensorflow mandates these.from collections import namedtupleimport functoolsimport tensorflow as tfslim = tf.contrib.slim# Conv and DepthSepConv namedtuple define layers of the MobileNet architecture# Conv defines 3x3 convolution layers# DepthSepConv defines 3x3 depthwise convolution followed by 1x1 convolution.# stride is the stride of the convolution# depth is the number of channels or filters in a layerConv = namedtuple('Conv', ['kernel', 'stride', 'depth'])DepthSepConv = namedtuple('DepthSepConv', ['kernel', 'stride', 'depth'])# _CONV_DEFS specifies the MobileNet body_CONV_DEFS = [    Conv(kernel=[3, 3], stride=2, depth=32),    DepthSepConv(kernel=[3, 3], stride=1, depth=64),    DepthSepConv(kernel=[3, 3], stride=2, depth=128),    DepthSepConv(kernel=[3, 3], stride=1, depth=128),    DepthSepConv(kernel=[3, 3], stride=2, depth=256),    DepthSepConv(kernel=[3, 3], stride=1, depth=256),    DepthSepConv(kernel=[3, 3], stride=2, depth=512),    DepthSepConv(kernel=[3, 3], stride=1, depth=512),    DepthSepConv(kernel=[3, 3], stride=1, depth=512),    DepthSepConv(kernel=[3, 3], stride=1, depth=512),    DepthSepConv(kernel=[3, 3], stride=1, depth=512),    DepthSepConv(kernel=[3, 3], stride=1, depth=512),    DepthSepConv(kernel=[3, 3], stride=2, depth=1024),    DepthSepConv(kernel=[3, 3], stride=1, depth=1024)]input_size = 160inputdepth = 3conv_defs = _CONV_DEFSsumcost = 0for i, conv_def in enumerate(conv_defs):    stride = conv_def.stride    kernel = conv_def.kernel    outdepth = conv_def.depth    output_size = round((input_size - int(kernel[0] / 2) * 2) / stride)    if isinstance(conv_def, Conv):        sumcost += output_size * output_size * kernel[0] * kernel[0] * inputdepth * outdepth    if isinstance(conv_def, DepthSepConv):        sumcost += output_size * output_size * kernel[0] * kernel[0] * inputdepth * outdepth    inputdepth = outdepth    input_size = output_sizeprint("src conv:    ", sumcost)input_size = 160inputdepth = 3conv_defs = _CONV_DEFSsumcost1 = 0for i, conv_def in enumerate(conv_defs):    stride = conv_def.stride    kernel = conv_def.kernel    outdepth = conv_def.depth    output_size = round((input_size - int(kernel[0] / 2) * 2) / stride)    if isinstance(conv_def, Conv):        sumcost1 += output_size * output_size * kernel[0] * kernel[0] * inputdepth * outdepth    if isinstance(conv_def, DepthSepConv):        #sumcost += output_size * output_size * kernel[0] * kernel[0] * inputdepth * outdepth        sumcost1 += output_size * output_size *(inputdepth * kernel[0] * kernel[0]  + inputdepth * outdepth * 1 * 1)    inputdepth = outdepth    input_size = output_sizeprint("DepthSepConv:", sumcost1)print("compare:", sumcost1 / sumcost)

src conv:            1045417824

DepthSepConv:   126373376
compare: 0.12088312739538674

 mobilenet V1介绍

转载地址:http://dtlta.baihongyu.com/

你可能感兴趣的文章
淘宝天猫上新辅助工具-新品填表
查看>>
再学 GDI+[43]: 文本输出 - 获取已安装的字体列表
查看>>
nginx反向代理
查看>>
操作系统真实的虚拟内存是什么样的(一)
查看>>
hadoop、hbase、zookeeper集群搭建
查看>>
python中一切皆对象------类的基础(五)
查看>>
modprobe
查看>>
android中用ExpandableListView实现三级扩展列表
查看>>
%Error opening tftp://255.255.255.255/cisconet.cfg
查看>>
java读取excel、txt 文件内容,传到、显示到另一个页面的文本框里面。
查看>>
《从零开始学Swift》学习笔记(Day 51)——扩展构造函数
查看>>
python多线程队列安全
查看>>
[汇编语言学习笔记][第四章第一个程序的编写]
查看>>
android 打开各种文件(setDataAndType)转:
查看>>
补交:最最原始的第一次作业(当时没有选上课,所以不知道)
查看>>
Vue实例初始化的选项配置对象详解
查看>>
PLM产品技术的发展趋势 来源:e-works 作者:清软英泰 党伟升 罗先海 耿坤瑛
查看>>
vue part3.3 小案例ajax (axios) 及页面异步显示
查看>>
浅谈MVC3自定义分页
查看>>
mybatis学习
查看>>