[英]Eigen + MKL slower than Matlab for matrix multiplication
我在C ++程序中進行了大量的矩陣乘法,並使用與英特爾MKL(2018.3.222)鏈接的Eigen(3.3.5)。 我使用MKL的順序版本,並禁用OpenMP。 問題是它比Matlab慢。
一些示例代碼:
#define NDEBUG
#define EIGEN_USE_MKL_ALL
#include <iostream>
#include <chrono>
#include <Core>
using namespace Eigen;
using namespace std;
int main(){
MatrixXd jac = 100*MatrixXd::Random(10*1228, 2850);
MatrixXd res = MatrixXd::Zero(2850, 2850);
for (int i=0; i<10; i++){
auto begin = chrono::high_resolution_clock::now();
res.noalias() = jac.transpose()*jac;
auto end = chrono::high_resolution_clock::now();
cout<<"time: "<<chrono::duration_cast<chrono::milliseconds>(end-begin).count() <<endl;
}
return 0;
}
它平均報告大約8秒。 用-O3編譯,在Ubuntu 16.04上用g ++ 6.4編譯沒有調試符號。
Matlab代碼:
m=100*(-1+2*rand(10*1228, 2850));
res = zeros(2850, 2850);
tic; res=m'*m; toc
它報告約4秒,這是兩倍快。 我在與maxNumCompThreads(1)相同的系統上使用了Matlab R2017a。 Matlab使用MKL 11.3。
如果沒有MKL並僅使用Eigen,則需要大約18秒。 我該怎么做才能將C ++的運行時間降低到與Matlab相同的值? 謝謝。
稍后編輯:正如@Qubit建議的那樣,Matlab認識到我正在嘗試將矩陣與其轉置相乘並進行一些“隱藏”優化。 當我在Matlab中乘以兩個不同的矩陣時,時間上升到那8秒。 所以,現在問題變成了:我怎么能告訴Eigen這個矩陣產品是“特殊的”並且可以進一步優化?
后來編輯2:我嘗試這樣做:
MatrixXd jac = 100*MatrixXd::Random(10*1228, 2850);
MatrixXd res = MatrixXd::Zero(2850, 2850);
auto begin = chrono::high_resolution_clock::now();
res.selfadjointView<Lower>().rankUpdate(jac.transpose(), 1);
res.triangularView<Upper>() = res.transpose();
auto end = chrono::high_resolution_clock::now();
MatrixXd oldSchool = jac.transpose()*jac;
if (oldSchool.isApprox(res)){
cout<<"same result!"<<endl;
}
cout<<"time: "<<chrono::duration_cast<chrono::milliseconds>(end-begin).count() <<endl;
但現在需要9.4秒(這是經典產品沒有MKL所需的Eigen的一半)。 禁用MKL對此時間沒有時間影響,因此我認為'rankUpdate'方法不使用MKL?!?
上次編輯:我在eigen頭文件中發現了一個錯誤:
Core/products/GeneralMatrixMatrixTriangular_BLAS.h
在第55行。有一個錯位的括號。 我改變了這個:
if ( lhs==rhs && ((UpLo&(Lower|Upper)==UpLo)) ) { \
對此:
if ( lhs==rhs && ((UpLo&(Lower|Upper))==UpLo) ) { \
現在,我的C ++版本和Matlab具有相同的執行速度(在我的系統上約為4秒)。
真的是答案,因為你已經找到了問題,但有些意見:
問題Core/products/GeneralMatrixMatrixTriangular_BLAS.h
已經在devel分支中得到修復,但事實證明它從未被包含到3.3分支中。
這個問題現在已在3.3分支中修復 。 修復將是3.3.6的一部分。
單線程模式下內置Eigen和MKL之間的加速因子x2沒有意義。 除了-O3 -DNDEBUG
之外,通過使用-march=native
進行編譯,確保啟用CPU支持的所有功能。 在我的Haswell 2.6GHz上,我得到3.4s vs 3s。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.