当前位置: 网站首页 > 拉斯维加斯3499手机版

记录:TensorFlow 中的 padding 方式

2019-07-04来源:www.33665357.com

TensorFlow 中卷积操作和池化操作中都有一个参数 padding,其可选值有 ["VALID", "SAME"]

在 TensorFlow 文档中只是给出了输出张量的维度计算方式,但是并没有说明当 padding="SAME" 时,如何进行补零操作。

其给出的输出张量的维度计算公式:

VALID 方式:

output_shape[i] = ceil((input_shape[i] - (filter_shape[i] - 1) * dilation_rate[i]) / strides[i])# 但实际上几乎不会去管 dilation_rate 参数,都是 1,于是output_shape[i] = ceil((input_shape[i] - filter_shape[i] + 1) / strides[i])# 上式也是常见的output_shape[i] = floor((input_shape[i] - filter_shape[i]) / strides[i]) + 1# 一般我们只对图像平面上做卷积和池化,也就是一般 i 指的是图像平面上的 height 和 width View Code

 

SAME 方式:

output_shape[i] = ceil(input_shape[i] / strides[i])View Code

VALID 方式其实是很好理解的,主要是 SAME 的 padding 方式,应该怎么样补零?

假设输入的张量平面上是 W×W 的矩阵,不考虑 batch 和 channel 这两个维度;filter 是 w×w 的矩阵;strides=[s, s]暂时考虑在第 0 轴上,设需要补零的列数为 x,易知我们进行补零操作后,执行的就是以 VALID 方式进行的卷积,而且卷积后该矩阵的 shape=[new_W, new_W],所以:

floor((W + x - w) / s) + 1 = new_WView Code

因为 floor 是向下取整,所以:

0 ≤ (W + x - w) / s - (new_W - 1) < 1View Code

由简单的不等式可以求出:

(s * (new_W - 1) + w - W) ≤ x < (s * new_W + w - W)View Code

但实际上只要是按照 VALID 方式进行卷积,那多余的行或者列必然是被丢弃的,所以 x 取最小值就行。如果得到 min(x) = 3,那应该怎么补零呢?当需要补零的列(还是只在第 0 轴考虑,因为第 1 轴上情况完全相同)数为 x 时,需要补零的列数为:

padding_for_left = |x / 2| (向下取整操作),padding_for_right = x - padding_for_left。涉及到上下时(也就是考虑高度方向时),把 left 换成 top,right 换成 bottom 即可。

下面使用一点代码片段来验证一下:

import numpy as npimport tensorflow as tfinput_7 = tf.constant([[1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7], [2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7], [3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7], [4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7], [5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7], [6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7], [7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7]]) input_7 = tf.reshape(input_7, [1, 7, 7, 1])filter = tf.constant(np.ones([4, 4, 1, 1]), dtype=tf.float32)stride = [1, 3, 3, 1]conv_output = tf.nn.conv2d(input_7, filter=filter, strides=stride, padding="SAME")with tf.Session() as sess: output = sess.run(conv_output) shape = output.shape[1], output.shape[2] print(output.reshape(shape))# 本测试中,W=7, s=3, w=4View Code

上述代码输出结果为:

[[19.8 29.4 15.9 ] [56.4 79.200005 41.199997] [40.2 55.600002 28.599998]]

这里计算出来的需要补零的列数为 3,如果简单的计算一下就可以知道在上边界和左边界分别补零一次,右边界和下边界补零两次(一次表示一行或者一列)。

而且通过计算可以看出,TensorFlow 是真的在进行补零,而不是边界复制或者镜像,更不是块复制,不是很明白为什么不进行边界复制,边界复制不是更好吗?

另外,池化过程和卷积操作有点区别,那就是卷积的 padding 是进行补零操作,但是池化并不是补零,而是补 -inf,-inf 表示负无穷大。为什么这样补值呢?因为我们的输出靠近边界的那些行或者列并不可能全是正数,也可能存在负数,但是负数是有意义的,是我们的网络提取出来的有意义的值,如果补零,那么就会丢失这些细节信息,所以补 -inf 保证这些信息能保留下来。