50

Python で多数の行列 - 行列乗算を実装しようとしています。最初は、NumPy はスレッド化された BLAS ライブラリを自動的に使用すると想定していました。これらのライブラリに対して NumPy をビルドしたからです。ただし、トップなどを見ると、コードがスレッドをまったく使用していないように見えます。

BLASのパフォーマンスを簡単に使用するために何が間違っているのか、何ができるのか考えていますか?

4

4 に答える 4

112

すでに別のスレッドにこれを投稿しましたが、このスレッドの方が適していると思います。

更新 (30.07.2014):

新しい HPC でベンチマークを再実行します。ハードウェアとソフトウェアスタックの両方が、元の回答のセットアップから変更されました。

結果をGoogleスプレッドシートに入れました(元の回答の結果も含まれています)。

ハードウェア

当社の HPC には、Intel Sandy Bridge CPU を搭載したノードと、より新しい Ivy Bridge CPU を搭載した 2 つの異なるノードがあります。

サンディ(MKL、OpenBLAS、ATLAS):

  • CPU : 2 x 16 Intel(R) Xeon(R) E2560 Sandy Bridge @ 2.00GHz (16 コア)
  • RAM:64GB

アイビー(MKL、OpenBLAS、ATLAS):

  • CPU : 2 x 20 Intel(R) Xeon(R) E2680 V2 Ivy Bridge @ 2.80GHz (20 コア、HT = 40 コア)
  • RAM:256GB

ソフトウェア

ソフトウェア スタックは、両方のノードの sam です。GotoBLAS2の代わりにOpenBLAS使用され、8 スレッドに設定された (ハードコードされた)マルチスレッド ATLAS BLAS もあります。

  • OS : スーズ
  • インテル コンパイラ: ictce-5.3.0
  • でこぼこ: 1.8.0
  • OpenBLAS: 0.2.6
  • アトラス: : 3.8.4

内積ベンチマーク

Benchmark-code は以下と同じです。ただし、新しいマシンでは、マトリックス サイズ5000および8000のベンチマークも実行しました。
以下の表には、元の回答のベンチマーク結果が含まれています (名前が変更されました: MKL --> Nehalem MKL、Netlib Blas --> Nehalem Netlib BLAS など)。

行列の乗算 (サイズ=[1000,2000,3000,5000,8000])

シングルスレッドのパフォーマンス: シングルスレッドのパフォーマンス

マルチスレッド性能 (8 スレッド): マルチスレッド (8 スレッド) のパフォーマンス

スレッド vs マトリックス サイズ (Ivy Bridge MKL) : マトリックスサイズとスレッド

ベンチマーク スイート

ベンチマーク スイート

シングルスレッドのパフォーマンス: ここに画像の説明を入力

マルチスレッド (8 スレッド) のパフォーマンス: ここに画像の説明を入力

結論

新しいベンチマークの結果は、元の回答のも​​のと似ています。OpenBLASMKLは、固有値テストを除いて、同じレベルで実行されます。固有値テストは、シングル スレッド モードのOpenBLASでのみ適切に実行されます。マルチスレッド モードでは、パフォーマンスが低下します。

マトリックス サイズとスレッドのグラフ」は、MKL と OpenBLAS は一般にコア/スレッドの数に応じて適切にスケーリングされますが、マトリックスのサイズに依存することも示しています。小さなマトリックスの場合、コアを追加してもパフォーマンスはあまり向上しません。

また、Sandy BridgeからIvy Bridgeへのパフォーマンスが約 30% 向上しています。これは、クロック レートが高い (+ 0.8 Ghz) か、アーキテクチャが改善されたことが原因である可能性があります。


元の回答 (04.10.2011):

少し前に、numpy と BLAS を使用して Python で記述されたいくつかの線形代数計算/アルゴリズムを最適化する必要があったため、さまざまな numpy/BLAS 構成をベンチマーク/テストしました。

具体的には、次のことをテストしました。

  • ATLAS でナンピー
  • GotoBlas2でナンピー(1.13)
  • MKL でナンピー (11.1/073)
  • Accelerate フレームワークを使用した Numpy (Mac OS X)

2 つの異なるベンチマークを実行しました。

  1. 異なるサイズの行列の単純な内積
  2. ここにあるベンチマークスイート。

ここに私の結果があります:

機械

Linux (MKL、ATLAS、MKL なし、GotoBlas2):

  • OS : Ubuntu Lucid 10.4 64 ビット。
  • CPU : 2 x 4 Intel(R) Xeon(R) E5504 @ 2.00GHz (8 コア)
  • RAM:24GB
  • インテル コンパイラ: 11.1/073
  • スキピー: 0.8
  • でこぼこ:1.5

Mac Book Pro (アクセラレート フレームワーク):

  • OS : Mac OS X Snow Leopard (10.6)
  • CPU : 1 Intel Core 2 Duo 2.93 Ghz (2 コア)
  • RAM:4GB
  • スキピー: 0.7
  • でこぼこ:1.3

Mac サーバー(アクセラレート フレームワーク):

  • OS : Mac OS X Snow Leopard サーバー (10.6)
  • CPU : 4 X Intel(R) Xeon(R) E5520 @ 2.26 Ghz (8 コア)
  • RAM:4GB
  • スキピー: 0.8
  • ナンピー:1.5.1

内積ベンチマーク

コード:

import numpy as np
a = np.random.random_sample((size,size))
b = np.random.random_sample((size,size))
%timeit np.dot(a,b)

結果

    システム | システム | サイズ = 1000 | サイズ = 2000 | サイズ = 3000 |
ネットライブラリ BLAS | 1350 ミリ秒 | 10900 ミリ秒 | 39200 ミリ秒 |    
アトラス (1 CPU) | 314 ミリ秒 | 2560 ミリ秒 | 8700 ミリ秒 |     
MKL (1 CPU) | 268 ミリ秒 | 2110 ミリ秒 | 7120 ミリ秒 |
MKL (2 CPU) | - | - | 3660 ミリ秒 |
MKL (8 CPU) | 39 ミリ秒 | 319 ミリ秒 | 1000 ミリ秒 |
GotoBlas2 (1 CPU) | 266 ミリ秒 | 2100 ミリ秒 | 7280 ミリ秒 |
GotoBlas2 (2 CPU)| 139 ミリ秒 | 1009 ミリ秒 | 3690 ミリ秒 |
GotoBlas2 (8 CPU)| 54 ミリ秒 | 389 ミリ秒 | 1250 ミリ秒 |
Mac OS X (1 CPU) | 143 ミリ秒 | 1060 ミリ秒 | 3605 ミリ秒 |
Mac サーバー (1 CPU)| 92 ミリ秒 | 714 ミリ秒 | 2130 ミリ秒 |

内積ベンチマーク - グラフ

ベンチマーク スイート

コード:
ベンチマーク スイートの詳細については、こちらを参照してください。

結果

    システム | システム | 固有値 | svd | 詳細 | 投資 | ドット |
ネットライブラリ BLAS | 1688 ミリ秒 | 13102 ミリ秒 | 438 ミリ秒 | 2155 ミリ秒 | 3522 ミリ秒 |
アトラス (1 CPU) | 1210 ミリ秒 | 5897 ミリ秒 | 170 ミリ秒 | 560 ミリ秒 | 893 ミリ秒 |
MKL (1 CPU) | 691 ミリ秒 | 4475 ミリ秒 | 141 ミリ秒 | 450 ミリ秒 | 736 ミリ秒 |
MKL (2 CPU) | 552 ミリ秒 | 2718 ミリ秒 | 96 ミリ秒 | 267 ミリ秒 | 423 ミリ秒 |
MKL (8 CPU) | 525 ミリ秒 | 1679 ミリ秒 | 60 ミリ秒 | 137 ミリ秒 | 197 ミリ秒 |  
GotoBlas2 (1 CPU) | 2124 ミリ秒 | 4636 ミリ秒 | 147 ミリ秒 | 456 ミリ秒 | 743 ミリ秒 |
GotoBlas2 (2 CPU)| 1560 ミリ秒 | 3278 ミリ秒 | 116 ミリ秒 | 295 ミリ秒 | 460 ミリ秒 |
GotoBlas2 (8 CPU)| 741 ミリ秒 | 2914 ミリ秒 | 82 ミリ秒 | 262 ミリ秒 | 192 ミリ秒 |
Mac OS X (1 CPU) | 948 ミリ秒 | 4339 ミリ秒 | 151 ミリ秒 | 318 ミリ秒 | 566 ミリ秒 |
Mac サーバー (1 CPU)| 1033 ミリ秒 | 3645 ミリ秒 | 99 ミリ秒 | 232 ミリ秒 | 342 ミリ秒 |

ベンチマーク スイート - チャート

インストール

MKLのインストールには、非常に簡単な完全なインテル コンパイラ スイートのインストールが含まれます。ただし、いくつかのバグ/問題のために、MKL サポートを使用して numpy を構成およびコンパイルするのは少し面倒でした。

GotoBlas2は、共有ライブラリとして簡単にコンパイルできる小さなパッケージです。ただし、バグのため、numpy で使用するには、ビルド後に共有ライブラリを再作成する必要があります。
このビルドに加えて、複数のターゲット プラットフォーム用のビルドが何らかの理由で機能しませんでした。そのため、最適化されたlibgoto2.soファイルが必要なプラットフォームごとに.soファイルを作成する必要がありました。

Ubuntu のリポジトリから numpy をインストールすると、 ATLASを使用するように numpy が自動的にインストールおよび構成されます。ソースからATLASをインストールするには時間がかかり、追加の手順 (fortran など) が必要になる場合があります。

FinkまたはMac Portsを備えた Mac OS X マシンに numpy をインストールすると、 ATLASまたはApple の Accelerate Frameworkを使用するように numpy が構成されます。numpy.core._dotblasファイルで ldd を実行するか、 numpy.show_config()を呼び出して確認できます。

結論

MKLが最高のパフォーマンスを発揮し、GotoBlas2が僅差で続きます。固有値
検定で は、GotoBlas2 のパフォーマンスは予想よりも驚くほど悪いものでした。なぜそうなのかはわかりません。Apple の Accelerate Frameworkは、特にシングル スレッド モードで非常に優れたパフォーマンスを発揮します (他の BLAS 実装と比較して)。

GotoBlas2MKLはどちらも、スレッド数に応じて非常にうまくスケーリングします。したがって、大きな行列を処理する必要がある場合は、複数のスレッドで実行すると非常に役立ちます。

いずれにしても、深刻な計算作業には遅すぎるため、デフォルトのnetlib blas実装を使用しないでください。

私たちのクラスターでは、AMD の ACMLもインストールしましたが、パフォーマンスはMKLおよびGotoBlas2と同様でした。難しい数字はありません。

インストールが簡単で無料であるため、個人的にはGotoBlas2を使用することをお勧めします。

C++/C でコーディングする場合は、場合によってはMKL/GotoBlas2よりも優れていると考えられ、非常に使いやすいEigen3もチェックしてください。

于 2011-10-04T09:41:43.487 に答える
3

行列 x 行列の乗算はメモリに制約があるため、同じメモリ階層にコアを追加してもあまり効果がない可能性があります。もちろん、Fortran 実装に切り替えたときに大幅な高速化が見られる場合は、間違っている可能性があります。

私の理解では、適切なキャッシングは、この種の問題では計算能力よりもはるかに重要です。おそらくBLASがこれを行います。

簡単なテストとして、比較のためにEnthought のpython ディストリビューションをインストールしてみてください。それらは Intel のMath Kernel Libraryにリンクしており、利用可能であれば複数のコアを利用していると私は信じています。

于 2011-03-11T20:27:46.243 に答える