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

时间:2017-08-10 19:37:54

标签: python arrays performance numpy optimization

我有一些代码最初用C语言(由其他人编写)使用C风格的malloc数组。我后来将其中很多内容转换为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

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

1 个答案:

答案 0 :(得分:6)

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

array = np.zeros(list((1024, 1024)), dtype=complex)).

可以写

array = np.zeros((1024, 1024), dtype=complex)

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

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

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

    优点:因为你只编写普通的Python几乎没有修改你的代码,在许多情况下表现出良好的性能。 Numba应该认识到一些NumPy操作,以避免Numba-&gt; Python-&gt; NumPy减速。
    缺点:安装和分发基于Numba的代码可能很繁琐。

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

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

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