特征矩阵乘法速度 我尝试在C++中进行线性代数数值计算。我使用Python NoMPy做快速模型,我想找到C++的线性代数包,以进一步加速。艾根似乎是一个很好的起点

特征矩阵乘法速度 我尝试在C++中进行线性代数数值计算。我使用Python NoMPy做快速模型,我想找到C++的线性代数包,以进一步加速。艾根似乎是一个很好的起点,c++,performance,numpy,compilation,eigen,C++,Performance,Numpy,Compilation,Eigen,我编写了一个小型性能测试,使用大型密集矩阵乘法测试处理速度。在努比,我是这样做的: 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' #include &l

我编写了一个小型性能测试,使用大型密集矩阵乘法测试处理速度。在努比,我是这样做的:

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'
#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;
}
在C++中,我这样做:

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'
#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;
}

用OFAST优化标志编译的C++可执行文件比简单的无优化编译运行大约快30X或更快。在我的2015 macbook pro上,它将在大约10000毫秒后返回结果

同时,Numpy将在1800毫秒后返回结果

与Numpy相比,我期望在使用Eigen时性能得到提升。然而,这出乎我的意料

是否有任何编译标志我错过了,这将进一步提高本征性能在这方面?或者是否有任何多线程开关可以打开以获得额外的性能增益?我只是好奇而已

多谢各位

2016年4月17日编辑:

在根据@ggael的答案进行了一些搜索之后,我找到了这个问题的答案

最好的解决方案是编译并链接到“英特尔MKL”作为Eigen的后端。对于osx系统,可在以下位置找到库:。安装了MKL后,我尝试使用启用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


使用MKL作为本征后端,在我的2.5Ghz Macbook Pro上,两个5000x5000操作的矩阵乘法将在大约900ms内完成。这比我的设备上的Python Numpy快得多。

使用VC2013编译您的小程序:

  • /fp:精确-10.5s
  • /fp:严格-10.4s
  • /fp:fast-10.3s
  • /fp:fast/arch:AVX2-6.6s
  • /fp:fast/arch:AVX2/openmp-2.7s

因此,使用AVX/AVX2并启用OpenMP将有很大帮助。您还可以尝试针对MKL()进行链接

要回答OSX方面的问题,首先要记住,在OSX上,g++实际上是clang++的别名,当前苹果版本的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编译器,例如使用自制或macport。这里使用macport的gcc 5,我得到:

$ g++-mp-5 -mfma -I ../eigen so_gemm_perf.cpp  -O3 -DNDEBUG -fopenmp -Wa,-q && ./a.out
804.939ms
和叮当声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
标志的本机汇编程序

最后,通过devel分支,您还可以告诉Eigen使用任何BLAS作为后端,例如苹果公司Accelerate的后端,如下所示:

$ g++ -framework Accelerate -DEIGEN_USE_BLAS -O3 -DNDEBUG so_gemm_perf.cpp  -I ../eigen  && ./a.out
802.837ms

您确定正在运行上述测试用例吗?对于500×500矩阵,我得到基准C++ 20MS,Python /NoMPY:310MS,对于5000 0x5000矩阵,C++也是一个数量级更快。(使用-Ofast)@CharlesPehlivanian我正在使用我的python Numpy计算500x500矩阵,这给了我3ms的运行时间,其中Eigen大约是10ms。仍然不能比Numpy更快。在这种情况下,OpenMP编译是否有g++或clang标志?更重要的是,这意味着Eigen比pythonnumpy慢吗?谢谢。@yc2986:Try
g++-Wall-Wextra-ffast math-O3-march=native-fopenmp
。您必须使用openMP pragmas for
-fopenmp
来执行任何操作,但可能Eigen已经使用了它们。另请参阅。我不是numpy方面的专家,但我猜它使用了高度优化的库(blas/LAPACK)。所以在速度上应该不会有太大的差别。@yc2986:也许gcc需要在编译时支持它?或者您使用的是一个古老的gcc版本,在这种情况下,您应该升级,因为更新的gcc会生成更好的代码。搜索此站点会产生大量结果,-fopenmp编译确实提高了性能。在我的2.5GHz macbook pro上大约是1200毫秒。对于使用BLAS作为后端,我在将mkl.h包含到编译中时遇到了问题。谢谢你的解决方案。真的很有帮助!对于AVX和通用BLAS后端,您需要devel分支(即将发布下一版本)