English · Español
01 — Tensores, shapes y einsum como gramática unificadora¶
🇪🇸 Un tensor es solo un array N-dimensional con shape. Aprender a leer einsum — "los índices repetidos se suman, los libres aparecen en la salida" — te da una notación que unifica dot, outer, matmul, batched matmul y contracción en una sola gramática. Esto es el alfabeto del resto del curso. Ejemplos: vectores one-hot que codifican formas verbales del §A13, matrices que actúan como tablas de búsqueda.
Qué significa "tensor" realmente aquí¶
En matemáticas, "tensor" tiene un significado preciso libre de coordenadas (mapa multilineal entre espacios vectoriales). En la práctica de ML, "tensor" significa un array N-dimensional de números, más un shape, más un dtype. Usaremos el significado de ML todo el tiempo, pero la visión matemática vale la pena tenerla cerca — las operaciones que hacemos sobre tensores son operaciones legítimas de álgebra lineal, expresadas en un marco de coordenadas.
Un tensor tiene tres atributos observables:
| Atributo | Ejemplo |
|---|---|
| Rango (ndim) | escalar = 0, vector = 1, matriz = 2, mayor = 3+ |
| Shape | una tupla de tamaños de dimensión: (3,), (4, 5), (2, 3, 4) |
| Dtype | np.float32, np.int64, etc. |
Para la Fase 3, el dtype es fp32 todo el tiempo. La Fase 2 cubrió el zoo de dtypes.
El bestiario de shapes del §A13¶
Los shapes que Borja verá en este currículo se agrupan en torno a un puñado de dimensiones nombradas:
| Símbolo | Significado | Valor típico (escala §A13) |
|---|---|---|
B |
tamaño de batch | 32 |
T |
longitud de secuencia (tokens) | 16 |
V |
tamaño del vocabulario | 600 (§A13) |
D |
dimensión de embedding / modelo | 64 |
H |
número de cabezas de attention | 4 |
D_k |
dimensión por cabeza (D / H) |
16 |
D_ff |
intermedia de feed-forward | 256 |
K |
top-k o rango | pequeño (5, 8, 32) |
Algunos ejemplos que Borja encontrará:
- Un batch de tokens:
tokens.shape = (B, T), dtypeint64, entradas en[0, V). - La matriz de embedding:
E.shape = (V, D). - Las activaciones post-embedding:
x.shape = (B, T, D). - Los scores de attention en una cabeza:
scores.shape = (B, H, T, T). - Los logits de salida sobre el vocabulario:
logits.shape = (B, T, V).
Si conviertes la anotación de shape en hábito ahora, cada fase posterior será más clara.
Aritmética de shapes¶
La mayoría de las operaciones tienen reglas de shape que puedes calcular a mano:
| Operación | Shapes de entrada | Shape de salida |
|---|---|---|
Elementwise (+, *, np.exp(x)) |
S, S |
S (con broadcasting; ver abajo) |
| Producto escalar (dot product) de vectores | (N,), (N,) |
() (escalar) |
| Producto externo (outer) | (M,), (N,) |
(M, N) |
| Matmul (2D) | (M, K), (K, N) |
(M, N) |
| Batched matmul | (B, M, K), (B, K, N) |
(B, M, N) |
Reducción (x.sum(axis=k)) |
S |
S con el eje k eliminado |
| Transposición | (D_0, D_1, ..., D_{n-1}) |
permutación de esas dimensiones |
| Reshape | S, S' (mismo total) |
S' |
Las compondrás constantemente. La habilidad: leer código y predecir el shape resultante antes de ejecutar.
Broadcasting — cuando los shapes no coinciden¶
NumPy (y PyTorch) extienden el emparejamiento de shapes con broadcasting: un eje de tamaño 1 se expande virtualmente para coincidir con el tamaño del otro operando. Las reglas, en orden:
- Alinea los shapes rellenando con
1s por la derecha al más corto. - Para cada eje (de derecha a izquierda), los tamaños deben ser iguales, o uno de ellos debe ser
1. - El shape resultante es el máximo por eje.
Ejemplo. x.shape = (B, T, D) y mean.shape = (B, T, 1). Calculando x - mean:
- Shapes alineados:
(B, T, D)y(B, T, 1). - Por eje:
B=B,T=T,D vs 1→ broadcast →D. - Resultado:
(B, T, D).
Escollo común: x.shape = (T, D) y bias.shape = (D,). Calculando x + bias:
- Shapes alineados:
(T, D)y(1, D)(relleno por la derecha). - Resultado:
(T, D). Correcto.
Pero x.shape = (T,) y bias.shape = (T,) suma elementwise — shape (T,). No es lo que querías si pretendías un vector columna + bias escalar. Piensa siempre en (T, 1) vs (T,). El lab de broadcasting de la Fase 6 lo machaca.
Sumación de Einstein — la gramática unificadora¶
La sumación de Einstein (einsum) es una notación que nombra cada eje con una sola letra y luego especifica qué ejes se contraen (se suman) y cuáles permanecen. Unifica dot, outer, matmul, batched matmul, transposición, suma y la mayoría de las demás operaciones de álgebra lineal bajo una sola gramática.
Las dos reglas¶
- Un índice repetido se suma. Si
iaparece en ambas entradas de una operación binaria, el resultado suma sobrei. - Un índice que aparece solo en la salida es una dimensión libre (un eje de la salida).
Eso es todo. Toda la gramática.
Seis patrones canónicos¶
| Operación | String einsum | Qué se contrae |
|---|---|---|
| Producto escalar (dot product) | 'i,i->' |
i (suma sobre el eje compartido) |
| Producto externo | 'i,j->ij' |
nada (sin índice compartido) |
| Matriz-vector | 'ij,j->i' |
j |
| Matriz-matriz | 'ij,jk->ik' |
j |
| Producto vectorial elementwise | 'i,i->i' |
nada (sin índice repetido libre en salida) |
| Producto interno de Frobenius | 'ij,ij->' |
tanto i como j |
La habilidad mental: leer los índices, identificar cuáles están repetidos (esos se suman), cuáles son libres (esos se convierten en ejes de salida) y calcular el shape.
Tres ejemplos anclados en §A13¶
Búsqueda de embedding como einsum. Dado un vector one-hot e_v de shape (V,) y una matriz de embedding E de shape (V, D):
Lectura: v está repetido (en ambos operandos), así que se suma. d es libre (solo en E), así que es el eje de salida. Shape: (D,). Valor: la fila de E indexada por la posición del 1 en e_v.
Búsqueda de embedding por lotes. Con tokens_one_hot de shape (B, T, V) y E de shape (V, D):
v se suma; b, t, d son libres. Shape resultante: (B, T, D). Esta es exactamente la operación que realiza la capa de embedding de entrada de un transformer (o más bien, simula — el código real usa indexación E[tokens]).
Scores de attention. Con Q y K cada uno de shape (B, H, T, D_k):
d (la dimensión por cabeza) se suma; b, h, q, k son libres. Shape resultante: (B, H, T, T). Esta es la matriz cruda de scores de attention para cada batch y cada cabeza. La Fase 15 se construye sobre esto.
Ellipsis (...)¶
... en un string einsum significa "cualquier número de ejes principales que se pasan tal cual". Útil cuando la misma operación debe funcionar tanto en entradas con batch como sin él:
Úsalo con moderación — los ejes explícitos son más fáciles de leer.
Reducción por suma vía einsum¶
Una suma sobre el último eje: np.einsum('ij->i', M). La j se omite en la salida, así que se suma. Equivalente a M.sum(axis=-1).
Extracción de diagonal¶
np.einsum('ii->i', M) extrae la diagonal de una matriz cuadrada M. Índice repetido en el mismo operando → diagonal.
Por qué einsum es la gramática correcta para ML¶
Tres razones:
- Shapes autodocumentados. Los índices del string einsum son las anotaciones de shape. No puedes escribir un matmul cuyos shapes no concuerden.
- Una operación, todos los backends.
np.einsum,torch.einsum,jax.numpy.einsume inclusotf.einsumaceptan los mismos strings (salvo unas pocas extensiones). El código escrito en einsum es portable entre frameworks. - Sin carga mental para combinaciones broadcasting + reducción. Un patrón como "para cada cabeza, dot Q rows con K rows" es un solo string einsum; en NumPy regular son tres líneas de transpose + reshape + matmul + reshape vuelta.
Escribirás quizás 50 strings einsum antes de la Fase 30. Los primeros 5 se sentirán incómodos. El resto se sentirán nativos.
Rendimiento — ¿cuesta einsum más que matmul?¶
Para contracciones de dos tensores, no. einsum de NumPy típicamente despacha a BLAS para los patrones estándar ('ij,jk->ik' → np.matmul).
Para contracciones de tres o más tensores (raras en inferencia ML, comunes en redes de tensores MERA), un einsum ingenuo puede ser mucho más lento que un orden de contracción óptimo. np.einsum(..., optimize=True) encuentra automáticamente el mejor orden.
Para los propósitos de la Fase 3 (y la mayor parte de este currículo), einsum es exactamente igual de rápido que el matmul subyacente. Lo único que negocias por claridad mental.
Convención de comentarios de shape¶
Esta convención la usa cada fase posterior. Adóptala ahora:
# (B, T, D) ← entrada
x = ...
# (V, D) ← peso
W = ...
# (B, T, V) ← logits de salida
logits = np.einsum('btd,vd->btv', x, W)
El comentario de shape vive en la línea de asignación. Si el shape cambia (transpose, reshape, contracción), el comentario se actualiza. CI no lo fuerza — la disciplina sí.
Problemas de práctica¶
Soluciones en solutions/01-tensors-and-shapes-ref.md (apertura de fase). Trabájalos en papel.
- Dado
A.shape = (3, 4, 5), ¿cuál es el shape denp.einsum('ijk->kji', A)? - Dados
x.shape = (B, T, D)yy.shape = (B, T, D), ¿cuál es el shape denp.einsum('btd,btd->bt', x, y)? ¿Qué está calculando? - Dados
e_v.shape = (V,)(one-hot, un solo token) yE.shape = (V, D), escribe el einsum que produce el embedding. Ahora escríbelo para un batch de vectores one-hottokens.shape = (B, T, V). - Dados
scores.shape = (B, H, T, T)(scores de attention) yV.shape = (B, H, T, D_k)(valores), escribe el einsum que calcula la salida de attention(B, H, T, D_k). - ¿Qué calcula
np.einsum('ii->', M)sobre una matriz cuadrada? - Los logits de MiniGPT en la capa final tienen shape
(B, T, D). Se proyectan de vuelta al espacio del vocabulario multiplicando conW_outde shape(V, D)— pero espera, la salida debería ser(B, T, V). Escribe el einsum. ¿Cuál es la regla sobre las convenciones de transpose?
Recapitulación en un párrafo¶
Los tensores son arrays N-dimensionales con shape y dtype; el shape es una firma de tipos que deberías comentar en todas partes. El broadcasting + einsum de NumPy juntos dan una gramática que expresa dot, outer, matmul, batched matmul, contracción, transpose y reducción en una sola notación. Memoriza las reglas de einsum (índice repetido se suma, índice libre va a la salida) hasta que puedas predecir shapes leyendo. Cada fase posterior depende de esta habilidad.
Lo que esta página NO cubre¶
- La precisión numérica de las contracciones (Fase 2 + 3.4 normas).
- Trucos de broadcast a medida que pelean contra las reglas (fuera de alcance).
- Diferencias de
torch.einsum(Fase 25).
Siguiente: theory/02-matmul-and-shapes.md.