8

我有一个存储为二维 numpy 数组(可能是多维)的图像。

我可以在该数组上创建一个反映二维滑动窗口的视图,但是当我对其进行整形以使每一行都是一个扁平窗口(行是窗口,列是该窗口中的一个像素)时,python 会制作一个完整的副本。这样做是因为我使用的是典型的跨步技巧,并且新形状在内存中并不连续。

我需要这个,因为我将整个大图像传递给一个 sklearn 分类器,该分类器接受 2d 矩阵,其中没有批处理/部分拟合过程,并且完整的扩展副本对于内存来说太大了。

我的问题:有没有办法在不完全复制视图的情况下做到这一点?

我相信答案要么是(1)我忽略的有关 strides 或 numpy 内存管理的东西,要么(2)python 的某种掩码内存结构可以模拟 numpy 数组,甚至可以模拟像 sklearn 这样的外部包,其中包括赛通。

这种在内存中移动二维图像窗口的训练任务很常见,但我所知道的直接解释补丁的唯一尝试是 Vigra 项目(http://ukoethe.github.io/vigra/)。

谢谢您的帮助。

>>> A=np.arange(9).reshape(3,3)
>>> print A
[[0 1 2]
 [3 4 5]
 [6 7 8]]
>>> xstep=1;ystep=1; xsize=2; ysize=2
>>> window_view = np.lib.stride_tricks.as_strided(A, ((A.shape[0] - xsize + 1) / xstep, (A.shape[1] - ysize + 1) / ystep, xsize, ysize),
...       (A.strides[0] * xstep, A.strides[1] * ystep, A.strides[0], A.strides[1]))
>>> print window_view 
[[[[0 1]
   [3 4]]

  [[1 2]
   [4 5]]]


 [[[3 4]
   [6 7]]

  [[4 5]
   [7 8]]]]
>>> 
>>> np.may_share_memory(A,window_view)
True
>>> B=window_view.reshape(-1,xsize*ysize)
>>> np.may_share_memory(A,B)
False
4

1 回答 1

4

仅使用步幅无法完成您的任务,但 NumPy 确实支持一种可以完成这项工作的数组。大步前进,masked_array 您可以为您的数据创建所需的视图。然而,并不是所有的 NumPy 函数都支持对 的操作masked_array,所以 scikit-learn 也可能对这些函数做得不好。

让我们首先重新审视一下我们在这里尝试做的事情。考虑您示例的输入数据。从根本上说,数据只是内存中的一维数组,如果我们考虑一下它的跨步,它会更简单。该数组似乎只是二维的,因为我们已经定义了它的形状。使用步幅,可以像这样定义形状:

from numpy.lib.stride_tricks import as_strided

base = np.arange(9)
isize = base.itemsize
A = as_strided(base, shape=(3, 3), strides=(3 * isize, isize))

现在的目标是将这样的步幅设置为base它对最终数组中的数字进行排序,B. 换句话说,我们要求整数ab这样

>>> as_strided(base, shape=(4, 4), strides=(a, b))
array([[0, 1, 3, 4],
       [1, 2, 4, 5],
       [3, 4, 6, 7],
       [4, 5, 7, 8]])

但这显然是不可能的。我们可以像这样实现的最接近的视图是滚动窗口base

>>> C = as_strided(base, shape=(5, 5), strides=(isize, isize))
>>> C
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6],
       [3, 4, 5, 6, 7],
       [4, 5, 6, 7, 8]])

但这里的区别是我们有额外的列和行,我们想去掉它们。因此,实际上我们要求的是一个不连续的滚动窗口,并且还会定期进行跳跃。在此示例中,我们希望每隔三个项目从窗口中排除,并在两行后跳过一个项目。

我们可以将其描述为masked_array

>>> mask = np.zeros((5, 5), dtype=bool)
>>> mask[2, :] = True
>>> mask[:, 2] = True
>>> D = np.ma.masked_array(C, mask=mask)

这个数组正好包含我们想要的数据,它只是原始数据的一个视图。我们可以确认数据相等

>>> D.data[~D.mask].reshape(4, 4)
array([[0, 1, 3, 4],
       [1, 2, 4, 5],
       [3, 4, 6, 7],
       [4, 5, 7, 8]])

但正如我一开始所说,scikit-learn 很可能不理解掩码数组。如果它只是将其转换为数组,则数据将是错误的:

>>> np.array(D)
array([[0, 1, 2, 3, 4],
       [1, 2, 3, 4, 5],
       [2, 3, 4, 5, 6],
       [3, 4, 5, 6, 7],
       [4, 5, 6, 7, 8]])
于 2015-05-24T14:13:41.780 回答