我們可以優化這似乎是瓶頸對數運算和被超越的一個函數可以用numexpr
module加速,然後sum-reduce
用NumPy加速,因爲NumPy做得好得多,因此給了我們一個混合版本,就像這樣 -
import numexpr as ne
def numexpr_app(X, a, b):
XT = X.T
return ne.evaluate('log(XT * b + a)').sum(0)
仔細觀察廣播業務:XT * b + a
,我們看到廣播有兩個階段,我們可以進一步優化。目的是要看看是否可以減少到一個階段,這在某些部門似乎是可能的。這給我們一個稍微修改後的版本,如下圖所示 -
def numexpr_app2(X, a, b):
ab = (a/b)
XT = X.T
return np.log(b).sum() + ne.evaluate('log(ab + XT)').sum(0)
運行測試和驗證
原始的方法 -
def numpy_app(X, a, b):
return np.sum(np.log(X.T * b + a).T, 1)
計時 -
In [111]: # Setup inputs
...: density = 0.08/100 # 0.08 % sparse
...: m,n = 30000, 1000
...: X = scipy.sparse.rand(m,n,density=density,format="csr").toarray()
...: a = np.random.rand(n,1)
...: b = np.random.rand(n,1)
...:
In [112]: out0 = numpy_app(X, a, b)
...: out1 = numexpr_app(X, a, b)
...: out2 = numexpr_app2(X, a, b)
...: print np.allclose(out0, out1)
...: print np.allclose(out0, out2)
...:
True
True
In [114]: %timeit numpy_app(X, a, b)
1 loop, best of 3: 691 ms per loop
In [115]: %timeit numexpr_app(X, a, b)
10 loops, best of 3: 153 ms per loop
In [116]: %timeit numexpr_app2(X, a, b)
10 loops, best of 3: 149 ms per loop
只是爲了證明在啓動log
部分與原NumPy的方法的瓶頸規定的觀察,這裏是它的時機 - 在其改善是顯著
In [44]: %timeit np.log(X.T * b + a)
1 loop, best of 3: 682 ms per loop
-
In [120]: XT = X.T
In [121]: %timeit ne.evaluate('log(XT * b + a)')
10 loops, best of 3: 142 ms per loop
什麼你用什麼結構來存儲X?你有沒有看過scipy.sparse.csc_matrix? –
這是一個現在的數組。不,我沒有看它.. –
冒險將這部分信息添加到帖子中,這是至關重要的。此外,人們可能會混淆NumPy稀疏矩陣和scipy稀疏矩陣,所以也編輯過標題。這個「稀疏」是我可以想象的最好的,而不會與SciPy稀疏矩陣混淆。 – Divakar