我需要依次运行此代码数千次:
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_mu
,V_posterior
变成prior_V
,a_posterior
成为prior_a
,并且b_posterior
成为下一次通话的prior_b
。每次通话中y和x都不相同。
此功能非常慢-我大约需要8秒钟才能运行。这是因为规模。我有〜5000个参数,所以prior_mu
是(1,5000),prior_V
是(5000,5000)且对称的positive-definite
,prior_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))
答案 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
进行直接反演。