How does average pooling function work in TensorFlow?

Let us assume a tensor like this:

x = tf.constant([[1., 2., 3.],
                  [4., 5., 6.],
                  [7., 8., 9.]])

To apply the average pooling function, I will do this:

x = tf.reshape(x, [1, 3, 3, 1])
avg_pool_2d = tf.keras.layers.AveragePooling2D(pool_size=(2, 2),strides=(2, 2), padding='same')
avg_pool_2d(x)

The result is:

<tf.Tensor: shape=(1, 2, 2, 1), dtype=float32, numpy=
array([[[[3. ],
         [4.5]],
        [[7.5],
         [9. ]]]], dtype=float32)>

I can follow the logic above:

(1+2+4+5)/4 = 3
(3+6)/2 = 4.5
(7+8)/2 = 7.5
(9/1) = 9

I think the logic is: The pooling filter is usually situated inside the tensor to perform the pooling operator. But when the entire filter does not situate inside the tensor (see the below figure for an example), we need to specify the number of elements of the filter that are situated inside the tensor (a ). The following figure illustrates the logic for a 4 by 3 tensor, with pooling filter and stride sizes of 2 by 2, and padding the same: Pasteboard - Uploaded Image

However, it is not always like this. For example, suppose the following tensor:

y = tf.constant([[1., 2., 3., 4., 5.],
                 [6., 7., 8., 9., 10.]])

Then, I do this:

y = tf.reshape(y, [1, 2, 5, 1])
avg_pool_2d = tf.keras.layers.AveragePooling2D(pool_size=(4, 4),strides=(4, 4), padding='same')
avg_pool_2d(y)

The result is like this:

    <tf.Tensor: shape=(1, 1, 2, 1), dtype=float32, numpy=
array([[[[4.5 ],
         [7.]]]], dtype=float32)>

If I wanted to follow the logic for the first example, I expected the result to be like this:

(1+2+3+4+6+7+8+9)/8 = 5
(5+10)/2 = 7.5

I am using TensorFlow 2.8.0. What mistake am I making?

1 Like

From the docs: tf.keras.layers.AveragePooling2D  |  TensorFlow v2.12.0

(simplified code)

x = tf.constant([[1., 2., 3.],
                 [4., 5., 6.],
                 [7., 8., 9.]])

x = tf.reshape(x, [1, 3, 3, 1])

AveragePooling2D(pool_size=(2, 2), strides=(1, 1))

Arranging things as 1,3,3,1 the pool size will pad the tensor to become 1,3,3,2

Now:

  • we should expect 4 numbers as a result
  • the first 4 averaged (size of the window) are 1,2,4,5 which is 3
  • The next will be 4 from (5+3+2+6)/4
    …

So my takeaways are

  1. first need to complete the last 2 dimensions, and then the pool will actually occupy all the remaining dimensions,
  2. and it just “works” in those inner 2 dimensions.

@Amir


Something interesting is that the pooling layers can be smaller than the window, but the layers completed automatically cant so this will fail:

import tensorflow as tf
tricky = 1 #must be larger than the 
x = tf.random.uniform((1,tricky,2,3))
avg_pool_2d = tf.keras.layers.AveragePooling2D(pool_size=(2, 2),
   strides=(1, 1), padding='valid')
avg_pool_2d(x)

The tricky dimension must be always larger or equal than the pooling tensor smaller dimension, I think.