Maxpooling 2x2 数组仅使用 numpy
Posted
技术标签:
【中文标题】Maxpooling 2x2 数组仅使用 numpy【英文标题】:Maxpooling 2x2 array only using numpy 【发布时间】:2021-11-18 06:58:00 【问题描述】:我需要关于使用 numpy
进行最大池化的帮助。
我正在学习用于数据科学的 Python,这里我必须对 2x2
矩阵进行最大池化和平均池化,输入可以是 8x8
或更多,但我必须对每个 2x2
矩阵进行最大池化。我使用
k = np.random.randint(1,64,64).reshape(8,8)
因此,我将得到8x8
矩阵作为随机输出。形成我想做的结果2x2
max pooling。提前感谢
【问题讨论】:
你已经尝试了什么? 我尝试拆分数组,但没有按预期工作 你能发布代码吗?发生了什么你没想到的事情?只是复制粘贴别人给你的功能不会帮助你学习它 这是我在 kaggle notebook 中执行的,我不知道如何详细说明,这是我的作业,我对 Python numpy 完全陌生 到目前为止,我们所能看到的只是创建一个矩阵。你说你试图拆分数组是 oyu 做的吗?为什么它没有达到您的预期? 【参考方案1】:您可以使用np.lib.stride_tricks
解决卷积部分,这实际上是 numpy 在后台从其方法生成视图的方式。不过要小心,这是对 numpy 数组的内存级别访问。
-
对 (8,8) 矩阵进行卷积得到 (2,2) 形状的 (4,4) 矩阵。
使用池化操作(例如均值)减少 (2,2) 矩阵以获得 (4,4) 输出。
这种方法无需任何修改即可扩展到更大的矩阵,并且还可以适应更大的卷积。
k = np.random.randint(1,64,64).reshape(8,8)
#Strides
x,y = 2,2
shape = k.shape[0]//x, k.shape[1]//y, x, y
strides = k.strides[0]*x, k.strides[1]*y, k.strides[0], k.strides[1]
print('expected shape:',shape)
print('required strides:',strides)
convolve = np.lib.stride_tricks.as_strided(k, shape=shape, strides=strides)
print('convolution output shape:',convolve.shape)
maxpool = np.mean(convolve, axis=(-1,-2))
print('maxpooled output shape:',maxpool.shape)
print(' ')
print('Input matrix:')
print(k)
print('--------')
print('Output matrix:')
print(maxpool)
expected shape: (4, 4, 2, 2)
required strides: (128, 16, 64, 8)
convolution output shape: (4, 4, 2, 2)
maxpooled output shape: (4, 4)
Input matrix:
[[19 32 28 25 31 49 17 18]
[ 4 19 50 57 29 42 5 8]
[44 16 54 13 15 1 58 50]
[18 36 29 12 39 45 47 44]
[34 31 17 28 35 62 30 54]
[38 50 14 50 25 24 36 4]
[58 27 20 34 55 22 63 59]
[61 30 37 24 23 34 5 16]]
--------
Output matrix:
[[18.5 40. 37.75 12. ]
[28.5 27. 25. 49.75]
[38.25 27.25 36.5 31. ]
[44. 28.75 33.5 35.75]]
确认一下,如果您只取矩阵的第一个 (2,2) 窗口并对其应用均值池化,您将得到 18.5,这是您的输出矩阵的第一个值,正如预期的那样。
first_window = [[19,32],
[4,19]]
np.mean(first_window)
# 18.5
解释
Numpy 将其 ndarray 存储为连续的内存块。每个元素在前一个元素之后每隔 n 个字节按顺序存储。
所以如果你的 3D 数组看起来像这样 -
np.arange(0,16).reshape(2,2,4)
#array([[[ 0, 1, 2, 3],
# [ 4, 5, 6, 7]],
#
# [[ 8, 9, 10, 11],
# [12, 13, 14, 15]]])
然后在内存中存储为 -
当检索一个元素(或一个元素块)时,NumPy 计算它需要遍历多少个strides
(每个 8 个字节)才能获取下一个元素in that direction/axis
。因此,对于上面的示例,对于axis=2
,它必须遍历 8 个字节(取决于datatype
),但对于axis=1
,它必须遍历8*4
字节,而axis=0
它需要8*8
字节。
这就是arr.strides
的用武之地。它显示了访问该方向的下一个元素所需的字节数。
对于您使用 (8,8) 矩阵的情况 -
您希望将 8x8 矩阵在每个方向上按 (2,2) 步进行卷积,从而得到 (4,4,2,2) 形状的矩阵。然后你想在你的 maxpooling 步骤中减少最后 2 个维度,平均得到一个 (4,4) 矩阵。
shape
是您定义的预期形状,在这种情况下为 (4,4,2,2)
卷积需要访问内存,但是通过在每个方向上采取 2 步(k.strides[0]*2 = 128 字节和 k.strides1*2 = 16 字节来获得 (2 ,2) 窗口,然后是另一个 (64,8) 字节。
注意:尽量不要在这个函数中硬编码步幅/形状。可能导致内存问题。始终使用原始矩阵的步幅和形状计算预期的步幅和形状。
希望这会有所帮助。阅读更多关于 stride_tricks here 和 here 的信息。
【讨论】:
太棒了,太棒了,但我必须了解 strides 和其他方面的知识,无论如何,谢谢伙计 绝对可以。如果你想掌握 numpy,stride_tricks 绝对是必不可少的,因为它允许你在内存级别使用数组并用它们做任何你想做的事情。它非常强大,并且是 numpy 中的大多数函数在其后台实际使用的实际方法。 检查我在答案中链接的最后一个链接。它是一个包含 25 个示例的很棒的教程,用于使用、理解和掌握 numpy 数组的跨步技巧。包括以 zig zag 方式访问值或简单转置之类的东西。【参考方案2】:您不必自己计算必要的步幅,只需注入两个辅助维度来创建一个 4d 数组,该数组是 2x2 块矩阵的 2d 集合,然后在块上取元素最大值:
import numpy as np
# use 2-by-3 size to prevent some subtle indexing errors
arr = np.random.randint(1, 64, 6*4).reshape(6, 4)
m, n = arr.shape
pooled = arr.reshape(m//2, 2, n//2, 2).max((1, 3))
上面的一个例子:
>>> arr
array([[40, 24, 61, 60],
[ 8, 11, 27, 5],
[17, 41, 7, 41],
[44, 5, 47, 13],
[31, 53, 40, 36],
[31, 23, 39, 26]])
>>> pooled
array([[40, 61],
[44, 47],
[53, 40]])
对于不假设 2×2 块的完全通用块池:
import numpy as np
# again use coprime dimensions for debugging safety
block_size = (2, 3)
num_blocks = (7, 5)
arr_shape = np.array(block_size) * np.array(num_blocks)
numel = arr_shape.prod()
arr = np.random.randint(1, numel, numel).reshape(arr_shape)
m, n = arr.shape # pretend we only have this
pooled = arr.reshape(m//block_size[0], block_size[0],
n//block_size[1], block_size[1]).max((1, 3))
【讨论】:
@ArockiaJegan 我建议避免使用stride_tricks.as_strided
,除非真的有必要。很容易得到垃圾数据。我们拥有像 transpose
和 reshape
这样的高级工具来安全地做所有事情。
当你说真的有必要时,你的意思是当涉及不同的步幅或扩张时,比如 pytorch 中的 MaxPool2d? reshape 也能处理这些情况吗?谢谢!
@Sam-gege “真正需要”是 reshape
、transpose
或 view
无法解决的问题。到目前为止,我有一个使用 as_strided
的用例,它被 numpy.org/devdocs/reference/generated/… 渲染为没有实际意义
而且我不知道 pytorch。但是看看github.com/vdumoulin/conv_arithmetic/blob/master/README.md(从pytorch docs链接):似乎填充不是问题,但确实任意步幅可能是有问题的。我可能会选择这种方法(如果适用)或sliding_window_view
(但根据需要跳过窗口)。
谢谢安德拉斯。看起来sliding_window_view
更容易。我在开始尝试as_strided
时遇到了一些困难,经常以垃圾数据结束哈哈。顺便说一句,我有另一个关于最大池的类似问题,你有兴趣看看吗? ***.com/questions/69423484/…以上是关于Maxpooling 2x2 数组仅使用 numpy的主要内容,如果未能解决你的问题,请参考以下文章