La notación de suma de Einstein es una forma concisa y potente de representar operaciones tensoriales, que se utiliza a menudo en física y aprendizaje automático. Nos permite escribir cálculos complejos sobre tensores de forma compacta. Cubriremos los conceptos básicos de la suma de Einstein, cómo usarla en Python con Numpy y Tensorflow, y brindaremos ejemplos para ilustrar su uso.
Conceptos básicos de la suma de Einstein
La notación de suma de Einstein (Einsum) se basa en la idea de sumar índices repetidos en expresiones tensoriales. Se basa en las dos reglas siguientes:
1. Suma de índices repetidos: Si un índice aparece dos veces en un término, se suma
2. Índices libres: Los índices que aparecen solo una vez son índices libres y representan los ejes del tensor de salida.
Ilustremos esto con el ejemplo de multiplicar dos matrices A y B: la matriz resultante C se define como
En Python, las bibliotecas Numpy y Tensorflow proporcionan una función einsum.
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]]
En el ejemplo anterior, ij,jk->ik
es la cadena einsum:
ij
representa los índices de la matriz A
jk
representa los índices de la matriz B
->ik
especifica los índices de la matriz de salida C
La operación suma sobre el índice j.
El mismo código en Tensorflow se vería así
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)
Más ejemplos
Producto interno de vectores
El producto interno (producto escalar) de dos vectores a y b se define como
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.einsum('i,i->', a, b)
print(c) # Output: 32
Producto exterior de vectores
El producto exterior de dos vectores a y b viene dado por:
C = np.einsum('i,j->ij', a, b)
print(C)
# Output
# [[4 5 6]
# [8 10 12]
# [12 15 18]]
Transpuesta de una matriz
La transpuesta de una matriz A se puede obtener intercambiando sus índices
A_transpose = np.einsum('ij->ji', A)
print(A_transpose)
# Output
# [[1. 3.]
# [2. 4.]]
Rastro de una matriz
La traza de una matriz A es la suma de sus elementos diagonales:
trace = np.einsum('ii->', A)
print(trace)
# Output: 5.0
Multiplicación de matrices por lotes
Einsum es particularmente útil para operaciones por lotes. Supongamos que tenemos un lote de matrices A y B y queremos multiplicar las matrices correspondientes en el lote:
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)
Aquí, "b" representa la dimensión del lote.
Ventajas de la notación Einsum
1. Concisión: La notación Einsum es compacta y puede representar operaciones complejas de manera sucinta.
2. Flexibilidad: Puede manejar una amplia variedad de operaciones tensoriales sin remodelar o transponer matrices explícitamente.
3. Eficiencia: Muchas bibliotecas optimizan las operaciones de einsum internamente, lo que potencialmente conduce a un mejor rendimiento.