本征矩阵乘法速度
Eigen Matrix Multiplication Speed
我正在尝试用 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;
}
我在文档和 Whosebug 上对编译优化标志进行了一些搜索。我尝试使用此命令编译程序:
g++ -g test.cpp -o test -Ofast -msse2
使用 -Ofast 优化标志编译的 C++ 可执行文件 运行 比简单的无优化编译快 30 倍或更多。它会在我的 2015 macbook pro 上 return 在大约 10000 毫秒内得到结果。
同时 Numpy 将 return 在大约 1800 毫秒内得到结果。
与 Numpy 相比,我期待使用 Eigen 的性能提升。然而,这却出乎我的意料。
是否有任何我遗漏的编译标志可以进一步提高 Eigen 的性能?或者是否有任何可以打开的多线程开关可以给我额外的性能提升?我只是好奇这个。
非常感谢!
2016 年 4 月 17 日编辑:
根据@ggael的回答做了一番搜索后,我得出了这个问题的答案。
对此的最佳解决方案是使用 link 编译为英特尔 MKL 作为 Eigen 的后端。对于 osx 系统,可以在 here. With MKL installed I tried to use the 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 快得多。
用VC2013编译你的小程序:
- /fp:精确 - 10.5s
- /fp:strict - 10.4s
- /fp:快 - 10.3s
- /fp:fast /arch:AVX2 - 6.6s
- /fp:fast /arch:AVX2 /openmp - 2.7s
因此,使用 AVX/AVX2 并启用 OpenMP 将大有帮助。您也可以尝试链接 MKL (http://eigen.tuxfamily.org/dox/TopicUsingIntelMKL.html)。
回答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 不知道如何正确地执行 assemble AVX/FMA 指令,因此您需要告诉它使用本机 assembler 和 -Wa,-q
旗帜。
最后,通过 devel 分支,您还可以告诉 Eigen 使用任何 BLAS 作为后端,例如来自 Apple 的 Accelerate,如下所示:
$ g++ -framework Accelerate -DEIGEN_USE_BLAS -O3 -DNDEBUG so_gemm_perf.cpp -I ../eigen && ./a.out
802.837ms
我正在尝试用 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;
}
我在文档和 Whosebug 上对编译优化标志进行了一些搜索。我尝试使用此命令编译程序:
g++ -g test.cpp -o test -Ofast -msse2
使用 -Ofast 优化标志编译的 C++ 可执行文件 运行 比简单的无优化编译快 30 倍或更多。它会在我的 2015 macbook pro 上 return 在大约 10000 毫秒内得到结果。
同时 Numpy 将 return 在大约 1800 毫秒内得到结果。
与 Numpy 相比,我期待使用 Eigen 的性能提升。然而,这却出乎我的意料。
是否有任何我遗漏的编译标志可以进一步提高 Eigen 的性能?或者是否有任何可以打开的多线程开关可以给我额外的性能提升?我只是好奇这个。
非常感谢!
2016 年 4 月 17 日编辑:
根据@ggael的回答做了一番搜索后,我得出了这个问题的答案。
对此的最佳解决方案是使用 link 编译为英特尔 MKL 作为 Eigen 的后端。对于 osx 系统,可以在 here. With MKL installed I tried to use the 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 快得多。
用VC2013编译你的小程序:
- /fp:精确 - 10.5s
- /fp:strict - 10.4s
- /fp:快 - 10.3s
- /fp:fast /arch:AVX2 - 6.6s
- /fp:fast /arch:AVX2 /openmp - 2.7s
因此,使用 AVX/AVX2 并启用 OpenMP 将大有帮助。您也可以尝试链接 MKL (http://eigen.tuxfamily.org/dox/TopicUsingIntelMKL.html)。
回答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 不知道如何正确地执行 assemble AVX/FMA 指令,因此您需要告诉它使用本机 assembler 和 -Wa,-q
旗帜。
最后,通过 devel 分支,您还可以告诉 Eigen 使用任何 BLAS 作为后端,例如来自 Apple 的 Accelerate,如下所示:
$ g++ -framework Accelerate -DEIGEN_USE_BLAS -O3 -DNDEBUG so_gemm_perf.cpp -I ../eigen && ./a.out
802.837ms