深度可分离卷积结构(depthwise separable convolution)计算复杂度分析
2017-11-29 09:16
441 查看
https://zhuanlan.zhihu.com/p/28186857
这个例子说明了什么叫做空间可分离卷积,这种方法并不应用在深度学习中,只是用来帮你理解这种结构。
在神经网络中,我们通常会使用深度可分离卷积结构(depthwise separable convolution)。
这种方法在保持通道分离的前提下,接上一个深度卷积结构,即可实现空间卷积。接下来通过一个例子让大家更好地理解。
假设有一个3×3大小的卷积层,其输入通道为16、输出通道为32。具体为,32个3×3大小的卷积核会遍历16个通道中的每个数据,从而产生16×32=512个特征图谱。进而通过叠加每个输入通道对应的特征图谱后融合得到1个特征图谱。最后可得到所需的32个输出通道。
针对这个例子应用深度可分离卷积,用1个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模型的效果可以看出,这种方法是比较有效的。由于能够有效利用参数,因此深度可分离卷积也可以用于移动设备中。
https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet_v1.py
src conv: 1045417824
DepthSepConv: 126373376
compare: 0.12088312739538674
这个例子说明了什么叫做空间可分离卷积,这种方法并不应用在深度学习中,只是用来帮你理解这种结构。
在神经网络中,我们通常会使用深度可分离卷积结构(depthwise separable convolution)。
这种方法在保持通道分离的前提下,接上一个深度卷积结构,即可实现空间卷积。接下来通过一个例子让大家更好地理解。
假设有一个3×3大小的卷积层,其输入通道为16、输出通道为32。具体为,32个3×3大小的卷积核会遍历16个通道中的每个数据,从而产生16×32=512个特征图谱。进而通过叠加每个输入通道对应的特征图谱后融合得到1个特征图谱。最后可得到所需的32个输出通道。
针对这个例子应用深度可分离卷积,用1个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的一个参数列表,计算的普通卷积与深度分离卷积的计算复杂程度比较https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet_v1.py
# Tensorflow mandates these. from collections import namedtuple import functools import tensorflow as tf slim = 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 layer Conv = 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 = 160 inputdepth = 3 conv_defs = _CONV_DEFS sumcost = 0 for 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_size print("src conv: ", sumcost) input_size = 160 inputdepth = 3 conv_defs = _CONV_DEFS sumcost1 = 0 for 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_size print("DepthSepConv:", sumcost1) print("compare:", sumcost1 / sumcost)
src conv: 1045417824
DepthSepConv: 126373376
compare: 0.12088312739538674
相关文章推荐
- 【Tensorflow】tf.nn.depthwise_conv2d如何实现深度卷积?
- 深度学习方法(十一):卷积神经网络结构变化——Google Inception V1-V4,Xception(depthwise convolution)
- 深度学习方法(十一):卷积神经网络结构变化——Google Inception V1-V4,Xception(depthwise convolution)
- 【Tensorflow】tf.nn.depthwise_conv2d如何实现深度卷积?
- 深度学习方法(十一):卷积神经网络结构变化——Google Inception V1-V4,Xception(depthwise convolution)
- 【深度学习】Depthwise Sparable Convolution(Xception的核心模块)
- caffe改进:prelu layer,cudnn batch norm layer,以及convolution depthwise separable layer
- 【Tensorflow】tf.nn.separable_conv2d如何实现深度可分卷积?
- [Paper note] Xception: Deep Learning with Depthwise Separable Convolutions
- 微软基于Web计算的框架结构分析
- 【数据结构与算法学习笔记】PART1:算法分析(计算,计算模型,大O记号,算法分析,迭代与递归,动态控制)
- leetcode:Maximum Depth of Binary Tree(计算二叉树深度) 【面试算法】
- [转载]对深度可分离卷积、分组卷积、扩张卷积、转置卷积(反卷积)的理解
- Google分析用户页面滚动深度分析jQuery插件 - jQuery Scroll Depth
- 数据结构——二叉树遍历、深度、叶子节点数计算
- 深度学习方法(十二):卷积神经网络结构变化——Spatial Transformer Networks
- 神经网络卷积结构及计算过程
- 经典重读 | 深度学习方法:卷积神经网络结构变化——Spatial Transformer Networks
- 【数据结构】根据主定理,计算时间复杂度
- 深度卷积网络图像风格转移(二)架构分析