Numpy View重塑没有复制(2d移动/滑动窗口,跨步,蒙面内存结构) [英] Numpy View Reshape Without Copy (2d Moving/Sliding Window, Strides, Masked Memory Structures)

查看:455
本文介绍了Numpy View重塑没有复制(2d移动/滑动窗口,跨步,蒙面内存结构)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个图像存储为2d numpy数组(可能是multi-d)。



我可以查看反映2d滑动窗口的数组,但是当我重塑它以使每行都是一个扁平的窗口(行是窗口,列是该窗口中的一个像素)时,python会生成一个完整的副本。这样做是因为我使用了典型的步幅技巧,并且新形状在内存中不连续。



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



我的问题:如果没有制作视图的完整副本,有没有办法做到这一点?



I相信一个答案将是(1)关于我忽略的步幅或numpy内存管理,或(2)python的某种掩盖内存结构,甚至可以模拟一个numpy数组,甚至包括cyle的包括cylearn在内的外部包。



这项在内存中移动2d图像窗口的培训任务很常见,但我所知道的唯一直接考虑补丁的尝试是Vigra项目(< a href =http://ukoethe.github.io/vigra/> http://ukoethe.github.io/vigra/ )。



感谢您的帮助。

 >>> A = np.arange(9).reshape(3,3)
>>>打印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)
错误


解决方案

只使用步幅不可能完成任务,但NumPy支持
一种完成工作的数组。使用步幅和 masked_array
,您可以为数据创建所需的视图。但是,并非所有的
NumPy函数都支持使用 masked_array 进行操作,因此scikit-learn可能与
相关。 / p>

让我们先来看看我们在这里要做的事情。
考虑你的例子的输入数据。从根本上说,数据是
只是存储器中的一维数组,如果我们考虑一下这个步骤,那么它就更简单了。该数组似乎只是2-d,因为我们
已经定义了它的形状。使用步幅,形状可以定义为
,如下所示:

 来自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 。换句话说,我们要求
整数 a b 这样

 >>> 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
数组([[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)
数组([[0,1,3,4],
[1,2,4,5],
[3,4,6,7],
[4,5,7,8]])

但正如我在开头所说的那样,scikit-learn
很可能不理解蒙面数组。如果它只是将其转换为
数组,则数据将是错误的:

 >>> np.array(D)
数组([[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]])


I have an image stored as a 2d numpy array (possibly 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. 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.

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.

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

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. With strides and masked_array you can create the desired view to your data. However, not all NumPy functions support operations with masked_array, so it is possible the scikit-learn doesn't do well with these either.

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. 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. In other words, we are asking for integers a and b such that

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

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

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

这篇关于Numpy View重塑没有复制(2d移动/滑动窗口,跨步,蒙面内存结构)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆