gpt4 book ai didi

python - Numpy - 创建重叠的 3D 子数组作为内存效率高的向量

转载 作者:太空宇宙 更新时间:2023-11-04 06:24:15 24 4
gpt4 key购买 nike

我正在尝试从一个更大的 3D 数组(用于基于补丁的分割)创建一个包含所有相同大小的重叠子数组的列表,其中每个子数组都需要展平(作为一维向量),因此我可以利用sklearn.neighbours.BallTree 中的球树。

因此,例如,给定一张 100x100x100 的图像,如果我将其分解为 5x5x5 的重叠 block (子阵列),我将有 96x96x96 = 884,736 个。

但是,如果没有 numpy 为每个展平/矢量化子数组分配更多内存,我还没有找到任何这样做的方法。这似乎是因为每个子数组在内存中不连续。

例如对于 100x100x100 图像,如果我希望每个 5x5x5 补丁作为一维向量(长度为 125),numpy 决定在内存中为所有 884,736 个分配一个全新的数组,然后它变得相当大,特别是如果我想处理超过一张 100x100x100 的图片!

我欢迎在 python/numpy 中克服这一内存挑战的任何解决方案。我正在考虑创建 numpy.ndarray 对象的子类,该对象存储指向大图像中补丁位置的指针,但仅在调用时将数据作为一维 numpy 数组返回(然后在不使用时再次删除)但是我还没有找到足够的关于子类化 ndarray 对象的细节来做到这一点。如果唯一的解决方案是用 C/C++ 实现所有内容,我会非常失望。感谢您提供的任何帮助,谢谢!

最佳答案

根据您的问题,您可能已经知道所有这些。然而,我发布这个“答案”更多是为了讨论问题是什么,因为很多人可能没有意识到它们......

如果您不是,您可以从 100x100x100 图像制作一个 96x96x96x5x5x5 数组,充当 5x5x5 移动窗口,无需分配任何额外的内存。

但是,因为每个维度只能有一个步幅,所以如果不制作副本,就无法将其 reshape 为 96x96x96x125 数组。

无论如何,这里有一个例子(基本上取自 straight from one of my previous answers ):

import numpy as np

def rolling_window_lastaxis(a, window):
"""Directly taken from Erik Rigtorp's post to numpy-discussion.
<http://www.mail-archive.com/numpy-discussion@scipy.org/msg29450.html>"""
if window < 1:
raise ValueError, "`window` must be at least 1."
if window > a.shape[-1]:
raise ValueError, "`window` is too long."
shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
strides = a.strides + (a.strides[-1],)
return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

def rolling_window(a, window):
"""Takes a numpy array *a* and a sequence of (or single) *window* lengths
and returns a view of *a* that represents a moving window."""
if not hasattr(window, '__iter__'):
return rolling_window_lastaxis(a, window)
for i, win in enumerate(window):
if win > 1:
a = a.swapaxes(i, -1)
a = rolling_window_lastaxis(a, win)
a = a.swapaxes(-2, i)
return a

x = np.zeros((100,100,100), dtype=np.uint8)
y = rolling_window(x, (5,5,5))
print 'Now *y* will be a 96x96x96x5x5x5 array...'
print y.shape
print 'Representing a "rolling window" into *x*...'
y[0,0,0,...] = 1
y[1,1,0,...] = 2
print x[:10,:10,0] # Note that *x* and *y* share the same memory!

这会产生:

Now *y* will be a 96x96x96x5x5x5 array...
(96, 96, 96, 5, 5, 5)
Representing a "rolling window" into *x*...
[[1 1 1 1 1 0 0 0 0 0]
[1 2 2 2 2 2 0 0 0 0]
[1 2 2 2 2 2 0 0 0 0]
[1 2 2 2 2 2 0 0 0 0]
[1 2 2 2 2 2 0 0 0 0]
[0 2 2 2 2 2 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0]]

但是,正如您已经注意到的,我们无法在不创建副本的情况下将其 reshape 为 96x96x96x125y.shape = (96,96,96,-1) 会报错,z = y.reshape((96,96,96,-1)) 会工作,但会返回一个副本。

(相关文档在 numpy.reshape 中,如果这看起来令人困惑。基本上 reshape 将尽可能避免复制,如果不是则返回一个副本,而设置shape 属性将在无法复制时引发错误。)

但是,即使您构建了一个更高效的数组容器,sklearn.neighbors.BallTree 几乎肯定会制作临时中间副本。

您提到您正在进行图像分割。为什么不研究一种比您似乎正在尝试的相当“蛮力”更有效的算法呢? (或者,如果这不可行,请向我们提供更多详细信息,说明原因……也许有人会有更好的主意?)

关于python - Numpy - 创建重叠的 3D 子数组作为内存效率高的向量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9518203/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com