ベンチマーク(BLASを使用したpython vs. c ++)と(numpy)


107

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

私は、いわば3人の競技者がいて、単純な行列と行列の乗算でそのパフォーマンスをテストしたいと考えています。出場者は次のとおりです。

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

シナリオ

さまざまな次元の行列-行列乗算を実装しましたii5の増分で5〜500が実行され、matricies 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セバスチャンはそのリンクを可能にした^^)


ctypesアプローチでは、測定された関数内にメモリ割り当てがあります。あなたのc ++コードはこのアプローチに従いますか?しかし、行列乗算に比べて、これは....大きな違いを作るべきではありません
rocksportrocker

@rocksportrocker正解です。rマトリックスのメモリ割り当ては不公平です。現在「問題」を解決しており、新しい結果を投稿しています。
ウォルタン、2011

1.配列のメモリレイアウトが同じであることを確認しますnp.ascontiguousarray()(CとFortranの順序を考慮してください)。2. np.dot()が同じを使用していることを確認してくださいlibblas.so
jfs '09 / 09/29

@JFSebastian両方の配列m1m2ascontiguousarrayフラグはTrueです。また、numpyはCと同じ共有オブジェクトを使用します。配列の順序について:現在、計算の結果には興味がないので、順序は関係ありません。
Woltan、2009

1
@ウォルタン:サービスがひどいファイルファクトリを使用しないでください。あなたのベンチマークをgithubに追加しました:woltan-benchmark。githubを使用している場合は、コラボレーターとして追加できます。
jfs '09 / 09/30

回答:


58

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

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

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

結果に違いがないため、公平に見えます。

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

番号。

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

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


4
では、元のポスターは何を間違っていたのでしょうか?彼がこの投稿にコメントしてくれたらいいのに。彼はNumpyがC ++と同じくらい高速であることを確認していますか?
wmac

あなたはC ++コードが元のポスターよりも実行が遅いです。最適化の下でコンパイルしましたか?
cdcdcd

@cdcdcdそれは私のコードではありません。リンクをクリックし、さまざまな最適化オプションを使用して自分でベンチマークを実行します(Makefileを参照)。ただし、コードはblasもlapackも再コンパイルしません。
jfs

73

更新(2014年7月30日):

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

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

ハードウェア

HPCには2つの異なるノードがあり、1つはIntel Sandy Bridge CPUを備え、もう1つは新しいIvy Bridge CPUを備えています。

Sandy(MKL、OpenBLAS、ATLAS):

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

Ivy(MKL、OpenBLAS、ATLAS):

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

ソフトウェア

ソフトウェアスタックは、SAMの両方のノード用です。代わりのGotoBLAS2OpenBLASが使用され、またあるマルチスレッドATLAS 8つのスレッドに設定されているBLAS(ハード)。

  • OS:Suse
  • インテルコンパイラ:ictce-5.3.0
  • Numpy: 1.8.0
  • OpenBLAS: 0.2.6
  • アトラス:: 3.8.4

ドット積ベンチマーク

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

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

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

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

スレッドとマトリックスのサイズ(Ivy Bridge MKL)行列サイズとスレッド

ベンチマークスイート

ベンチマークスイート

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

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

結論

新しいベンチマークの結果は、元の回答の結果と同様です。OpenBLASMKLは、固有値テストを除いて、同じレベルで動作します。固有値にのみ合理的試験を行うOpenBLASシングルスレッドモード。マルチスレッドモードでは、パフォーマンスが低下します。

「スレッド対行列サイズチャート」もMKLならびにOpenBLASは、一般的にコア/スレッドの数とよくスケーリングするが、それはマトリックスのサイズに依存することを示します。小さな行列の場合、コアを追加してもパフォーマンスはあまり向上しません。

また、サンディブリッジからアイビーブリッジへのパフォーマンスは約30%向上しています。これは、クロックレートが高い(+ 0.8 Ghz)か、アーキテクチャが優れているためと考えられます。


元の回答(2011年4月10日):

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

特に私はテストしました:

  • ATLASを使用したNumpy
  • Numpy with GotoBlas2(1.13)
  • Numpy with MKL(11.1 / 073)
  • Numpy with Accelerate Framework(Mac OS X)

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

  1. 異なるサイズの行列の単純な内積
  2. ここで見つけることができるベンチマークスイート。

これが私の結果です:

機械

Linux(MKL、ATLAS、No-MKL、GotoBlas2):

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

Mac Book Pro(Accelerate Framework):

  • OS:Mac OS X Snow Leopard(10.6)
  • CPU:1 Intel Core 2 Duo 2.93 Ghz(2コア)
  • RAM:4 GB
  • 辛味:0.7
  • Numpy:1.3

Mac Server(Accelerate Framework):

  • OS:Mac OS X Snow Leopard Server(10.6)
  • CPU:4 X Intel(R)Xeon(R)E5520 @ 2.26 Ghz(8コア)
  • RAM:4 GB
  • スパイシー:0.8
  • Numpy: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 |
netlib BLAS | 1350ミリ秒| 10900ミリ秒| 39200ミリ秒|    
ATLAS(1 CPU)| 314ミリ秒| 2560 ms | 8700 ms |     
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 ms | 2130ミリ秒|

ドット製品ベンチマーク-チャート

ベンチマークスイート

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

結果

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

ベンチマークスイート-グラフ

取り付け

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

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

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

FinkまたはMacポートを備えた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をインストールし、パフォーマンスはMKLGotoBlas2に似ていました。タフな数字はありません。

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

C ++ / Cでコーディングする場合は、MKL / GotoBlas2よりもパフォーマンスが高く、使いやすいEigen3もチェックしてください。


この精巧な回答をありがとうございました!
Woltan

とても包括的です、ありがとう!3年後、OpenBLAS(私の知る限りでは、GotoBLASの子孫です)の方がパフォーマンスが良いのかどうか疑問に思います。MKLよりも優れていることをどこかで読んだことがありますが、現在ソースを見つけることができません。

ありがとう!これは私の印象です0(これが自分のインストールだけであるのかと思っていました):OpenBLASは、マルチスレッドモードではマトリックスを対角化することに関してあまりパフォーマンスを発揮しません(OpenBLASにリンクされているscipyで対角化します)。

@William:通常、scipyをopenblasにリンクする必要はありません。インストール中にnumpy設定を使用し、実際にほとんどのBLAS / Lapack呼び出しはとにかくnumpyに転送されるためです。したがって、numpyがopenblasに対して適切にリンクされている場合、すべてが正常に動作するはずです。
ウミト

@Ümit:ありがとう!MKLにリンクするようにnumpyを設定しようとしています。

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 ---そしてこれが重要な場合は、おそらくベンチマークが壊れています。)

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

編集CalcTime関数の波括弧を数えることに失敗しました-それは大丈夫です。

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


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

$ python
Python 2.7.2以降(デフォルト、2011年8月16日07:24:41) 
[GCC 4.6.1] on linux2
詳細については、「help」、「copyright」、「credits」、または「license」と入力してください。
>>> 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たパッケージを(名前は変更になる場合があります) 。


私はあなたのベンチマークを実行しました。結果は 同じです
jfs '09 / 09/29

投稿ありがとうございます。私はこの結果であなたのベンチマークを実行しました。だから私はあなたのものを再現することはできません。numpyが使用しているBLASを確認するには:できませんimport numpy.core._dotblas。ここで何が問題になるのでしょうか?他の人がテストできるように、ベンチマークのクリーンアップとmakefileの書き込みを試みます。
Woltan、2009

2
@Woltan:numpy.core._dotblasをインポートできないという事実は、Numpyが、使用しているBLASライブラリーではなく、BLASの内部フォールバックコピー(低速で、パフォーマンスコンピューティングでの使用を意図していない!)を使用していることを意味しますシステムで。これは、ベンチマークから得た結果を説明しています。状況を修正するには、Numpyが動作するBLASバージョンをインストールする必要があります---つまり、ATLASまたはMKLを意味します。手順は次のとおり
pv。

@pv .: Woltanのベンチマークを実行して結果を比較できますか。
jfs 2009

1
Macでは、Linuxのotool -L代わりに使用できますldd
RichVel

9

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

numpy / pythonアプローチでは、妥当な複雑さのマトリックスにオーバーヘッドを追加しないと考えていました。複雑さが増すにつれて、pythonが関与する割合は小さくなるはずです。グラフの右側にある結果の方が興味がありますが、問題があることを示す桁違いの差異があります。

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

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

numpyをmklでコンパイルしましたか?(http://software.intel.com/en-us/articles/intel-mkl/)。Linuxで実行している場合は、numlをmklでコンパイルする手順は次のとおりです。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を使用している場合は、mklを使用してコンパイル済みのバイナリを入手できます(また、pyfftwや他の多くの関連アルゴリズムも入手できます)。http://www.lfd.uci.edu/~gohlke/pythonlibs/ で、カリフォルニア大学アーバイン校、蛍光ダイナミクス研究所でクリストフゴールケに感謝の意を表します。

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


精巧な「コメント」ありがとうございます^^。python / numpy / BLAS設定を明確にするために:このインストールガイドに従いました。私はLinux OSを使用していて、バージョンはPython 2.7、Scipy 0.9 Numpy 1.6です。残念ながら、私は事前にFFTWを構築していませんでした
。mkl

ある意味で、それは幸運です。つまり、Pythonの結果には改善の余地があり、Pythonを使用したいようです。リンクに示されているものにビルドを変更すると、numpyの速度にはるかに満足するでしょうが、C ++実装と比較した場合、それがどのように表示されるかはまだわかりません。
Profane、2009

ATLASを構築することもできますが、これは私のパフォーマンスのニーズに対してあまりにも多くの頭痛の種のように聞こえたので、経験はありません。Pythonを使用することに興味があり、C ++を使用できる場合は、特別なコンパイルをたくさん行うことによるセットアップコストが言語の節約を上回って、C ++を実行する方が簡単な場合があると思います。しかし、mklとfftwはどちらもかなり単純なはずです。
Profane、2009

1
現在、MKL、Accelerate、OpenBLASのパフォーマンスは類似しています。ただし、OpenBLASはMKLよりもスケーラブルです。
Sturla Molden、2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.