https://jalammar.github.io/illustrated-transformer/
https://lena-voita.github.io/nlp_course/seq2seq_and_attention.html#transformer_intro
Los modelos Transformer son una clase de arquitecturas de aprendizaje profundo que han revolucionado el campo del procesamiento del lenguaje natural (NLP) y más allá. Introducidos en el paper "Attention Is All You Need" por Vaswani et al. en 2017, los Transformers se destacan por su capacidad para manejar secuencias de datos, como texto, de una manera muy eficiente y efectiva. A diferencia de las arquitecturas anteriores como las redes neuronales recurrentes (RNN) y las redes neuronales convolucionales (CNN), los Transformers se basan principalmente en un mecanismo llamado "atención", especialmente la "atención de múltiples cabezas".
Aquí hay algunos puntos clave sobre los modelos Transformer:
Mecanismo de Atención: El componente central de un Transformer es el mecanismo de atención, que permite al modelo ponderar la importancia de diferentes partes de la entrada. En el contexto del NLP, esto significa que un Transformer puede prestar más atención a palabras relevantes y menos a las irrelevantes al procesar un texto.
Atención de Múltiples Cabezas: Los Transformers utilizan lo que se llama "atención de múltiples cabezas". Esto les permite prestar atención a diferentes partes de la secuencia de entrada simultáneamente, lo que mejora la capacidad del modelo para aprender relaciones complejas.
Arquitectura de Codificador y Decodificador: Los Transformers originales se componen de una serie de bloques de codificadores y decodificadores. El codificador procesa la entrada (por ejemplo, un texto en un idioma fuente para la traducción automática), y el decodificador genera la salida (por ejemplo, el texto traducido). Cada bloque de codificador y decodificador contiene capas de atención y redes neuronales feed-forward.
Paralelización y Escalabilidad: A diferencia de las RNN, los Transformers no requieren que los datos se procesen secuencialmente. Esto significa que pueden manejar secuencias completas de datos a la vez, lo que permite una paralelización masiva y hace que los Transformers sean particularmente adecuados para el hardware moderno de GPU.
Aplicaciones en NLP y Más Allá: Aunque los Transformers fueron diseñados originalmente para tareas de NLP como la traducción automática, su aplicación se ha extendido a una amplia gama de tareas, incluyendo la generación de texto (como GPT-3), el entendimiento del lenguaje (como BERT), el procesamiento de imágenes, y más.
Transferencia y Aprendizaje Pre-entrenado: Modelos como BERT y GPT-3 son pre-entrenados en grandes cantidades de datos y luego afinados en tareas específicas, lo que les permite alcanzar un rendimiento destacado en una amplia gama de tareas de NLP con relativamente poco esfuerzo de ajuste específico de la tarea.
Suponiendo que tenemos los vectores Q, K y V, implementa el mecanismo de auto-atención del modelo Transformer.
import torch
Q = torch.tensor([[0.0, 0.0, 0.0], [1, 1, 1], [0.2, 0.2, 0.2], [0.3, 0.3, 0.3]])
K = torch.tensor([[0.1, 0.1, 0.1], [0.2, 0.2, 0.2], [0.3, 0.3, 0.3], [0.4, 0.4, 0.4]])
V = torch.tensor([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.], [0., 1., 1.]])
Una vez realizado el resultado debe ser:
Attn 1 | 0.2500 | 0.5000 | 0.5000 |
Attn 2 | 0.1892 | 0.5432 | 0.5857 |
Attn 3 | 0.2372 | 0.5087 | 0.5173 |
Attn 4 | 0.2309 | 0.5130 | 0.5260 |
El enmascaramiento durante la etapa del decodificador en los modelos Transformer es crucial para evitar que el decodificador tenga acceso a información futura, especialmente en tareas de generación secuencial como la traducción automática o la generación de texto. Este concepto se conoce como "enmascaramiento de atención causal".
En el contexto de los Transformers, el decodificador genera una salida secuencialmente, palabra por palabra. Durante la generación de cada palabra, es importante que el modelo solo tenga en cuenta las palabras anteriores y no las futuras, ya que estas últimas no deberían estar disponibles (en un escenario de generación de texto, por ejemplo, las palabras futuras aún no se han generado).
Una vez realizado el resultado debe ser:
Attn 1 | 1.0000 | 0.0000 | 0.0000 |
Attn 2 | 0.4568 | 0.5432 | 0.0000 |
Attn 3 | 0.3219 | 0.3332 | 0.3449 |
Attn 4 | 0.2309 | 0.5130 | 0.5260 |
"Layer Normalization" es una técnica de normalización utilizada en el entrenamiento de redes neuronales profundas, introducida por Jimmy Lei Ba, Jamie Ryan Kiros y Geoffrey Hinton en 2016 (https://arxiv.org/pdf/1607.06450.pdf). Esta técnica es fundamental para mejorar la estabilidad y acelerar el entrenamiento de modelos de aprendizaje profundo, especialmente en el contexto de redes neuronales recurrentes (RNN) y modelos de atención como los Transformers.
Normalización por Ejemplo: La Layer Normalization normaliza los datos a lo largo de las características para cada ejemplo individual en un lote. Esto significa que, para cada dato en el lote, la normalización se realiza calculando la media y la varianza de todas sus características.
Cálculo de la Media y la Varianza: Para cada ejemplo, se calcula la media y la varianza de todas sus características. Estos valores se utilizan para normalizar las características de ese ejemplo específico.
Proceso de Normalización: La normalización se realiza restando la media y dividiendo por la desviación estándar (raíz cuadrada de la varianza) de las características de cada ejemplo. Se añade un pequeño valor, conocido como epsilon, al denominador para evitar la división por cero.
Parámetros Aprendibles: Después de normalizar las características, se aplican dos parámetros aprendibles a cada una de ellas: un factor de escala (gamma) y un término de desplazamiento (beta). Estos parámetros son específicos para cada capa de la red y se ajustan durante el proceso de entrenamiento.
Aplicaciones en Modelos de Secuencia: La Layer Normalization ha demostrado ser particularmente efectiva en modelos que procesan datos secuenciales, como las redes neuronales recurrentes y los modelos basados en el mecanismo de atención, donde ayuda a mejorar la estabilidad y eficiencia del entrenamiento.
La Layer Normalization se centra en normalizar las activaciones dentro de una capa para cada ejemplo de datos. A continuación se describe el proceso matemáticamente:
Dado un tensor de entrada $ X $ para una capa específica en la red, donde $ X $ tiene dimensiones $[N, F]$ (con $ N $ siendo el tamaño del lote y $ F $ el número de características o neuronas en la capa), la Layer Normalization se realiza de la siguiente manera para cada ejemplo $ n $ en el lote:
Calcular la Media: $$ \mu_n = \frac{1}{F} \sum_{f=1}^{F} x_{nf} $$ Aquí, $ \mu_n $ es la media de las activaciones para el ejemplo $ n $.
Calcular la Varianza: $$ \sigma_n^2 = \frac{1}{F} \sum_{f=1}^{F} (x_{nf} - \mu_n)^2 $$ Donde $ \sigma_n^2 $ es la varianza de las activaciones para el ejemplo $ n $.
Normalizar: $$ \hat{x}_{nf} = \frac{x_{nf} - \mu_n}{\sqrt{\sigma_n^2 + \epsilon}} $$ Cada activación $ x_{nf} $ se normaliza restando la media $ \mu_n $ y dividiendo por la raíz cuadrada de la varianza $ \sigma_n^2 $, con un pequeño número $ \epsilon $ añadido para la estabilidad numérica (evitar la división por cero).
Aplicar Parámetros Aprendibles: $$ y_{nf} = \gamma \hat{x}_{nf} + \beta $$ Finalmente, se aplica una transformación lineal a las activaciones normalizadas, donde $ \gamma $ y $ \beta $ son parámetros aprendibles específicos de la capa. Estos parámetros permiten que la normalización se ajuste de manera flexible durante el entrenamiento.
En esta formulación, $ n $ indexa los ejemplos en el lote y $ f $ indexa las características. Cada ejemplo se normaliza de forma independiente. Los parámetros $ \gamma $ y $ \beta $ son de la misma dimensión que el número de características $ F $, permitiendo una escala y un desplazamiento distintos para cada característica.
La Layer Normalization es especialmente útil en modelos de secuencias como los Transformers y las RNN, donde normaliza las activaciones a lo largo de las características para cada paso de tiempo o posición en la secuencia, contribuyendo a un entrenamiento más estable y eficiente.
Asumiento los parámetros $\gamma$ y $\beta$ como 1 y 0 respectivamente, desarrolla un código que normalice los siguientes vectores de características:
import torch
v1 = torch.tensor([1.0, 2.0, 3.0])
v2 = torch.tensor([2.0, 2.0, 2.0])
v3 = torch.tensor([23.0, 0.01, 5.0])
El resultado debe ser:
nl = torch.nn.LayerNorm(3, eps=1e-05, elementwise_affine=True)
print(nl(v1))
print(nl(v2))
print(nl(v3))
tensor([-1.2247, 0.0000, 1.2247], grad_fn=<NativeLayerNormBackward0>) tensor([0., 0., 0.], grad_fn=<NativeLayerNormBackward0>) tensor([ 1.3838, -0.9446, -0.4392], grad_fn=<NativeLayerNormBackward0>)