我试图估计Python的性能与C++相比有多好。
这是我的Python代码:
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)
这是我在发行版中使用Xcode编译的C++代码:
#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;
}
结果是:
Starting matrix multiplication test with 1000matrices
time elapsed for 1 multiplication: 0.148856 seconds
Program ended with exit code: 0
这意味着C++程序要慢10倍。
另外,我尝试在MAC终端中编译cpp代码:
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,但是看起来问题出在矩阵定义中。在我的示例中,我使用默认的 Eigen 函数根据均匀分布创建矩阵。
谢谢,
米哈伊尔
编辑:我发现,虽然numpy使用多线程,但Eigen默认情况下不使用多个线程(由
Eigen::nbThreads()
函数检查)。如建议的那样,我使用
-march=native
选项将计算时间减少了3倍。考虑到MAC上有8个线程,我相信多线程numpy的运行速度快了3倍。 最佳答案
经过漫长而痛苦的安装和编译,我已经在Matlab,C++和Python中执行了基准测试。
我的计算机:MAC OS High Sierra 10.13.6,带有Intel®Core™i7-7920HQ CPU @ 3.10GHz(4核,8线程)。我有Radeon Pro 560 4096 MB,因此这些测试中没有GPU(而且我从未配置过openCL,也没有在np.show_config()
中看到它)。
软件:
Matlab 2018a,Python 3.6,C++编译器:Apple LLVM版本9.1.0(clang-902.0.39.2),g++-8(Homebrew GCC 8.2.0)8.2.0
1)Matlab性能:时间=(14.3 +-0.7)ms,执行10次运行
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库。 numpy与mkl相关联:14.4 + -0.7-它有帮助,但作用很小。
3)C++性能。对原始(请参阅问题)代码进行了以下更改:
noalias
函数可避免不必要的时间矩阵创建。 chorno
库在这里,我使用了一堆不同的选项和两个不同的编译器:
3.1 clang++ -std=c++11 -I/usr/local/Cellar/eigen/3.3.5/include/eigen3/eigen main.cpp -O3
执行时间〜146毫秒
3.2 Added -march=native option:
执行时间〜46 + -2毫秒
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 ms
3.4 Added - march=native option:
执行时间〜45.5 +-1毫秒
在这一点上,我意识到Eigen不使用多个线程。我安装了openmp并添加了-fopenmp标志。请注意,在最新的clang版本上,openmp不起作用,因此从现在开始,我必须使用g++。我还通过监视
Eigen::nbthreads()
的值并使用MAC OS Activity 监视器来确保实际上在使用所有可用线程。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.7毫秒
3.6最后,我安装了英特尔mkl库。在代码中,使用它们非常容易:我刚刚添加了
#define EIGEN_USE_MKL_ALL
宏,仅此而已。虽然很难链接所有库: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.26毫秒。 (编者注:这个答案最初声称使用了not supported,即results.。也许以前曾经使用过,或者碰巧起作用了。)
结论:
我本可以安装支持openmp的旧式clang编译器,但是由于单线程性能相似(〜46 ms),因此这似乎无济于事。
-DMKL_ILP64
一起尝试。不幸的是,这是专有软件,与Intel mkl库不同。 感谢您的有益讨论,
米哈伊尔
编辑:为了进行比较,我还使用cublasDgemm函数对GTX 980 GPU进行了基准测试。计算时间= 12.6 ms,与其他not supported.兼容。CUDA几乎与CPU一样好的原因如下:我的GPU不能优化为 double 。使用浮点运算时,GPU时间= 0.43毫秒,而Matlab的为7.2毫秒
编辑2:要获得显着的GPU加速,我需要对尺寸更大的矩阵进行基准测试,例如10k x 10k
编辑3:由于ILP64为ojit_a,因此将接口(interface)从MKL_ILP64更改为MKL_LP64
关于python - 基准矩阵乘法性能: C++ (eigen) is much slower than Python,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51656818/