Come si fa a ottimizzare questo codice (senza vettorializzazione, in quanto ciò conduce ad usare la semantica del calcolo, che è spesso lontano da essere non banale):veloce Numpy Loops
slow_lib.py:
import numpy as np
def foo():
size = 200
np.random.seed(1000031212)
bar = np.random.rand(size, size)
moo = np.zeros((size,size), dtype = np.float)
for i in range(0,size):
for j in range(0,size):
val = bar[j]
moo += np.outer(val, val)
Il punto è che tali loop di tipo corrispondono molto spesso alle operazioni in cui si hanno somme doppie rispetto ad un'operazione vettoriale.
Questo è piuttosto lento:
>>t = timeit.timeit('foo()', 'from slow_lib import foo', number = 10)
>>print ("took: "+str(t))
took: 41.165681839
Ok, quindi cerchiamo di cynothize e aggiungere annotazioni di tipo ama non c'è domani:
c_slow_lib.pyx:
import numpy as np
cimport numpy as np
import cython
@cython.boundscheck(False)
@cython.wraparound(False)
def foo():
cdef int size = 200
cdef int i,j
np.random.seed(1000031212)
cdef np.ndarray[np.double_t, ndim=2] bar = np.random.rand(size, size)
cdef np.ndarray[np.double_t, ndim=2] moo = np.zeros((size,size), dtype = np.float)
cdef np.ndarray[np.double_t, ndim=1] val
for i in xrange(0,size):
for j in xrange(0,size):
val = bar[j]
moo += np.outer(val, val)
>>t = timeit.timeit('foo()', 'from c_slow_lib import foo', number = 10)
>>print ("took: "+str(t))
took: 42.3104710579
... ehr ... che cosa? Numba in soccorso!
numba_slow_lib.py:
import numpy as np
from numba import jit
size = 200
np.random.seed(1000031212)
bar = np.random.rand(size, size)
@jit
def foo():
bar = np.random.rand(size, size)
moo = np.zeros((size,size), dtype = np.float)
for i in range(0,size):
for j in range(0,size):
val = bar[j]
moo += np.outer(val, val)
>>t = timeit.timeit('foo()', 'from numba_slow_lib import foo', number = 10)
>>print("took: "+str(t))
took: 40.7327859402
Quindi non c'è davvero alcun modo per accelerare questo? Il punto è:
- Se converto il ciclo interno in un vettorizzati versione (la costruzione di una matrice più grande che rappresenta il ciclo interno e quindi chiamando np.outer sulla matrice più grande) ottengo molto codice più veloce.
- se implemento qualcosa di simile in Matlab (R2016a) questo si comporta abbastanza bene a causa di JIT.
Né cython né jit stanno accelerando perché il codice C è già in esecuzione (tramite np.outer). Il problema qui è in realtà il ciclo stesso, è necessario modificare la sua struttura interna in modo che tali metodi possano essere effettivamente accelerati. – pekapa
So che la vettorizzazione dei cicli interni (o di entrambi) accelererà significativamente il codice. Il mio punto è che apparentemente il ciclo crea un sovraccarico significativo che non dovrebbe esserci. In altre parole: Perché chiamare np.outer 200 volte tanto più lentamente di chiamare np.outer una volta su una matrice con diciamo 200 righe (vettorizzazione) al contrario di dire loop Matlab dove questo è un non-problema ... E come può essere superato? – ndbd
Non credo di poter aiutare ulteriormente, ma dare un'occhiata a questa risposta su come ciascuno (Python e Matlab) tratta i loop: http: // stackoverflow.it/a/17242928/2752305 – pekapa