Die Einstein-Summierung

Aktualisiert auf September 02, 2024 3 Minuten gelesen

Die Einstein-Summierung cover image

Die Einstein-Summationsnotation ist eine prägnante und leistungsstarke Methode zur Darstellung von Tensoroperationen, die häufig in der Physik und beim maschinellen Lernen verwendet wird. Es ermöglicht uns, komplexe Berechnungen zu Tensoren in kompakter Form zu schreiben. Wir behandeln die Grundlagen der Einstein-Summierung, deren Verwendung in Python mit Numpy und Tensorflow und stellen Beispiele zur Veranschaulichung ihrer Verwendung bereit.

Grundlagen der Einstein-Summierung

Die Einstein-Summationsnotation (Einsum) basiert auf der Idee der Summierung über wiederholte Indizes in Tensorausdrücken. Es basiert auf den folgenden zwei Regeln:

1. Summierung über wiederholte Indizes: Wenn ein Index in einem Begriff zweimal vorkommt, wird er summiert

2. Freie Indizes: Indizes, die nur einmal vorkommen, sind freie Indizes und stellen die Achsen des Ausgabetensors dar

Lassen Sie uns dies am Beispiel der Multiplikation zweier Matrizen A und B veranschaulichen: Die resultierende Matrix C ist definiert als

$$ C_{ik} = \sum\limits_{j}^{}A_{ij}B_{jk} $$

In Python bieten sowohl die Numpy- als auch die Tensorflow-Bibliothek eine Einsum-Funktion.

Numpy

import numpy as np

# Define two matrices A and B
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

# Perform matrix multiplication using einsum
C = np.einsum('ij,jk->ik', A, B)

print(C)
# [[19 22]
#  [43 50]]

Im obigen Beispiel ist „ij,jk->ik“ die Einsum-Zeichenfolge:

„ij“ repräsentiert die Indizes der Matrix A

„jk“ repräsentiert die Indizes der Matrix B

->ik gibt die Indizes der Ausgabematrix C an

Die Operation summiert über den Index j

Der gleiche Code in Tensorflow würde so aussehen

import tensorflow as tf

# Define two matrices A and B
A = tf.constant([[1, 2], [3, 4]], dtype=tf.float32)
B = tf.constant([[5, 6], [7, 8]], dtype=tf.float32)

# Perform matrix multiplication using einsum
C = tf.einsum('ij,jk->ik', A, B)

print(C)
# tf.Tensor(
# [[19. 22.]
#  [43. 50.]], shape=(2, 2), dtype=float32)

Weitere Beispiele

Inneres Produkt von Vektoren

Das innere Produkt (Skalarprodukt) zweier Vektoren a und b ist definiert als

$$ c = \sum\limits_{i}^{}a_{i}b_{i} $$

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

c = np.einsum('i,i->', a, b)

print(c)  # Output: 32

Äußeres Produkt von Vektoren

Das äußere Produkt zweier Vektoren a und b ist gegeben durch:

$$ C_{ij} = a_{i}b_{j} $$

C = np.einsum('i,j->ij', a, b)

print(C)
# Output
# [[4 5 6]
#  [8 10 12]
#  [12 15 18]]

Transponieren einer Matrix

Die Transponierte einer Matrix A kann durch Vertauschen ihrer Indizes erhalten werden

A_transpose = np.einsum('ij->ji', A)

print(A_transpose)
# Output
# [[1. 3.]
#  [2. 4.]]

Spur einer Matrix

Die Spur einer Matrix A ist die Summe ihrer Diagonalelemente:

$$ Tr(A) = \sum\limits_{i}^{}A_{ii}A_{ii} $$


trace = np.einsum('ii->', A)

print(trace)
# Output: 5.0

Batch-Matrix-Multiplikation

Einsum ist besonders nützlich für Batch-Vorgänge. Angenommen, wir haben einen Stapel der Matrizen A und B und möchten die entsprechenden Matrizen im Stapel multiplizieren:


A = np.random.rand(3, 2, 2)
B = np.random.rand(3, 2, 2)

# Perform batch matrix multiplication
C = np.einsum('bij,bjk->bik', A, B)

print(C)

Hier stellt „b“ die Chargendimension dar.

Vorteile der Einsum-Notation

1. Prägnanz: Die Einsum-Notation ist kompakt und kann komplexe Operationen prägnant darstellen

2. Flexibilität: Es kann eine Vielzahl von Tensoroperationen verarbeiten, ohne Arrays explizit umzuformen oder zu transponieren

3. Effizienz: Viele Bibliotheken optimieren die Einsum-Operationen intern, was möglicherweise zu einer besseren Leistung führt.