c++大特征分解速度

Posted

技术标签:

【中文标题】c++大特征分解速度【英文标题】:c++ Large eigendecomposition speed 【发布时间】:2016-02-22 16:46:26 【问题描述】:

作为我管道的一部分,我需要按 6000x6000 的顺序对一个大矩阵进行特征分解。矩阵是密集的,所以除非我简化问题(如果可能的话,请确定),否则不能使用稀疏方法。

目前我正在玩玩具数据。将 Eigen 库用于 513x513 矩阵我需要约 6.5 秒,而对于 2049x2049 矩阵我需要约 130 秒,这听起来令人望而却步,因为增加不是线性的。这是通过Eigen::SelfAdjointEigenSolver 实现的,而使用Eigen::EigenSolverEigen::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&lt; double, LARGEST_ALGE, DenseGenMatProd&lt;double&gt; &gt; eigs(&amp;op, 10, 30);

【讨论】:

ARPACK-Eigen 现在被 Spectra 取代。而ncv参数应该是请求特征值数量的大约两三倍,所以eigs(&amp;op, 10, 30)可能更合适。 @yixuan 感谢您的更正,我编辑了我的答案。

以上是关于c++大特征分解速度的主要内容,如果未能解决你的问题,请参考以下文章

是否有任何 C++ opencv 代码来计算每帧视频中关键特征点的速度? [关闭]

阻塞与非阻塞winsock的速度/性能特征

最便捷最强大速度最快的C++序列化框架

LibSVM 在大特征向量上失败 (SEGFAULT)

大数据的特征

C++的大数除法最快速度的算法