Python Numpy stride技巧“抱怨”;数组太大“;,为什么?

Python Numpy stride技巧“抱怨”;数组太大“;,为什么?,python,arrays,numpy,stride,Python,Arrays,Numpy,Stride,在numpy(1.8)中,我希望将此计算从Python循环转移到更numpy的循环中,以获得更好的性能: (width, height) = base.shape (toolw, toolh) = tool.shape for i in range(0, width-toolw): for j in range(0, height-toolh): zdiff[i,j] = (tool - base[i:i+toolw, j:j+toolh]).min() base是~2

在numpy(1.8)中,我希望将此计算从Python循环转移到更numpy的循环中,以获得更好的性能:

(width, height) = base.shape
(toolw, toolh) = tool.shape
for i in range(0, width-toolw):
    for j in range(0, height-toolh):
        zdiff[i,j] = (tool - base[i:i+toolw, j:j+toolh]).min()
base
是~2000x2000数组,
tool
是25x25数组。(背景背景:底座和工具是高度贴图,我试图找出工具移动到整个底座的最接近方法。)

我尝试使用跨步技巧,从以下开始:

base_view = np.lib.stride_tricks.as_strided(base, shape=(2000, 2000, 25, 25), 
                                            strides=(base.strides * 2))
这将使
base\u视图[10,20]
成为(10,20)左上角base的25x25个值数组

然而,这是失败的“数组太大”。从值测试来看,当数组的潜在大小(例如2000*2000*25*25*8)超过2^32 ish时,它似乎会报告此问题,并触发溢出检查,将所有维度相乘。(我正在安装32位Python)

我觉得我遗漏了一些东西——为什么当步幅值明显起作用时,它不让我创建这个“步幅视图”?有没有办法强迫你这么做

更一般地说,有没有办法优化上面的循环

更新:确切错误:

ValueError                                Traceback (most recent call last)
<ipython-input-14-313b3d6c74fa> in <module>()
----> 1 newa = np.lib.stride_tricks.as_strided(base, shape=(1000, 1000, 25, 25), strides=(base.strides * 2))

C:\Python27\lib\site-packages\numpy\lib\stride_tricks.pyc in as_strided(x, shape, strides)
     28     if strides is not None:
     29         interface['strides'] = tuple(strides)
---> 30     array = np.asarray(DummyArray(interface, base=x))
     31     # Make sure dtype is correct in case of custom dtype
     32     array.dtype = x.dtype

C:\Python27\lib\site-packages\numpy\core\numeric.pyc in asarray(a, dtype, order)
    458 
    459     """
--> 460     return array(a, dtype, copy=False, order=order)
    461 
    462 def asanyarray(a, dtype=None, order=None):

ValueError: array is too big.
ValueError回溯(最近一次调用)
在()
---->1 newa=np.lib.stride\u tricks.as_跨步(base,shape=(1000,1000,25,25),strips=(base.strips*2))
C:\Python27\lib\site packages\numpy\lib\stride\u tricks.pyc在as\u stripped(x,shape,strippes)中
28如果跨步不是无:
29接口['strips']=元组(strips)
--->30数组=np.asarray(DummyArray(接口,基=x))
31#如果是自定义数据类型,请确保数据类型正确
32 array.dtype=x.dtype
asarray中的C:\Python27\lib\site packages\numpy\core\numeric.pyc(a,数据类型,顺序)
458
459     """
-->460返回数组(a,数据类型,copy=False,order=order)
461
462 def asanyarray(a,数据类型=无,订单=无):
ValueError:数组太大。

我无法真正帮助您实现跨步方法,但确实有一种方法应该比您的原始代码更快。它在
工具
数组上循环,而不是在
数组上循环,这意味着,尽管没有完全矢量化,numpy仍需要做更多的工作

请注意,在您的原始代码中,我更改了范围并切换了宽度和高度,因为我假设这是您想要的

import numpy as np

height, width = 500, 500
toolh, toolw = 6, 6

base = np.random.rand(height, width)
tool = np.random.rand(toolh, toolw)

m, n = height-toolh+1, width-toolw+1

def height_diff_old(base, tool):
    zdiff = np.empty((m, n))
    for i in range(m):
        for j in range(n):
            zdiff[i, j] = (tool - base[i:i+toolh, j:j+toolw]).min()
    return zdiff

def height_diff_new(base, tool):
    zdiff = np.empty((m, n))
    zdiff.fill(np.inf)
    for i in range(toolh):
        for j in range(toolw):
            diff_ij = tool[i, j] - base[i:i+m, j:j+n]
            np.minimum(zdiff, diff_ij, out=zdiff)
    return zdiff
当然,您希望在实际函数中计算高度和宽度,但是对于测试来说,将它们作为全局变量更容易

对于给定的数组大小,原始代码的运行时间为7.38秒,而新代码在我的系统上仅需206毫秒。我假设新代码对于您的数组大小也更快,但我不确定它的扩展程度如何
:)


您可能感兴趣,也可能不感兴趣的其他备选方案是使用Numba或Cython,在许多情况下,它们应该比任何“矢量化”更快“您想到的numpy代码..

确切的错误是什么?另一方面,这是一个很好的
scipy.ndimage.generic_过滤器
,尽管这可能比您的快速方法慢。我查看了scipy.ndimage generic过滤器。过滤器是一个Python函数,它不会将循环移动到numpy中,而numpy是(我怀疑)真正的加速的地方。@alko:正是那个线程让我走上了这条路。但是,如果维度相乘太大,这种方法就会失效。你看到的错误正在上升。它计算数组的总大小,该数组溢出一个
np.intp
,在32位系统上是一个int32。看起来阵列的虚拟大小不应该是个问题。似乎您只需要将当前检查替换为基于跨步与其相应尺寸乘积之和的检查。如果您切换到64位版本的Numpy,您的所有问题都将消失…@JoeKington No,
因为没有检查这一点,如果您计算错误,开始在实际数组边界之外写入或读取,您可能会把事情搞得一团糟。