作者: 邓红卫,衡阳师范学院信息工程学院副院长,教授
一、卷积神经网络的padding规则
(一)卷积函数 tf.nn.conv2d
TensorFlow里使用tf.nn.conv2d函数来实现卷积,其格式如下。
tf.nn.conv2d (input, filter, strides, padding, use_ cudnn on_ gpu=None,name=None)
除去参数name参数用以指定该操作的name,与方法有关的共有5个参数。
(1)input: 指需要做卷积的输入图像,它要求是一个Tensor, 具有[batch, in_height,in_width, in_channels]这样的形状,具体含义是“训练时一个batch的图片数量, 图片高度,图片宽度,图像通道数”,注意这是一个四维的Tensor,要求类型为float32和float64其中之一。
(2)filter: 相当于中的卷积核,它要求是一个Tensor, 具有[filter_height, filter_width,in_channels, out_channels]这样的形状,具体含义是“卷积核的高度,滤波器的宽度,图像通道数,滤波器个数”,要求类型与参数input相同。有一个地方需要注意,第三维in_channels,就是参数input的第四维。
(3)strides:卷积时在图像每一维的步长, 这是一个一维的向量,长度为4(分别是[batch方向,height方向,width方向,channels方向)很多同学只认为第一维和最后一维默认必须置1,其实strides参数确定了滑动窗口在各个维度上移动的步数。
(4)padding: 定义元素边框与元素内容之间的空间。string类型的量,只能是SAME和VALID其中之一,这个值决定了不同的卷积方式,padding 的值为VALID时,表示边缘不填充,当其为’SAME时,表示填充到滤波器可以到达图像边缘。
(5)use_ cudnn on_ gpu: bool类型,是否使用cudnn加速,默认为true.
(6)返回值: tf.nn.conv2d函数结果返回一个Tensor, 这个输出就是常说的feature map.
注意:
在卷积函数中, padding参数是最容易引起歧义的,该参数仅仅决定是否要补0,因此一定要清楚padding设为SAME的真正含义。在设为SAME的情况下,只有在步长为1时生成的feature map才会与输入值相等。
(二)padding规则介绍
padding属性的意义是定义元素边框与元素内容之间的空间。
在tf.nn.conv2d函数中,当变量padding为VALID和SAME时,行列数具体是怎么计算的呢?其实是有公式的。为了方便演示,先来定义几个变量:
输入的尺寸中高和宽定义成in_height、in_width。
卷积核的高和宽定义成filter_height、filter_width。
输出的尺寸中高和宽定义成output_height、output_widh。
步长的高宽方向定义成strides_height、 strides_width。
1.VALID情况
输出宽和高的公式代码分别为:
output_width = (in_width - filter_width + 1)/strides_width (结果问上取整)output_height = (in_height - filter_height + 1)/strides_height (结果向上取整)
2.SAME情况
输出的宽和高将与卷积核没有关系,具休公式代码如下:
out_height = in_height / strides_height (结果向上取整)out_width = in_width / strides_width (结果向上取整)
这里有一个很重要的知识点一补零的规则,见如下代码:
pad_height = max( (out_height - 1) X strides_height + filter_height - in_height,0)pad_width = max((out_width - 1) X strides_width + filter_width - in_width, 0)pad_top = pad_height / 2(结果取整)pad_bottom = pad_height - pad_ toppad_left = pad_width / 2(结果取整)pad_right = pad_width - pad_left
可以看到补零的规则是优先在输入矩阵的右边和底边补零,例如补零的行数为三行。则top一行,bottom两行;如果补零的行数为一行,则补在bottom。因为filter是从左向右从上到下滑动的,所以滑动到右边或者底边的时候有可能会因为大步长而损失边界信息,所以优先在右边和底边补零。
注意:
pad_height代表高度方向填充0的行数,pad_width代表宽度方向填充0的列数,以此类推。
二、卷积函数使用实例详解
(一) 源程序
import tensorflow as tf # [batch, in_height, in_width, in_channels] [训练时一个batch的图片数量, 图片高度, 图片宽度, 图像通道数] input = tf.Variable(tf.constant(1.0,shape = [1, 5, 5, 1]))input2 = tf.Variable(tf.constant(1.0,shape = [1, 5, 5, 2]))input3 = tf.Variable(tf.constant(1.0,shape = [1, 4, 4, 1])) # [filter_height, filter_width, in_channels, out_channels] [卷积核的高度,卷积核的宽度,图像通道数,卷积核个数] filter1 = tf.Variable(tf.constant([-1.0,0,0,-1],shape = [2, 2, 1, 1]))filter2 = tf.Variable(tf.constant([-1.0,0,0,-1,-1.0,0,0,-1],shape = [2, 2, 1, 2]))filter3 = tf.Variable(tf.constant([-1.0,0,0,-1,-1.0,0,0,-1,-1.0,0,0,-1],shape = [2, 2, 1, 3]))filter4 = tf.Variable(tf.constant([-1.0,0,0,1, -1.0,0,0,2, -1.0,0,0,3, -1.0,0,0,4],shape = [2, 2, 2, 2]))filter5 = tf.Variable(tf.constant([-1.0,0,0,-1,-1.0,0,0,-1],shape = [2, 2, 2, 1])) # padding的值为‘VALID’,表示边缘不填充, 当其为‘SAME’时,表示填充到卷积核可以到达图像边缘 op1 = tf.n