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 icc
Intel kompiliert und mit Intel verknüpft ist mkl
. Eine AMD-CPU mit der Nummer 1.6.1, die mit gcc
ohne kompiliert mkl
wurde, 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 if
Unterschied 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.sum
Funktion 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.kron
und np.sum
unabhängig davon , axes
Auswahl. Die np.dot
Hauptausnahme ist der Aufruf von DGEMM aus einer BLAS-Bibliothek. Warum ist es also np.einsum
schneller 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.einsum
der 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.