我正试图优化三对角矩阵的特征值/向量的计算。我的代码目前需要大约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
包含奇异值(在这里等价于特征值(,U
和V
包含奇异向量(在这里等效于特征向量(。理论上,如果H
是对称矩阵,则U
应与V.T
相同。我没有发现这个例子是这样的,这让我有点困惑。。。但我还是会继续发布这篇文章,因为事实上这篇文章只需要一秒钟的时间,所以可能是你的解决方案。
然而,还有一个更大的警告。你把which="SM"
传递给eigsh
,据我所知,这意味着你要400个最小的特征值。这真的是你想要的吗?在我所知道的几乎所有应用中,你都想要400个最大的特征值。如果事实上你真的想要400个最小的特征值,那么这是行不通的,因为它依赖于这样一个事实,即使用随机矩阵投影更容易哄出最大的特征值。
结果是,你会想测试一下,看看它是否真的给出了你可以使用的结果。但这是一个有趣的可能的解决方案,考虑到你到目前为止所说的问题。