Saya ingin menulis program yang memanfaatkan fungsi aljabar linier BLAS dan LAPACK secara ekstensif. Karena kinerja adalah masalah, saya melakukan beberapa pembandingan dan ingin tahu, apakah pendekatan yang saya ambil itu sah.
Bisa dibilang, saya memiliki tiga kontestan dan ingin menguji kinerja mereka dengan perkalian matriks-matriks sederhana. Para kontestannya adalah:
- Numpy, hanya memanfaatkan fungsionalitas
dot
. - Python, memanggil fungsionalitas BLAS melalui objek bersama.
- C ++, memanggil fungsionalitas BLAS melalui objek bersama.
Skenario
Saya menerapkan perkalian matriks-matriks untuk dimensi yang berbeda i
. i
berjalan dari 5 hingga 500 dengan kenaikan 5 dan matriks m1
dan m2
diatur seperti ini:
m1 = numpy.random.rand(i,i).astype(numpy.float32)
m2 = numpy.random.rand(i,i).astype(numpy.float32)
1. Numpy
Kode yang digunakan terlihat seperti ini:
tNumpy = timeit.Timer("numpy.dot(m1, m2)", "import numpy; from __main__ import m1, m2")
rNumpy.append((i, tNumpy.repeat(20, 1)))
2. Python, memanggil BLAS melalui objek bersama
Dengan fungsinya
_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))
kode tes terlihat seperti ini:
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 ++, memanggil BLAS melalui objek bersama
Sekarang kode c ++ secara alami sedikit lebih lama jadi saya mengurangi informasinya seminimal mungkin.
Saya memuat fungsi dengan
void* handle = dlopen("libblas.so", RTLD_LAZY);
void* Func = dlsym(handle, "sgemm_");
Saya mengukur waktu dengan gettimeofday
seperti ini:
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);
dimana j
loop berjalan 20 kali. Saya menghitung waktu berlalu dengan
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;
}
Hasil
Hasilnya ditunjukkan pada plot di bawah ini:
Pertanyaan
- Apakah menurut Anda pendekatan saya adil, atau adakah biaya tambahan yang tidak perlu yang dapat saya hindari?
- Apakah Anda berharap bahwa hasilnya akan menunjukkan perbedaan yang sangat besar antara pendekatan c ++ dan python? Keduanya menggunakan objek bersama untuk penghitungannya.
- Karena saya lebih suka menggunakan python untuk program saya, apa yang dapat saya lakukan untuk meningkatkan kinerja saat memanggil rutinitas BLAS atau LAPACK?
Unduh
Benchmark lengkapnya bisa diunduh disini . (JF Sebastian memungkinkan tautan itu ^^)
r
matriks tidak adil. Saya sedang menyelesaikan "masalah" sekarang dan memposting hasil baru.
np.ascontiguousarray()
(pertimbangkan urutan C vs. Fortran). 2. pastikan bahwa np.dot()
menggunakan sama libblas.so
.
m1
dan m2
memiliki ascontiguousarray
flag sebagai True
. Dan numpy menggunakan objek bersama yang sama seperti C. Adapun urutan larik: Saat ini saya tidak tertarik dengan hasil penghitungan sehingga urutannya tidak relevan.