在大型阵列上进行手动元素操作的numpy更快的替代方案?

BZ1*_*BZ1 1 python arrays optimization performance numpy

我有一些代码最初使用C风格的malloc数组用C语言(由其他人编写).我后来将其中很多内容转换为C++样式,使用vector<vector<vector<complex>>>数组与我项目的其余部分保持一致.我从来没有计时,但两种方法似乎速度相似.

我最近在python中开始了一个新项目,我想使用一些旧的代码.我不想将数据移回到项目之间,我决定将这些旧代码移植到python中,以便将它们全部放在一个项目中.我天真地用python语法输入所有代码,用numpy数组替换旧代码中的任何数组(像这样初始化它们array = np.zeros(list((1024, 1024)), dtype=complex)).代码工作正常,但速度极慢.如果我不得不猜测,我会说它的速度慢了1000倍.

现在看了一下,我看到很多人说numpy对于元素操作非常缓慢.虽然我已经将一些numpy函数用于常见的数学运算,例如FFT和矩阵乘法,但我的大部分代码都涉及嵌套for循环.很多都很复杂,在我看来似乎不适合简​​化为numpy更快的简单数组操作.

所以,我想知道是否有一种替代numpy,这种计算更快.理想情况是我可以导入一个具有许多相同功能的模块,因此我不必重写我的大部分代码(即,可以执行FFT并以相同方式初始化数组的东西)但是,如果没有这个,我会很满意我至少可以用于代码中计算要求更高的部分,并根据需要在numpy数组之间来回转换.

cpython数组听起来很有希望,但我见过的很多基准测试并没有为我的目的显示出足够的速度差异.为了解我正在谈论的事情,这是减慢我的代码的方法之一.这称为数百万次,该vz_at()方法包含一个查找表,并进行一些插值以给出最终的返回值:

    def tra(self, tr, x, y, z_number, i, scalex, idx, rmax2, rminsq):
        M = 1024
        ixo = int(x[i] / scalex)
        iyo = int(y[i] / scalex)
        nx1 = ixo - idx
        nx2 = ixo + idx
        ny1 = iyo - idx
        ny2 = iyo + idx

        for ix in range(nx1, nx2 + 1):
            rx2 = x[i] - float(ix) * scalex
            rx2 = rx2 * rx2
            ixw = ix
            while ixw < 0:
                ixw = ixw + M
            ixw = ixw % M
            for iy in range(ny1, ny2 + 1):
                rsq = y[i] - float(iy) * scalex
                rsq = rx2 + rsq * rsq
                if rsq <= rmax2:
                    iyw = iy
                    while iyw < 0:
                        iyw = iyw + M
                    iyw = iyw % M
                    if rsq < rminsq:
                        rsq = rminsq
                    vz = P.vz_at(z_number[i], rsq)
                    tr[ixw, iyw] += vz
Run Code Online (Sandbox Code Playgroud)

总而言之,有几千行代码; 这只是一个例子的小片段.需要说明的是,我的很多数组都是1024x1024x1024或1024x1024,并且是复数值的.其他是一百万个元素的一维数组.什么是我可以加快这些元素操作的最佳方法?

Pie*_*uyl 6

有关信息,您的一些代码可以更简洁,因此更具可读性.例如:

array = np.zeros(list((1024, 1024)), dtype=complex)).
Run Code Online (Sandbox Code Playgroud)

可以写

array = np.zeros((1024, 1024), dtype=complex)
Run Code Online (Sandbox Code Playgroud)

当您尝试Python时,这至少是一个很好的好处:-)

现在,针对您的问题,目前的Python科学领域有几种解决方案:

  1. Numba是Python的即时编译器,专门用于阵列处理,在NumPy达到极限时实现良好的性能.

    优点:只需编写纯Python就很难修改代码,在许多情况下都表现出良好的性能.Numba应该认识到一些NumPy操作,以避免Numba-> Python-> NumPy减速.
    缺点:安装并因此分发基于Numba的代码可能很繁琐.

  2. Cython是Python和C的混合体,用于生成编译函数.您可以从纯Python文件开始,通过类型注释和一些"C"主题来加速代码.

    优点:稳定,广泛使用,相对容易分发基于Cython的代码.
    缺点:需要重写性能关键代码,即使只是部分代码.

作为一个额外的提示,Nicolas Rougier(法国科学家)写了一本在线书籍,在很多情况下你可以利用NumPy加速Python代码:http://www.labri.fr/perso/nrougier/from-python-到numpy的/