【问题标题】:Calculate "v^T A v" for a matrix of vectors v计算向量矩阵的“v^T A v”
【发布时间】:2020-04-17 02:18:01
【问题描述】:

我有一个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 函数而不是循环)。

【问题讨论】:

    标签: numpy


    【解决方案1】:

    这似乎做得很好: (X.T.dot(A)*X.T).sum(axis=1)

    编辑:这有点快。 np.einsum('...i,...i->...', X.T.dot(A), X.T)。如果 XA 是 Fortran 连续的,则两者都可以更好地工作。

    【讨论】:

    • 似乎轻松击败了我的原始代码:对于n=10000, k=10,我的代码是76.2ms,新代码是1.64ms。不错!
    【解决方案2】:

    您可以使用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'
        )
    

    【讨论】:

    • 这对于现代处理器上的大尺寸来说要慢得多,因为它能够使用线程化的 BLAS。
    • @Ophion 好点,但我相信它仍然会比 Python for 循环更快...值得一试
    • Python for 循环 cython/numpy for 循环无关紧要。时间真的不在循环中。
    • 我没有线程化的 BLAS(尽管我显然应该在某个时候得到它)。对于n=10000,这优于我的原始代码(76.2ms vs. 1.48ms)。
    • 嗯,你可能是对的。感谢einsum 链接;很高兴知道它可以做什么。太糟糕了,这不是最快的解决方案。 (非常令人惊讶的是,它比 @IanH 在一个内核上的 n=10000, k=10 解决方案更快)
    【解决方案3】:

    除非您将整个事情并行化,否则您无法更快地做到这一点:每列一个线程。你仍然会使用循环——你无法摆脱它。

    Map reduce 是解决这个问题的好方法:map step multiples,reduce step sums。

    【讨论】:

    • 当然,从复杂性的角度来看,我不能变得更快,但是避免 Python 循环(有利于 NumPy 构造)通常可以通过避免较慢的 Python 代码来提高速度。
    猜你喜欢
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    • 2017-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多