我有一个k*n
矩阵 X 和一个k*k
矩阵 A。对于X
的每一列,我想计算标量
X[:, i].T.dot(A).dot(X[:, i])
(或在数学上,Xi' * A * Xi
)。
目前,我有一个for
循环:
out = np.empty((n,))
for i in xrange(n):
out[i] = X[:, i].T.dot(A).dot(X[:, i])
但是由于n
很大,如果可能的话,我想更快地做到这一点(即使用一些 NumPy 函数而不是循环)。
这似乎做得很好:(X.T.dot(A)*X.T).sum(axis=1)
编辑:这有点快。np.einsum('...i,...i->...', X.T.dot(A), X.T)
。如果X
和A
是 Fortran 连续的,则两者都可以更好地工作。
您可以使用numpy.einsum
:
np.einsum('ji,jk,ki->i',x,a,x)
这会得到相同的结果,让我们看看它是否快得多:
看起来dot
仍然是最快的选择,特别是因为它使用线程 BLAS,而不是在一个内核上运行的einsum
。
import perfplot
import numpy as np
def setup(n):
k = n
x = np.random.random((k, n))
A = np.random.random((k, k))
return x, A
def loop(data):
x, A = data
n = x.shape[1]
out = np.empty(n)
for i in range(n):
out[i] = x[:, i].T.dot(A).dot(x[:, i])
return out
def einsum(data):
x, A = data
return np.einsum('ji,jk,ki->i', x, A, x)
def dot(data):
x, A = data
return (x.T.dot(A)*x.T).sum(axis=1)
perfplot.show(
setup=setup,
kernels=[loop, einsum, dot],
n_range=[2**k for k in range(10)],
logx=True,
logy=True,
xlabel='n, k'
)
你不能做得更快,除非你并行化整个事情:每列一个线程。
映射减少是一个很好的方式来看待这个问题:映射步长倍数,减少步骤和。
本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处
评论列表(22条)