使用Eigen和C ++做一个大规模矩阵乘积的colsum

时间:2015-06-05 19:15:41

标签: c++ matrix eigen

我正在尝试计算colsum(N * P),其中N是稀疏的1M乘2500矩阵,P是2500 x 1.5M的密集矩阵。我正在使用Eigen C ++库和Intel的MKL库。问题是矩阵N * P实际上不能存在于内存中,它太大了(~10 TB)。我的问题是Eigen是否能够通过惰性求值和并行性的某种组合来处理这种计算?它在这里说Eigen不会不必要地制作临时矩阵:http://eigen.tuxfamily.org/dox-devel/TopicLazyEvaluation.html

但是Eigen是否知道计算出实际适合内存的分段块中的N * P? IE:它必须做类似colsum(N * P_1)++ colsum(N * P_2)++ .. ++ colsum(N * P_n)的事情,其中​​P按列分为n个不同的子矩阵和“+ +“是连接。

我正在使用128 GB RAM。

2 个答案:

答案 0 :(得分:1)

我尝试了一下但最终得到了一个糟糕的malloc(我只在Win8上以8GB运行)。我设置了main()并使用了我写的非内联colsum函数。

int main(int argc, char *argv[])
{
    Eigen::MatrixXd dense = Eigen::MatrixXd::Random(1000, 100000);
    Eigen::SparseMatrix<double> sparse(100000, 1000);
    typedef Triplet<int> Trip;
    std::vector<Trip> trps(dense.rows());
    for(int i = 0; i < dense.rows(); i++)
    {
        trps[i] = Trip(20*i, i, 2);
    }
    sparse.setFromTriplets(trps.begin(), trps.end());

    VectorXd res = colsum(sparse, dense);
    std::cout << res;
    std::cin >> argc;
    return 0;
}

尝试只是:

__declspec(noinline) VectorXd 
colsum(const Eigen::SparseMatrix<double> &sparse, const Eigen::MatrixXd &dense)
{
    return (sparse * dense).colwise().sum();
}

那有一个糟糕的malloc。 Sol看起来你必须自己手动拆分(除非别人有更好的解决方案)。

修改

我稍微改进了一下这个功能,但得到了同样糟糕的malloc:

__declspec(noinline) VectorXd 
colsum(const Eigen::SparseMatrix<double> &sparse, const Eigen::MatrixXd &dense)
{
    return (sparse * dense).topRows(4).colwise().sum();
}

编辑2

另一种选择是使稀疏矩阵密集并强制进行惰性评估。我不认为它适用于稀疏矩阵(哦,好吧)。

__declspec(noinline) VectorXd 
colsum(const Eigen::SparseMatrix<double> &sparse, const Eigen::MatrixXd &dense)
{
    Eigen::MatrixXd denseSparse(sparse);
    return denseSparse.lazyProduct(dense).colwise().sum();
}

这并没有给我带来错误的malloc,但计算了许多毫无意义的0*x_i表达式。

答案 1 :(得分:0)

回答你的问题:特别是,当涉及到产品时,Eigen经常会将部分表达式评估为临时表。在某些情况下,这可以进行优化但尚未实现,在某些情况下,这实际上是实现它的最有效方式。

但是,在您的情况下,您可以简单地计算N(1 x 2500向量)的colsum并将其乘以P也许 Eigen的未来版本将能够自己进行这种优化,但大多数情况下,在让计算机完成其余工作之前,最好自己进行特定于问题的优化。

Btw:我担心sparse.colwise()尚未实现,因此您必须手动计算。如果你很懒,你可以改为计算Eigen::RowVectorXd Nsum = Eigen::RowVectorXd::Ones(N.rows())*P;(我没有检查它,但实际上这可能会被优化到接近最佳代码,使用最新版本的Eigen)。