2014-04-04 25 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'的函數作爲參數。 –

相關問題