Numpy 加速矩阵求逆

Numpy 加速矩阵求逆,numpy,optimization,scipy,statistics,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) resid

我需要按顺序运行此代码数千次:

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_-poster
变成
prior_-mu
V_-poster
变成
prior_-V
a_-poster
变成
prior_-a
,以及
b_-poster
变成
prior_-b
,用于下一次调用。每次调用的y和x都不同

这个函数的运行速度太慢了,大约需要8秒。这是因为规模。我有大约5000个参数,所以
prior\u mu
是(15000),
prior\u V
是(50005000)和对称的
正定的
,以及
prior\u a
prior\u b
是标量。y是标量,x是(15000)

以下是按行列出的时间明细:

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)
有没有办法加快速度?我试着用Cholesky分解法,但速度更慢?!我猜想有一种更有效的方法可以在Python中实现Cholesky分解

prior_cov_inverse2 = np.linalg.inv(np.linalg.cholesky(prior_V))
prior_cov_inverse2 = np.dot(prior_cov_inverse2.transpose(), prior_cov_inverse2)
编辑:以下是一些示例数据来说明这个问题

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))
编辑二:

我已经能够通过去除矩阵的逆运算,并使用谢尔曼-莫里森公式,将其从~8s/run降到~1.4s/run。这是我目前的代码。如果有人对如何进一步加快速度有任何想法,请分享!:)


稳定性方面,编写
solve(A,单位矩阵)
几乎总是比编写
inv(A)
更好。但这对性能没有帮助

这里线性代数的性能几乎肯定是由底层的LAPACK库固定的。Stock ATLAS可能速度最慢,OpenBLAS或MKL更好,有时更好


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

你是否100%肯定你真的需要反转这些矩阵?确定
y
是标量吗?如果是这样,
n=len(y)
有点误导。我想发布y、x、prior_mu、prior_V、prior_a和prior_b的样本数据可能会有所帮助。顺便说一句,你可以看看。@PaulBrodersen我不是100%确定我需要反转它们,但我不确定如何重组它们,这样我就不必反转它们了。我目前执行的是“教科书等式”版本。y不必是标量,但实际上我一次只在模型中输入一个x,y对。@joni我添加了一些示例数据,谢谢!根据你的建议,我把它降到了1.3秒!不过不使用Cholesky会更快。你有没有其他的小贴士来帮助你加快速度?考虑到我需要的重复次数,仍然相当慢。
def update_posterior(y, x, prior_mu, prior_V, prior_a, prior_b, I):

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

    # Calculation of posterior parameters
    # Below is equivalent to np.linalg.inv(prior_V_inverse + np.dot(x_transpose, x)) but significantly faster    
    V_posterior = prior_V - np.true_divide(np.linalg.multi_dot((prior_V, x_transpose, x, prior_V)), 1 + np.matmul(np.matmul(x, prior_V), x_transpose))

    # Below is equivalent to mu_posterior = np.dot(V_posterior, (np.matmul(prior_V_inverse, prior_mu.transpose()) + np.matmul(x_transpose, y))).transpose() but significantly faster
    mu_posterior = np.dot(V_posterior, np.linalg.solve(prior_V, prior_mu.transpose()) + np.matmul(x_transpose, y)).transpose()
    a_posterior = prior_a + n/2
    b_posterior = np.asscalar(prior_b + (np.matmul(np.matmul(residuals.transpose(), np.linalg.inv((np.identity(n) + np.matmul(np.matmul(x, prior_V), x_transpose)))), residuals))/2)

    return mu_posterior, V_posterior, a_posterior, b_posterior