矩阵乘法性能 numpy 和 eigen c++

Posted

技术标签:

【中文标题】矩阵乘法性能 numpy 和 eigen c++【英文标题】:Matrix multiplication performance numpy and eigen c++ 【发布时间】:2017-12-19 01:53:00 【问题描述】:

我正在尝试使用 C++ 和 numpy 比较 eigen 的矩阵乘法性能。

这里是矩阵乘法的 c++ 代码

#include<iostream>
#include <Eigen/Dense>
#include <ctime>
#include <iomanip> 

using namespace Eigen;
using namespace std;


    int main()

    time_t begin,end;
    double difference=0;
    time (&begin);
    for(int i=0;i<500;++i)
    
    MatrixXd m1 = MatrixXd::Random(500,500);
    MatrixXd m2 = MatrixXd::Random(500,500);
    MatrixXd m3 = MatrixXd::Zero(500,500);
    m3=m1*m2;
    
    time (&end); 
    difference = difftime (end,begin);
    std::cout<<"time = "<<std::setprecision(10)<<(difference/500.)<<" seconds"<<std::endl;

    return 0;

使用g++ -Wall -Wextra -I "path-to-eigen-directory" prog5.cpp -o prog5 -O3 -std=gnu++0x编译

输出:

time = 0.116 seconds

这是python代码。

import timeit
import numpy as np

start_time = timeit.default_timer()
for i in range(500):

    m1=np.random.rand(500,500)
    m2=np.random.rand(500,500)
    m3=np.zeros((500,500))
    m3=np.dot(m1,m2)

stop_time = timeit.default_timer()
print('Time =  seconds'.format((stop_time-start_time)/500))

输出:

Time = 0.01877937281645333 seconds

看起来 C++ 代码比 python 慢 6 倍。有人可以提供见解我是否在这里遗漏了什么?

我正在使用 Eigen 3.3.4、g++ 编译器 (MinGW.org GCC-6.3.0-1) 6.3.0、python 3.6.1、numpy 1.11.3。使用 spyder ide 运行的 Python。使用 Windows。

更新:

根据答案和cmets,我更新了代码。

使用g++ -Wall -Wextra -I "path-to-eigen-directory" prog5.cpp -o prog5 -O3 -std=gnu++0x -march=native 编译的C++ 代码。我无法让-fopenmp 工作 - 如果我使用此标志,似乎没有输出。

#include<iostream>
#include <Eigen/Dense>
#include <ctime>
#include <iomanip> 

using namespace Eigen;
using namespace std;

int main()

    time_t begin,end;
    double difference=0;
    time (&begin);
    for(int i=0;i<10000;++i)
    
    MatrixXd m1 = MatrixXd::Random(500,500);
    MatrixXd m2 = MatrixXd::Random(500,500);
    MatrixXd m3 = MatrixXd::Zero(500,500);
    m3=m1*m2;
    
    time (&end); // note time after execution
    difference = difftime (end,begin);
    std::cout<<"Total time = "<<difference<<" seconds"<<std::endl;
    std::cout<<"Average time = "<<std::setprecision(10)<<(difference/10000.)<<" seconds"<<std::endl;

    return 0;

输出:

Total time = 328 seconds
Average time = 0.0328 seconds

Python 代码:

import timeit
import numpy as np

start_time = timeit.default_timer()
for i in range(10000):

    m1=np.random.rand(500,500)
    m2=np.random.rand(500,500)
    m3=np.zeros((500,500))
    m3=np.dot(m1,m2)

stop_time = timeit.default_timer()
print('Total time =  seconds'.format(stop_time-start_time))
print('Average time =  seconds'.format((stop_time-start_time)/10000))

使用 spyder IDE 使用runfile('filename.py') 命令运行。

输出:

Total time = 169.35587796526667 seconds
Average time = 0.016935587796526666 seconds

现在使用 eigen 的性能更好,但不等于或快于 numpy。可能是-fopenmp 可以解决问题,但不确定。但是,我没有在 numpy 中使用任何并行化,除非它隐式地这样做。

【问题讨论】:

让测试运行几分钟。您提供的时间在统计上并不合理。 更新了问题。 矩阵乘法很大程度上取决于您使用的 BLAS/Linpack 库。您必须添加 numpy 和 eigen 使用哪一个。 (例如英特尔 MKL) 【参考方案1】:

您的基准有几个问题:

    您正在对系统rand() 功能进行基准测试,这是非常昂贵的! 您缺少编译器 -march=native 以获得 AVX/FMA 提升 您缺少-fopenmp 来启用多线程。

在我的 quad i7 2.6GHz CPU 上,我得到:

initial code:                       0.024s
after replacing `Random` by `Ones`: 0.018s
adding `-march=native`:             0.006s
adding `-fopenmp`:                  0.003s

矩阵有点太小,无法获得良好的多线程优势。

【讨论】:

(1) 我在 python 代码中使用 rand() 等价物,所以它也应该很昂贵(如果真的如此的话)。 (2) 将问题更新为-march=native。它使代码更快(3) 不幸的是我无法开始工作-fopenmp 但 python 的 rand() 可能更快,请检查通过将 Random 替换为 Ones 以消除此来源,然后请指定您的 CPU。我的已经 4 岁了,所以你应该能够获得类似的性能。我们目前观察到一个大于 5 的因子(即使没有 openmp),所以您这边一定有问题。

以上是关于矩阵乘法性能 numpy 和 eigen c++的主要内容,如果未能解决你的问题,请参考以下文章

在 ARM / Raspberry PI 上的多个内核上运行 Eigen 密集矩阵乘法时性能下降

numpy 和 tensorflow 中的各种乘法(点乘和矩阵乘)

numpy 和 tensorflow 中的各种乘法(点乘和矩阵乘)

比较 Python、Numpy、Numba 和 C++ 的矩阵乘法

numpy 矩阵乘法的奇怪性能结果

求问C++的Eigen矩阵运算库有没有提供两个矩阵对应元素相乘的方法