我正在尝试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
和cooccurance_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
[注意:由于问题的对称性,我可以将执行时间缩短一半 - 但这不是我主要关注的问题]
答案 0 :(得分:2)
我的猜测是,由于调用了sum
,您正在点击对象层而不是生成本机代码,这意味着Numba不会显着加快速度。它只是不知道如何优化/翻译sum
(此时)。另外,通常使用Numba将矢量化操作展开到显式循环中会更好。请注意,您链接到的ipynb仅调用np.sqrt
,我相信它会转换为机器代码,并且它对元素而不是切片进行操作。我会尝试将内部循环中的总和扩展为元素的显式附加循环,而不是采用切片并使用sum
方法。
我的经验是,Numba有时可以创造奇迹,但它并没有加速任意python代码。您需要了解限制以及可以有效优化的内容。另请注意,v0.11在这方面略有不同,而0.12和0.13由于Numba在这些版本之间经历的重大重构而有所不同。
答案 1 :(得分:1)
以下是使用Josh的建议的解决方案,这是一个现场。但是看起来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
结果:
%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