首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无拷贝的Numpy视图重塑(2d移动/滑动窗口,步幅,屏蔽内存结构)

无拷贝的Numpy视图重塑(2d移动/滑动窗口,步幅,屏蔽内存结构)
EN

Stack Overflow用户
提问于 2014-07-18 10:16:30
回答 1查看 2.4K关注 0票数 8

我有一个存储为2dnumpy数组的图像(可能是多个d数组)。

我可以在反映二维滑动窗口的数组上创建一个视图,但是当我重塑它,使每一行都是一个平坦的窗口(行是窗口,列是该窗口中的一个像素)时,python会生成一个完整的副本。它之所以这样做,是因为我使用了典型的步幅技巧,而新形状在内存中是不连续的。

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

我的问题是:有没有一种方法可以在不复制视图的情况下做到这一点?

我相信答案要么是(1)关于我忽略的跨度或numpy内存管理,要么是(2) python的某种屏蔽内存结构,它可以模拟numpy数组,甚至可以模拟到包含cython的外部包,如sklearn。

这种在内存中对2d图像的移动窗口进行训练的任务很常见,但据我所知,唯一直接解决补丁问题的尝试是Vigra项目(http://ukoethe.github.io/vigra/)。

谢谢你的帮助。

代码语言:javascript
复制
>>> 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
EN

回答 1

Stack Overflow用户

发布于 2015-05-24 22:13:42

您的任务不可能只使用步长,但是NumPy支持一种类型的数组来完成这项工作。使用strides和masked_array,您可以为数据创建所需的视图。然而,并不是所有的NumPy函数都支持使用masked_array的操作,因此scikit learn也可能不能很好地使用这些操作。

让我们首先重新看一下我们在这里要做的事情。考虑一下示例中的输入数据。从根本上说,数据只是内存中的一个一维数组,如果我们考虑一下它的跨度,就会更简单。这个数组看起来只是二维的,因为我们已经定义了它的形状。使用strides,可以像这样定义形状:

代码语言:javascript
复制
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,以便

代码语言:javascript
复制
>>> 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上滚动窗口

代码语言:javascript
复制
>>> 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

代码语言:javascript
复制
>>> mask = np.zeros((5, 5), dtype=bool)
>>> mask[2, :] = True
>>> mask[:, 2] = True
>>> D = np.ma.masked_array(C, mask=mask)

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

代码语言:javascript
复制
>>> 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很可能不理解掩码数组。如果它简单地将其转换为数组,则数据将是错误的:

代码语言:javascript
复制
>>> 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]])
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24816334

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档