Vergleichen von Python-Beschleunigern (Cython, Numba, f2py) mit Numpy einsum

8

Ich vergleiche Python-Beschleuniger (Numba, Cython, f2py) mit einfachen For-Schleifen und Numpys Einsum für ein bestimmtes Problem (siehe unten). Bisher ist Numpy der Schnellste für dieses Problem (Faktor 6x schneller), aber ich wollte Feedback, wenn es zusätzliche Optimierungen gibt, die ich ausprobieren sollte, oder wenn ich etwas falsch mache. Dieser einfache Code basiert auf einem größeren Code, der eine Anzahl dieser einsum-Aufrufe, aber keine expliziten for-Schleifen enthält. Ich überprüfe, ob einer dieser Beschleuniger besser ist.

Timings mit Python 2.7.9 unter Mac OS X Yosemite, mit gcc-5.3.0 (--with-fortran - ohne-multilib) von Homebrew. Habe auch% Zeit Anrufe getätigt; diese einzelnen Anrufzeiten sind ziemlich genau.

%Vor%

Der Hauptcode:

%Vor%

Die Datei f2py (kompiliert mit f2py -c -m test_f2py test_f2py.F90):

%Vor%

Und die Cython-.pyx-Datei (kompiliert mit pyximport in der Hauptroutine):

%Vor%     
Michael 29.01.2016, 17:36
quelle

2 Antworten

6

Normalerweise werden diese Beschleuniger verwendet, um Code mit Python-Schleifen oder vielen Zwischenergebnissen zu beschleunigen, während einsum bereits ziemlich gut optimiert ist ( Quelle anzeigen ). Sie sollten nicht erwarten, dass einsum leicht zu schlagen ist, aber Sie könnten sich in der Leistung nähern.

Für Numba ist es wichtig, die Kompilierungszeit vom Benchmark auszuschließen. Dies kann einfach dadurch erreicht werden, dass die Jitted-Funktion zweimal ausgeführt wird (mit der gleichen Art von Eingängen). Z.B. Mit IPython bekomme ich:

%Vor%

Für Ihren Cython-Code können einige Verbesserungen vorgenommen werden:

  1. Deaktivieren Sie die Überprüfung von Array-Grenzen und -Wraparounds, siehe Compiler-Richtlinien .
  2. Geben Sie an, dass die Arrays zusammenhängend sind.
  3. Verwenden Sie getippte Speichersichten .

Etwas wie:

%Vor%

Auf einem aktuellen Ubuntu 15.10 (x86) gibt mir das die gleiche Geschwindigkeit wie einsum . Unter Windows (x86) auf demselben PC mit der Anaconda-Distribution ist dieser Cython-Code jedoch etwa halb so schnell wie einsum . Ich denke, dass dies mit gcc-Versionen (5.2.1 vs 4.7.0) und der Möglichkeit, SSE-Anweisungen einzufügen ( einsum ist mit SSE2 intrinsics codiert) zu tun haben. Vielleicht würde die Bereitstellung verschiedener Compiler-Optionen helfen, aber ich bin mir nicht sicher.

Ich kenne kaum einen Fortran, also kann ich dazu nichts sagen.

Da Ihr Ziel darin besteht, einsum zu übertreffen, denke ich, dass der nächstliegende Schritt die zunehmende Parallelität ist. Es sollte ziemlich einfach sein, einige Threads mit cython.parallel zu erstellen. Wenn die Systemspeicherbandbreite noch nicht ausreicht, können Sie versuchen, die neuesten CPU-Anweisungen wie AVX2 und Fused Multiply-Add explizit hinzuzufügen.

Eine andere Sache, die Sie versuchen könnten, ist, f neu anzuordnen und umzuformen und Ihre Operation mit np.dot auszuführen. Wenn Ihr Numpy mit einer guten BLAS-Bibliothek geliefert wird, sollte dies so ziemlich jede Optimierung ermöglichen, die Sie sich vorstellen können, allerdings auf Kosten eines Verlustes der Allgemeinheit und möglicherweise einer sehr teuren Kopie des f -Arrays.

    
user2379410 30.01.2016 14:58
quelle
1

Sobald der Stringparameter analysiert wurde, verwendet einsum eine kompilierte Version von nditer , um eine Produktsummenberechnung für alle Achsen durchzuführen. Der Quellcode ist leicht auf dem numpy github zu finden.

Vor einiger Zeit habe ich ein einsum work-alike ausgearbeitet, um einen Patch zu schreiben. Als Teil davon schrieb ich ein cython -Skript, das die Summe des Produkts ausführt. Sie können diesen Code unter:

sehen

Ссылка

Ich habe nicht versucht, meinen Code bei einsum speed laufen zu lassen. Ich habe nur versucht zu verstehen, wie es funktioniert hat.

    
hpaulj 29.01.2016 18:50
quelle

Tags und Links