加快矩阵求逆

时间:2018-11-19 05:33:51

标签: numpy optimization scipy statistics

我需要依次运行此代码数千次:

def update_posterior(y, x, prior_mu, prior_V, prior_a, prior_b):

    # Building blocks used to keep following calculation cleaner
    prior_cov_inverse = np.linalg.inv(prior_V)
    x_transpose = x.transpose()
    n = len(y)
    residuals = y - np.dot(x, prior_mu.transpose())

    # Calculation of posterior parameters
    V_posterior = np.linalg.inv((prior_cov_inverse + x_transpose * x))
    mu_posterior = (V_posterior * (prior_cov_inverse * prior_mu.transpose() + x_transpose * y)).transpose()
    a_posterior = prior_a + n/2
    b_posterior = np.asscalar(prior_b + (residuals.transpose() * np.linalg.inv((np.identity(n) + x * prior_V * x_transpose)) * residuals)/2)

    return mu_posterior, V_posterior, a_posterior, b_posterior

它的工作方式是将函数的输出反馈到其中,其中mu_posterior变成prior_muV_posterior变成prior_Va_posterior成为prior_a,并且b_posterior成为下一次通话的prior_b。每次通话中y和x都不相同。

此功能非常慢-我大约需要8秒钟才能运行。这是因为规模。我有〜5000个参数,所以prior_mu是(1,5000),prior_V是(5000,5000)且对称的positive-definiteprior_a和{{1} }是标量。 y是标量,x是(1,5000)。

以下是按时间细分的时间:

prior_b

有什么想法可以加快速度吗?我尝试使用Cholesky分解,但速度更慢?我的猜测是有一种在Python中实现Cholesky分解的更有效方法。

3.75s: prior_cov_inverse = np.linalg.inv(prior_V)
3.86s: V_posterior = np.linalg.inv((prior_cov_inverse + x_transpose * x))
0.13s: b_posterior = np.asscalar(prior_b + (residuals.transpose() * np.linalg.inv((np.identity(n) + x * prior_V * x_transpose)) * residuals)/2)

编辑:这是一些示例数据来说明问题。...

prior_cov_inverse2 = np.linalg.inv(np.linalg.cholesky(prior_V))
prior_cov_inverse2 = np.dot(prior_cov_inverse2.transpose(), prior_cov_inverse2)

编辑II:

通过消除矩阵求逆并支持Sherman Morrison公式,我能够将其从〜8s / run降至〜1.4s / run。这是我当前的代码。如果有人对如何进一步加快速度有任何想法,请分享! :)

import numpy as np

prior_mu = np.asmatrix(np.full((1, 5040), 5))
prior_V = np.diagflat(np.asmatrix(np.full((1, 5040), 30))) #usually not diagonal, but always symmetric positive definitive
a = 2
b = 2
y = np.asmatrix([10])
x = np.asmatrix(np.concatenate(([1], np.zeros(5039))))

print(update_posterior(y, x, prior_mu, prior_V, a, b))

1 个答案:

答案 0 :(得分:1)

在稳定性方面,写solve(A, unit_matrix)而不是inv(A)总是更好。但这对性能没有帮助。

这里的线性代数的性能几乎肯定由基础的LAPACK库固定。股票ATLAS可能最慢,OpenBLAS或MKL可能更好,有时更好。

但是,我敢肯定,这里的主要改进确实是算法上的。首先,对于PSD矩阵,Cholecky(cholesky / cho_solve)应该更好。其次,您似乎正在执行一次秩更新(x.T @x),并且 通常可以通过Shermann-Morrison公式的某种变体在N**2操作中实现,而不是N**3进行直接反演。