BLASおよびLAPACK線形代数機能を多用するプログラムを作成したいと思います。パフォーマンスは問題であるため、ベンチマークを行い、私が採用したアプローチが正当であるかどうかを知りたいと思います。
いわば3人の参加者がいて、単純なマトリックスマトリックスを使用してパフォーマンスをテストしたいと考えています。乗算。出場者は次のとおりです。
- Numpy、
dot
の機能のみを使用します。 - Python、共有オブジェクトを介してBLAS機能を呼び出します。
- C ++、共有オブジェクトを介してBLAS機能を呼び出します。
シナリオ
さまざまな次元の行列-行列乗算を実装しました私
。 i
は5から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; }
結果
結果は次のプロットに表示されます:
質問
- 私のアプローチは公平だと思いますか、それとも不要なオーバーヘッドがありますか避けますか?
- 結果がc++とpythonのアプローチの間にこのような大きな矛盾を示すと思いますか?どちらも計算に共有オブジェクトを使用しています。
- プログラムにPythonを使用したいので、BLASまたはLAPACKルーチンを呼び出すときのパフォーマンスを向上させるにはどうすればよいですか?
ダウンロード
完全なベンチマークは