c++ - Eigen 矩阵乘法速度

标签 c++ performance numpy compilation eigen

我试图用 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/

相关文章:

.net - 在 .Net 应用程序中使用 OnPaint 的正确方法是什么?

python - 为什么我的 3D numpy 数组中的值在我将其写入文件时会发生变化?

python - 如何将numpy二维数组作为一种可以用C++读取的二进制格式存储到磁盘上

python - 如何减去两个无符号的 numpy 数组以给出带符号的结果?

c++ - Valgrind 在不应该的时候报告竞争条件

c++ - 在 C++ 中如何为结构类型分配内存

java - 用文件编写的 C 结构,用 Java 打开

javascript - 我应该缓存 firebase refs 吗?

c++ - C++ 映射中的 C 风格数组

algorithm - 快速整数坐标在以原点为中心、半径为 r 的圆内/沿圆