c++大特征分解速度
Posted
技术标签:
【中文标题】c++大特征分解速度【英文标题】:c++ Large eigendecomposition speed 【发布时间】:2016-02-22 16:46:26 【问题描述】:作为我管道的一部分,我需要按 6000x6000 的顺序对一个大矩阵进行特征分解。矩阵是密集的,所以除非我简化问题(如果可能的话,请确定),否则不能使用稀疏方法。
目前我正在玩玩具数据。将 Eigen 库用于 513x513 矩阵我需要约 6.5 秒,而对于 2049x2049 矩阵我需要约 130 秒,这听起来令人望而却步,因为增加不是线性的。这是通过Eigen::SelfAdjointEigenSolver
实现的,而使用Eigen::EigenSolver
或Eigen::ComplexEigenSolver
等其他方法我没有得到显着的改进。当我用arma::eig_sym
尝试犰狳时发生了同样的情况,即使使用选项“dc”` 应该给出更快但近似的结果。 Armadillo 有一些方法只返回前 X 个特征值以提高速度,但这仅适用于稀疏方法。目前我可能可以摆脱前 10-20 个特征值。
有没有一种方法或库/方法可以给我带来显着的加速?
【问题讨论】:
如果您只需要几个最高或最小的特征向量,那么还有更有效的方法。 这正是我提到的,这可能是一个足够好的解决方法。这些方法是什么?请问有什么指点吗? Lapack 提供了这样的例程。关于您的数字,我仅使用Eigen::SelfAdjointEigenSolver
获得了 2049x2049 矩阵的 7.5 秒,以及 6000x6000 矩阵的 280 秒。确保在编译器优化打开的情况下进行编译。当然,这仍然令人望而却步,最好使用仅提取第一个特征向量的专用算法。
【参考方案1】:
Spectra用于检索大矩阵的几个特征值。
计算最大和最小 10 个特征值的示例代码可能如下所示:
#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <MatOp/DenseGenMatProd.h>
#include <MatOp/DenseSymShiftSolve.h>
#include <SymEigsSolver.h>
#include <iostream>
using namespace Spectra;
int main()
srand(0);
// We are going to calculate the eigenvalues of M
Eigen::MatrixXd A = Eigen::MatrixXd::Random(1000, 1000);
Eigen::MatrixXd M = A.transpose() * A;
// Matrix operation objects
DenseGenMatProd<double> op_largest(M);
DenseSymShiftSolve<double> op_smallest(M);
// Construct solver object, requesting the largest 10 eigenvalues
SymEigsSolver< double, LARGEST_MAGN, DenseGenMatProd<double> >
eigs_largest(&op_largest, 10, 30);
// Initialize and compute
eigs_largest.init();
eigs_largest.compute();
std::cout << "Largest 10 Eigenvalues :\n" <<
eigs_largest.eigenvalues() << std::endl;
// Construct solver object, requesting the smallest 10 eigenvalues
SymEigsShiftSolver< double, LARGEST_MAGN, DenseSymShiftSolve<double> >
eigs_smallest(&op_smallest, 10, 30, 0.0);
eigs_smallest.init();
eigs_smallest.compute();
std::cout << "Smallest 10 Eigenvalues :\n" <<
eigs_smallest.eigenvalues() << std::endl;
return 0;
【讨论】:
【参考方案2】:我建议尝试 Arpack-Eigen。我从 Octave/Matlab 知道它可以在一秒钟内计算出随机 2049x2049 的最大特征值,并在 5-20 秒内计算出最大的 10,eigs(rand(2049), 10)
。
现在,它的文档help eigs
指向 ARPACK。 Arpack-Eigen
https://github.com/yixuan/arpack-eigen 允许您从较大的矩阵中请求 10 个特征值,如下所示:SymEigsSolver< double, LARGEST_ALGE, DenseGenMatProd<double> > eigs(&op, 10, 30);
。
【讨论】:
ARPACK-Eigen 现在被 Spectra 取代。而ncv
参数应该是请求特征值数量的大约两三倍,所以eigs(&op, 10, 30)
可能更合适。
@yixuan 感谢您的更正,我编辑了我的答案。以上是关于c++大特征分解速度的主要内容,如果未能解决你的问题,请参考以下文章