114

BLASとLAPACKの線形代数機能を多用するプログラムを書きたいと思います。パフォーマンスが問題であるため、ベンチマークを実行しました。私が採用したアプローチが正当であるかどうかを知りたいと思います。

私には、いわば3人の出場者がいて、単純な行列-行列乗算を使用して彼らのパフォーマンスをテストしたいと思います。出場者は次のとおりです。

  1. Numpy、の機能のみを利用していますdot
  2. Python、共有オブジェクトを介してBLAS機能を呼び出します。
  3. C ++、共有オブジェクトを介してBLAS機能を呼び出します。

シナリオ

さまざまな次元の行列-行列乗算を実装しましたii5から500まで、5の増分と行列m1で実行され、次のm2ように設定されます。

m1 = numpy.random.rand(i,i).astype(numpy.float32)
m2 = numpy.random.rand(i,i).astype(numpy.float32)

1. Numpy

使用されるコードは次のようになります。

tNumpy = timeit.Timer("numpy.dot(m1, m2)", "import numpy; from __main__ import m1, m2")
rNumpy.append((i, tNumpy.repeat(20, 1)))

2. Python、共有オブジェクトを介してBLASを呼び出す

機能付き

_blaslib = ctypes.cdll.LoadLibrary("libblas.so")
def Mul(m1, m2, i, r):

    no_trans = c_char("n")
    n = c_int(i)
    one = c_float(1.0)
    zero = c_float(0.0)

    _blaslib.sgemm_(byref(no_trans), byref(no_trans), byref(n), byref(n), byref(n), 
            byref(one), m1.ctypes.data_as(ctypes.c_void_p), byref(n), 
            m2.ctypes.data_as(ctypes.c_void_p), byref(n), byref(zero), 
            r.ctypes.data_as(ctypes.c_void_p), byref(n))

テストコードは次のようになります。

r = numpy.zeros((i,i), numpy.float32)
tBlas = timeit.Timer("Mul(m1, m2, i, r)", "import numpy; from __main__ import i, m1, m2, r, Mul")
rBlas.append((i, tBlas.repeat(20, 1)))

3. c ++、共有オブジェクトを介してBLASを呼び出す

これで、c ++コードは当然少し長くなるので、情報を最小限に抑えます。
関数をロードします

void* handle = dlopen("libblas.so", RTLD_LAZY);
void* Func = dlsym(handle, "sgemm_");

私はこのように時間を測定しgettimeofdayます:

gettimeofday(&start, NULL);
f(&no_trans, &no_trans, &dim, &dim, &dim, &one, A, &dim, B, &dim, &zero, Return, &dim);
gettimeofday(&end, NULL);
dTimes[j] = CalcTime(start, end);

ここで、jは20回実行されるループです。経過時間を計算します

double CalcTime(timeval start, timeval end)
{
double factor = 1000000;
return (((double)end.tv_sec) * factor + ((double)end.tv_usec) - (((double)start.tv_sec) * factor + ((double)start.tv_usec))) / factor;
}

結果

結果を以下のプロットに示します。

ここに画像の説明を入力してください

質問

  1. 私のアプローチは公平だと思いますか、それとも回避できる不要なオーバーヘッドがありますか?
  2. 結果は、c ++とpythonのアプローチの間にこのような大きな矛盾を示すと思いますか?どちらも計算に共有オブジェクトを使用しています。
  3. プログラムにPythonを使用したいので、BLASまたはLAPACKルーチンを呼び出すときにパフォーマンスを向上させるために何ができますか?

ダウンロード

完全なベンチマークはここからダウンロードできます。(JFセバスティアンはそのリンクを可能にしました^^)

4

5 に答える 5

76

更新 (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:33:50.307 に答える
62

ベンチマークを実行しました。私のマシンでは、C++ と numpy に違いはありません。

ウォルタンのベンチマーク

私のアプローチは公平だと思いますか、それとも回避できる不必要なオーバーヘッドはありますか?

結果に差がないので公平に見えます。

結果が c++ と python のアプローチの間に大きな相違を示すと思いますか? どちらも計算に共有オブジェクトを使用しています。

いいえ。

プログラムに Python を使用したいので、BLAS または LAPACK ルーチンを呼び出すときのパフォーマンスを向上させるにはどうすればよいですか?

numpy がシステムで BLAS/LAPACK ライブラリの最適化されたバージョンを使用していることを確認してください。

于 2011-09-30T18:00:19.917 に答える
20

別のベンチマークは次のとおりです (Linux では、単に入力しますmake): http://dl.dropbox.com/u/5453551/blas_call_benchmark.zip

http://dl.dropbox.com/u/5453551/blas_call_benchmark.png

Numpy、Ctypes、および Fortran の間で、大きな行列のさまざまな方法に本質的な違いは見られません。(C++ ではなく Fortran --- これが問題になる場合は、ベンチマークが壊れている可能性があります。)

C ++ のCalcTime関数に符号エラーがあるようです。... + ((double)start.tv_usec))代わりにする必要があります... - ((double)start.tv_usec))おそらく、ベンチマークには他のバグもあります。たとえば、異なる BLAS ライブラリ間の比較、スレッド数などの異なる BLAS 設定の比較、またはリアルタイムと CPU 時間の比較などです。

EDITCalcTime :関数内の中かっこを数えることができませんでした。問題ありません。

ガイドラインとして: ベンチマークを行う場合は、常にすべてのコードをどこかに投稿してください。完全なコードを用意せずにベンチマークにコメントすることは、特に驚くような場合には、通常は生産的ではありません。


どの BLAS Numpy がリンクされているかを調べるには、次のようにします。

$パイソン
Python 2.7.2+ (デフォルト、2011 年 8 月 16 日 07:24:41)
[GCC 4.6.1] Linux2 で
詳細については、「ヘルプ」、「著作権」、「クレジット」、または「ライセンス」と入力してください。
>>> numpy.core._dotblas をインポート
>>> numpy.core._dotblas.__file__
「/usr/lib/pymodules/python2.7/numpy/core/_dotblas.so」
>>>
$ ldd /usr/lib/pymodules/python2.7/numpy/core/_dotblas.so
    linux-vdso.so.1 => (0x00007fff5ebff000)
    libblas.so.3gf => /usr/lib/libblas.so.3gf (0x00007fbe618b3000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbe61514000)

更新: numpy.core._dotblas をインポートできない場合、Numpy は BLAS の内部フォールバック コピーを使用しています。これは遅く、パフォーマンス コンピューティングで使用することを意図していません! 以下の@Woltanからの返信は、これが彼/彼女がNumpyとCtypes + BLASで見た違いの説明であることを示しています。

この状況を解決するには、ATLAS または MKL が必要です --- 次の手順を確認してください: http://scipy.org/Installing_SciPy/Linux ほとんどの Linux ディストリビューションには ATLAS が同梱されているため、最適なオプションはlibatlas-devパッケージをインストールすることです (名前は異なる場合があります) 。 .

于 2011-09-29T18:04:53.910 に答える
9

あなたがあなたの分析で示した厳密さを考えると、私はこれまでの結果に驚いています。私はこれを「答え」としていますが、コメントするには長すぎて可能性を提供しているからです(あなたがそれを検討したと思いますが)。

複雑さが増すにつれて、Pythonが参加する割合は少なくなるはずなので、numpy / pythonのアプローチでは、妥当な複雑さのマトリックスに多くのオーバーヘッドが追加されることはないと思います。グラフの右側の結果にもっと興味がありますが、そこに示されている桁違いの不一致は気がかりです。

numpyが活用できる最高のアルゴリズムを使用しているのではないかと思います。Linux用のコンパイルガイドから:

"ビルドFFTW(3.1.2):SciPyバージョン>=0.7およびNumpy>=1.2:ライセンス、構成、およびメンテナンスの問題により、FFTWのサポートはSciPy>=0.7およびNumPy>=1.2のバージョンで削除されました。組み込みバージョンのfftpack。分析に必要な場合は、FFTWの速度を利用する方法がいくつかあります。サポートを含むNumpy / Scipyバージョンにダウングレードします。FFTWの独自のラッパーをインストールまたは作成します。http:を参照してください。承認されていない例として//developer.berlios.de/projects/pyfftw/。」

mklでnumpyをコンパイルしましたか?(http://software.intel.com/en-us/articles/intel-mkl/)。Linuxで実行している場合、mklを使用してnumpyをコンパイルする手順は次のとおりです:http ://www.scipy.org/Installing_SciPy/Linux#head-7ce43956a69ec51c6f2cedd894a4715d5bfff974 (URLにもかかわらず)。重要な部分は次のとおりです。

[mkl]
library_dirs = /opt/intel/composer_xe_2011_sp1.6.233/mkl/lib/intel64
include_dirs = /opt/intel/composer_xe_2011_sp1.6.233/mkl/include
mkl_libs = mkl_intel_lp64,mkl_intel_thread,mkl_core 

Windowsを使用している場合は、http://www.lfd.uci.edu/~gohlke/pythonlibs/で、mklを使用してコンパイル済みのバイナリを取得できます(また、pyfftwやその他の多くの関連アルゴリズムを取得できます) 。カリフォルニア大学アーバイン校の蛍光ダイナミクス研究所のクリストフ・ゴールケに感謝の意を表します。

どちらの場合も、注意すべきライセンスの問題などがたくさんありますが、Intelページでそれらについて説明しています。繰り返しになりますが、これを検討したと思いますが、ライセンス要件(Linuxでは非常に簡単です)を満たしている場合、FFTWを使用せずに、単純な自動ビルドを使用する場合に比べて、厄介な部分が大幅に高速化されます。このスレッドをフォローして、他の人の意見を見てみたいと思います。とにかく、優れた厳密さと優れた質問。投稿していただきありがとうございます。

于 2011-09-29T12:09:48.137 に答える