2012-08-08 17 views
13

scusate per così tante domande. Sto eseguendo Mac OSX 10.6 su Intel core 2 Duo. Sto conducendo alcuni benchmark per la mia ricerca e mi sono imbattuto in un'altra cosa che mi confonde.Numpy dot prodotto molto lento con inti

Se corro

python -mtimeit -s 'import numpy as np; a = np.random.randn(1e3,1e3)' 'np.dot(a,a)'

ottengo il seguente output: 10 loops, best of 3: 142 msec per loop

Tuttavia, se corro

python -mtimeit -s 'import numpy as np; a = np.random.randint(10,size=1e6).reshape(1e3,1e3)' 'np.dot(a,a)'

ottengo il seguente output: 10 loops, best of 3: 7.57 sec per loop

Poi corsi

python -mtimeit -s 'import numpy as np; a = np.random.randn(1e3,1e3)' 'a*a' E poi

python -mtimeit -s 'import numpy as np; a = np.random.randint(10,size=1e6).reshape(1e3,1e3)' 'a*a'

Sia corse a circa 7,6 msec per loop in modo che non è la moltiplicazione. L'aggiunta ha avuto anche velocità simili, quindi nessuno di questi dovrebbe influenzare il prodotto dot, giusto? Quindi perché è più di 50 volte più lento calcolare il prodotto con punti usando gli interi che l'uso dei galleggianti?

+0

stesso per me su Linux - ho circa 3 secondi per float64 e 10 secondi per Int32 (si tratta di una vecchia macchina). Non un fattore di 50, ma ancora molto strano. – Luke

risposta

12

molto interessante, ero curioso di vedere come è stato implementato così ho fatto:

>>> import inspect 
>>> import numpy as np 
>>> inspect.getmodule(np.dot) 
<module 'numpy.core._dotblas' from '/Library/Python/2.6/site-packages/numpy-1.6.1-py2.6-macosx-10.6-universal.egg/numpy/core/_dotblas.so'> 
>>> 

Quindi sembra che il suo uso della libreria BLAS .

così:

>>> help(np.core._dotblas) 

da cui ho trovato questo:

Quando Numpy è costruito con un BLAS accelerati come ATLAS, queste funzioni sono sostituiti a fare uso delle implementazioni più veloci. Le implementazioni più veloci riguardano solo gli array float32, float64, complex64 e complex128 .Inoltre, l'API BLAS include solo matrice matrice, matrice vettoriale e vettori vettoriali. I prodotti di array con dimensioni maggiori di utilizzano le funzioni integrate e non sono accelerati.

Quindi sembra che ATLAS metta a punto determinate funzioni ma è applicabile solo a determinati tipi di dati, molto interessanti.

così yeah Sembra sarò con carri più spesso ...

+0

Mi piace la tua risposta meglio :) – Luke

+0

@Luke grazie +1 per aver fatto un backtrace, è anche un altro metodo utile. –

+0

Buono a sapersi. Quando vado a lavorare userò lo stesso metodo per vedere se è vero anche per MKL. Grazie per l'aiuto. A Luke piace questa risposta in modo migliore per ottenere l'accettazione. – Nino

7

Utilizzando int vs tipi di dati float provoca diversi percorsi di codice da eseguire:

L'analisi dello stack per float assomiglia a questo:

(gdb) backtr 
#0 0x007865a0 in dgemm_() from /usr/lib/libblas.so.3gf 
#1 0x007559d5 in cblas_dgemm() from /usr/lib/libblas.so.3gf 
#2 0x00744108 in dotblas_matrixproduct (__NPY_UNUSED_TAGGEDdummy=0x0, args=(<numpy.ndarray at remote 0x85d9090>, <numpy.ndarray at remote 0x85d9090>), 
kwargs=0x0) at numpy/core/blasdot/_dotblas.c:798 
#3 0x08088ba1 in PyEval_EvalFrameEx() 
... 

..mentre l'analisi dello stack per int simile a questa:

(gdb) backtr 
#0 LONG_dot (ip1=0xb700a280 "\t", is1=4, ip2=0xb737dc64 "\a", is2=4000, op=0xb6496fc4 "", n=1000, __NPY_UNUSED_TAGGEDignore=0x85fa960) 
at numpy/core/src/multiarray/arraytypes.c.src:3076 
#1 0x00659d9d in PyArray_MatrixProduct2 (op1=<numpy.ndarray at remote 0x85dd628>, op2=<numpy.ndarray at remote 0x85dd628>, out=0x0) 
at numpy/core/src/multiarray/multiarraymodule.c:847 
#2 0x00742b93 in dotblas_matrixproduct (__NPY_UNUSED_TAGGEDdummy=0x0, args=(<numpy.ndarray at remote 0x85dd628>, <numpy.ndarray at remote 0x85dd628>), 
kwargs=0x0) at numpy/core/blasdot/_dotblas.c:254 
#3 0x08088ba1 in PyEval_EvalFrameEx() 
... 

Entrambe le chiamate portano a dotblas_matrixproduct, ma sembra che la chiamata galleggiante rimane nella libreria BLAS (probabilmente l'accesso a un codice ben ottimizzato), mentre il int call viene rimandato indietro a PyArray_MatrixProduct2 di numpy.

Quindi questo è un bug o BLAS non supporta i tipi di interi in matrixproduct (che sembra piuttosto improbabile).

Ecco una soluzione semplice e poco costoso:

af = a.astype(float) 
np.dot(af, af).astype(int) 
+0

Vale la pena notare che questa soluzione alternativa può causare errori se i dati hanno valori molto grandi e probabilmente richiederà la copia dell'intera matrice, quindi è costoso se la matrice è molto grande. – Dougal

+0

Grazie, Luca. Questa soluzione alternativa copia le matrici e risulta essere piuttosto fastidioso (per problemi di memoria), ma per quanto riguarda il tempo, è migliaia di volte più veloce per le matrici 1e4x1e4! Qualsiasi più grande ed è troppo lento per testare la moltiplicazione usando gli interi. @Dougal Questo sarebbe valido solo per numeri maggiori di 2^52 usando un float a 64 bit, giusto? I numeri non saranno più grandi di questo e vorrei approfittare di questa velocità, se possibile. – Nino

+0

@Nino Sì, da queste parti. È davvero un peccato che le librerie BLAS non funzionino per i tipi interi e che il 'dot' predefinito di numpy sia molto più lento. Se i problemi di memoria sono un problema, potresti prendere in considerazione di scrivere una piccola interfaccia in ctypes che faccia la moltiplicazione in [Eigen] (http://eigen.tuxfamily.org/) o simile, che dovrebbe essere più veloce. – Dougal