如何实现 maxpool:在图像或张量上滑动 window 取最大值

How to implement maxpool: taking a maximum on sliding window on image or tensor

简而言之: 我正在寻找 Maxpool 的简单 numpy(也许是单行)实现 - 在 window 上最大numpy.narray 用于跨维度的 window 的所有位置。

更多细节:我正在实现一个卷积神经网络("CNN"),这种网络中的典型层之一是MaxPool层(例如 here)。写作 y = MaxPool(x, S)x是一个输入narrayS是一个参数,使用伪代码,MaxPool的输出由下式给出:

     y[b,h,w,c] = max(x[b, s*h + i, s*w + j, c]) over i = 0,..., S-1; j = 0,...,S-1.

也就是说,ynarray,其中索引 b,h,w,c 处的值等于第二个 window 大小 S x S 的最大值并且输入的第三维 x,window "corner" 位于索引 b,h,w,c 处。

一些额外的细节: 网络是使用 numpy 实现的。 CNN 有许多 "layers",其中一层的输出是下一层的输入。层的输入是 numpy.narray,称为 "tensors"。在我的例子中,张量是 4 维 numpy.narrayx。即x.shape是一个元组(B,H,W,C)。在张量被一层处理后,每个维度的大小都会发生变化,例如层 i= 4 的输入可以有大小 B = 10, H = 24, W = 24, C = 3,而输出,也就是 i+1 层的输入有 B = 10, H = 12, W = 12, C = 5。如评论中所示,应用 MaxPool 后的大小为 (B, H - S + 1, W - S + 1, C)

具体来说: 如果我使用

import numpy as np

y = np.amax(x, axis = (1,2)) 

其中 x.shape 是说 (2,3,3,4) 这将给我我想要的但是对于一个退化的情况,我正在最大化的 window 的大小是 3 x 3x的第二和第三维度的大小,这不是我想要的。

这是一个使用 np.lib.stride_tricks.as_strided 创建滑动 windows 的解决方案,导致 6D 形状数组:(B,H-S+1,W-S+1,S,S,C) 然后简单地沿第四和第五轴执行最大值,导致输出数组的形状:(B,H-S+1,W-S+1,C)。中间 6D 数组将是输入数组的视图,因此不会再占用内存。 max 作为缩减的后续操作将有效地利用滑动 views.

因此,一个实现将是 -

# Based on 
def patchify(img, patch_shape):
    a, X, Y, b = img.shape
    x, y = patch_shape
    shape = (a, X - x + 1, Y - y + 1, x, y, b)
    a_str, X_str, Y_str, b_str = img.strides
    strides = (a_str, X_str, Y_str, X_str, Y_str, b_str)
    return np.lib.stride_tricks.as_strided(img, shape=shape, strides=strides)

out = patchify(x, (S,S)).max(axis=(3,4))

样本运行-

In [224]: x = np.random.randint(0,9,(10,24,24,3))

In [225]: S = 5

In [226]: np.may_share_memory(patchify(x, (S,S)), x)
Out[226]: True

In [227]: patchify(x, (S,S)).shape
Out[227]: (10, 20, 20, 5, 5, 3)

In [228]: patchify(x, (S,S)).max(axis=(3,4)).shape
Out[228]: (10, 20, 20, 3)