如何实现 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
是一个输入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
处的值等于第二个 window 大小 S x S
的最大值并且输入的第三维 x
,window "corner" 位于索引 b,h,w,c
处。
一些额外的细节: 网络是使用 numpy
实现的。 CNN 有许多 "layers",其中一层的输出是下一层的输入。层的输入是 numpy.narray
,称为 "tensors"。在我的例子中,张量是 4 维 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)
这将给我我想要的但是对于一个退化的情况,我正在最大化的 window 的大小是 3 x 3
,x
的第二和第三维度的大小,这不是我想要的。
这是一个使用 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)
简而言之: 我正在寻找 Maxpool
的简单 numpy
(也许是单行)实现 - 在 window 上最大numpy.narray
用于跨维度的 window 的所有位置。
更多细节:我正在实现一个卷积神经网络("CNN"),这种网络中的典型层之一是MaxPool
层(例如 here)。写作
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
处的值等于第二个 window 大小 S x S
的最大值并且输入的第三维 x
,window "corner" 位于索引 b,h,w,c
处。
一些额外的细节: 网络是使用 numpy
实现的。 CNN 有许多 "layers",其中一层的输出是下一层的输入。层的输入是 numpy.narray
,称为 "tensors"。在我的例子中,张量是 4 维 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)
这将给我我想要的但是对于一个退化的情况,我正在最大化的 window 的大小是 3 x 3
,x
的第二和第三维度的大小,这不是我想要的。
这是一个使用 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)