2016-04-01 9 views
9

Ho un collo di bottiglia per le prestazioni. Sto calcolando la media di colonne di grandi dimensioni (250 righe & 1,3 milioni di colonne) e lo faccio più di un milione di volte nella mia applicazione.Mezzo array ad alte prestazioni

Il mio banco di prova in Python:

import numpy as np 
big_array = np.random.random((250, 1300000)) 
%timeit mean = big_array.mean(axis = 0) # ~400 milliseconds 

Numpy dura circa 400 millisecondi sulla mia macchina, in esecuzione su un singolo core. Ho provato diverse altre librerie di matrici in diverse lingue (Cython, R, Julia, Torch), ma ho trovato solo Julia per battere Numpy, impiegando circa 250 millisecondi.

Qualcuno può fornire prove di miglioramenti sostanziali nelle prestazioni in questo compito? Forse questo è un compito adatto per la GPU?

Modifica: la mia applicazione è evidentemente vincolata alla memoria e le sue prestazioni sono notevolmente migliorate accedendo a elementi di un array di grandi dimensioni solo una volta, anziché più volte. (Vedere il commento qui sotto)

+1

Questo calcolo è probabilmente più sull'accesso alla memoria che sul lavoro della CPU. Non mi aspetto che nessun sistema possa migliorare significativamente su Numpy qui. La mia intuizione è che l'utilizzo di core multipli o GPU non sarebbe di grande utilità. Ridurre a float32 potrebbe essere d'aiuto. – MRocklin

+0

Il test potrebbe essere stato troppo semplice. Il mio tipo di array sarà in realtà booleano, quindi ogni elemento è memorizzato come un byte con Numpy. Paradossalmente, ci vuole più tempo per ottenere media o somma per un array booleano che per i float come nell'esempio. Qualche idea su come eseguire l'operazione su array bitpacked, che ridurrebbe il traffico di memoria del ~ 90%? –

+0

Nella mia particolare applicazione, prendo la media di array che sono sottoinsiemi di 250 righe di un array di 22.000 righe. Gli accessi alla memoria da soli ammontano a 24+ ore per l'intero calcolo. Se opero su una matrice più grande, tuttavia, e tocco ogni elemento una sola volta, la memoria accede a meno di 10 secondi. Dovrò provarlo! Grazie a @MRocklin per aver segnalato il collo di bottiglia. –

risposta

9

Julia, se non sbaglio, utilizza l'ordine fortran in memoria anziché numpy che utilizza il layout di memoria C per impostazione predefinita. Quindi, se si risistemare le cose per aderire allo stesso layout in modo che la media sta avvenendo lungo memoria contigua, si ottiene una migliore performance:

In [1]: import numpy as np 

In [2]: big_array = np.random.random((250, 1300000)) 

In [4]: big_array_f = np.asfortranarray(big_array) 

In [5]: %timeit mean = big_array.mean(axis = 0) 
1 loop, best of 3: 319 ms per loop 

In [6]: %timeit mean = big_array_f.mean(axis = 0) 
1 loop, best of 3: 205 ms per loop 

Oppure si può semplicemente te cambiare le dimensioni e prendere la media sopra l'altro asse:

In [10]: big_array = np.random.random((1300000, 250)) 

In [11]: %timeit mean = big_array.mean(axis = 1) 
1 loop, best of 3: 205 ms per loop 
+0

Sul mio computer, i tempi sono invertiti: In [56]:% timeit big_array.mean (0) -> 705 ms per loop; In [57]:% timeit big_arrayf.mean (0) -> 1201 ms per loop; Hai qualche idea? –