2014-04-04 26 views
2

我试图在Numba加速计算联合发生的最小条件概率的函数。为什么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_probabilitycooccurance_probability_numba性能是大同小异的。

%timeit cooccurance_probability(X) 
1 loops, best of 3: 302 ms per loop 

%timeit cooccurance_probability_numba(X) 
1 loops, best of 3: 307 ms per loop 

这是为什么?它可能是由于元素操作的numpy元素?

我下面作为一个例子: http://nbviewer.ipython.org/github/ellisonbg/talk-sicm2-2013/blob/master/NumbaCython.ipynb

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

回答

2

我的猜测可能是因为对sum的调用而触发对象层,而不是生成本机代码,这意味着Numba不会显着提高速度。它只是不知道如何优化/翻译sum(在这一点上)。此外,将矢量化操作展开为与Numba进行显式循环通常会更好。请注意,您链接到的ipynb只会调用到np.sqrt,我相信这会转换为机器码,并且它对元素进行操作,而不是对片进行操作。我会尝试扩展内循环中的总和作为元素上的显式附加循环,而不是采用切片并使用sum方法。

我的经验是,Numba有时可以创造奇迹,但它不会加速任意Python代码。您需要了解局限性以及它可以有效优化的内容。还要注意,由于Numba在这些版本之间进行了重大的重构,v0.11在这方面与0.12和0.13相比稍有不同。

1

下面是使用乔希的建议,这是现货的解决方案。然而,似乎max()在下面的实现中工作正常。如果有一个“安全” python/numpy函数的列表,那将是非常好的。

注:我原来矩阵的维数减少到100×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结果:

%timeit cooccurance_probability(X) 
10 loops, best of 3: 83 ms per loop 


%timeit cooccurance_probability_explicit(X) 
1 loops, best of 3: 2.55s per loop 

%timeit cooccurance_probability_explicit_numba(X) 
100 loops, best of 3: 7.72 ms per loop 

一下,结果有趣的是,在精确由python执行的书面版本非常缓慢,因为大型的检查开销。但通过Numba的作品是神奇的。 (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 
+0

如果'X'具有形状'[ m,n]',你需要结果是'[m,m]还是'[n,n]'?你的问题和你的答案是不同的。 –

+0

原问题已更正......谢谢......''X''有形状''[m,n]''并计算共点我比较所有可能的列向量组合,因此导致''[n, n]矩阵。 – sanguineturtle

+0

我问过,因为现在你的代码运行得足够快,所以对缓存友好性进行优化是明智的。目前,您正在非连续地访问'X',假设'X'是连续的并且是C-次序的,这导致次优的RAM访问。为了看到性能的差异,使'X'为方形数组,并将具有'X'和'X.T'的函数作为参数。 –

相关问题