【发布时间】:2020-10-17 10:37:14
【问题描述】:
我一直在尝试 Python 3 中可用的不同稀疏求解器,并比较它们之间的性能以及与 Octave 和 Matlab 的性能。我选择了直接和迭代两种方法,我将在下面更详细地解释这一点。
为了生成具有带状结构的适当稀疏矩阵,使用具有 N=250、N=500 和 N=1000 的平方网格的有限元来解决泊松问题。这导致矩阵 A=N^2xN^2 和向量 b=N^2x1 的维度,即最大的 NxN 是一百万。如果有人有兴趣复制我的结果,我已经在以下链接中上传了矩阵 A 和向量 b(它将在 30 天后过期)Get systems used here。矩阵存储在三元组 I、J、V 中,即前两列分别是行和列的索引,第三列是对应于这些索引的值。请注意,V 中有一些值几乎为零,是故意留下的。尽管如此,带状结构在 Matlab 和 Python 中的“间谍”矩阵命令之后仍然保留。
为了比较,我使用了以下求解器:
Matlab 和 Octave,直接求解器:规范的 x=A\b。
Matlab 和 Octave,pcg 求解器:预处理共轭梯度,pcg 求解器pcg(A,b,1e-5,size(b,1))(未使用预处理器)。
Scipy (Python),直接求解器:linalg.spsolve(A, b),其中 A 之前以 csr_matrix 格式格式化。
Scipy (Python)、pcg 求解器:sp.linalg.cg(A, b, x0=None, tol=1e-05)
Scipy (Python),UMFPACK 求解器:spsolve(A, b) 使用 from scikits.umfpack import spsolve。这个求解器显然(仅?)在 Linux 下可用,因为它使用了 libsuitesparse [Timothy Davis, Texas A&M]。在 ubuntu 中,必须先将其安装为 sudo apt-get install libsuitesparse-dev。
此外,上述 python 求解器已在以下位置进行测试:
- 窗户。
- Linux。
- Mac 操作系统。
条件:
- 在系统求解之前和之后进行计时。即,不考虑读取矩阵的开销。
- 对每个系统进行十次计时,然后计算平均值和标准差。
硬件:
- Windows 和 Linux:Dell intel (R) Core(TM) i7-8850H CPU @2.6GHz 2.59GHz,32 Gb RAM DDR4。
- Mac 操作系统:Macbook Pro Retina 2014 年中 intel (R) quad-core(TM) i7 2.2GHz 16 Gb Ram DDR3。
观察:
- Matlab A\b 是速度最快的,尽管使用的是较旧的计算机。
- Linux 和 Windows 版本之间存在显着差异。例如,参见 NxN=1e6 处的直接求解器。尽管 Linux 在 Windows (WSL) 下运行。
- 在 Scipy 求解器中可能会有很大的分散。也就是说,如果多次运行相同的解决方案,其中一次可能会增加两倍以上。
- python 中最快的选项可能比在更有限的硬件中运行的 Matlab 慢近四倍。真的吗?
如果你想重现测试,我在这里留下非常简单的脚本。 对于 matlab/octave:
IJS=load('KbN1M.txt');
b=load('FbN1M.txt');
I=IJS(:,1);
J=IJS(:,2);
S=IJS(:,3);
Neval=10;
tsparse=zeros(Neval,1);
tsolve_direct=zeros(Neval,1);
tsolve_sparse=zeros(Neval,1);
tsolve_pcg=zeros(Neval,1);
for i=1:Neval
tic
A=sparse(I,J,S);
tsparse(i)=toc;
tic
x=A\b;
tsolve_direct(i)=toc;
tic
x2=pcg(A,b,1e-5,size(b,1));
tsolve_pcg(i)=toc;
end
save -ascii octave_n1M_tsparse.txt tsparse
save -ascii octave_n1M_tsolvedirect.txt tsolve_direct
save -ascii octave_n1M_tsolvepcg.txt tsolve_pcg
对于python:
import time
from scipy import sparse as sp
from scipy.sparse import linalg
import numpy as np
from scikits.umfpack import spsolve, splu #NEEDS LINUX
b=np.loadtxt('FbN1M.txt')
triplets=np.loadtxt('KbN1M.txt')
I=triplets[:,0]-1
J=triplets[:,1]-1
V=triplets[:,2]
I=I.astype(int)
J=J.astype(int)
NN=int(b.shape[0])
Neval=10
time_sparse=np.zeros((Neval,1))
time_direct=np.zeros((Neval,1))
time_conj=np.zeros((Neval,1))
time_umfpack=np.zeros((Neval,1))
for i in range(Neval):
t = time.time()
A=sp.coo_matrix((V, (I, J)), shape=(NN, NN))
A=sp.csr_matrix(A)
time_sparse[i,0]=time.time()-t
t = time.time()
x=linalg.spsolve(A, b)
time_direct[i,0] = time.time() - t
t = time.time()
x2=sp.linalg.cg(A, b, x0=None, tol=1e-05)
time_conj[i,0] = time.time() - t
t = time.time()
x3 = spsolve(A, b) #ONLY IN LINUX
time_umfpack[i,0] = time.time() - t
np.savetxt('pythonlinux_n1M_tsparse.txt',time_sparse,fmt='%.18f')
np.savetxt('pythonlinux_n1M_tsolvedirect.txt',time_direct,fmt='%.18f')
np.savetxt('pythonlinux_n1M_tsolvepcg.txt',time_conj,fmt='%.18f')
np.savetxt('pythonlinux_n1M_tsolveumfpack.txt',time_umfpack,fmt='%.18f')
有没有办法使用 python 进一步改善稀疏求解时间?或者至少与Matlab的性能顺序相似?我对使用 C/C++ 或 Fortran 以及 python 包装器的建议持开放态度,但我相信它不会比 UMFPACK 选择更好。非常欢迎提出建议。
附:我知道以前的帖子,例如scipy slow sparse matrix solver Issues using the scipy.sparse.linalg linear system solvers How to use Numba to speed up sparse linear system solvers in Python that are provided in scipy.sparse.linalg? 但我认为没有一个比这个更全面,突出了使用 python 库时操作系统之间的更多问题。
EDIT_1: 我使用 cmets 中建议的 python 包装器使用来自英特尔 MKL 的 QR 求解器添加了一个带有结果的新图。然而,这仍然落后于 Matlab 的性能。 为此,需要添加:
from sparse_dot_mkl import sparse_qr_solve_mkl
和
sparse_qr_solve_mkl(A.astype(np.float32), b.astype(np.float32))
原始帖子中提供的脚本。可以省略“.astype(np.float32)”,并且该系统的性能会稍微变差(大约 10 %)。
【问题讨论】:
-
试试 mkl 求解器。我经常使用 mkl QR 求解器进行直接求解,因为它比 scipy 直接求解器快得多。 FGMRES 对于某些事情也是一个很好的迭代求解器,但我发现它对我糟糕的初始近似值有点敏感。
-
感谢您的回复。我知道英特尔 MKL 例程,但我忽略了是否有包装器/库可以在 python 中使用此类例程。您指的是后者吗?如果是这样,如果您能参考一些文档,我将不胜感激。无论如何,一些 MKL 例程在后台使用 BLAS、LAPACK 和类似的例程,不是吗?也可能使用这种例程英特尔编译器可以实现更好的优化级别。无论如何,通过 Python 使用这些工具中的任何一个都是非常理想的。
-
我有自己的 FGMRES 包装器——老实说,它们很容易从 python 内部调用,因为你可以很容易地从 numpy 数组中获取指针。谷歌表示,QR 求解器有一个包装器:pypi.org/project/sparse-dot-mkl
-
感谢您的回复。我已经使用您建议的包装器尝试了 QR 求解器。我在原始帖子中添加了一个情节。然而,它仍然有点落后于 Matlab 的性能,与 UFMPACK 非常相似。我很想用 Petsc 之类的东西来测试这个问题。顺便说一句,您是否知道比 Scipy 中更好的共轭梯度求解器?根据我的经验,在 Matlab 中使用不完整的 Cholesky 分解和 PCG 中的预处理对于非常大的系统非常有用。比直接求解器更快。在 scipy 中期待这样的东西。干杯!。
-
我可能会在 mkl 中使用 CG 求解器。还有一个 LU 预处理器。总的来说,我倾向于将 mkl 用于稀疏求解器而不是 scipy。不过,我不知道有任何包可以充当迭代求解器的包装器。
标签: python performance matlab sparse-matrix scientific-computing