Skip to main content
 首页 » 编程设计

python之Tensorflow:具有 'SAME' 填充的 tf.nn.avg_pool() 不会对填充像素进行平均

2024年09月07日29tuyile006

我正在尝试理解 tf.nn.avg_pool()。不知道结果第一行怎么是[1.0, 1.0, 1.0, 1.0]。

img = tf.constant([ 
    [[0,4], [0,4], [0,4], [0,4]], 
    [[1,5], [1,5], [1,5], [1,5]], 
    [[2,6], [2,6], [2,6], [2,6]], 
    [[3,7], [3,7], [3,7], [3,7]] 
], dtype=tf.float32) 
 
pooling2 = tf.nn.avg_pool(img, ksize=[1,4,4,1], strides=[1,1,1,1], padding='SAME') 
 
with tf.Session() as sess: 
    tf.global_variables_initializer().run() 
    print('pooling2.shape: {}'.format(sess.run(pooling2).shape)) 
    print('pooling2:\n{}'.format( 
        sess.run(pooling2).transpose([0,3,1,2]).reshape([2,4,4])             )) 

打印结果为

pooling2.shape: (1, 4, 4, 2) 
pooling2: 
[[[1.  1.  1.  1. ] 
  [1.5 1.5 1.5 1.5] 
  [2.  2.  2.  2. ] 
  [2.5 2.5 2.5 2.5]] 
 
 [[5.  5.  5.  5. ] 
  [5.5 5.5 5.5 5.5] 
  [6.  6.  6.  6. ] 
  [6.5 6.5 6.5 6.5]]] 

它似乎在顶部填充了一行,在左侧填充了一列,在右侧和底部填充了两行和两列,然后将 4x4 窗口/内核应用于与左上角对齐的填充结果:

_ _ _ _ _ _ _ 
_ 0 0 0 0 _ _ 
_ 1 1 1 1 _ _ 
_ 2 2 2 2 _ _ 
_ 3 3 3 3 _ _ 
_ _ _ _ _ _ _ 
_ _ _ _ _ _ _ 

放大到左上角

_ _ _ _ 
_ 0 0 0 
_ 1 1 1 
_ 2 2 2 

为什么看起来像 reshape 的pooling2[0, 0, 0],即1来自

(0+0+0 + 1+1+1 + 2+2+2) / 9, 

为什么不是 /16?

请您参考如下方法:

是的,被填充的像素不被计算在平均值中。因此,对于 4x4 池化,在图像中间计算的结果是 16 个值的平均值,但如果填充了两个边缘,则角落中的值只能使用 9 值。

例如你可以看到它here in the source关于对 CuDNN 的调用,其中为平均填充选择了选项 CUDNN_POOLING_AVERAGE_COUNT_EXCLUDE_PADDING。 CuDNN 还提出了 CUDNN_POOLING_AVERAGE_COUNT_INCLUDE_PADDING,这将考虑平均填充像素,但 tensorflow 没有公开此选项。

这可能是平均池化与(跨步)卷积不同的一种方式,尤其是对于空间范围较小的层。

请注意,情况与最大池化类似:填充的像素被忽略(或者等效地,虚拟设置为 -inf 的值)。

import tensorflow as tf 
 
x = -tf.ones((1, 4, 4, 1)) 
max_pool = tf.nn.max_pool(x, (1, 4, 4, 1), (1, 1, 1, 1), 'SAME') 
sess = tf.InteractiveSession() 
print(max_pool.eval().squeeze()) 
# [[-1. -1. -1. -1.] 
#  [-1. -1. -1. -1.] 
#  [-1. -1. -1. -1.] 
#  [-1. -1. -1. -1.]] 

显然文档可以更明确地说明它。