如何优化三对角矩阵的特征值/矢量计算



我正试图优化三对角矩阵的特征值/向量的计算。我的代码目前需要大约30秒才能运行,我需要它以更快的速度运行,大约1秒。我目前使用scipy.sparse.linalg.eigsh方法来寻找特征值/向量,但我认为应该有其他更快的方法。我会在下面发布我的代码,这样可以更容易地看到我正在尝试做什么。非常欢迎任何建议,如果有什么不清楚的地方,请告诉我。

H = (dx**-2)*diags([-1, 2, -1], [-1, 0, 1], shape=(N, N))
H = sp.lil_matrix(H)
H[0,0]=0.5*H[0,0]
H[N-1,N-1]=0.5*H[N-1,N-1]
lam, phi = eigsh(H, 400, which="SM")

您不太可能找到将此计算速度提高30倍的简单方法。正如你从这篇文章中的时间安排中看到的,即使是谷歌令人印象深刻的优化jax库,在scipy中的基本SVD实现上也只能实现不到3倍的加速。由于对称矩阵的SVD等价于eigsh,我们可以预期eigsh的加速速度最多也差不多。

因此,即使是谷歌也无法加快这一计算速度,至少以传统方式是这样。

然而,对于非常大的稀疏矩阵,有专门的随机算法可以在适当的情况下以更大的因素加速。其中一个有sklearn实现:sklearn.utils.extmath.randomized_swd。(我相信它是基于这里描述的算法,当algorithm='randomized'时,它也可能与sklearn.decomposition.TruncatedSVD相同。(

下面是您的示例的一个稍微修改过的版本,展示了如何使用它:

from scipy.sparse import diags, lil_matrix
from scipy.sparse.linalg import eigsh
from sklearn.utils.extmath import randomized_svd
N = 3200
k = 400
dx = 1.0
H = (dx**-2)*diags([-1, 2, -1], [-1, 0, 1], shape=(N, N))
H = lil_matrix(H)
H[0, 0] = 0.5*H[0, 0]
H[N-1, N-1] = 0.5*H[N-1, N-1]
# lam, phi = eigsh(H, k, which="SM")
U, s, V = randomized_svd(H, k)

这里,s包含奇异值(在这里等价于特征值(,UV包含奇异向量(在这里等效于特征向量(。理论上,如果H是对称矩阵,则U应与V.T相同。我没有发现这个例子是这样的,这让我有点困惑。。。但我还是会继续发布这篇文章,因为事实上这篇文章只需要一秒钟的时间,所以可能是你的解决方案。

然而,还有一个更大的警告。你把which="SM"传递给eigsh,据我所知,这意味着你要400个最小的特征值。这真的是你想要的吗?在我所知道的几乎所有应用中,你都想要400个最大的特征值。如果事实上你真的想要400个最小的特征值,那么这是行不通的,因为它依赖于这样一个事实,即使用随机矩阵投影更容易哄出最大的特征值。

结果是,你会想测试一下,看看它是否真的给出了你可以使用的结果。但这是一个有趣的可能的解决方案,考虑到你到目前为止所说的问题。

最新更新