了解keras中的平均(总和)池填充

Understanding average (sum) pooling padding in keras

我在 keras tensorflow 中实现了一个简单的总和池,使用 AveragePooling2D*N*N,因此它创建了具有某种形状的池中元素的总和,same 填充因此形状不会改变:

import numpy as np
import seaborn as sns
import matplotlib.pylab as plt
import tensorflow as tf
from tensorflow.keras.backend import square

#generating the example matrix
def getMatrixByDefinitions(definitions, width, height):
    matrix = np.zeros((width, height))
    for definition in definitions:
        x_cor = definition[1]
        y_cor = definition[0]
        value = definition[2]
        matrix.itemset((x_cor, y_cor), value)
    return  matrix

generated = getMatrixByDefinitions(width=32, height=32, definitions =[[7,16,1]])

def avg_pool(pool):
    return tf.keras.layers.AveragePooling2D(pool_size=(pool,pool), strides=(1, 1), padding='same')

def summer(pool, tensor):
    return avg_pool(pool)(tensor)*pool*pool

def numpyToTensor(numpy_data):
    numpy_as_array = np.asarray(numpy_data)
    tensor_data = numpy_as_array.reshape(1, numpy_data.shape[1], numpy_data.shape[1], 1)
    return tensor_data

data = numpyToTensor(generated)
pooled_data = summer(11, data)

def printMatrixesToHeatMap(matrixes, title):
    # f = pyplot.figure()  # width and height in inches
    matrix_count = len(matrixes)
    width_ratios = [4] * matrix_count + [0.2]

    mergedMatrixes = matrixes[0][0]
    for matrix in matrixes:
        mergedMatrixes = np.concatenate((mergedMatrixes, matrix[0]), axis=0)

    vmin = np.min(mergedMatrixes)
    vmax = np.max(mergedMatrixes)

    fig, axs = plt.subplots(ncols=matrix_count + 1, gridspec_kw=dict(width_ratios=width_ratios))
    fig.set_figheight(20)
    fig.set_figwidth(20 * matrix_count + 5)
    axis_id = 0

    for matrix in matrixes:
        sns.heatmap(matrix[0], annot=True, cbar=False, ax=axs[axis_id], vmin=vmin, vmax=vmax)
        axs[axis_id].set_title(matrix[1])
        axis_id = axis_id + 1

    #fig.colorbar(axs[1].collections[0], cax=axs[matrix_count])
    fig.savefig(title+".pdf", bbox_inches='tight')

def tensorToNumpy(tensor):
    width = tensor.get_shape()[1]
    height = tensor.get_shape()[2]

    output = tf.reshape(tensor, [width, height])
    #output = output.eval(session=tf.compat.v1.Session())
    output = output.numpy()
    return np.array(output)

printMatrixesToHeatMap([[tensorToNumpy(pooled_data), "Pooled data"]],
                              "name")

在非常简单的二维数组上对其进行测试后,我发现它没有达到我的预期(原始数据和合并数据):

你可以看到,单一的 sum-pooled(根据平均池化)最终在边界附近的总和大于实际总和,即 1。 (在这种情况下可以使用 max,但实际数据更复杂,我们需要求和)这意味着平均近边界不是来自填充数据而是来自原始数据。或者这是我这边对 padding 的误解?我需要在 1.1、1.2、1.4 所在的索引上有一个。为什么会这样,我该如何解决这个问题?

请注意,我不想手动设置正确的总和,因此我正在寻找一种在 keras 池化本身中实现此目的的方法。

这似乎是“SAME”填充算法的问题。不幸的是,无法为 avg_pool2d 操作指定显式填充。不过,可以用 tf.pad 手动填充输入。这是一种非常简单的填充方法,适用于奇数形状的池过滤器和步幅大小 1 :

generated = getMatrixByDefinitions(width=32, height=32, definitions =[[7,16,1]])
gen_nhwc = tf.constant(generated[np.newaxis,:,:,np.newaxis])
pool = 11
paddings = [[0,0],[pool//2,pool//2],[pool//2,pool//2],[0,0]]
gen_pad = tf.pad(gen_nhwc, paddings, "CONSTANT")
res = tf.nn.avg_pool2d(gen_pad, (pool,pool), (1,1),"VALID")*pool*pool
result = np.squeeze(res.numpy())
printMatrixesToHeatMap([[generated, "input"],[result, "output"]], "name")

图片结果:


编辑:我创建了一个关于这个问题的issue on Github