简体   繁体   English

Numpy View重塑没有复制(2d移动/滑动窗口,跨步,蒙面内存结构)

[英]Numpy View Reshape Without Copy (2d Moving/Sliding Window, Strides, Masked Memory Structures)

I have an image stored as a 2d numpy array (possibly multi-d). 我有一个图像存储为2d numpy数组(可能是multi-d)。

I can make a view onto that array that reflects a 2d sliding window, but when I reshape it so that each row is a flattened window (rows are windows, column is a pixel in that window) python makes a full copy. 我可以在反射2d滑动窗口的数组上进行视图,但是当我重塑它以使每行都是一个平坦的窗口(行是窗口,列是该窗口中的一个像素)时,python会生成一个完整的副本。 It does this because I'm using the typical stride trick, and the new shape isn't contiguous in memory. 它这样做是因为我使用了典型的步幅技巧,并且新形状在内存中不连续。

I need this because I'm passing entire large images to an sklearn classifier, which accepts 2d matrices, where there's no batch/partial fit procedure, and the full expanded copy is far too large for memory. 我需要这个,因为我将整个大图像传递给sklearn分类器,该分类器接受2d矩阵,其中没有批处理/部分拟合程序,并且完整的扩展副本对于存储器来说太大了。

My Question: Is there a way to do this without making a fully copy of the view? 我的问题:如果没有完整地复制视图,有没有办法做到这一点?

I believe an answer will either be (1) something about strides or numpy memory management that I've overlooked, or (2) some kind of masked memory structure for python that can emulate a numpy array even to an external package like sklearn that includes cython. 我相信一个答案将是(1)关于我忽略的步幅或numpy内存管理,或者(2)python的某种屏蔽内存结构,它可以模拟一个numpy数组,甚至包括像sklearn这样的外部包用Cython。

This task of training over moving windows of a 2d image in memory is common, but the only attempt I know of to account for patches directly is the Vigra project ( http://ukoethe.github.io/vigra/ ). 这种在内存中移动二维图像窗口的训练任务很常见,但我所知道的唯一一个直接考虑补丁的尝试是Vigra项目( http://ukoethe.github.io/vigra/ )。

Thanks for the help. 谢谢您的帮助。

>>> 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

Your task isn't possible using only strides, but NumPy does support one kind of array that does the job. 仅使用步幅不可能完成任务,但NumPy确实支持一种完成工作的数组。 With strides and masked_array you can create the desired view to your data. 使用masked_arraymasked_array您可以为数据创建所需的视图。 However, not all NumPy functions support operations with masked_array , so it is possible the scikit-learn doesn't do well with these either. 但是,并非所有NumPy函数都支持使用masked_array操作,因此scikit-learn可能也不能很好地处理这些操作。

Let's first take a fresh look at what we are trying to do here. 让我们首先重新审视一下我们在这里要做的事情。 Consider the input data of your example. 考虑您的示例的输入数据。 Fundamentally the data is just a 1-d array in the memory, and it is simpler if we think about the strides with that. 从根本上说,数据只是内存中的一维数组,如果我们考虑这方面的进步,它就更简单了。 The array only appears to be 2-d, because we have defined its shape. 该数组似乎只是2-d,因为我们已经定义了它的形状。 Using strides, the shape could be defined like this: 使用步幅,形状可以这样定义:

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))

Now the goal is to set such strides to base that it orders the numbers like in the end array, B . 现在的目标是设置这样的进展,以base在于它命令数字像端阵列,在B In other words, we are asking for integers a and b such that 换句话说,我们要求整数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]])

But this is clearly impossible. 但这显然是不可能的。 The closest view we can achieve like this is with a rolling window over base : 就可以达到这样的最接近的观点与在滚动窗口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]])

But the difference here is that we have extra columns and rows, which we would like to get rid of. 但这里的区别在于我们有额外的列和行,我们想要摆脱它们。 So, effectively we are asking for a rolling window which is not contiguous and also makes jumps at regular intervals. 所以,实际上我们要求的是一个不连续的滚动窗口,并且还会定期跳转。 With this example we want to have every third item excluded from the window and jump over one item after two rows. 在这个例子中,我们希望从窗口中排除每三个项目,并在两行之后跳过一个项目。

We can describe this as a masked_array : 我们可以将其描述为masked_array

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

This array contains exactly the data that we want, and it is only a view to the original data. 此数组包含我们想要的数据,它只是原始数据的视图。 We can confirm that the data is equal 我们可以确认数据是否相等

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

But as I said in the beginning, it is quite likely that scikit-learn doesn't understand masked arrays. 但正如我在开始时所说,scikit-learn很可能不了解蒙面数组。 If it simply converts this to an array, the data will be wrong: 如果它只是将其转换为数组,则数据将是错误的:

>>> 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]])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM