我试图用 C++ 进行线性代数数值计算。我使用 Python Numpy 作为快速模型,我想找到一个 C++ 线性代数包来进一步加速。 Eigen 似乎是一个很好的起点。
我使用大型密集矩阵乘法编写了一个小型性能测试来测试处理速度。在 Numpy 中我是这样做的:
import numpy as np
import time
a = np.random.uniform(size = (5000, 5000))
b = np.random.uniform(size = (5000, 5000))
start = time.time()
c = np.dot(a, b)
print (time.time() - start) * 1000, 'ms'
在 C++ Eigen 中,我是这样做的:
#include <time.h>
#include "Eigen/Dense"
using namespace std;
using namespace Eigen;
int main() {
MatrixXf a = MatrixXf::Random(5000, 5000);
MatrixXf b = MatrixXf::Random(5000, 5000);
time_t start = clock();
MatrixXf c = a * b;
cout << (double)(clock() - start) / CLOCKS_PER_SEC * 1000 << "ms" << endl;
return 0;
}
我在文档和 stackoverflow 上对编译优化标志进行了一些搜索。我尝试使用此命令编译程序:
g++ -g test.cpp -o test -Ofast -msse2
使用 -Ofast 优化标志编译的 C++ 可执行文件的运行速度比简单的无优化编译快 30 倍或更多。在我的 2015 macbook pro 上,它将在大约 10000 毫秒内返回结果。
同时 Numpy 将在大约 1800 毫秒内返回结果。
与 Numpy 相比,我期待使用 Eigen 时的性能提升。然而,这出乎我的意料。
有没有我遗漏的任何编译标志可以进一步提高 Eigen 的性能?或者是否有任何可以打开的多线程开关可以给我额外的性能提升?我只是对此感到好奇。
非常感谢!
2016 年 4 月 17 日编辑:
根据@ggael 的回答做了一些搜索,我得出了这个问题的答案。
对此的最佳解决方案是使用英特尔 MKL 链接作为 Eigen 的后端进行编译。对于 osx 系统,可以在 here 找到该库。 .安装 MKL 后,我尝试使用 Intel MKL link line advisor为 Eigen 启用 MKL 后端支持。
我以这种方式为所有 MKL 启用编译:
g++ -DEIGEN_USE_MKL_ALL -L${MKLROOT}/lib -lmkl_intel_lp64 -lmkl_core -lmkl_intel_thread -liomp5 -lpthread -lm -ldl -m64 -I${MKLROOT}/include -I. -Ofast -DNDEBUG test.cpp -o test
如果 MKLROOT 有任何环境变量错误,只需运行 MKL 包中提供的环境设置脚本,该脚本默认安装在我设备上的/opt/intel/mkl/bin 中。
在我的 2.5Ghz Macbook Pro 上,使用 MKL 作为特征后端,两个 5000x5000 运算的矩阵乘法将在大约 900 毫秒内完成。这比我设备上的 Python Numpy 快得多。
最佳答案
要回答OSX方面的问题,首先回想一下在OSX上g++其实是clang++的别名,目前Apple的clang版本不支持openmp。尽管如此,使用 Eigen3.3-beta-1 和默认的 clang++,我得到了 macbookpro 2.6Ghz:
$ clang++ -mfma -I ../eigen so_gemm_perf.cpp -O3 -DNDEBUG && ./a.out
2954.91ms
然后要获得对多线程的支持,您需要最新的 gcc 编译器,例如使用 homebrew 或 macport。这里使用来自 macport 的 gcc 5,我得到:
$ g++-mp-5 -mfma -I ../eigen so_gemm_perf.cpp -O3 -DNDEBUG -fopenmp -Wa,-q && ./a.out
804.939ms
和 clang 3.9:
$ clang++-mp-3.9 -mfma -I ../eigen so_gemm_perf.cpp -O3 -DNDEBUG -fopenmp && ./a.out
806.16ms
请注意 osx 上的 gcc 不知道如何正确汇编 AVX/FMA 指令,因此您需要告诉它使用带有 -Wa,-q
标志的 native 汇编器。
最后,通过 devel 分支,您还可以告诉 Eigen 使用任何 BLAS 作为后端,例如来自 Apple 的 Accelerate,如下所示:
$ g++ -framework Accelerate -DEIGEN_USE_BLAS -O3 -DNDEBUG so_gemm_perf.cpp -I ../eigen && ./a.out
802.837ms
关于c++ - Eigen 矩阵乘法速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36659004/