CNN中卷积池化层tensorflow内置函数参数的实际含义及作用

前段时间亲手搭建了CNN模型,使用tensorflow的许多内置函数时其中的参数数值都是借鉴别人的配置,对其中道理并不了解。昨天和mentor sync的时候真的觉得好惭愧,知其然不知其所以然一问就尴尬==这篇文章总结一下这些参数的含义和设置吧~

1. 卷积层和input的channel

在CNN中,想搞清楚每一层的传递关系,主要就是 height,width 和 channels 的变化情况。

首先看内置函数conv2d(卷积层)

conv2d

其中input是输入, filter是卷积核

input : [batch, in_height, in_width, in_channels] , 
filter : [filter_height, filter_width, in_channels, out_channels] 

因为进行计算的时候是卷积核和input的部分tensor进行卷积,所以input.in_channel === filter.in_channels。看一下图示:

假设现有一个为 6×6×3 的图片样本,使用 3×3×3 的卷积核(filter)进行卷积操作。此时输入图片的 channels 为 3(stride=1) ,而卷积核中的 in_channels 与 需要进行卷积操作的数据的 channels 一致(这里就是图片样本,为3)。卷积操作,卷积核中的27个数字与分别与样本对应相乘后,再进行求和,得到第一个结果。依次进行,最终得到 4×4 的结果。步骤完成后,由于只有一个卷积核,所以最终得到的结果为 4×4×1 , out_channels 为 1。所以out.channel就是卷积核的数量,一般都会使用不止一个卷积核(我的理解是分别投影到不同的空间,可以防止单核的过拟合,下面讲feature map的作用会分析)。

cnn

图一

å个å·ç§¯æ ¸

图二

总结一下,把上面提到的 channels 分为三种:

  • 最初输入的图片样本的 channels ,取决于图片类型,比如RGB;
  • 卷积操作完成后输出的 out_channels ,取决于卷积核的数量。此时的 out_channels 也会作为下一次卷积时的卷积核的 in_channels
  • 卷积核中的 in_channels ,刚刚2中已经说了,就是上一次卷积的 out_channels ,如果是第一次做卷积,就是1中样本图片的 channels 。
  • 最后,对于输入样本,一般的RGB图片,channels数量是 3 (红、绿、蓝);而monochrome图片,channels 数量是 1 。

2. filter, feature map以及如何实现权值共享

CNN之所以适合进行图像处理原因之一是它解决了传统NN的指数爆炸权重的计算问题,解决方式就是在同一个featur e马屁中可以权重共享。所谓的feature map,就是同一个卷积核和input卷积的结果。如图二只有一个卷积核,最后卷积的4*4matrix就是一个feature map,  feature map的每个点都是一个神经元的输出。所以 神经元个数 = 特征图大小。

CNN权值共享就是同一个Feature Map中神经元权值共享,该Feature Map中的所有神经元使用同一个权值。这与全连接相比,参数减少太多了(整个图像的矩阵大小到卷积核的矩阵大小)

feature map 和 神经元的关系:

  • 单个卷积核情况下:

 神经元是 前一层wx+b 到下一层的计算过程,所谓这一层的连接数,也就是有多少个连接(shape(filter)+1)(一个卷积核有多个w只有一个bias
 一个feature map 是多个(比如M个)神经元计算的结果汇总

  • 多个卷积核情况下:

同一层可以有多个(比如N个)卷积核,每个卷积核对应(卷积的结果是)一个feature map ,也就是这一层有N个feature map, 那这一层共有 N*M个神经元。(如果每个fm的神经元个数不一样,则累加每个fm的神经元个数)
---------------------

煮个栗子: 

输入input: 32 x 32 的图像
使用:    6个 5x5  stride为 1的卷积核

神经元 个数: (32-5+1) * (32 -5 +1) = 28 * 28 个。也就是每一个feature map的大小就是28 * 28 。  
其中,32-5是卷积核可以滑过并得到一次计算结果的次数(因为步幅是1),+1是卷积核放在最开始的位置上还没开始滑动时的一次计算结果。
那么这一层一共有 (5*5 +1)*6个可训练参数,其中5*5为卷积核的大小,1为一个bias参数, 6为6种卷积核。
注意如果是三通道,三个通道的权重并不共享。 所以对于以上的计算,三通道的参数数量应该还要乘以3。


为什么要使用多个卷积核生成多个feature map?

  • 使用多层卷积:

在卷积神经网络中,我们希望用一个网络模拟视觉通路的特性,分层的概念是自底向上构造简单到复杂的神经元。

  • 同一层中使用多个卷积核:

我们希望构造一组基,这组基能够形成对于一个事物完备的描述,例如描述一个人时我们通过描述身高/体重/相貌等,在卷积网中也是如此。在同一层,我们希望得到对于一张图片多种角度的描述,具体来讲就是用多种不同的卷积核对图像进行卷,得到不同核(这里的核可以理解为描述)上的响应,作为图像的特征。他们的联系在于形成图像在同一层次不同基上的描述。

下层的核主要是一些简单的边缘检测器(更细节的描述特征,也可以理解为生理学上的simple cell)。

上层的核主要是一些简单核的叠加(或者用其他词更贴切),可以理解为complex cell。


如何选取适当的卷积核个数?

某层卷积核的个数,有多少个卷积核,经过卷积就会产生多少个feature map,也就是下图中 `豆腐皮儿`的层数、同时也是下图`豆腐块`的深度(宽度)!!这个宽度可以手动指定,一般网络越深的地方这个值越大,因为随着网络的加深,feature map的长宽尺寸缩小,本卷积层的每个map提取的特征越具有代表性(精华部分),所以后一层卷积层需要增加feature map的数量,才能更充分的提取出前一层的特征,一般是成倍增加(不过具体论文会根据实验情况具体设置)


卷积核的运算过程
例如输入224x224x3(rgb三通道),输出是32位深度,卷积核尺寸为5x5。

那么我们需要32个卷积核,每一个的尺寸为5x5x3(最后的3就是原图的rgb位深3),每一个卷积核的每一层是5x5(共3层)分别与原图的每层224x224卷积,然后将得到的三张新图叠加(算术求和),变成一张新的feature map。 每一个卷积核都这样操作,就可以得到32张新的feature map了。  也就是说:

不管输入图像的深度为多少,经过一个卷积核(filter),最后都通过下面的公式变成一个深度为1的特征图。不同的filter可以卷积得到不同的特征,也就是得到不同的feature map。D就是卷积核的个数,F就是卷积核的宽度(一般width=height)

CNN的学习过程:更新卷积核的值(更新提取的图像特征)
因为卷积核实际上就是如3x3,5x5这样子的权值(weights)矩阵。我们的网络要学习的,或者说要确定下来的,就是这些权值(weights)的数值。网络不断前后向的计算学习,一直在更新出合适的weights,也就是一直在更新卷积核们。卷积核在更新了,学习到的特征也就被更新了(因为卷积核的值(weights)变了,与上一层的map卷积计算的结果也就变了,得到的新map就也变了。)。对分类问题而言,目的就是:对图像提取特征,再以合适的特征来判断它所属的类别。类似这种概念:你有哪些个子的特征,我就根据这些特征,把你划分到某个类别去。

这样就很说的通了,卷积神经网络的一整套流程就是:更新卷积核参数(weights),就相当于是一直在更新所提取到的图像特征,以得到可以把图像正确分类的最合适的特征们。(一句话:更新weights以得到可以把图像正确分类的特征。) 

3. 各层的作用(对于优化问题的作用)

卷积层与池化层的作用在于: 
1. invariance(不变性),这种不变性包括translation(平移),rotation(旋转),scale(尺度); 
2. 保留主要的特征同时减少参数(降维,效果类似PCA)和计算量,防止过拟合,提高模型泛化能力。

卷积层的示意图:

è¿éåå¾çæè¿°

 

池化层与卷积层的作用、计算方法类似,也有池化filter、步长、填充方式等参数,所不同的是,池化计算比较简单,常取filter覆盖部分的最大值、或者均值,分别称之为最大池化、平均池化,最大池化的示意图如下所示: 最大池化的filter shape为(2,2), 步长也为(2,2),每个filter滑动覆盖处取最大值,得到右侧所示的结果。
 è¿éåå¾çæè¿°

 全连接层在整个卷积神经网络中起到“分类器”的作用、也是模型表示能力的“防火墙”。全连接层的运算形如X*W+b,X*W为矩阵乘法,其中X为输入2维数组(shape为[batch_size, k]),W为权重2维数组(shape为[k,out_k]),b为偏置,W的第2个元素(out_k)决定了全连接层运算后输出的2维数组形状(shape为[batch_size, out_k])。 
由于全连接层参数冗余(仅全连接层参数就可占整个网络参数80%左右),需要使用tf.nn.dropout来随机丢弃一些节点,或者使用一些性能优异的网络模型如ResNet和GoogLeNet等来取代全连接层融合学到的深度特征。

扁平化(Flatten)层将上一层得到的全部feature map拉直成列向量,作为全连接网络的输入。拉直方式为height*width*channels。 

输出层运算与全连接层类似,只是在设定运算参数时输出节点数量需与分类标记数量相一致,并且在运算完成后再使用tf.nn.softmax函数,得到测试图像属于各分类的概率,该所有概率值之和为1。 

4. conv2d,max_pool,flatten, dropout中一些参数说明

tf.nn.conv2d(
    input,
    filter,
    strides,
    padding,
    use_cudnn_on_gpu=True,
    data_format='NHWC',
    dilations=[1, 1, 1, 1],
    name=None
)
  • input:需要做卷积的输入图像,它要求是一个Tensor,shape为[batch, in_height, in_width, in_channels],具体含义是[训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数],注意这是一个4维的Tensor,要求类型为float32和float64其中之一;
  • filter:相当于CNN中的卷积核,它要求是一个Tensor,shape为[filter_height, filter_width, in_channels, out_channels],具体含义是[卷积核的高度,卷积核的宽度,图像通道数,卷积核个数],要求类型与参数input相同,filter的通道数要求与input的in_channels一致,有一个地方需要注意,第三维in_channels,就是参数input的第四维;
  • strides:卷积时在图像每一维的步长,这是一个一维的向量,长度4,strides[0]=strides[3]=1;
  • padding:string类型的量,只能是”SAME”、”VALID”其中之一,这个值决定了不同的卷积方式;卷积运算时卷积核滑动过程中当输入图像(input)的in_height、in_width不是filter的filter_height、filter_width的整数倍时,”SAME”方式是在input周围填充0以将其in_height、in_width补充为filter相应部分的整数倍,”VALID”方式将input的多余部分丢弃,详细介绍请参看这里;
  • use_cudnn_on_gpu:bool类型,是否使用cudnn加速,默认为true;
  • data_format:指定输入数据、输出数据的格式,取值为”NHWC”、”NCHW”,前者对应于 [batch, height, width, channels],后者对应于 [batch, channels, height, width],默认为’NHWC’。
  • dilations:一个可选的ints列表;默认为[1,1,1,1]。长度为4的一维张量,每个input维度的膨胀系数; 如果设置为k> 1,则每个该维度上的过滤器元素之间会有k-1个跳过的单元格; 维度顺序由data_format的值决定; 在Dilations中批次和深度尺寸必须为1;
  • name:为该操作指定名称;
  • 返回值:Tensor,也就是我们常说的feature map。

输入图像经过卷积运算后,其高度、宽度变为—— 
‘SAME’ 类型的padding,其输出的height和width计算如下: 
out_height = ceil(float(in_height) / float(strides[1])) ceil:向上取整 
out_width = ceil(float(in_width) / float(strides[2]))

‘VALID’类型的padding, 其输出的height和width计算如下: 
out_height = ceil(float(in_height – filter_height + 1) / float(strides[1])) 
out_width = ceil(float(in_width – filter_width + 1) / float(strides[2]))
 


tf.nn.max_pool(
    value,
    ksize,
    strides,
    padding,
    data_format='NHWC',
    name=None
)

 

池化层参数说明如下:

value:输入4D张量, 其格式由data_format指定;
ksize:含有4个元素的1D张量,指定池化核的尺寸;
strides:含有4个元素的1D int 张量,指定池化时在图像每一维的步长,strides[0]=strides[3]=1;
padding: 边界填充方式,string类型的量,只能是”SAME”、”VALID”其中之一;
data_format:数据格式,string类型的量, 只能是’NHWC’、 ‘NCHW’ 、’NCHW_VECT_C’ 其中之一;
name:为该操作指定名称;
返回值: Tensor,也就是我们常说的feature map。
上层feature map经池化运算后,其batch、channels均不发生变化,只有height、width会发生变化,输出height、width计算方式同卷积层。
 


tf.contrib.layers.flatten(
    inputs,
    outputs_collections=None,
    scope=None
)

扁平化层

inputs:形如 [batch_size, …]的张量,注意张量的第1个元素必须为batch_size;
outputs_collections:添加到输出的集合;
scope:name_scope的可选范围。
返回值:形如[batch_size, k]的扁平化张量。
图像分类模型训练完成后,本层返回张量的shape(主要是k)就确定了,从而限定了模型预测时输入图像的尺寸——因为在模型确定的情况下,卷积层、池化层等结构、数量均不再改变,预测图像与训练图像尺寸一致时,经卷积、池化等运算后,扁平化输出shape与模型一致;预测图像与训练图像尺寸不一致时,经卷积、池化等运算后,扁平化输出的shape与模型不一致,从而无法继续运算。这也是迁移学习时,预训练模型均约定输入图像height、width的原因。

从该层开始,分类模型的网络结构类似于“多层前馈神经网络”。
 


tf.nn.dropout(
    x,
    keep_prob,
    noise_shape=None,
    seed=None,
    name=None
)

x: A floating point tensor.
keep_prob: A scalar Tensor with the same type as x. The probability that each element is kept.
noise_shape: A 1-D Tensor of type int32, representing the shape for randomly generated keep/drop flags.
seed: A Python integer. Used to create random seeds. See tf.set_random_seed for behavior.
name: A name for this operation (optional).
Returns: A Tensor of the same shape of x.
 

5. 完整模型

batch为训练时每批输入的图像数量,视训练环境的硬件配置而定,本文设置为512
卷积核height,width:(3,3)
卷积步长:(1,1,1,1)
卷积 padding:SAME
激活函数:tf.nn.relu
最大池化height,width:(2,2)
最大池化步长:(1,2,2,1)
池化 padding:SAME
Dropout时保留节点的比例:0.5
Epochs(训练轮数):30
训练构建好的CNN图像分类模型时,单张图片用3D数组表示,多张图片用4D数组表示,经过卷积、激活函数、池化、扁平化、全连接、Dropout等运算,其batch、height、width、channels、feature map数量、节点数量、数据shape有的会发生变化,有的不会发生变化,如下表所示:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章