在 Tensorflow 中具有相同填充的均匀大小的内核
Even sized kernels with SAME padding in Tensorflow
在 Tensorflow 中,SAME 填充旨在产生与输入相同大小的输出,给定 stride = 1,通过适当地用零填充输入。对于奇数大小的内核,例如 5x5,它将内核的中心 (2,2) 放在输入的第一个像素 (0,0) 上并开始卷积。在 x 和 y 坐标中,都需要 2 个像素的零填充。
如果改用偶数内核(例如 6x6)怎么办?它不会以像素的中心作为其实际中心。 VALID padding 如何处理这个问题?例如,根据 Image convolution with even-sized kernel,一般图像处理文献中的惯例是在零之前再放置一个像素,如本例中的 -3 -2 -1 0 1 2
。填充区域将命中三个像素。为此,我参考了 Tensorflow 文档,但找不到明确的答案。
就像你说的那样,文档似乎没有明确说明。查看2D卷积核的出处(conv_ops.cc),有评论解释:
// Total padding on rows and cols is
// Pr = (R' - 1) * S + (Kr - 1) * Dr + 1 - R
// Pc = (C' - 1) * S + (Kc - 1) * Dc + 1 - C
// where (R', C') are output dimensions, (R, C) are input dimensions, S
// is stride, (Dr, Dc) are dilations, (Kr, Kc) are filter dimensions.
// We pad Pr/2 on the left and Pr - Pr/2 on the right, Pc/2 on the top
// and Pc - Pc/2 on the bottom. When Pr or Pc is odd, this means
// we pad more on the right and bottom than on the top and left.
所以看起来你会在右列和底行用均匀大小的内核得到一个额外的填充。我们可以看一个例子:
import tensorflow as tf
input_ = tf.ones((1, 10, 10, 1), dtype=tf.float32)
kernel = tf.ones((6, 6, 1, 1), dtype=tf.float32)
conv = tf.nn.conv2d(input_, kernel, [1, 1, 1, 1], 'SAME')
with tf.Session() as sess:
print(sess.run(conv)[0, :, :, 0])
输出:
[[16. 20. 24. 24. 24. 24. 24. 20. 16. 12.]
[20. 25. 30. 30. 30. 30. 30. 25. 20. 15.]
[24. 30. 36. 36. 36. 36. 36. 30. 24. 18.]
[24. 30. 36. 36. 36. 36. 36. 30. 24. 18.]
[24. 30. 36. 36. 36. 36. 36. 30. 24. 18.]
[24. 30. 36. 36. 36. 36. 36. 30. 24. 18.]
[24. 30. 36. 36. 36. 36. 36. 30. 24. 18.]
[20. 25. 30. 30. 30. 30. 30. 25. 20. 15.]
[16. 20. 24. 24. 24. 24. 24. 20. 16. 12.]
[12. 15. 18. 18. 18. 18. 18. 15. 12. 9.]]
确实,看起来确实在右侧和底部添加了额外的零。
在 Tensorflow 中,SAME 填充旨在产生与输入相同大小的输出,给定 stride = 1,通过适当地用零填充输入。对于奇数大小的内核,例如 5x5,它将内核的中心 (2,2) 放在输入的第一个像素 (0,0) 上并开始卷积。在 x 和 y 坐标中,都需要 2 个像素的零填充。
如果改用偶数内核(例如 6x6)怎么办?它不会以像素的中心作为其实际中心。 VALID padding 如何处理这个问题?例如,根据 Image convolution with even-sized kernel,一般图像处理文献中的惯例是在零之前再放置一个像素,如本例中的 -3 -2 -1 0 1 2
。填充区域将命中三个像素。为此,我参考了 Tensorflow 文档,但找不到明确的答案。
就像你说的那样,文档似乎没有明确说明。查看2D卷积核的出处(conv_ops.cc),有评论解释:
// Total padding on rows and cols is
// Pr = (R' - 1) * S + (Kr - 1) * Dr + 1 - R
// Pc = (C' - 1) * S + (Kc - 1) * Dc + 1 - C
// where (R', C') are output dimensions, (R, C) are input dimensions, S
// is stride, (Dr, Dc) are dilations, (Kr, Kc) are filter dimensions.
// We pad Pr/2 on the left and Pr - Pr/2 on the right, Pc/2 on the top
// and Pc - Pc/2 on the bottom. When Pr or Pc is odd, this means
// we pad more on the right and bottom than on the top and left.
所以看起来你会在右列和底行用均匀大小的内核得到一个额外的填充。我们可以看一个例子:
import tensorflow as tf
input_ = tf.ones((1, 10, 10, 1), dtype=tf.float32)
kernel = tf.ones((6, 6, 1, 1), dtype=tf.float32)
conv = tf.nn.conv2d(input_, kernel, [1, 1, 1, 1], 'SAME')
with tf.Session() as sess:
print(sess.run(conv)[0, :, :, 0])
输出:
[[16. 20. 24. 24. 24. 24. 24. 20. 16. 12.]
[20. 25. 30. 30. 30. 30. 30. 25. 20. 15.]
[24. 30. 36. 36. 36. 36. 36. 30. 24. 18.]
[24. 30. 36. 36. 36. 36. 36. 30. 24. 18.]
[24. 30. 36. 36. 36. 36. 36. 30. 24. 18.]
[24. 30. 36. 36. 36. 36. 36. 30. 24. 18.]
[24. 30. 36. 36. 36. 36. 36. 30. 24. 18.]
[20. 25. 30. 30. 30. 30. 30. 25. 20. 15.]
[16. 20. 24. 24. 24. 24. 24. 20. 16. 12.]
[12. 15. 18. 18. 18. 18. 18. 15. 12. 9.]]
确实,看起来确实在右侧和底部添加了额外的零。