加速科学python计划

时间:2015-09-06 18:24:23

标签: python numpy scientific-computing

我在python中有以下代码:

def P(z, u0):
    x = np.inner(z, u0)
    tmp = x*u0
    return (z - tmp)


def powerA2(A, u0):
    x0 = np.random.rand(len(A))
    for i in range(ITERATIONS):
        x0 = P(np.dot(A, x0), u0)
        x0 = x0 / np.linalg.norm(x0)
    return (np.inner(np.dot(A, x0), x0))

np numpy 包。

我有兴趣为大小为100,000 * 100,000的矩阵运行此代码,但似乎该程序没有机会快速运行(我需要多次运行,大约10,000次)。

多线程技巧是否有可能在这里发挥作用?

还有什么能帮助加速吗?

3 个答案:

答案 0 :(得分:8)

您可以考虑使用Pythran。编译以下代码(norm.py):

#pythran export powerA2(float [][], float[])
import numpy as np

def P(z, u0):
    x = np.inner(z, u0)
    tmp = x*u0
    return (z - tmp)

def norm(x):
    return np.sqrt(np.sum(np.abs(x)**2))

def powerA2(A, u0):
    ITERATIONS = 100
    x0 = np.random.random(len(A))
    for i in range(ITERATIONS):
        x0 = P(np.dot(A, x0), u0)
        x0 = x0 / norm(x0)
    return (np.inner(np.dot(A, x0), x0))

使用:

pythran norm.py

产生以下加速:

$ python -m timeit -s 'import numpy as np; A = np.random.rand(100, 100); B = np.random.random(100); import norm' 'norm.powerA2(A, B)'
100 loops, best of 3: 3.1 msec per loop
$ pythran norm.py -O3 -march=native
$ python -m timeit -s 'import numpy as np; A = np.random.rand(100, 100); B = np.random.random(100); import norm' 'norm.powerA2(A, B)'
1000 loops, best of 3: 937 usec per loop

答案 1 :(得分:2)

只是为了检查:你想做10 ^ 10的10 ^ 4操作......所以即使你的操作是O(1),那仍然是10 ^ 14的操作,这是相当困难的问题(正如haraldkl在他的评论中所指出的那样,这也消耗了大量的内存)只是为了检查:你打算给powerA2召唤10,000次,或者是ITERATIONS所需的10,000。如果是前者,你可以使用线程(或更好的,单独的进程)来获得一些并行化,但我不知道这是否足够;如果是后者,除非我缺少一个技巧,否则你的输入看起来并不平行,因为每个循环迭代的输入都取决于前一个的输出。可能有一种方法可以在GPU上执行此操作(我想认为这是一种至少执行规范化位的有效方法,以便通过使用矢量化可以快速完成大量的操作)

编辑以回应评论:cpython(这是最常见的python实现)具有Global Interpeter Lock(GIL);其他一些python实现(jython,ironpython)没有;每https://wiki.python.org/moin/GlobalInterpreterLock ,.

  

请注意可能阻塞或长时间运行的操作,例如   I / O,图像处理和NumPy数字运算都发生在外面   GIL。因此,只有在多线程程序中花费很多   GIL内部的时间,解释CPython字节码,即GIL   成为瓶颈。

据我所知,应该可以使用numpy的线程而不是可怕的瓶颈,但你的问题仍然很难转换为线程,除非我缺少一些数学知识。

答案 2 :(得分:2)

通过以这种方式重新定义功能,我比未填充的serge-sans-paille版本提高了10%:

def P0(z, u0):
    x = np.inner(z, u0)
    x *= u0
    return (z - x)

def norm0(x):
    return np.sqrt(np.sum(x*x))

def powerA20(A, u0):
    ITERATIONS = 100
    x0 = np.random.random(len(A))
    for i in range(ITERATIONS):
        x0 = P0(np.dot(A, x0), u0)
        x0 /= norm0(x0)
    return (np.inner(np.dot(A, x0), x0))

执行*= u0而不是x = x*u0这样的操作可以避免RAM中变量的不必要副本,从而加快程序的运行速度。 此外,在这种情况下,您不需要abs。最后,x*x略快于x**2