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

the*_*hem 4 python numpy neural-network conv-neural-network array-broadcasting

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

更详细地说:我正在实现一个卷积神经网络(“CNN”),此类网络中的典型层之一是MaxPool层(例如此处)。写 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.
Run Code Online (Sandbox Code Playgroud)

也就是说,y如果narray索引处的值等于沿着输入的第二维和第三维大小的b,h,w,c窗口所取的最大值,则窗口“角”被放置在索引处。S x Sxb,h,w,c

一些其他细节:网络是使用numpy. CNN 有许多“层”,其中一层的输出是下一层的输入。层的输入numpy.narray称为“张量”。就我而言,张量是 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)) 
Run Code Online (Sandbox Code Playgroud)

据说这会给我想要的东西,x.shape但是(2,3,3,4)对于退化的情况,我最大化的窗口的大小为3 x 3,第二维和第三维的大小x,这不完全是我想要的。

Div*_*kar 5

这是一个解决方案,用于np.lib.stride_tricks.as_strided创建滑动窗口,产生6D形状为 : 的数组(B,H-S+1,W-S+1,S,S,C),然后简单地沿第四和第五轴执行 max,产生形状为 : 的输出数组(B,H-S+1,W-S+1,C)。中间6D数组将是输入数组的视图,因此不会占用更多内存。后续的归约操作max将有效地利用滑动views

因此,实施将是 -

# Based on http://stackoverflow.com/a/41850409/3293881
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))
Run Code Online (Sandbox Code Playgroud)

样本运行 -

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)
Run Code Online (Sandbox Code Playgroud)