BLASとLAPACKの線形代数機能を多用するプログラムを書きたいと思います。パフォーマンスは問題なので、いくつかのベンチマークを行い、知りたいのですが、私が取ったアプローチが正当なものかどうかを確認します。
私は、いわば3人の競技者がいて、単純な行列と行列の乗算でそのパフォーマンスをテストしたいと考えています。出場者は次のとおりです。
- Numpy、の機能のみを利用
dot
。 - Python、共有オブジェクトを介してBLAS機能を呼び出します。
- C ++、共有オブジェクトを介してBLAS機能を呼び出す。
シナリオ
さまざまな次元の行列-行列乗算を実装しましたi
。i
5の増分で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;
}
結果
結果を以下のプロットに示します。
ご質問
- 私のアプローチは公平だと思いますか、それとも私が回避できるいくつかの不要なオーバーヘッドがありますか?
- 結果がc ++とpythonのアプローチの間に非常に大きな不一致を示すと予想しますか?どちらも計算に共有オブジェクトを使用しています。
- 私はプログラムにpythonを使用したいので、BLASまたはLAPACKルーチンを呼び出すときにパフォーマンスを向上させるにはどうすればよいですか?
ダウンロード
r
マトリックスのメモリ割り当ては不公平です。現在「問題」を解決しており、新しい結果を投稿しています。
np.ascontiguousarray()
(CとFortranの順序を考慮してください)。2. np.dot()
が同じを使用していることを確認してくださいlibblas.so
。
m1
でm2
、ascontiguousarray
フラグはTrue
です。また、numpyはCと同じ共有オブジェクトを使用します。配列の順序について:現在、計算の結果には興味がないので、順序は関係ありません。