Cómo funcionan las capas de embedding: del texto a los IDs de token y a los vectores en un LLM
Una explicación para principiantes de las capas de embedding: tokenización, tablas de búsqueda, vectores aprendidos, el ejemplo de 205 millones de parámetros y una breve demo en PyTorch con nn.Embedding.
Escriba la frase "I love cats" en un LLM y el modelo nunca llegará a ver tres palabras en inglés. Las redes neuronales trabajan con números. Entonces, ¿cómo se convierte esa frase corta en algo que un Transformer pueda procesar? La respuesta empieza en la capa de embedding.
1. Del texto a los IDs de token
Primero viene la tokenización. Un tokenizador divide el texto en trozos llamados tokens y le da un ID a cada uno. Para simplificar, supongamos este vocabulario diminuto:
"I" → 10
"love" → 25
"cats" → 47
La frase se convierte entonces en una lista corta de enteros:
"I love cats"
↓
[10, 25, 47]
Esos son los IDs de token, y por sí solos no significan nada. El número 47 no dice que "cats" valga cuarenta y siete de algo. Es solo un índice, una etiqueta que apunta a una entrada del vocabulario. Hace falta un paso más antes de que el modelo pueda hacer algo útil.
2. De los IDs de token a los embeddings
Ese paso le corresponde a la capa de embedding. Imagínela como una gran tabla con una fila, es decir, un vector, por cada token del vocabulario.
Supongamos que el vocabulario tiene solo 50 tokens y que cada token se describe con 4 números. Cada fila es un vector de embedding:
Embedding vector
La tabla podría empezar así:
Token 0 → [ 0.2, -0.4, 0.7, 0.1 ]
Token 1 → [ 0.6, 0.1, -0.3, 0.8 ]
...
Token 10 → [ 0.3, -0.2, 0.9, 0.4 ]
...
Token 25 → [-0.5, 0.7, 0.2, -0.1 ]
...
Token 47 → [ 0.8, 0.1, -0.6, 0.5 ]
...
Ahora tomemos la secuencia de entrada:
[10, 25, 47]
La capa simplemente busca esas filas. El token 10 recibe su vector:
10 → [ 0.3, -0.2, 0.9, 0.4 ]
y los otros dos siguen el mismo camino:
25 → [-0.5, 0.7, 0.2, -0.1 ]47 → [ 0.8, 0.1, -0.6, 0.5 ]
Así que el texto original pasa por estas etapas:
"I love cats"
↓ Tokenizer[10, 25, 47] ↓ Embedding lookup[
[ 0.3, -0.2, 0.9, 0.4 ],
[-0.5, 0.7, 0.2, -0.1 ],
[ 0.8, 0.1, -0.6, 0.5 ]
] ↓Transformer
Ese es su trabajo en pocas palabras: la capa de embedding convierte los IDs de token en vectores.
3. ¿Por qué vectores y no los IDs tal cual?
Quizá se pregunte por qué el Transformer no puede recibir los IDs directamente. La razón es que los IDs son solo etiquetas. Fíjese en los tres valores:
10
25
47
La distancia entre 25 y 47 no dice nada sobre cómo se relaciona "love" con "cats". Los vectores de embedding son distintos porque son representaciones aprendidas. Durante el entrenamiento, el modelo ajusta sus valores hasta que ayudan al Transformer a manejar el lenguaje.
4. De dónde salen los números
Nadie escribe a mano los valores de la matriz de embeddings. Se aprenden durante el entrenamiento. Al principio, los vectores contienen valores sin ninguna información lingüística. Después el modelo lee cantidades enormes de texto y practica predecir el siguiente token. Ante un prompt como "I love cats because they are ___", hace una apuesta.
Cuando la apuesta falla, el error viaja hacia atrás por la red mediante retropropagación. Los vectores de embedding se actualizan junto con todos los demás pesos. Tras el entrenamiento, la matriz contiene representaciones en las que el modelo ha aprendido a apoyarse.
5. Qué representa un embedding
Tomemos un vector para "cats":
cats → [0.8, 0.1, -0.6, 0.5]
Es tentador leer cada número como una propiedad con nombre, algo así:
0.8 → animal
0.1 → size
-0.6 → shape
0.5 → plural
En general, los embeddings de un LLM no funcionan así. El significado está repartido entre todas las dimensiones a la vez. Una dimensión rara vez corresponde a un único concepto que una persona pueda nombrar. La representación es el vector completo.
6. Las matrices de embedding reales son enormes
Pasemos ahora del ejemplo de juguete a un modelo realista con estas dimensiones:
Vocabulary size = 50,000
Embedding dimension = 4,096
La matriz de embeddings tiene entonces unos 205 millones de parámetros, que es mucho. Lo que parece una simple tabla de búsqueda puede contener una parte sorprendentemente grande de los pesos de un modelo.
7. Qué ocurre después
Una vez que "I love cats" se ha convertido en un conjunto de vectores de embedding, estos entran en el Transformer. Este es el flujo:
"I love cats"
│
▼
Tokenizer
│
▼
[10, 25, 47]
│
▼
Embedding Layer
│
▼
[vector, vector, vector]
│
▼
Transformer
│
▼
Next-token prediction
El embedding es el puente entre los tokens discretos y las representaciones numéricas continuas con las que trabaja la red neuronal.
8. La misma idea en Python
Bastan unas pocas líneas de PyTorch para mostrarlo:
import torch
import torch.nn as nn
# Vocabulary contains 50 tokens
# Each token is represented by 4 numbers
embedding = nn.Embedding(
num_embeddings=50,
embedding_dim=4
)
# Token IDs for "I love cats"
tokens = torch.tensor([10, 25, 47])
# Look up their embeddings
vectors = embedding(tokens)
print(vectors)
print(vectors.shape)
El resultado impreso se parece más o menos a esto:
tensor([
[ 0.31, -0.21, 0.91, 0.42],
[-0.52, 0.73, 0.19, -0.12],
[ 0.79, 0.08, -0.61, 0.54]
])
Y la forma confirma tres tokens con cuatro números cada uno:
torch.Size([3, 4])
La capa de embedding es, en esencia, una tabla de búsqueda aprendida. Si se juntan las piezas, el pipeline queda así:
Text
↓
Tokenizer
↓
Token IDs
↓
Embedding lookup
↓
Vectors
Transformer
El tokenizador identifica qué tokens hay. La capa de embedding convierte sus IDs en representaciones numéricas aprendidas. El Transformer toma esas representaciones, interpreta el contexto y hace predicciones.
La próxima vez que se encuentre esta línea en la definición de un modelo:
nn.Embedding(vocab_size, embedding_dim)
léala como la instrucción de construir una tabla con vocab_size filas, donde cada token recibe su propio vector entrenable de longitud embedding_dim.