美文网首页计算机中的数学程序员
Eigen 与 CUDA cusolver 解大规模稀疏矩阵方程

Eigen 与 CUDA cusolver 解大规模稀疏矩阵方程

作者: 石小鑫 | 来源:发表于2020-04-26 13:04 被阅读0次

    近期在解决一个解大型稀疏矩阵方程的问题,用到了Eigen库和cuSolver库,并对二者的不同算法进行了时间上的比较。

    1.Eigen解稀疏矩阵方程

    1.1 解法流程

    调用c++的eigen库解方程的参考资料比较多,这里只是简单地总结一下大致流程。给项目配置好eigen环境后
    首先是引用头文件和命名空间,

    #include"Eigen/Sparse"
    ...
    
    using namespace Eigen;
    ...
    

    这样就可以在后面调用eigen sparse的一些功能。
    我们要解的方程Ax=b,接下来就是根据自己的需求构造稀疏系数矩阵A,和向量b,最后调用一些solver来解方程。

    typedef Eigen::SparseMatrix<float> SpMat;
    typedef Eigen::Triplet<float> T;
    
    //1.构造A矩阵
    int nx = 10000,ny=10000;
    int estimateNZN = nx*5;//矩阵中非零项的大致个数
    SpMat A(nx,ny);//10000*10000的稀疏矩阵
    A.reserve(estimateNZN);//提前为A分配estimateNZN个元素的内存
    
    std::vector<T> tripletList;//为矩阵A批量赋值的三元组
    tripletList.reserve(estimateNZN);
    
    //根据需要构造A
    for(...){
    ...
    tripletList.push_back(T(rowId, colId,value));//push每个三元组(行,列,值)
    ...
    }
    //给A批量赋值
    A.setFromTriplets(tripletList.begin(), tripletList.end());
    
    //2.根据自己的需求构造向量b
    Eigen::VectorXf bx(interior_num);
    bx.setZero();
    ...
    
    //3.构造系数方程的solver,解方程
    Eigen::SimplicialCholesky<SpMat> solver(A);
    //Eigen::SparseLU<SpMat> solver(A);
    //Eigen::SparseQR<SpMat, COLAMDOrdering<int>> solver(A);
    
    Eigen::VectorXf x = solver.solve(bx);//最后的结果为x
    

    1.2稀疏矩阵不同的赋值方法

    为A矩阵的赋值方法,这里用的是通过三元组来批量赋值,但也可用A.coeffRef(rowId, colId) = value;来逐一赋值,值得一提的是,当元素个数较多时,批量赋值的速度远远快于逐一插入,因此推荐使用批量的赋值。

    1.3 不同的求解器与reordering 类型

    几种不同的solver:Eigen提供了很多方程求解器,上面代码中标注了几个常用的,如cholesky分解,qr分解和lu分解,他们针对不同属性的矩阵,且运算速度不同,详细的求解器说明参考这里(Eigen:Solving Sparse Linear Systems)。
    运算速度也受不同的reordering参数影响(Eigen:OrderingMethods module),QR分解需要显式指出reordering类型,另外两种则有默认的类型。

    2.cuSolver解稀疏矩阵方程

    2.1 CUDA环境配置

    我的这篇文章介绍了如何在windows系统配置CUDA10环境,有需要的可以参考一下:(vs+CUDA10.2环境配置

    2.2 cuSparse中稀疏矩阵格式

    cuSparse中支持多种稀疏矩阵的格式,这里只介绍比较常见的COO和CSR两种。

    COO格式是坐标系格式,有三个数组表示,三个数组分别记录元素的行坐标,列坐标和数值,排列方式为行优先。


    coo

    CSR是将COO格式的行坐标向量进行压缩,压缩后行向量的长度变为m+1,m为稀疏矩阵的行数。行坐标向量的前m位的值为当前行第一个非零元素的列坐标,行坐标向量的第m+1位为非零元素总数加上行坐标向量的第一位。


    csr

    2.2 解法流程

    这篇文章(利用cuda的cusparse模块计算超大型稀疏矩阵方程的解)仿照cuda提供的cusolver的示例代码讲解了如何构造求解稀疏方程,这里不再赘述。


    需要注意的是:

    • 示例代码中用的是low level的函数,即将解方程的每一步都单独作为一个函数,来逐一运行;
    • 我们往往不需要那么繁琐的细节,可以直接调用cusolver提供的high level的函数如cusolverSpScsrlsvchol()(choleskey解法),cusolverSpScsrlsvqr()(QR解法)等等,关于这些函数的详细解释请参考cusolver的官方文档(https://docs.nvidia.com/cuda/cusolver/index.html)。

    3. 两类方法的时间比较

    笔者测试了eigen和cusolver的不同解法的时间,将比较结果记录一下。


    设备信息:intel 酷睿i7处理器;8g内存;NVIDIA GTX 960M 的显卡;
    测试的稀疏矩阵维度为10000*10000,记录一下累计解100次Ax=b方程的时间:

    Eigen cpu解法 cuSolver gpu解法
    QR分解 非常慢,不予考虑 31s
    LU分解 3.5s 不支持gpu,只有cpu版本
    choleskey分解 1.3s 11s

    P.S.以上都是使用默认的reordering类型。


    结果很出乎意料,对于我构造的矩阵,cuda gpu的choleskey分解要比Eigen在cpu的解法要慢。需要注意,这些时间数据只代表我的运行结果,不一定具有普遍性。





    相关文章

      网友评论

        本文标题:Eigen 与 CUDA cusolver 解大规模稀疏矩阵方程

        本文链接:https://www.haomeiwen.com/subject/xuhdwhtx.html