# 3. Token Embeddings ## Token Embeddings Después de tokenizar los datos de texto, el siguiente paso crítico en la preparación de datos para entrenar modelos de lenguaje grandes (LLMs) como GPT es crear **token embeddings**. Los token embeddings transforman tokens discretos (como palabras o subpalabras) en vectores numéricos continuos que el modelo puede procesar y aprender. Esta explicación desglosa los token embeddings, su inicialización, uso y el papel de los embeddings posicionales en la mejora de la comprensión del modelo sobre las secuencias de tokens. {% hint style="success" %} El objetivo de esta tercera fase es muy simple: **Asignar a cada uno de los tokens anteriores en el vocabulario un vector de las dimensiones deseadas para entrenar el modelo.** Cada palabra en el vocabulario será un punto en un espacio de X dimensiones.\ Tenga en cuenta que inicialmente la posición de cada palabra en el espacio se inicializa "aleatoriamente" y estas posiciones son parámetros entrenables (se mejorarán durante el entrenamiento). Además, durante el token embedding **se crea otra capa de embeddings** que representa (en este caso) la **posición absoluta de la palabra en la oración de entrenamiento**. De esta manera, una palabra en diferentes posiciones en la oración tendrá una representación (significado) diferente. {% endhint %} ### **What Are Token Embeddings?** **Token Embeddings** son representaciones numéricas de tokens en un espacio vectorial continuo. Cada token en el vocabulario está asociado con un vector único de dimensiones fijas. Estos vectores capturan información semántica y sintáctica sobre los tokens, lo que permite al modelo entender relaciones y patrones en los datos. * **Vocabulary Size:** El número total de tokens únicos (por ejemplo, palabras, subpalabras) en el vocabulario del modelo. * **Embedding Dimensions:** El número de valores numéricos (dimensiones) en el vector de cada token. Dimensiones más altas pueden capturar información más matizada, pero requieren más recursos computacionales. **Example:** * **Vocabulary Size:** 6 tokens \[1, 2, 3, 4, 5, 6] * **Embedding Dimensions:** 3 (x, y, z) ### **Initializing Token Embeddings** Al comienzo del entrenamiento, los token embeddings se inicializan típicamente con pequeños valores aleatorios. Estos valores iniciales se ajustan (se afinan) durante el entrenamiento para representar mejor los significados de los tokens en función de los datos de entrenamiento. **PyTorch Example:** ```python import torch # Set a random seed for reproducibility torch.manual_seed(123) # Create an embedding layer with 6 tokens and 3 dimensions embedding_layer = torch.nn.Embedding(6, 3) # Display the initial weights (embeddings) print(embedding_layer.weight) ``` **Salida:** ```lua luaCopy codeParameter containing: tensor([[ 0.3374, -0.1778, -0.1690], [ 0.9178, 1.5810, 1.3010], [ 1.2753, -0.2010, -0.1606], [-0.4015, 0.9666, -1.1481], [-1.1589, 0.3255, -0.6315], [-2.8400, -0.7849, -1.4096]], requires_grad=True) ``` **Explicación:** * Cada fila corresponde a un token en el vocabulario. * Cada columna representa una dimensión en el vector de embedding. * Por ejemplo, el token en el índice `3` tiene un vector de embedding `[-0.4015, 0.9666, -1.1481]`. **Accediendo al embedding de un token:** ```python # Retrieve the embedding for the token at index 3 token_index = torch.tensor([3]) print(embedding_layer(token_index)) ``` **Salida:** ```lua tensor([[-0.4015, 0.9666, -1.1481]], grad_fn=) ``` **Interpretación:** * El token en el índice `3` está representado por el vector `[-0.4015, 0.9666, -1.1481]`. * Estos valores son parámetros entrenables que el modelo ajustará durante el entrenamiento para representar mejor el contexto y el significado del token. ### **Cómo Funcionan las Embeddings de Tokens Durante el Entrenamiento** Durante el entrenamiento, cada token en los datos de entrada se convierte en su vector de embedding correspondiente. Estos vectores se utilizan luego en varios cálculos dentro del modelo, como mecanismos de atención y capas de redes neuronales. **Escenario de Ejemplo:** * **Tamaño del Lote:** 8 (número de muestras procesadas simultáneamente) * **Longitud Máxima de Secuencia:** 4 (número de tokens por muestra) * **Dimensiones de Embedding:** 256 **Estructura de Datos:** * Cada lote se representa como un tensor 3D con forma `(batch_size, max_length, embedding_dim)`. * Para nuestro ejemplo, la forma sería `(8, 4, 256)`. **Visualización:** ```css cssCopy codeBatch ┌─────────────┐ │ Sample 1 │ │ ┌─────┐ │ │ │Token│ → [x₁₁, x₁₂, ..., x₁₂₅₆] │ │ 1 │ │ │ │... │ │ │ │Token│ │ │ │ 4 │ │ │ └─────┘ │ │ Sample 2 │ │ ┌─────┐ │ │ │Token│ → [x₂₁, x₂₂, ..., x₂₂₅₆] │ │ 1 │ │ │ │... │ │ │ │Token│ │ │ │ 4 │ │ │ └─────┘ │ │ ... │ │ Sample 8 │ │ ┌─────┐ │ │ │Token│ → [x₈₁, x₈₂, ..., x₈₂₅₆] │ │ 1 │ │ │ │... │ │ │ │Token│ │ │ │ 4 │ │ │ └─────┘ │ └─────────────┘ ``` **Explicación:** * Cada token en la secuencia está representado por un vector de 256 dimensiones. * El modelo procesa estas incrustaciones para aprender patrones de lenguaje y generar predicciones. ## **Incrustaciones Posicionales: Agregando Contexto a las Incrustaciones de Tokens** Mientras que las incrustaciones de tokens capturan el significado de tokens individuales, no codifican inherentemente la posición de los tokens dentro de una secuencia. Comprender el orden de los tokens es crucial para la comprensión del lenguaje. Aquí es donde entran en juego las **incrustaciones posicionales**. ### **Por qué se Necesitan las Incrustaciones Posicionales:** * **El Orden de los Tokens Importa:** En las oraciones, el significado a menudo depende del orden de las palabras. Por ejemplo, "El gato se sentó en la estera" vs. "La estera se sentó en el gato." * **Limitación de la Incrustación:** Sin información posicional, el modelo trata los tokens como un "saco de palabras", ignorando su secuencia. ### **Tipos de Incrustaciones Posicionales:** 1. **Incrustaciones Posicionales Absolutas:** * Asignan un vector de posición único a cada posición en la secuencia. * **Ejemplo:** El primer token en cualquier secuencia tiene la misma incrustación posicional, el segundo token tiene otra, y así sucesivamente. * **Usado Por:** Modelos GPT de OpenAI. 2. **Incrustaciones Posicionales Relativas:** * Codifican la distancia relativa entre tokens en lugar de sus posiciones absolutas. * **Ejemplo:** Indican cuán separados están dos tokens, independientemente de sus posiciones absolutas en la secuencia. * **Usado Por:** Modelos como Transformer-XL y algunas variantes de BERT. ### **Cómo se Integran las Incrustaciones Posicionales:** * **Mismas Dimensiones:** Las incrustaciones posicionales tienen la misma dimensionalidad que las incrustaciones de tokens. * **Adición:** Se suman a las incrustaciones de tokens, combinando la identidad del token con la información posicional sin aumentar la dimensionalidad general. **Ejemplo de Adición de Incrustaciones Posicionales:** Supongamos que un vector de incrustación de token es `[0.5, -0.2, 0.1]` y su vector de incrustación posicional es `[0.1, 0.3, -0.1]`. La incrustación combinada utilizada por el modelo sería: ```css Combined Embedding = Token Embedding + Positional Embedding = [0.5 + 0.1, -0.2 + 0.3, 0.1 + (-0.1)] = [0.6, 0.1, 0.0] ``` **Beneficios de los Embeddings Posicionales:** * **Conciencia Contextual:** El modelo puede diferenciar entre tokens según sus posiciones. * **Comprensión de Secuencias:** Permite al modelo entender la gramática, la sintaxis y los significados dependientes del contexto. ## Ejemplo de Código Siguiendo con el ejemplo de código de [https://github.com/rasbt/LLMs-from-scratch/blob/main/ch02/01\_main-chapter-code/ch02.ipynb](https://github.com/rasbt/LLMs-from-scratch/blob/main/ch02/01\_main-chapter-code/ch02.ipynb): ```python # Use previous code... # Create dimensional emdeddings """ BPE uses a vocabulary of 50257 words Let's supose we want to use 256 dimensions (instead of the millions used by LLMs) """ vocab_size = 50257 output_dim = 256 token_embedding_layer = torch.nn.Embedding(vocab_size, output_dim) ## Generate the dataloader like before max_length = 4 dataloader = create_dataloader_v1( raw_text, batch_size=8, max_length=max_length, stride=max_length, shuffle=False ) data_iter = iter(dataloader) inputs, targets = next(data_iter) # Apply embeddings token_embeddings = token_embedding_layer(inputs) print(token_embeddings.shape) torch.Size([8, 4, 256]) # 8 x 4 x 256 # Generate absolute embeddings context_length = max_length pos_embedding_layer = torch.nn.Embedding(context_length, output_dim) pos_embeddings = pos_embedding_layer(torch.arange(max_length)) input_embeddings = token_embeddings + pos_embeddings print(input_embeddings.shape) # torch.Size([8, 4, 256]) ``` ## Referencias * [https://www.manning.com/books/build-a-large-language-model-from-scratch](https://www.manning.com/books/build-a-large-language-model-from-scratch)