Die Idee von zu erfassen numpy.einsum()ist sehr einfach, wenn Sie es intuitiv verstehen. Beginnen wir als Beispiel mit einer einfachen Beschreibung der Matrixmultiplikation .
Um dies zu verwenden numpy.einsum(), müssen Sie lediglich die sogenannte Indexzeichenfolge als Argument übergeben, gefolgt von Ihren Eingabearrays .
Angenommen, Sie haben zwei 2D - Arrays, Aund B, und Sie wollen Matrix - Multiplikation zu tun. Also tust du es:
np.einsum("ij, jk -> ik", A, B)
Hier entspricht die Indexzeichenfolge ij dem Array, Awährend die Indexzeichenfolge jk dem Array entspricht B. Das Wichtigste dabei ist auch, dass die Anzahl der Zeichen in jeder tiefgestellten Zeichenfolge mit den Abmessungen des Arrays übereinstimmen muss . (dh zwei Zeichen für 2D-Arrays, drei Zeichen für 3D-Arrays usw.) Wenn Sie die Zeichen zwischen tiefgestellten Zeichenfolgen ( jin unserem Fall) wiederholen , bedeutet dies, dass die einSumme entlang dieser Dimensionen erfolgen soll. Somit werden sie summenreduziert. (dh diese Dimension wird weg sein )
Die Indexzeichenfolge danach ->ist unser resultierendes Array. Wenn Sie es leer lassen, wird alles summiert und als Ergebnis ein Skalarwert zurückgegeben. Andernfalls hat das resultierende Array Dimensionen entsprechend der tiefgestellten Zeichenfolge . In unserem Beispiel wird es sein ik. Dies ist intuitiv, da wir wissen, dass für die Matrixmultiplikation die Anzahl der Spalten im Array Amit der Anzahl der Zeilen im Array übereinstimmen muss, Bwas hier geschieht (dh wir codieren dieses Wissen, indem wir das Zeichen jin der tiefgestellten Zeichenfolge wiederholen ).
Hier sind einige weitere Beispiele , die kurz und bündig die Verwendung / Leistungsfähigkeit bei der np.einsum()Implementierung einiger gängiger Tensor- oder nd-Array- Operationen veranschaulichen .
Eingänge
# a vector
In [197]: vec
Out[197]: array([0, 1, 2, 3])
# an array
In [198]: A
Out[198]:
array([[11, 12, 13, 14],
[21, 22, 23, 24],
[31, 32, 33, 34],
[41, 42, 43, 44]])
# another array
In [199]: B
Out[199]:
array([[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3],
[4, 4, 4, 4]])
1) Matrixmultiplikation (ähnlich wie np.matmul(arr1, arr2))
In [200]: np.einsum("ij, jk -> ik", A, B)
Out[200]:
array([[130, 130, 130, 130],
[230, 230, 230, 230],
[330, 330, 330, 330],
[430, 430, 430, 430]])
2) Elemente entlang der Hauptdiagonale extrahieren (ähnlich wie np.diag(arr))
In [202]: np.einsum("ii -> i", A)
Out[202]: array([11, 22, 33, 44])
3) Hadamard-Produkt (dh elementweises Produkt zweier Arrays) (ähnlich arr1 * arr2)
In [203]: np.einsum("ij, ij -> ij", A, B)
Out[203]:
array([[ 11, 12, 13, 14],
[ 42, 44, 46, 48],
[ 93, 96, 99, 102],
[164, 168, 172, 176]])
4) Elementweises Quadrieren (ähnlich np.square(arr)oder arr ** 2)
In [210]: np.einsum("ij, ij -> ij", B, B)
Out[210]:
array([[ 1, 1, 1, 1],
[ 4, 4, 4, 4],
[ 9, 9, 9, 9],
[16, 16, 16, 16]])
5) Spur (dh Summe der Hauptdiagonalelemente) (ähnlich wie np.trace(arr))
In [217]: np.einsum("ii -> ", A)
Out[217]: 110
6) Matrixtransponierung (ähnlich wie np.transpose(arr))
In [221]: np.einsum("ij -> ji", A)
Out[221]:
array([[11, 21, 31, 41],
[12, 22, 32, 42],
[13, 23, 33, 43],
[14, 24, 34, 44]])
7) Äußeres Produkt (von Vektoren) (ähnlich np.outer(vec1, vec2))
In [255]: np.einsum("i, j -> ij", vec, vec)
Out[255]:
array([[0, 0, 0, 0],
[0, 1, 2, 3],
[0, 2, 4, 6],
[0, 3, 6, 9]])
8) Inneres Produkt (von Vektoren) (ähnlich np.inner(vec1, vec2))
In [256]: np.einsum("i, i -> ", vec, vec)
Out[256]: 14
9) Summe entlang der Achse 0 (ähnlich wie np.sum(arr, axis=0))
In [260]: np.einsum("ij -> j", B)
Out[260]: array([10, 10, 10, 10])
10) Summe entlang der Achse 1 (ähnlich wie np.sum(arr, axis=1))
In [261]: np.einsum("ij -> i", B)
Out[261]: array([ 4, 8, 12, 16])
11) Batch-Matrix-Multiplikation
In [287]: BM = np.stack((A, B), axis=0)
In [288]: BM
Out[288]:
array([[[11, 12, 13, 14],
[21, 22, 23, 24],
[31, 32, 33, 34],
[41, 42, 43, 44]],
[[ 1, 1, 1, 1],
[ 2, 2, 2, 2],
[ 3, 3, 3, 3],
[ 4, 4, 4, 4]]])
In [289]: BM.shape
Out[289]: (2, 4, 4)
# batch matrix multiply using einsum
In [292]: BMM = np.einsum("bij, bjk -> bik", BM, BM)
In [293]: BMM
Out[293]:
array([[[1350, 1400, 1450, 1500],
[2390, 2480, 2570, 2660],
[3430, 3560, 3690, 3820],
[4470, 4640, 4810, 4980]],
[[ 10, 10, 10, 10],
[ 20, 20, 20, 20],
[ 30, 30, 30, 30],
[ 40, 40, 40, 40]]])
In [294]: BMM.shape
Out[294]: (2, 4, 4)
12) Summe entlang der Achse 2 (ähnlich wie np.sum(arr, axis=2))
In [330]: np.einsum("ijk -> ij", BM)
Out[330]:
array([[ 50, 90, 130, 170],
[ 4, 8, 12, 16]])
13) Summiere alle Elemente im Array (ähnlich wie np.sum(arr))
In [335]: np.einsum("ijk -> ", BM)
Out[335]: 480
14) Summe über mehrere Achsen (dh Marginalisierung)
(ähnlich wie np.sum(arr, axis=(axis0, axis1, axis2, axis3, axis4, axis6, axis7)))
# 8D array
In [354]: R = np.random.standard_normal((3,5,4,6,8,2,7,9))
# marginalize out axis 5 (i.e. "n" here)
In [363]: esum = np.einsum("ijklmnop -> n", R)
# marginalize out axis 5 (i.e. sum over rest of the axes)
In [364]: nsum = np.sum(R, axis=(0,1,2,3,4,6,7))
In [365]: np.allclose(esum, nsum)
Out[365]: True
15) Double Dot Produkte (ähnlich np.sum (hadamard Produkt) s 3 )
In [772]: A
Out[772]:
array([[1, 2, 3],
[4, 2, 2],
[2, 3, 4]])
In [773]: B
Out[773]:
array([[1, 4, 7],
[2, 5, 8],
[3, 6, 9]])
In [774]: np.einsum("ij, ij -> ", A, B)
Out[774]: 124
16) 2D- und 3D-Array-Multiplikation
Eine solche Multiplikation kann sehr nützlich sein, wenn Sie ein lineares Gleichungssystem ( Ax = b ) lösen, bei dem Sie das Ergebnis überprüfen möchten.
# inputs
In [115]: A = np.random.rand(3,3)
In [116]: b = np.random.rand(3, 4, 5)
# solve for x
In [117]: x = np.linalg.solve(A, b.reshape(b.shape[0], -1)).reshape(b.shape)
# 2D and 3D array multiplication :)
In [118]: Ax = np.einsum('ij, jkl', A, x)
# indeed the same!
In [119]: np.allclose(Ax, b)
Out[119]: True
Im Gegenteil, wenn man np.matmul()für diese Überprüfung verwenden muss, müssen wir einige reshapeOperationen ausführen, um das gleiche Ergebnis zu erzielen:
# reshape 3D array `x` to 2D, perform matmul
# then reshape the resultant array to 3D
In [123]: Ax_matmul = np.matmul(A, x.reshape(x.shape[0], -1)).reshape(x.shape)
# indeed correct!
In [124]: np.allclose(Ax, Ax_matmul)
Out[124]: True
Bonus : Lesen Sie hier mehr Mathe: Einstein-Summation und definitiv hier: Tensor-Notation
(A * B)^Toder gleichwertigB^T * A^T.