设置无内存开销的Eigen::SparseMatrix的稀疏模式
我需要设置我已经知道的Eigen::SparseMatrix的稀疏模式(我有唯一排序的列索引和行偏移量)。显然,可以通过setFromTriplets实现,但遗憾的是,setFromTriplets需要大量额外内存(至少在我的情况下是这样)
我写了一个小例子
const long nRows = 5000000;
const long nCols = 100000;
const long nCols2Skip = 1000;
//It's quite big!
const long nTriplets2Reserve = nRows * (nCols / nCols2Skip) * 1.1;
Eigen::SparseMatrix<double, Eigen::RowMajor, long> mat(nRows, nCols);
std::vector<Eigen::Triplet<double, long>> triplets;
triplets.reserve(nTriplets2Reserve);
for(long row = 0; row < nRows; ++row){
for(long col = 0; col < nCols; col += nCols2Skip){
triplets.push_back(Eigen::Triplet<double, long>(row, col, 1));
}
}
std::cout << "filling mat" << std::endl << std::flush;
mat.setFromTriplets(triplets.begin(), triplets.end());
std::cout << "Finished! nnz " << mat.nonZeros() << std::endl;
//Stupid way to check memory consumption
std::cin.get();
在我的例子中,这个示例在峰值时(在"填充垫子"和"已完成"行之间)消耗了大约26 GB,最终消耗了18 GB。(我通过htop
进行了所有检查)。~8 GB的开销对我来说相当大(在我的"现实世界"任务中,我有更大的开销)。
所以我有两个问题:
- 如何以尽可能少的开销填充Eigen::SparseMatrix的稀疏模式
- 为什么setFromTriplets需要这么多内存?
如果我的示例有误,请让我知道。
我的本征版本是3.3.2
PS为我的英语道歉
编辑: 它看起来像inserting(使用preallocation),每个三元组手动工作更快,并且在峰值时需要更少的内存。但我还是想知道是否可以手动设置稀疏模式
解决方案
广告1:如果您能保证按词典顺序插入元素,使用内部函数startVec
和insertBack
甚至可以比普通的insert
更高效。
ad2:如果您使用setFromTriplets
,您需要大约两倍于矩阵的最终大小(加上三元组容器的大小),因为元素首先被插入到矩阵的转置版本中,然后被转置到最终的矩阵中,以确保所有内部向量都被排序。如果您知道前面矩阵的结构,这显然是相当浪费内存,但它的目的是处理任意输入数据。
Triplet
需要8+8+8=24个字节(对于vector
大约12 GB),稀疏矩阵的每个元素需要8+8=16个字节(一个double
用于值,一个long
用于内部索引),即每个矩阵大约8 GB,所以总共需要大约28 GB,大约26 Gib。
奖金:
如果您的矩阵有一些特殊的结构,可以更高效地存储,并且您愿意更深入地挖掘Eigen的内部结构,那么您也可以考虑实现一个继承自Eigen::SparseBase<>
的新类型(但我不会对此进行重新注释,除非内存/性能对您非常重要,并且您愿意经历大量"稀疏的"文档记录的内部Eigen代码...)。但是,在这种情况下,考虑您打算如何处理矩阵并尝试仅对其执行特殊操作可能更容易。
相关文章