2016-03-29 14 views
1
birine süre geri gönderildi

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 soruda

True 
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.

+0

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

+0

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. –

cevap

1

2 Yorumlar, hızın sadece python yükünden kaynaklandığını ve bunun doğru olduğunu düşünüyorum. Tepegöz çoğunlukla işlev çağrılarıdır, aynı zamanda döngüler içindir ve np.dot'un üzerinde ek bir ek yük vardır. yürütüldüğünde, böylece

@jit(nopython=True) 
def dot(mat1, mat2): 
    s = 0 
    mat = np.empty(shape=(mat1.shape[1], mat2.shape[0]), dtype=mat1.dtype) 
    for r1 in range(mat1.shape[0]): 
     for c2 in range(mat2.shape[1]): 
      s = 0 
      for j in range(mat2.shape[0]): 
       s += mat1[r1,j] * mat2[j,c2] 
      mat[r1,c2] = s 
    return mat 

Sonra diziler çoğalmaya işlevlere kurmak, nokta işlevini çağırır bir ve döngü içine inşa nokta işlevi vardır biri: Ben Naif dot ürün fonksiyonunu kurmak ilave işlev çağrısı olmadan: 2x2 dizileri ve 10x10 diziler:
@jit(nopython=True) 
def loopMultJit_dot(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] = dot(ArrMult[i], Arr[j, i]) 
    return ArrMult 

@jit(nopython=True) 
def loopMultJit_dotInternal(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]): 
      s = 0.0 
      for r1 in range(ArrMult.shape[1]): 
       for c2 in range(Arr.shape[3]): 
        s = 0.0 
        for r2 in range(Arr.shape[2]): 
         s += ArrMult[i,r1,r2] * Arr[j,i,r2,c2] 
        ArrMult[i,r1,c2] = s 
    return ArrMult 

Sonra 2 karşılaştırmaları çalıştırabilirsiniz. verir

print "2x2 Time Test:" 
Arr = rand(500,201,2,2) 
%timeit loopMult(Arr) 
%timeit loopMultJit(Arr) 
%timeit loopMultJit_2X2(Arr) 
%timeit loopMultJit_dot(Arr) 
%timeit loopMultJit_dotInternal(Arr) 

print "10x10 Time Test:" 
Arr = rand(500,201,10,10) 
%timeit loopMult(Arr) 
%timeit loopMultJit(Arr) 
%timeit loopMultJit_dot(Arr) 
%timeit loopMultJit_dotInternal(Arr) 

: Bunlarla ben işlev için ödenen cezalar bazı fikri genel olarak çağırır ve özellikle np.dot işlev çağrısında ve np.dot içinde BLAS optimizasyonlarından kazançlar için olsun

2x2 Time Test: 
10 loops, best of 3: 55.8 ms per loop # einsum 
10 loops, best of 3: 48.7 ms per loop # np.dot 
1000 loops, best of 3: 1.09 ms per loop # 2x2 
10 loops, best of 3: 28.3 ms per loop # naive dot, separate function 
100 loops, best of 3: 2.58 ms per loop # naive dot internal 

10x10 Time Test: 
1 loop, best of 3: 499 ms per loop # einsum 
10 loops, best of 3: 91.3 ms per loop # np.dot 
10 loops, best of 3: 170 ms per loop # naive dot, separate function 
10 loops, best of 3: 161 ms per loop # naive dot internal 

ben eve verilen mesajlardır varsayalım: Eğer numba kullanarak veya bir gömlekler gerekmez eğer

  • einsum güzel, ama matris çoğalması için, daha hızlı seçenek vardır
  • Küçük matrislerle çalışıyorsanız, büyük matrisler için her şeyi ayrı ayrı yapmak ve ayrı işlevler çağırmak için daha hızlı olabilir,
  • BLAS'ın icat edilmesinin bir nedeni vardır ve aslında, hızlar boyutlarda oldukça dikkat çekicidir 10x10 kadar küçük.