2016-04-01 16 views
9

Ich habe einen Performance-Engpass. Ich berechne den spaltenweisen Mittelwert von großen Arrays (250 Zeilen & 1,3 Millionen Spalten), und ich mache das mehr als eine Million Mal in meiner Anwendung.Hohe Leistung Array-Mittelwert

Mein Testfall in Python:

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

Numpy dauert etwa 400 Millisekunden auf meinem Rechner, auf einem einzigen Kern läuft. Ich habe mehrere andere Matrixbibliotheken in verschiedenen Sprachen (Cython, R, Julia, Torch) ausprobiert, aber nur Julia gefunden, um Numpy zu schlagen, indem ich ungefähr 250 Millisekunden nahm.

Kann jemand bei dieser Aufgabe deutliche Leistungsverbesserungen nachweisen? Vielleicht ist das eine Aufgabe, die für die GPU geeignet ist?

Bearbeiten: Meine Anwendung ist offensichtlich Speicher beschränkt, und die Leistung wird drastisch verbessert durch den Zugriff auf Elemente eines großen Arrays nur einmal statt wiederholt. (Siehe Kommentar unten.)

+1

Diese Berechnung ist wahrscheinlich mehr über Speicherzugriff als über CPU-Arbeit. Ich würde nicht erwarten, dass sich hier irgendein System signifikant verbessert. Meine Intuition ist, dass die Verwendung eines Mehrfachkerns oder einer GPU nicht viel nutzen würde. Die Reduzierung auf float32 könnte jedoch helfen. – MRocklin

+0

Testfall war vielleicht zu einfach. Mein Array-Typ ist eigentlich boolesch, also wird jedes Element als ein Byte mit Numpy gespeichert. Paradoxerweise dauert es länger, um für ein Boolesches Array den Mittelwert oder die Summe zu erhalten als für Floats wie im Beispiel. Irgendeine Idee, wie man Operation auf bitpacked Array durchführt, die Speicherverkehr um ~ 90% verringern würde? –

+0

In meiner speziellen Anwendung nehme ich den Mittelwert von Arrays, die 250-Zeilen-Teilmengen eines 22.000-Zeilen-Array sind. Speicherzugriffe belaufen sich für die gesamte Berechnung auf insgesamt 24 Stunden. Wenn ich jedoch auf einer größeren Matrix operiere und jedes Element nur einmal berühre, greift der Speicher insgesamt auf weniger als 10 Sekunden zu. Ich werde es versuchen müssen! Danke @MRocklin für den Hinweis auf den Flaschenhals. –

Antwort

9

Julia, wenn ich mich nicht irre, verwendet Fortran Bestellung im Speicher im Gegensatz zu Numpy, die C-Speicher-Layout standardmäßig verwendet. Also, wenn Sie die Dinge neu ordnen zu dem gleichen Layout haften, so dass die mittlere entlang zusammenhängenden Speicher geschieht, erhalten Sie eine bessere Leistung:

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 

Oder Sie können einfach Dimensionen ändern und die Mittel über die andere Achse nehmen:

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

Auf meinem Computer ist das Timing umgekehrt: In [56]:% timeit big_array.mean (0) -> 705 ms pro Schleife; In [57]:% Zeitweite big_arrayf.mean (0) -> 1201 ms pro Schleife; Haben Sie eine Idee? –