背景

在CNN中,池化函数一般放在卷积层之后,图片经过卷积层,获得的特征更加适合分类器的学习,然而如果进行的是同卷积或者全卷积,得到的特征大小不比原来的小,这样我们就需要降维,为此引入池化函数。

池化函数tf.nn.max_pool(avg_pool)

在TensorFlow中池化函数如下:
tf.nn.max_pool(input,ksize,strides,padding,name=None)
tf.nn.avg_pool(input,ksize,strides,padding,name=None)
说明:
input:需要池化的输入,一般池化层接在卷积层之后,所以通常输入的是feature map,依然是[batch,height,width,channels]这样的shape
ksize:池化窗口的大小,取一个四维向量,一般是[1,height,width,1],因为我们不想在batch和channels上做池化,所以这两个维度设为1.
strides:和卷积参数含义一样,窗口在每个维度上滑动的步长,一般也是[1,stride,stride,1].
padding:和卷积参数含义一样,也是取VALID或者SAME,VALID是不padding操作,SAME是padding操作。

实例:池化函数的使用

1.定义输入变量
定义1个输入变量用来模拟输入图片,4×4大小的2通道矩阵,并将其赋予指向的值。2个通道分别为:4个0到4个3组成的矩阵,4个4到4个7组成的矩阵。

import tensorflow as tf
img = tf.constant([[[0.0,4.0],[0.0,4.0],[0.0,4.0],[0.0,4.0]],
                   [[1.0,5.0],[1.0,5.0],[1.0,5.0],[1.0,5.0]],
                   [[2.0,6.0],[2.0,6.0],[2.0,6.0],[2.0,6.0]],
                   [[3.0,7.0],[3.0,7.0],[3.0,7.0],[3.0,7.0]]])
img = tf.reshape(img,shape=[1,4,4,2])

2.定义池化操作
这里定义了4个池化操作和一个取均值操作。前两个操作是最大池化操作,接下来两个是均值池化操作,最后一个是取均值操作。

pooling = tf.nn.max_pool(img,[1,2,2,1],[1,2,2,1],padding='VALID')
pooling1 = tf.nn.max_pool(img,[1,2,2,1],[1,1,1,1],padding='VALID')
pooling2 = tf.nn.avg_pool(img,[1,4,4,1],[1,1,1,1],padding='SAME')
pooling3 = tf.nn.avg_pool(img,[1,4,4,1],[1,4,4,1],padding='SAME')
nt_hpool2_flat = tf.reshape(tf.transpose(img),[-1,16])
pooling4 = tf.reduce_mean(nt_hpool2_flat,1)#1表示对行求均值(轴是行),0表示对列求均值

3.运行池化操作

with tf.Session() as sess:
    # tf.global_variables_initializer()
    sess.run(tf.global_variables_initializer())
    print("image:")
    images = sess.run(img)
    print(images)
    result=sess.run(pooling)
    print("result:\n",result)
    result = sess.run(pooling1)
    print("result1:\n",result)
    result = sess.run(pooling2)
    print("result2:\n", result)
    result = sess.run(pooling3)
    print("result3:\n", result)
    flat,result = sess.run([nt_hpool2_flat,pooling4])
    print("result4:\n",result)
    print("flat:\n",flat)

结果:


image:
[[[[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.]]]]
通过上面的输出可以看出,img与我们设置的初始值是一样的,即第一个通道为
[[0 0 0 0],
[1 1 1 1],
[2 2 2 2],
[3 3 3 3]]
第二个通道为
[[4 4 4 4],
[5 5 5 5],
[6 6 6 6],
[7 7 7 7]]。


result:
[[[[1. 5.]
[1. 5.]]

[[3. 7.]
[3. 7.]]]]
这个操作在卷积神经网络中是最常用的,一般步长都会设成与池化滤波器尺寸一致(池化的卷积尺寸为2×2,所以步长为2),生成2个通道的2×2矩阵。矩阵的内容是从原始输入中取最大值,由于池化filter中对应的通道维度是1,所以结果仍然保持源通道数


result1:
[[[[1. 5.]
[1. 5.]
[1. 5.]]

[[2. 6.]
[2. 6.]
[2. 6.]]

[[3. 7.]
[3. 7.]
[3. 7.]]]]

result2:
[[[[1. 5. ]
[1. 5. ]
[1. 5. ]
[1. 5. ]]

[[1.5 5.5]
[1.5 5.5]
[1.5 5.5]
[1.5 5.5]]

[[2. 6. ]
[2. 6. ]
[2. 6. ]
[2. 6. ]]

[[2.5 6.5]
[2.5 6.5]
[2.5 6.5]
[2.5 6.5]]]]
result1和result2分别演示了VALID和SAME的两种padding的取值。
1.VALID中使用的filter为2×2,步长为1×1,生成了2×2大小的矩阵。
2.在SAME中使用的filter,步长仍然为1×1,生成4×4的矩阵,padding之后在计算avg_pool时,是将输入矩阵与filter对应尺寸内的元素总和除以这些元素中非0的个数(而不是filter的总个数)


result3:
[[[[1.5 5.5]]]]
result4:
[1.5 5.5]
flat:
[[0. 1. 2. 3. 0. 1. 2. 3. 0. 1. 2. 3. 0. 1. 2. 3.]
[4. 5. 6. 7. 4. 5. 6. 7. 4. 5. 6. 7. 4. 5. 6. 7.]]

result3是常用的操作手法,也叫全局池化法,就是使用一个与原有输入同样尺寸的filter进行池化,一般放在最后一层,用于表达图像通过卷积网络处理后的最终特征。而result4是一个均值操作 ,可以看到将数据转置后的均值操作得到的值,与全局池化平均值是一样的结果。