Fortgeschrittene Einsum-Operationen
Nachdem wir uns mit den grundlegenden einsum
-Operationen vertraut gemacht haben, wollen wir einige fortgeschrittenere Anwendungen erkunden. Diese Operationen zeigen die wahre Stärke und Flexibilität der einsum
-Funktion.
Das Extrahieren der Diagonalelemente einer Matrix ist eine häufige Operation in der linearen Algebra. Für eine Matrix A bilden ihre Diagonalelemente einen Vektor d, wobei:
d_i = A_{ii}
So extrahiert man die Diagonale mit einsum
:
## Create a random square matrix
A = np.random.rand(4, 4)
print("Matrix A:")
print(A)
## Extract diagonal using einsum
diagonal = np.einsum('ii->i', A)
print("\nDiagonal elements using einsum:")
print(diagonal)
## Verify with NumPy's diagonal function
numpy_diagonal = np.diagonal(A)
print("\nDiagonal elements using np.diagonal():")
print(numpy_diagonal)
Die Notation 'ii->i'
bedeutet:
ii
repräsentiert den wiederholten Index für die Diagonalelemente von A
i
bedeutet, dass wir diese Elemente in ein 1D-Array extrahieren
Matrixspur
Die Spur einer Matrix ist die Summe ihrer Diagonalelemente. Für eine Matrix A ist ihre Spur:
\text{trace}(A) = \sum_i A_{ii}
So berechnet man die Spur mit einsum
:
## Using the same matrix A from above
trace = np.einsum('ii->', A)
print("Trace of matrix A using einsum:", trace)
## Verify with NumPy's trace function
numpy_trace = np.trace(A)
print("Trace of matrix A using np.trace():", numpy_trace)
Die Notation 'ii->'
bedeutet:
ii
repräsentiert den wiederholten Index für die Diagonalelemente
- Der leere Ausgabeindex bedeutet, dass wir alle Diagonalelemente summieren, um ein Skalar zu erhalten
Batch-Matrixmultiplikation
einsum
zeigt seine Stärke besonders bei Operationen auf höherdimensionalen Arrays. Beispielsweise umfasst die Batch-Matrixmultiplikation das Multiplizieren von Matrixpaaren aus zwei Batches.
Wenn wir einen Batch von Matrizen A mit der Form (n, m, p) und einen Batch von Matrizen B mit der Form (n, p, q) haben, ergibt die Batch-Matrixmultiplikation ein Ergebnis C mit der Form (n, m, q):
C_{ijk} = \sum_l A_{ijl} \times B_{ilk}
So führt man die Batch-Matrixmultiplikation mit einsum
aus:
## Create batches of matrices
n, m, p, q = 5, 3, 4, 2 ## Batch size and matrix dimensions
A = np.random.rand(n, m, p) ## Batch of 5 matrices, each 3x4
B = np.random.rand(n, p, q) ## Batch of 5 matrices, each 4x2
print("Shape of batch A:", A.shape)
print("Shape of batch B:", B.shape)
## Batch matrix multiplication using einsum
C = np.einsum('nmp,npq->nmq', A, B)
print("\nShape of result batch C:", C.shape) ## Should be (5, 3, 2)
## Let's check the first matrix multiplication in the batch
print("\nFirst result matrix from batch using einsum:")
print(C[0])
## Verify with NumPy's matmul function
numpy_batch_matmul = np.matmul(A, B)
print("\nFirst result matrix from batch using np.matmul:")
print(numpy_batch_matmul[0])
Die Notation 'nmp,npq->nmq'
bedeutet:
nmp
repräsentiert die Indizes von Batch A (n für Batch, m für Zeilen, p für Spalten)
npq
repräsentiert die Indizes von Batch B (n für Batch, p für Zeilen, q für Spalten)
nmq
repräsentiert die Indizes des Ausgabe-Batches C (n für Batch, m für Zeilen, q für Spalten)
- Der wiederholte Index
p
wird summiert (Matrixmultiplikation)
Warum Einsum verwenden?
Sie fragen sich vielleicht, warum wir einsum
verwenden sollten, wenn NumPy bereits spezialisierte Funktionen für diese Operationen bietet. Hier sind einige Vorteile:
- Einheitliche Schnittstelle:
einsum
bietet eine einzige Funktion für viele Array-Operationen
- Flexibilität: Es kann Operationen ausdrücken, die sonst mehrere Schritte erfordern würden
- Lesbarkeit: Wenn Sie die Notation verstehen, wird der Code prägnanter
- Leistung: In vielen Fällen sind
einsum
-Operationen optimiert und effizient
Für komplexe Tensoroperationen bietet einsum
oft die klarste und direkteste Implementierung.