【问题标题】:Eigen + MKL or OpenBLAS slower than Numpy/Scipy + OpenBLASEigen + MKL 或 OpenBLAS 比 Numpy/Scipy + OpenBLAS 慢
【发布时间】:2018-02-22 16:46:06
【问题描述】:

我从 c++ atm 开始,想使用矩阵并总体上加快速度。之前使用过 Python+Numpy+OpenBLAS。 认为 c++ + Eigen + MKL 可能会更快,或者至少不会更慢。

我的 C++ 代码:

#define EIGEN_USE_MKL_ALL
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/LU>
#include <chrono>

using namespace std;
using namespace Eigen;

int main()
{
    int n = Eigen::nbThreads( );
    cout << "#Threads: " << n << endl;

    uint16_t size = 4000;
    MatrixXd a = MatrixXd::Random(size,size);

    clock_t start = clock ();
    PartialPivLU<MatrixXd> lu = PartialPivLU<MatrixXd>(a);

    float timeElapsed = double( clock() - start ) / CLOCKS_PER_SEC; 
    cout << "Elasped time is " << timeElapsed << " seconds." << endl ;
}

我的 Python 代码:

import numpy as np
from time import time
from scipy import linalg as la

size = 4000

A = np.random.random((size, size))

t = time()
LU, piv = la.lu_factor(A)
print(time()-t)

我的时间安排:

C++     2.4s
Python  1.2s

为什么 c++ 比 Python 慢?

我正在编译 c++ 使用:

g++ main.cpp -o main -lopenblas -O3 -fopenmp  -DMKL_LP64 -I/usr/local/include/mkl/include

MKL 确实可以工作:如果我禁用它,运行时间大约是 13 秒。

我还尝试了 C++ + OpenBLAS,它也给了我大约 2.4 秒。

知道为什么 C++ 和 Eigen 比 numpy/scipy 慢吗?

【问题讨论】:

  • 为 Numpy 做实际工作的代码是用 C 编写的。如果您想了解速度差异,您需要查看不同底层库使用的算法。您编写的程序调用库的语言是完全不相关的。
  • 是的@SvenMarnach 我不希望 c++ 更快我只是希望他们应该有相似的速度,因为他们应该在后端都使用 MKL 或 OpenBLAS。
  • -DNDEBUG编译的时机是什么?
  • @HenriMenke 它的 2.4s 也是如此
  • 你的 CPU 是什么?在这里,在 2.6GHz core7 (Haswell) 上,我只使用 Eigen 而不使用 openmp 得到 1.4s,如果使用 openmp,我得到 0.7s。当然,您需要使用 -march=native 进行编译才能充分利用您的 CPU。

标签: python c++ performance numpy eigen


【解决方案1】:

时机不对。这是wall clock time vs. CPU time 的典型症状。当我使用 &lt;chrono&gt; 标头中的 system_clock 时,它“神奇地”变得更快。

#define EIGEN_USE_MKL_ALL
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/LU>
#include <chrono>

int main()
{
    int const n = Eigen::nbThreads( );
    std::cout << "#Threads: " << n << std::endl;

    int const size = 4000;
    Eigen::MatrixXd a = Eigen::MatrixXd::Random(size,size);

    auto start = std::chrono::system_clock::now();

    Eigen::PartialPivLU<Eigen::MatrixXd> lu(a);

    auto stop = std::chrono::system_clock::now();

    std::cout << "Elasped time is "
              << std::chrono::duration<double>{stop - start}.count()
              << " seconds." << std::endl;
}

我用编译

icc -O3 -mkl -std=c++11 -DNDEBUG -I/usr/include/eigen3/ test.cpp

得到输出

#Threads: 1
Elasped time is 0.295782 seconds.

您的 Python 版本在我的机器上报告 0.399146080017


或者,要获得可比较的时间,您可以在 Python 中使用 time.clock()(CPU 时间)而不是 time.time()(挂钟时间)。

【讨论】:

    【解决方案2】:

    这不是一个公平的比较。 python 例程以浮点精度运行,而 C++ 代码需要处理双精度数。这恰好使计算时间加倍。

    >>> type(np.random.random_sample())
    <type 'float'>
    

    您应该与 MatrixXf 而不是 MatrixXd 进行比较,并且您的 MKL 代码应该同样快。

    【讨论】:

    • 它们确实同样快,但是 numpy 使用 float64,这与 C++ 中的 double 相同。
    • Numpy 也使用 openblas 和 MKL。所以无论如何它都使用 32 位精度进行 LU 分解。
    猜你喜欢
    • 2023-03-10
    • 2013-12-24
    • 1970-01-01
    • 2015-06-19
    • 2016-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多