Numpy 计算;v^T A v";对于向量v的矩阵
我有一个Numpy 计算;v^T A v";对于向量v的矩阵,numpy,Numpy,我有一个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函数而不是循环)。除非将整个事情并行化:每列一个线程,否则你做
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函数而不是循环)。除非将整个事情并行化:每列一个线程,否则你做不到更快。你仍然会使用循环-你无法摆脱它
Map reduce是解决这个问题的一个很好的方法:映射步长倍数,减少步长和。您可以使用
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'
)
这似乎做得很好:
(X.T.dot(A)*X.T).和(轴=1)
编辑:这要快一点<代码>np.einsum(“…i,…i->…”,X.T.dot(A),X.T)。如果
X
和A
是Fortran连续的,那么两者都能更好地工作。当然,从复杂性的角度来看,我不能更快,但要避免Python循环(支持NumPy构造)通常通过避免较慢的Python代码来提供加速。这对于现代处理器上的大维度来说是相当慢的,因为它能够使用线程BLAS。@Ophion很好,但我相信它仍然比Pythonfor
循环快。。。值得检查pythonfor
循环cython/numpyfor
循环的东西并不重要。时间真的不在循环中。我没有线程BLAS(虽然我应该在某个时候得到它)。对于n=10000
,这比我原来的代码(76.2ms vs.1.48ms)要好。嗯,你可能是对的。感谢einsum
链接;很高兴知道它能做什么。可惜这不是最快的解决方案。(非常令人惊讶的是,它比@IanH在一个内核上的n=10000,k=10
的解决方案要快)似乎轻松地击败了我的原始代码:对于n=10000,k=10
,我的代码是76.2ms,新代码是1.64ms。美好的