Eigen 库:SVD 比 GSL 慢
Eigen library: SVD is slow compared to GSL
我正在比较 Eigen (v3.2.8) 和 GSL (v2.1) 库在各种线性代数运算中的性能。虽然在大多数操作中 Eigen 以很大的优势(少数因素)获胜,但在奇异值分解的计算中它落后了。我使用了 SVD 的两种实现——JacobiSVD 和 BDCSVD(后者仍然在这个版本的 'unsupported' 模块中),并在几个平台上测试了以下代码:
#include <gsl/gsl_rng.h>
#include <gsl/gsl_linalg.h>
#include <unsupported/Eigen/SVD>
#include <ctime>
#include <iostream>
void testSVD(const int size)
{
clock_t tbegin;
gsl_rng* rng = gsl_rng_alloc(gsl_rng_default);
gsl_rng_set(rng, 42);
Eigen::MatrixXd mat(size, size);
for(int i=0; i<size; i++)
for(int j=0; j<size; j++)
mat(i, j) = gsl_rng_uniform(rng);
gsl_matrix_view matv = gsl_matrix_view_array(mat.data(), size, size);
gsl_matrix* mat1 = &matv.matrix;
gsl_matrix* mat2 = gsl_matrix_alloc(size, size);
gsl_vector* vec1 = gsl_vector_alloc(size);
gsl_vector* vec2 = gsl_vector_alloc(size);
tbegin = std::clock();
Eigen::JacobiSVD<Eigen::MatrixXd> jac(mat, Eigen::ComputeThinU | Eigen::ComputeThinV);
double tjac = (std::clock() - tbegin)*1.0/CLOCKS_PER_SEC;
tbegin = std::clock();
Eigen::BDCSVD<Eigen::MatrixXd> bdc(mat, Eigen::ComputeThinU | Eigen::ComputeThinV);
double tbdc = (std::clock() - tbegin)*1.0/CLOCKS_PER_SEC;
tbegin = std::clock();
gsl_linalg_SV_decomp(mat1, mat2, vec1, vec2);
double tgsl = (std::clock() - tbegin)*1.0/CLOCKS_PER_SEC;
std::cout << "Matrix size: "<<size<<", GSL SVD: "<<tgsl<<" s, JacobiSVD: "<<tjac<<" s, BDCSVD: "<<tbdc<<" s\n";
gsl_vector_free(vec2);
gsl_vector_free(vec1);
gsl_matrix_free(mat2);
}
机器 1(旧的,gcc 4.2.1,编译器选项 -O3):
Matrix size: 125, GSL SVD: 0.054497 s, JacobiSVD: 0.143428 s, BDCSVD: 0.177061 s
Matrix size: 250, GSL SVD: 0.457591 s, JacobiSVD: 1.16189 s, BDCSVD: 1.291 s
Matrix size: 500, GSL SVD: 6.01799 s, JacobiSVD: 15.2217 s, BDCSVD: 12.1353 s
Matrix size: 1000, GSL SVD: 67.3727 s, JacobiSVD: 155.501 s, BDCSVD: 114.372 s
机器 2(gcc 4.8.3,-O3):
Matrix size: 125, GSL SVD: 0.008666 s, JacobiSVD: 0.029863 s, BDCSVD: 0.026779 s
Matrix size: 250, GSL SVD: 0.082332 s, JacobiSVD: 0.318304 s, BDCSVD: 0.235657 s
Matrix size: 500, GSL SVD: 0.807378 s, JacobiSVD: 2.93758 s, BDCSVD: 1.98003 s
Matrix size: 1000, GSL SVD: 23.1846 s, JacobiSVD: 59.1015 s, BDCSVD: 27.8348 s
机器 3(icc 13.1.3,-O3):
Matrix size: 125, GSL SVD: 0.02 s, JacobiSVD: 0.05 s, BDCSVD: 0.04 s
Matrix size: 250, GSL SVD: 0.15 s, JacobiSVD: 0.4 s, BDCSVD: 0.28 s
Matrix size: 500, GSL SVD: 2.18 s, JacobiSVD: 3.51 s, BDCSVD: 2.41 s
Matrix size: 1000, GSL SVD: 10 s, JacobiSVD: 42.87 s, BDCSVD: 23.4 s
问题是,为什么Eigen打不过GSL?
JacobiSVD
对于大型矩阵预计会很慢。关于 BDCSVD
,请尝试 3.3-beta1 版本(或 devel 分支)中的那个。它现在在官方 Eigen/SVD
模块中,并且得到了相当大的改进。
郑重声明,在 OSX,使用 MacPorts 的 GSL,-O3 -mavx
:
Matrix size: 100, GSL SVD: 0.006717 s, JacobiSVD: 0.01651 s, BDCSVD: 0.007867 s
Matrix size: 200, GSL SVD: 0.060359 s, JacobiSVD: 0.179859 s, BDCSVD: 0.031222 s
Matrix size: 300, GSL SVD: 0.228808 s, JacobiSVD: 0.806909 s, BDCSVD: 0.073439 s
Matrix size: 400, GSL SVD: 0.644856 s, JacobiSVD: 1.98206 s, BDCSVD: 0.132627 s
Matrix size: 600, GSL SVD: 4.24252 s, JacobiSVD: 7.24865 s, BDCSVD: 0.345525 s
Matrix size: 1000, GSL SVD: 33.7155 s, JacobiSVD: 78.6189 s, BDCSVD: 1.31173 s
我正在比较 Eigen (v3.2.8) 和 GSL (v2.1) 库在各种线性代数运算中的性能。虽然在大多数操作中 Eigen 以很大的优势(少数因素)获胜,但在奇异值分解的计算中它落后了。我使用了 SVD 的两种实现——JacobiSVD 和 BDCSVD(后者仍然在这个版本的 'unsupported' 模块中),并在几个平台上测试了以下代码:
#include <gsl/gsl_rng.h>
#include <gsl/gsl_linalg.h>
#include <unsupported/Eigen/SVD>
#include <ctime>
#include <iostream>
void testSVD(const int size)
{
clock_t tbegin;
gsl_rng* rng = gsl_rng_alloc(gsl_rng_default);
gsl_rng_set(rng, 42);
Eigen::MatrixXd mat(size, size);
for(int i=0; i<size; i++)
for(int j=0; j<size; j++)
mat(i, j) = gsl_rng_uniform(rng);
gsl_matrix_view matv = gsl_matrix_view_array(mat.data(), size, size);
gsl_matrix* mat1 = &matv.matrix;
gsl_matrix* mat2 = gsl_matrix_alloc(size, size);
gsl_vector* vec1 = gsl_vector_alloc(size);
gsl_vector* vec2 = gsl_vector_alloc(size);
tbegin = std::clock();
Eigen::JacobiSVD<Eigen::MatrixXd> jac(mat, Eigen::ComputeThinU | Eigen::ComputeThinV);
double tjac = (std::clock() - tbegin)*1.0/CLOCKS_PER_SEC;
tbegin = std::clock();
Eigen::BDCSVD<Eigen::MatrixXd> bdc(mat, Eigen::ComputeThinU | Eigen::ComputeThinV);
double tbdc = (std::clock() - tbegin)*1.0/CLOCKS_PER_SEC;
tbegin = std::clock();
gsl_linalg_SV_decomp(mat1, mat2, vec1, vec2);
double tgsl = (std::clock() - tbegin)*1.0/CLOCKS_PER_SEC;
std::cout << "Matrix size: "<<size<<", GSL SVD: "<<tgsl<<" s, JacobiSVD: "<<tjac<<" s, BDCSVD: "<<tbdc<<" s\n";
gsl_vector_free(vec2);
gsl_vector_free(vec1);
gsl_matrix_free(mat2);
}
机器 1(旧的,gcc 4.2.1,编译器选项 -O3):
Matrix size: 125, GSL SVD: 0.054497 s, JacobiSVD: 0.143428 s, BDCSVD: 0.177061 s Matrix size: 250, GSL SVD: 0.457591 s, JacobiSVD: 1.16189 s, BDCSVD: 1.291 s Matrix size: 500, GSL SVD: 6.01799 s, JacobiSVD: 15.2217 s, BDCSVD: 12.1353 s Matrix size: 1000, GSL SVD: 67.3727 s, JacobiSVD: 155.501 s, BDCSVD: 114.372 s
机器 2(gcc 4.8.3,-O3):
Matrix size: 125, GSL SVD: 0.008666 s, JacobiSVD: 0.029863 s, BDCSVD: 0.026779 s Matrix size: 250, GSL SVD: 0.082332 s, JacobiSVD: 0.318304 s, BDCSVD: 0.235657 s Matrix size: 500, GSL SVD: 0.807378 s, JacobiSVD: 2.93758 s, BDCSVD: 1.98003 s Matrix size: 1000, GSL SVD: 23.1846 s, JacobiSVD: 59.1015 s, BDCSVD: 27.8348 s
机器 3(icc 13.1.3,-O3):
Matrix size: 125, GSL SVD: 0.02 s, JacobiSVD: 0.05 s, BDCSVD: 0.04 s Matrix size: 250, GSL SVD: 0.15 s, JacobiSVD: 0.4 s, BDCSVD: 0.28 s Matrix size: 500, GSL SVD: 2.18 s, JacobiSVD: 3.51 s, BDCSVD: 2.41 s Matrix size: 1000, GSL SVD: 10 s, JacobiSVD: 42.87 s, BDCSVD: 23.4 s
问题是,为什么Eigen打不过GSL?
JacobiSVD
对于大型矩阵预计会很慢。关于 BDCSVD
,请尝试 3.3-beta1 版本(或 devel 分支)中的那个。它现在在官方 Eigen/SVD
模块中,并且得到了相当大的改进。
郑重声明,在 OSX,使用 MacPorts 的 GSL,-O3 -mavx
:
Matrix size: 100, GSL SVD: 0.006717 s, JacobiSVD: 0.01651 s, BDCSVD: 0.007867 s
Matrix size: 200, GSL SVD: 0.060359 s, JacobiSVD: 0.179859 s, BDCSVD: 0.031222 s
Matrix size: 300, GSL SVD: 0.228808 s, JacobiSVD: 0.806909 s, BDCSVD: 0.073439 s
Matrix size: 400, GSL SVD: 0.644856 s, JacobiSVD: 1.98206 s, BDCSVD: 0.132627 s
Matrix size: 600, GSL SVD: 4.24252 s, JacobiSVD: 7.24865 s, BDCSVD: 0.345525 s
Matrix size: 1000, GSL SVD: 33.7155 s, JacobiSVD: 78.6189 s, BDCSVD: 1.31173 s