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

Python 如何实现maxpool:在图像或张量上的滑动窗口上取最大值,python,numpy,neural-network,conv-neural-network,array-broadcasting,Python,Numpy,Neural Network,Conv Neural Network,Array Broadcasting,简言之:我正在寻找一个简单的numpy(可能是一个线性)实现Maxpool-在numpy.narray上的窗口最大值,用于跨维度的所有窗口位置 更多细节:我正在实现一个卷积神经网络(“CNN”),这种网络中的一个典型层是MaxPool层(例如)。书写 y=MaxPool(x,S),x是一个输入narray,S是一个参数,使用伪码,MaxPool的输出由以下公式给出: y[b,h,w,c] = max(x[b, s*h + i, s*w + j, c]) over i = 0,...,

简言之:我正在寻找一个简单的
numpy
(可能是一个线性)实现
Maxpool
-在
numpy.narray
上的窗口最大值,用于跨维度的所有窗口位置

更多细节:我正在实现一个卷积神经网络(“CNN”),这种网络中的一个典型层是
MaxPool
层(例如)。书写
y=MaxPool(x,S)
x
是一个输入
narray
S
是一个参数,使用伪码,
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.
也就是说,
y
narray
,其中索引
b,h,w,c
处的值等于沿输入
x
的第二和第三维度的大小
S x
窗口的最大接收量,窗口“角”位于索引
b,h,w,c

一些附加细节:网络是使用
numpy
实现的。CNN有许多“层”,其中一层的输出是下一层的输入。层的输入是
numpy.narray
s,称为“张量”。在我的例子中,张量是四维的
numpy.narray
x
。也就是说,
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)
时,这将给出我想要的,但对于退化情况,我最大化的窗口大小为
3 x 3
,即
x
的第二和第三维度的大小,这并不是我想要的。

这里有一个使用
np.lib.strude\u技巧的解决方案。as\u-strude
创建滑动窗口,生成一个
6D
形状数组:
(B,H-s+1,W-s+1,s,s,C)
,然后简单地沿第四和第五轴执行max,生成一个形状输出数组:
(B,H-s+1,W-s+1,C)
。中间
6D
数组将是输入数组的视图,因此不会占用更多内存。
max
的后续操作是一个缩减操作,可以有效地利用滑动
视图

因此,将需要实施-

# 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))
样本运行-

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)

因此,输出的形状是:
(B,H-S+1,W-S+1,C)
,对吗?@Divakar是的,你是对的,输出取决于你能在滑动窗口中适应多少次,为非重叠面片实现O(n)算法(独立于窗口大小),即
(a,((X-X)/X)+1,(Y-Y/Y)+1,X,Y,B)
,或者干脆
(a,X/X,Y/Y,X,Y,b)
,我应该使用什么样的步幅?有没有一种简单的方法将转换步幅(1,2,3..,窗口大小或全步幅)与numpy使用的步幅关联起来?我认为SaravanabalagiRamachandran使用scikit image的视图块可能更简单。