https://www.cnblogs.com/huty/p/8517892.html
對於機器學習的很多問題來說,計算的瓶頸往往在於大規模以及頻繁的矩陣運算,主要在於以下兩方面:
- (Dense/Sparse) Matrix – Vector product
- (Dense/Sparse) Matrix – Dense Matrix product
如何使機器學習算法運行更高效擺在我們面前,很多人都會在代碼中直接采用一個比較成熟的矩陣運算數學庫,面對繁多的數學庫,選擇一個合適的庫往往會令人頭疼,這既跟你的運算環境有關,也跟你的運算需求有關,不是每個庫都能完勝的。
這篇文章的主要目的就是比較幾個常見的BLAS庫的矩陣運算性能,分別是
- EIGEN: 是一個線性算術的C++模板庫。功能強大、快速、優雅以及支持多平台,可以使用該庫來方便處理一些矩陣的操作,達到類似matlab那樣的快捷。 需要定義 EIGEN_NO_DEBUG 阻止運行時assertion。編譯單線程版本需要開啟 -DEIGEN_DONT_PARALLELIZE. 在試驗中,我們采用 EIGEN 原生 BLAS 實現。
- Intel MKL: 英特爾數學核心函數庫是一套經過高度優化和廣泛線程化的數學例程,專為需要極致性能的科學、工程及金融等領域的應用而設計。它可以為當前及下一代英特爾處理器提供性能優化,包括更出色地與 Microsoft Visual Studio、Eclipse和XCode相集成。英特爾 MKL 支持完全集成英特爾兼容性 OpenMP 運行時庫,以實現更出色的 Windows/Linux 跨平台兼容性。在試驗中的多線程版本需要鏈接到 mkl_gnu_thread,而不是 mkl_intel_thread,單線程版本需要鏈接到 mkl_sequential_thread。
- OpenBLAS: 是一個高性能多核 BLAS 庫,是 GotoBLAS2 1.13 BSD 版本的衍生版。OpenBLAS 的編譯依賴系統環境,並且沒有原生單線程版本,在實驗這哦那個,通過設置 OMP_NUM_THREADS=1 來模擬單線程版本,可能會帶來一點點的性能下降。
每個測試程序的編譯都采用 “-O4 -msse2 -msse3 -msse4” 優化, 通過設置 OMP_NUM_THREADS 來控制使用的線程數量. 除了 OpenBLAS,其他兩個庫的測試程序都分別有單線程和多線程的編譯版本。
如果MKL編譯出現問題,建議參考Intel Math Kernel Library Link Line Advisor
- 單線程版本
我在實驗中進行了一系列的非稀疏矩陣相乘運算,矩陣規模也逐漸增大,單線程的運行時間如下表所示,其中采用的測試輪數為5輪,其中紅色表示性能最好的一組實驗結果。
Matrix-Dimension | Eigen | MKL | OpenBLAS |
500 | 0.04159 | 0.03122 | 0.03058 |
1000 | 0.31789 | 0.24339 | 0.23730 |
1500 | 1.04589 | 0.81445 | 0.79869 |
2000 | 2.37567 | 1.92036 | 1.87102 |
2500 | 4.68266 | 3.78569 | 3.64548 |
3000 | 8.28073 | 6.42630 | 6.29797 |
3500 | 13.07470 | 10.25096 | 9.98417 |
4000 | 19.34550 | 15.21931 | 14.87500 |
4500 | 27.52767 | 21.45024 | 21.18227 |
5000 | 37.67552 | 29.31631 | 29.07229 |
從圖中可以看出,OpenBLAS的性能最好,MKL的表現也很不錯,而EIGEN的表現卻很糟糕。
- 多線程版本
在多線程的測試中,我們采用多個CPU核心來做矩陣乘法運算,所有的結果也同樣采用5輪訓練,我們采用的CPU核數分別是8,16,32,48。
- Cores = 8
Matrix-Dimension | Eigen | MKL | OpenBLAS |
1000 | 0.05658 | 0.03955 | 0.06468 |
2000 | 0.34981 | 0.26200 | 0.23879 |
3000 | 1.20781 | 0.85449 | 0.80737 |
4000 | 2.65490 | 1.90273 | 1.88366 |
5000 | 5.03304 | 3.73005 | 3.67966 |
6000 | 8.78654 | 6.52766 | 6.31980 |
7000 | 13.55611 | 10.13758 | 10.07120 |
8000 | 19.81634 | 15.03530 | 14.89440 |
9000 | 29.11329 | 21.54359 | 21.26992 |
10000 | 39.01563 | 29.93075 | 29.22034 |
- Cores = 16
Matrix-Dimension | Eigen | MKL | OpenBLAS |
1000 | 0.05708 | 0.02185 | 0.03897 |
2000 | 0.26694 | 0.13807 | 0.30461 |
3000 | 0.70686 | 0.43692 | 0.93511 |
4000 | 1.45129 | 0.97720 | 2.06761 |
5000 | 2.59477 | 1.90665 | 2.49280 |
6000 | 5.43438 | 3.30945 | 7.01299 |
7000 | 8.01124 | 5.17896 | 6.84496 |
8000 | 11.22280 | 7.81439 | 12.99240 |
9000 | 15.15625 | 11.08906 | 21.82488 |
10000 | 19.91151 | 15.22039 | 30.86908 |
- Cores = 32
Matrix-Dimension | Eigen | MKL | OpenBLAS |
1000 | 0.04003 | 0.02792 | 0.02244 |
2000 | 0.51213 | 0.14363 | 0.16990 |
3000 | 1.13647 | 0.51105 | 0.54635 |
4000 | 1.58793 | 1.10219 | 1.26401 |
5000 | 2.88341 | 2.07923 | 2.48735 |
6000 | 5.92779 | 3.42785 | 4.26794 |
7000 | 7.91650 | 5.32176 | 6.69391 |
8000 | 11.96467 | 7.65395 | 9.98951 |
9000 | 17.45420 | 10.28328 | 14.14108 |
10000 | 23.31314 | 15.10077 | 19.34171 |
- Cores = 40
Matrix-Dimension | Eigen | MKL | OpenBLAS |
1000 | 0.03691 | 0.02877 | 0.01779 |
2000 | 0.37739 | 0.14037 | 0.13655 |
3000 | 0.61183 | 0.41057 | 0.44113 |
4000 | 2.43670 | 1.02625 | 1.01414 |
5000 | 3.18099 | 1.91092 | 1.97898 |
6000 | 8.24002 | 2.96157 | 3.40685 |
7000 | 11.59889 | 4.68312 | 5.38634 |
8000 | 9.50613 | 6.98434 | 7.95971 |
9000 | 14.83066 | 9.60891 | 11.37585 |
10000 | 23.67187 | 15.52151 | 15.52680 |
- Cores = 48
Matrix-Dimension | Eigen | MKL | OpenBLAS |
1000 | 0.03635 | 0.02398 | 0.01548 |
2000 | 0.36417 | 0.13408 | 0.11496 |
3000 | 2.32388 | 0.39291 | 0.36669 |
4000 | 2.32030 | 1.13244 | 0.85790 |
5000 | 2.08269 | 1.75812 | 1.66785 |
6000 | 8.70766 | 2.98694 | 2.85609 |
7000 | 8.23543 | 4.62340 | 4.53257 |
8000 | 21.18603 | 6.68886 | 6.72820 |
9000 | 19.86504 | 9.59635 | 9.50597 |
10000 | 16.10920 | 13.13038 | 13.04432 |
可以看出,MKL和OpenBLAS都提供了比較好的性能,MKL性能還更好一點,在各別多線程條件下了,可能某些原因或者我機器設置的問題,出現了各別性能異常,比如小矩陣運算時間反倒比大矩陣運算長,或者更多的線程卻不能提供更好的性能。這些情況后面可能還需要查一查。
- 伸縮性
另外,我也測試了使用不同的cpu核數對性能的影響,下面兩個圖描述了把cpu從1增加到20的條件下,5000×5000的矩陣相乘的時間開銷和加速比。
- 結論
就我的測試環境而言,Intel MKL 和 OpenBLAS 似乎是矩陣相乘運算方面性能最佳的 BLAS 庫,在多核以及不同規模的矩陣方面都具有較好的伸展性和穩定性,而對於單線程情況,OpenBLAS相比 MKL 在性能上有一定提升。
本文參考gcdart的文章,代碼可以下載。