为什么Numba不改进这个迭代。。。?

2024-04-26 06:53:14 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试Numba来加速一个计算联合发生的最小条件概率的函数。在

    import numpy as np
    from numba import double
    from numba.decorators import jit, autojit

    X = np.random.random((100,2))

    def cooccurance_probability(X):
        P = X.shape[1]      
        CS = np.sum(X, axis=0)                  #Column Sums
        D = np.empty((P, P), dtype=np.float)    #Return Matrix
        for i in range(P):
            for j in range(P):
                D[i, j] = (X[:,i] * X[:,j]).sum() / max(CS[i], CS[j])
        return D 

    cooccurance_probability_numba = autojit(cooccurance_probability)

然而,我发现cooccurance_probability和{}的性能几乎相同。在

^{pr2}$

为什么会这样?可能是因为逐元素操作造成的吗?在

我举个例子: http://nbviewer.ipython.org/github/ellisonbg/talk-sicm2-2013/blob/master/NumbaCython.ipynb

[注意:由于问题的对称性,我可以将执行时间缩短一半-但这不是我主要关心的问题]


Tags: infromimportfornprangerandomcs
2条回答

下面是一个使用乔希的建议的解决方案,这是正确的。但是,max()在下面的实现中工作得很好。如果有一个“safe”python/numpy函数的列表,那就太好了。在

注:我将原始矩阵的维数降为100 x 200]

import numpy as np
from numba import double
from numba.decorators import jit, autojit

X = np.random.random((100,200))

def cooccurance_probability_explicit(X):
    C = X.shape[0]
    P = X.shape[1]      
    # - Column Sums - #
    CS = np.zeros((P,), dtype=np.float)
    for p in range(P):
        for c in range(C):
            CS[p] += X[c,p]
    D = np.empty((P, P), dtype=np.float)    #Return Matrix
    for i in range(P):
        for j in range(P):
            # - Compute Elemental Pairwise Sums over each Product Vector - #
            pws = 0
            for c in range(C):
                pws += (X[c,i] * X[c,j])
            D[i,j] = pws / max(CS[i], CS[j])
    return D 

cooccurance_probability_explicit_numba = autojit(cooccurance_probability_explicit)

%timeit结果:

^{pr2}$

结果中有趣的一点是,python显式编写的版本执行速度非常慢,因为类型检查开销很大。但是通过麻木工厂是有魔力的。(Numba比使用Numpy的python解决方案快11.5倍)。在


更新:添加了一个Cython函数进行比较(感谢moarningsun:Cython function with variable sized matrix input

%load_ext cythonmagic
%%cython
import numpy as np
cimport numpy as np

def cooccurance_probability_cy(double[:,:] X):
    cdef int C, P, i, j, k
    C = X.shape[0]
    P = X.shape[1]
    cdef double pws
    cdef double [:] CS = np.sum(X, axis=0)
    cdef double [:,:] D = np.empty((P,P), dtype=np.float)

    for i in range(P):
        for j in range(P):
            pws = 0.0
            for c in range(C):
                pws += (X[c, i] * X[c, j])
            D[i,j] = pws / max(CS[i], CS[j]) 
    return D

%timeit结果:

%timeit cooccurance_probability_cy(X)
100 loops, best of 3: 12 ms per loop

我的猜测是,由于对sum的调用而不是生成本机代码,这意味着Numba不会显著加快速度。它只是不知道如何优化/翻译sum(此时)。此外,通常最好使用Numba将矢量化操作展开为显式循环。请注意,您链接到的ipynb只调用np.sqrt,我相信它确实被翻译成了机器代码,它对元素而不是切片进行操作。我将尝试将内部循环中的和展开为元素上显式的附加循环,而不是采取切片和使用sum方法。在

我的经验是,Numba有时可以创造奇迹,但它不会加快任意python代码的速度。您需要了解它的局限性以及它可以有效地优化什么。还要注意,v0.11在这方面与0.12和0.13有点不同,这是因为Numba在这些版本之间进行了重大的重构。在

相关问题 更多 >