在C ++中解决稀疏线性系统的最佳方法 - GPU可能吗?

时间:2017-02-08 14:48:54

标签: c++ sparse-matrix eigen cusolver suitesparse

我目前正在开展一个需要解决的项目

|Ax - b|^2

在这种情况下,A是一个非常稀疏的矩阵,A'A每行最多有5个非零元素。

我们正在使用图片,A'A的尺寸为NxN,其中N是像素数。在这种情况下N = 76800。我们计划转到RGB,然后尺寸将为3Nx3N

在matlab中解决(A'A)\(A'b)大约需要0.15秒,使用双打。

我现在已经对Eigens稀疏求解器进行了一些实验。我试过了:

SimplicialLLT
SimplicialLDLT
SparseQR
ConjugateGradient

和一些不同的排序。到目前为止最好的是

SimplicialLDLT

使用0.35 - 0.5大约AMDOrdering

例如,当我使用ConjugateGradient时,大约6 s,使用0作为初始化。

解决问题的代码是:

    A_tot.makeCompressed();
     // Create solver
    Eigen::SimplicialLDLT<Eigen::SparseMatrix<float>, Eigen::Lower, Eigen::AMDOrdering<int> > solver;
    // Eigen::ConjugateGradient<Eigen::SparseMatrix<float>, Eigen::Lower> cg;
    solver.analyzePattern(A_tot);
    t1 = omp_get_wtime();
    solver.compute(A_tot);
    if (solver.info() != Eigen::Success)
     {
         std::cerr << "Decomposition Failed" << std::endl;
         getchar();
     }
    Eigen::VectorXf opt = solver.solve(b_tot);
    t2 = omp_get_wtime();
    std::cout << "Time for normal equations: " << t2 - t1 << std::endl;

这是我第一次在C ++及其求解器中使用稀疏矩阵。对于这个项目,速度至关重要,低于0.1 s是最低的。

我想得到一些反馈意见,哪些是最好的策略。例如,应该可以在SuiteSparse中使用OpenMPEigen。您对这些类型的问题有什么经验?有没有办法提取结构? conjugateGradient真的应该那么慢吗?

编辑:

感谢有价值的评论!今晚我一直在读关于Nvidia的cuSparse。它似乎能够分解甚至解决系统。特别是它似乎可以重复使用模式等等。问题是这有多快,可能的开销是多少?

鉴于我的矩阵A中的数据量与图像中的数据量相同,因此内存复制不应该是这样的问题。几年前我做了用于实时3D重建的软件,然后你复制每帧的数据,慢速版本仍然以超过50赫兹的速度运行。因此,如果分解速度更快,那么可能会加速吗?特别是项目的其余部分将在GPU上,所以如果可以直接在那里解决它并保留解决方案,我猜是没有任何缺点。

在Cuda领域发生了很多事情,我并不是最新的。

以下是我找到的两个链接:Benchmark?MatlabGPU

1 个答案:

答案 0 :(得分:4)

您的矩阵非常稀疏并且对应于2D域上的离散化,因此预期SimplicialLDLT在这里是最快的。由于稀疏模式已修复,请调用analyzePattern一次,然后调用factorize而不是compute。这应该节省几毫秒。此外,由于您正在使用常规网格,您可能还会尝试使用NaturalOrdering绕过重新排序步骤(不是100%肯定,您必须替补)。如果仍然不够快,你可以搜索为天际线矩阵量身定制的Cholesky求解器(在这种情况下,Cholesky分解更简单,因此速度更快)。