Beginnen wir mit drei Arrays von dtype=np.double. Timings werden auf einer Intel-CPU unter Verwendung von numpy 1.7.1 durchgeführt, das mit iccIntel kompiliert und mit Intel verknüpft ist mkl. Eine AMD-CPU mit der Nummer 1.6.1, die mit gccohne kompiliert mklwurde, wurde ebenfalls verwendet, um die Timings zu überprüfen. Bitte beachten Sie, dass die Timings nahezu linear mit der Systemgröße skalieren und nicht auf den geringen Overhead zurückzuführen sind, der in den Numpy-Funktionsanweisungen anfällt. Dieser ifUnterschied wird in Mikrosekunden und nicht in Millisekunden angezeigt :
arr_1D=np.arange(500,dtype=np.double)
large_arr_1D=np.arange(100000,dtype=np.double)
arr_2D=np.arange(500**2,dtype=np.double).reshape(500,500)
arr_3D=np.arange(500**3,dtype=np.double).reshape(500,500,500)
Schauen wir uns zunächst die np.sumFunktion an:
np.all(np.sum(arr_3D)==np.einsum('ijk->',arr_3D))
True
%timeit np.sum(arr_3D)
10 loops, best of 3: 142 ms per loop
%timeit np.einsum('ijk->', arr_3D)
10 loops, best of 3: 70.2 ms per loop
Befugnisse:
np.allclose(arr_3D*arr_3D*arr_3D,np.einsum('ijk,ijk,ijk->ijk',arr_3D,arr_3D,arr_3D))
True
%timeit arr_3D*arr_3D*arr_3D
1 loops, best of 3: 1.32 s per loop
%timeit np.einsum('ijk,ijk,ijk->ijk', arr_3D, arr_3D, arr_3D)
1 loops, best of 3: 694 ms per loop
Äußeres Produkt:
np.all(np.outer(arr_1D,arr_1D)==np.einsum('i,k->ik',arr_1D,arr_1D))
True
%timeit np.outer(arr_1D, arr_1D)
1000 loops, best of 3: 411 us per loop
%timeit np.einsum('i,k->ik', arr_1D, arr_1D)
1000 loops, best of 3: 245 us per loop
Alle oben genannten sind doppelt so schnell mit np.einsum. Dies sollten Vergleiche zwischen Äpfeln sein, da alles spezifisch ist dtype=np.double. Ich würde die Geschwindigkeit bei einer Operation wie dieser erwarten:
np.allclose(np.sum(arr_2D*arr_3D),np.einsum('ij,oij->',arr_2D,arr_3D))
True
%timeit np.sum(arr_2D*arr_3D)
1 loops, best of 3: 813 ms per loop
%timeit np.einsum('ij,oij->', arr_2D, arr_3D)
10 loops, best of 3: 85.1 ms per loop
Einsum scheint mindestens doppelt so schnell zu sein np.inner, np.outer, np.kronund np.sumunabhängig davon , axesAuswahl. Die np.dot Hauptausnahme ist der Aufruf von DGEMM aus einer BLAS-Bibliothek. Warum ist es also np.einsumschneller als andere gleichwertige Numpy-Funktionen?
Der DGEMM-Fall der Vollständigkeit halber:
np.allclose(np.dot(arr_2D,arr_2D),np.einsum('ij,jk',arr_2D,arr_2D))
True
%timeit np.einsum('ij,jk',arr_2D,arr_2D)
10 loops, best of 3: 56.1 ms per loop
%timeit np.dot(arr_2D,arr_2D)
100 loops, best of 3: 5.17 ms per loop
Die führende Theorie stammt aus dem Kommentar von @sebergs, np.einsumder SSE2 verwenden kann , aber die Ufuncs von numpy werden erst bei numpy 1.8 angezeigt (siehe Änderungsprotokoll ). Ich glaube, dies ist die richtige Antwort, konnte sie aber nicht bestätigen. Einige begrenzte Beweise können gefunden werden, indem der Typ des Eingabearrays geändert und der Geschwindigkeitsunterschied sowie die Tatsache beobachtet werden, dass nicht jeder die gleichen zeitlichen Trends beobachtet.





