首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >基准测试矩阵乘法性能: C++ (eigen)比Python慢得多

基准测试矩阵乘法性能: C++ (eigen)比Python慢得多
EN

Stack Overflow用户
提问于 2018-08-02 23:03:48
回答 1查看 5.1K关注 0票数 8

我正在尝试评估与C++相比,Python的性能有多好。

以下是我的Python代码:

代码语言:javascript
复制
a=np.random.rand(1000,1000) #type is automaically float64
b=np.random.rand(1000,1000) 
c=np.empty((1000,1000),dtype='float64')

%timeit a.dot(b,out=c)

#15.5 ms ± 560 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

下面是我的C++代码,它是我在发布机制中用Xcode编译的:

代码语言:javascript
复制
#include <iostream>
#include <Dense>
#include <time.h>

using namespace Eigen;
using namespace std;

int main(int argc, const char * argv[]) {
    //RNG generator
    unsigned int seed = clock();
    srand(seed);

    int Msize=1000, Nloops=10;

    MatrixXd m1=MatrixXd::Random(Msize,Msize);
    MatrixXd m2=MatrixXd::Random(Msize,Msize);
    MatrixXd m3=MatrixXd::Random(Msize,Msize);

    cout << "Starting matrix multiplication test with " << Msize << 
    "matrices" << endl;
    clock_t start=clock();
    for (int i=0; i<Nloops; i++)
        m3=m1*m2;
    start = clock() - start;

    cout << "time elapsed for 1 multiplication: " << start / ((double) 
CLOCKS_PER_SEC * (double) Nloops) << " seconds" <<endl;
return 0;

}

结果是:

代码语言:javascript
复制
Starting matrix multiplication test with 1000matrices
time elapsed for 1 multiplication: 0.148856 seconds
Program ended with exit code: 0

这意味着C++程序要慢10倍。

或者,我尝试在MAC终端中编译cpp代码:

代码语言:javascript
复制
g++ -std=c++11 -I/usr/local/Cellar/eigen/3.3.5/include/eigen3/eigen main.cpp -o my_exec -O3

./my_exec

Starting matrix multiplication test with 1000matrices
time elapsed for 1 multiplication: 0.150432 seconds

我知道非常类似的question,但是,看起来问题出现在矩阵定义中。在我的例子中,我使用了默认的特征函数从均匀分布中创建矩阵。

谢谢,米哈伊尔

编辑:我发现,虽然numpy使用多线程,但Eigen在默认情况下不使用多线程(由Eigen::nbThreads()函数检查)。正如建议的那样,我使用了-march=native选项,它将计算时间减少了3倍。考虑到我的MAC上有8个线程,我相信使用多线程的numpy运行速度会快3倍。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-03 23:07:00

在经历了漫长而痛苦的安装和编译之后,我用Matlab、C++和Python进行了基准测试。

我的电脑: MAC OS High Sierra 10.13.6,带英特尔(R)酷睿(TM) i7-7920HQ CPU @3.10 CPU (4核、8线程)。我有Radeon Pro5604096MB,所以在这些测试中没有涉及到GPU(而且我从来没有配置过openCL,也没有在np.show_config()中看到它)。

软件: Matlab 2018a,Python3.6,C++编译器: Apple LLVM version9.1.0 (clang-902.0.39.2),g++-8 (自制软件GCC 8.2.0) 8.2.0

1) Matlab性能: time= (14.3±- 0.7 ) ms,运行10次

代码语言:javascript
复制
a=rand(1000,1000);
b=rand(1000,1000);
c=rand(1000,1000);
tic
for i=1:100
    c=a*b;
end
toc/100

2) Python性能(%timeit a.dot(b,out=c)):15.5 +- 0.8

我还为python安装了mkl库。与mkl链接的numpy : 14.4+-0.7 -它有帮助,但很少。

3) C++性能。对原始代码(请参阅问题)进行了以下更改:

用于避免创建不必要的时间矩阵的

  • noalias函数。
  • 时间是使用c++11 chorno

测量的

这里我使用了一堆不同的选项和两个不同的编译器:

代码语言:javascript
复制
3.1 clang++ -std=c++11 -I/usr/local/Cellar/eigen/3.3.5/include/eigen3/eigen main.cpp -O3

执行时间约146毫秒

代码语言:javascript
复制
3.2 Added -march=native option:

执行时间约为46 +-2毫秒

代码语言:javascript
复制
3.3 Changed compiler to GNU g++ (in my mac it is called gpp by custom-defined alias):

gpp -std=c++11 -I/usr/local/Cellar/eigen/3.3.5/include/eigen3/eigen main.cpp -O3

执行时间222毫秒

代码语言:javascript
复制
3.4 Added - march=native option:

执行时间~ 45.5 +- 1毫秒

在这一点上,我意识到Eigen不使用多线程。我安装了openmp并添加了-fopenmp标志。请注意,在最新的clang版本中,openmp不起作用,因此我不得不从现在开始使用g++。我还通过监视Eigen::nbthreads()的值和使用MAC活动监视器来确保我实际上使用了所有可用的线程。

代码语言:javascript
复制
3.5  gpp -std=c++11 -I/usr/local/Cellar/eigen/3.3.5/include/eigen3/eigen main.cpp -O3 -march=native -fopenmp

执行时间: 16.5 +- 0.7ms

3.6最后,我安装了英特尔mkl库。在代码中,它们的使用非常简单:我只添加了#define EIGEN_USE_MKL_ALL宏,仅此而已。然而,很难链接所有的库:

代码语言:javascript
复制
gpp -std=c++11 -DMKL_LP64 -m64 -I${MKLROOT}/include -I/usr/local/Cellar/eigen/3.3.5/include/eigen3/eigen -L${MKLROOT}/lib -Wl,-rpath,${MKLROOT}/lib -lmkl_intel_ilp64 -lmkl_intel_thread -lmkl_core -liomp5 -lpthread -lm -ldl   main.cpp -o my_exec_intel -O3 -fopenmp  -march=native

执行时间: 14.33 +-0.26ms。(编者按:这个答案最初声称使用了not supported-DMKL_ILP64。也许它曾经是,或者碰巧起作用了。)

结论:

  • Matrix-matrix乘法在Python/Matlab中得到了高度优化。不可能(或至少很难)在处理器上做得更好。
  • CPP代码(至少在MAC平台上)只有在完全优化的情况下才能实现类似的性能,其中包括全套优化选项和英特尔MKL库。我可以安装支持openmp的旧clang编译器,但由于单线程性能相似(约46 ms),这看起来没有什么帮助。
  • 如果能用本机英特尔编译器icc尝试一下,那就太好了。遗憾的是,这是专有软件,与英特尔mkl库不同。

感谢有用的讨论,

米哈伊尔

编辑:为了进行比较,我还使用cublasDgemm函数对我的GTX980GPU进行了基准测试。计算时间=12.6ms,这与其他results.兼容CUDA几乎和CPU一样好的原因如下:我的GPU对于doubles的优化很差。使用浮点数时,GPU时间=0.43毫秒,而Matlab为7.2毫秒

编辑2:为了获得显著的GPU加速,我需要对大得多的矩阵进行基准测试,例如10k x 10k

编辑3:将接口从MKL_ILP64更改为MKL_LP64,因为ILP64为not supported.

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51656818

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档