Bu soru ilişkilendirir matris boyutuna önemli ölçüde bağlıdır , matris yığınının yığınının çarpımıyla Daha önce olduğu gibi (201,2,2) dizisini sonuç olarak elde etmek için (2x2) matrisleri, ilk eksen boyunca (yani 500 çarpma) çarparak, (500,201,2,2) bir diziye koyuyordum. . Çıktı İşteoptimum numba uygulamaları
from numba import jit # numba 0.24, numpy 1.9.3, python 2.7.11
Arr = rand(500,201,2,2)
def loopMult(Arr):
ArrMult = Arr[0]
for i in range(1,len(Arr)):
ArrMult = np.einsum('fij,fjk->fik', ArrMult, Arr[i])
return ArrMult
@jit(nopython=True)
def loopMultJit(Arr):
ArrMult = np.empty(shape=Arr.shape[1:], dtype=Arr.dtype)
for i in range(0, Arr.shape[1]):
ArrMult[i] = Arr[0, i]
for j in range(1, Arr.shape[0]):
ArrMult[i] = np.dot(ArrMult[i], Arr[j, i])
return ArrMult
@jit(nopython=True)
def loopMultJit_2X2(Arr):
ArrMult = np.empty(shape=Arr.shape[1:], dtype=Arr.dtype)
for i in range(0, Arr.shape[1]):
ArrMult[i] = Arr[0, i]
for j in range(1, Arr.shape[0]):
x1 = ArrMult[i,0,0] * Arr[j,i,0,0] + ArrMult[i,0,1] * Arr[j,i,1,0]
y1 = ArrMult[i,0,0] * Arr[j,i,0,1] + ArrMult[i,0,1] * Arr[j,i,1,1]
x2 = ArrMult[i,1,0] * Arr[j,i,0,0] + ArrMult[i,1,1] * Arr[j,i,1,0]
y2 = ArrMult[i,1,0] * Arr[j,i,0,1] + ArrMult[i,1,1] * Arr[j,i,1,1]
ArrMult[i,0,0] = x1
ArrMult[i,0,1] = y1
ArrMult[i,1,0] = x2
ArrMult[i,1,1] = y2
return ArrMult
A1 = loopMult(Arr)
A2 = loopMultJit(Arr)
A3 = loopMultJit_2X2(Arr)
print np.allclose(A1, A2)
print np.allclose(A1, A3)
%timeit loopMult(Arr)
%timeit loopMultJit(Arr)
%timeit loopMultJit_2X2(Arr)
edilir: Burada
Python kodudur önceki sorudaTrue
True
10 loops, best of 3: 40.5 ms per loop
10 loops, best of 3: 36 ms per loop
1000 loops, best of 3: 808 µs per loop
kabul cevap f2py ile detaylı optimizasyon olmadan 8x bir hızlanma olduğunu gösterdi . Burada, Numba ile, bir einsum loop üzerinden numba kullanarak yaklaşık% 10 hızlanma elde ediyorum, ancak döngüde np.dot kullanmak yerine 45x hızlanma elde ediyorum, sadece 2x2 matris çarpımını elle yapıyorum. Bu neden? Bu jit fonksiyonlarının her ikisini de guvectorize versiyonları olarak uygun tipte imzalarla uyguladığımı belirtmeliyim ki bu da temel olarak aynı hızlandırma faktörlerini sağlıyor, ben de onları dışarıda bıraktım. Ayrıca 201.500,2,2 matrisin üzerinde yinelemenin hızlanması da azdır.
Sadece np.dot işlevini çağırmak için makul bir Python ek yükünün olduğunu düşünüyorum (türleri kontrol etme, numpy dizilerini ayırma, vb.). Np.dot'un oldukça optimize edilmiş olmasına rağmen, 2x2'lik bir dizi küçücük ve yüke değmez. Böylece, numba ile kendiniz yaparak kolayca yapabilirsiniz (tüm Python yüklerini atlar). Muhtemelen 'np.dot' kelimesini 100x100 matris çarpımını atmak için oldukça zor bulursunuz. – DavidW
BLAS ve boilerplate'in genel giderlerini düşünüyorum. Numba kaynak kodunda bu dosyayı kontrol edin (https://github.com/numba/numba/blob/0.24.0/numba/targets/linalg.py). Ve ayrıca genellik. Normalde matris çarpımı en az 3 döngüyü içerir, ancak hepsini "loopMultiJit_2x2" şeklinde açmış olursunuz. –