BLAS ve LAPACK lineer cebir işlevlerini kapsamlı bir şekilde kullanan bir program yazmak istiyorum. Performans bir sorun olduğu için biraz kıyaslama yaptım ve bu yaklaşımın meşru olup olmadığını bilmek istiyorum.
Tabii ki üç yarışmacım var ve performanslarını basit bir matris matrisiyle test etmek istiyorum. çarpma işlemi. Yarışmacılar:
- Numpy, yalnızca
dot
işlevselliğinden yararlanıyor. - Python, paylaşılan bir nesne aracılığıyla BLAS işlevlerini çağırıyor.
- C++, paylaşılan bir nesne aracılığıyla BLAS işlevlerini çağırıyor.
Senaryo
Farklı boyutlar için bir matris-matris çarpımı uyguladım ben
. i
, 5'lik artışlarla 5'ten 500'e kadar çalışır ve m1
ve m2
matrisleri şu şekilde ayarlanır:
m1 = numpy.random.rand(i,i).astype(numpy.float32) m2 = numpy.random.rand(i,i).astype(numpy.float32)
1. Numpy
Kullanılan kod şöyle görünür:
tNumpy = timeit.Timer("numpy.dot(m1, m2)", "import numpy; from __main__ import m1 , m2") rNumpy.append((i, tNumpy.repeat(20, 1)))
2. Python, paylaşılan bir nesne aracılığıyla BLAS'ı çağırma
İşlev ile
_blaslib = ctypes.cdll.LoadLibrary("libblas.so") def Mul(m1, m2, i , r): no_trans = c_char("n") n = c_int(i) bir = c_float(1.0) sıfır = 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))
test kodu şöyle görünür:
r = numpy.zeros ((i,i), numpy.float32) tBlas = timeit.Timer("Mul(m1, m2, i, r)", "import numpy; __main__ import i, m1, m2, r, Mul") rBlas. append((i, tBlas.repeat(20, 1)))
3. c++, paylaşılan bir nesne aracılığıyla BLAS'ı çağırma
Şimdi c++ kodu doğal olarak biraz daha uzun, bu yüzden bilgiyi minimuma indiriyorum.
İşlevi
void* tutamaç = dlopen("libblas.so", RTLD_LAZY); void* İşlev = dlsym(işleç, "sgemm_");
Saati şu şekilde gettimeofday
ile ölçüyorum:
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(başlangıç, bitiş);
burada j
20 kez çalışan bir döngüdür. Geçen süreyi
double CalcTime(timeval start, timeval end) { double factor = 1000000; dönüş (((double)end.tv_sec) * faktör + ((double)end.tv_usec) - (((double)start.tv_sec) * faktör + ((double)start.tv_usec))) / faktör; }
Sonuçlar
Sonuç aşağıdaki grafikte gösterilmiştir:
Sorular
- Yaklaşımımın adil olduğunu mu düşünüyorsunuz, yoksa yapabileceğim bazı gereksiz masraflar var mı? kaçının?
- Sonucun c++ ve python yaklaşımı arasında bu kadar büyük bir farklılık göstermesini bekler miydiniz? Her ikisi de hesaplamaları için paylaşılan nesneleri kullanıyor.
- Programım için python kullanmayı tercih ettiğim için, BLAS veya LAPACK rutinlerini çağırırken performansı artırmak için ne yapabilirim?
İndirin
Karşılaştırmanın tamamı buradan indirilebilir. (JF Sebastian bu bağlantıyı mümkün kıldı^^)