我们可以优化这似乎是瓶颈对数运算和被超越的一个函数可以用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