Phase 07 - Lesson 07
GPT — Modelado de Lenguaje Causal
This lesson includes a graded coding exercise that runs in your browser, unlocked with lifetime access.
BERT ve ambos lados. GPT ve solo el pasado. La máscara triangular es la línea de código individual más trascendental en la IA moderna.
Tipo: Build Lenguajes: Python Requisitos previos: Fase 7 · 02 (Self-Attention), Fase 7 · 05 (Full Transformer), Fase 7 · 06 (BERT) Tiempo: ~75 minutos
El Problema
Un modelo de lenguaje responde a una pregunta: dados los primeros t-1 tokens, ¿cuál es la distribución de probabilidad sobre el token t? Entrena con esa señal — predicción del próximo token — y obtendrás un modelo que puede generar texto arbitrario un token a la vez.
Para entrenarlo de extremo a extremo en una secuencia completa en paralelo, necesitas que la predicción de cada posición dependa solo de las posiciones anteriores. De lo contrario, el modelo hace trampa de manera trivial al mirar la respuesta.
La máscara causal hace esto. Es una única matriz triangular superior de valores -inf añadida a las puntuaciones de atención antes de softmax. Después de softmax, esas posiciones se convierten en 0. Cada posición puede atender solo a sí misma y a las posiciones anteriores. Y dado que la aplicas una vez a toda la secuencia, obtienes N predicciones paralelas del próximo token en un solo forward pass.
GPT-1 (2018), GPT-2 (2019), GPT-3 (2020), GPT-4 (2023), GPT-5 (2024), Claude, Llama, Qwen, Mistral, DeepSeek, Kimi — todos son transformers causales de solo decodificador (decoder-only) con el mismo bucle central. Solo que con datos más grandes y mejores, y mejor RLHF.
El Concepto
La máscara
Dada una secuencia de longitud N, construye una matriz N × N:
M[i, j] = 0 if j <= i
M[i, j] = -inf if j > i
Añade M a las puntuaciones de atención brutas antes de softmax. exp(-inf) = 0, por lo que las posiciones enmascaradas contribuyen con peso cero. Cada fila de la matriz de atención es una distribución de probabilidad solo sobre las posiciones anteriores.
Costo de implementación: una sola llamada a torch.tril(). Tiempo de cómputo: nanosegundos. Impacto en el campo: todo.
Entrenamiento paralelo, inferencia serial
Entrenamiento: realiza el forward pass de toda la secuencia (N, d_model) una vez, calcula N pérdidas de entropía cruzada (una por posición), suma y realiza backprop. Paralelo a lo largo de la secuencia. Es por esto que el entrenamiento de GPT escala: procesas 1M de tokens en un lote (batch) en un solo paso de GPU.
Inferencia: generas token por token. Alimentas [t1, t2, t3], obtienes t4. Alimentas [t1, t2, t3, t4], obtienes t5. Alimentas [t1, t2, t3, t4, t5], obtienes t6. El caché KV (Lección 12) guarda los estados ocultos (hidden states) de t1…tn para no recalcularlos en cada paso. Pero la profundidad serial en la inferencia = longitud de salida. Ese es el impuesto autorregresivo (autoregressive tax) y la razón por la cual la decodificación es el cuello de botella de latencia de todo LLM.
La pérdida — desplazamiento por uno (shift-by-one)
Dados los tokens [t1, t2, t3, t4]:
- Entrada:
[t1, t2, t3] - Objetivos:
[t2, t3, t4]
Para cada posición i, calcula -log P(target_i | inputs[:i+1]). Suma. Esta es la entropía cruzada para toda la secuencia.
Cada transformer LM que hayas escuchado se entrena con esta pérdida. Preentrenamiento, ajuste fino (fine-tuning), SFT — misma pérdida, diferentes datos.
Estrategias de decodificación
Después del entrenamiento, las opciones de muestreo (sampling) importan más de lo que la gente piensa.
| Método | Qué hace | Cuándo usar |
|---|---|---|
| Greedy | Argmax en cada paso | Tareas deterministas, completado de código |
| Temperatura | Divide los logits por T, realiza el muestreo | Tareas creativas, una T más alta = más diversidad |
| Top-k | Muestrea solo de los top-k tokens | Elimina las colas de baja probabilidad |
| Top-p (núcleo) | Muestrea del conjunto más pequeño con prob acumulada ≥ p | Predeterminado post-2020; se adapta a la forma de la distribución |
| Min-p | Mantiene tokens con p > min_p * max_p |
Post-2024; mejor para rechazar colas largas que top-p |
| Decodificación especulativa | El modelo de borrador propone N tokens, el modelo grande verifica | Reducción de 2–3× en la latencia con la misma calidad |
En 2026, min-p + temperatura 0.7 es un valor predeterminado razonable para modelos de pesos abiertos (open-weights). La decodificación especulativa es un requisito básico para cualquier stack de inferencia en producción.
Qué hizo que la "receta de GPT" funcionara
- Solo decodificador (Decoder-only). Sin sobrecarga del codificador (encoder). Una sola pasada de atención + FFN por capa.
- Escalamiento (Scaling). 124M → 1.5B → 175B → billones. Las leyes de escalamiento de Chinchilla (Lección 13) te indican cómo gastar el cómputo.
- Aprendizaje en contexto (In-context learning). Surgió alrededor de 6B–13B. El modelo puede seguir ejemplos few-shot sin ajuste fino.
- RLHF. El postentrenamiento en preferencias humanas convirtió el texto preentrenado bruto en asistentes de chat.
- Pre-norm + RoPE + SwiGLU. Entrenamiento estable a escala.
La arquitectura principal no ha cambiado mucho desde GPT-2. Todo lo interesante ha ocurrido en los datos, la escala y el postentrenamiento.
Build It
Paso 1: la máscara causal
Ver code/main.py. Una sola línea:
def causal_mask(n):
return [[0.0 if j <= i else float("-inf") for j in range(n)] for i in range(n)]
Agrégala a las puntuaciones de atención antes de softmax. Ese es todo el mecanismo.
Paso 2: un modelo tipo GPT de 2 capas
Apila dos bloques decodificadores (self-attention enmascarado + FFN, sin atención cruzada/cross-attention). Añade un embedding de token, una codificación posicional (positional encoding) y un unembedding (vinculado a la matriz de embedding de tokens, un truque estándar desde GPT-2).
Paso 3: predicción del próximo token, de extremo a extremo
En un vocabulario de juguete de 20 tokens, produce logits en cada posición. Calcula la pérdida de entropía cruzada contra el objetivo desplazado por uno. Sin gradiente: esta es una prueba de sanidad del forward pass.
Paso 4: muestreo (sampling)
Implementa greedy, temperatura, top-k, top-p, min-p. Ejecuta cada uno en un prompt fijo y compara las salidas. Una función de muestreo tiene unas 10 líneas.
Use It
PyTorch, estilo de 2026:
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3.2-3B-Instruct")
tok = AutoTokenizer.from_pretrained("meta-llama/Llama-3.2-3B-Instruct")
prompt = "Attention is all you need because"
inputs = tok(prompt, return_tensors="pt")
out = model.generate(
**inputs,
max_new_tokens=64,
temperature=0.7,
top_p=0.9,
do_sample=True,
)
print(tok.decode(out[0]))
Bajo el capó, generate() ejecuta el forward pass, extrae los logits de la posición final, realiza el muestreo del siguiente token, lo añade y repete. Cada stack de inferencia de LLM en producción (vLLM, TensorRT-LLM, llama.cpp, Ollama, MLX) implementa el mismo bucle con una fuerte optimización: prefill por lotes (batched prefill), procesamiento por lotes continuo (continuous batching), paginación de caché KV (KV cache paging) y decodificación especulativa.
GPT vs BERT, una línea cada uno: GPT predice P(x_t | x_{<t}). BERT predice P(x_masked | x_unmasked). La pérdida determina si el modelo puede generar.
Ship It
Ver outputs/skill-sampling-tuner.md. La habilidad (skill) elige los parámetros de muestreo para una nueva tarea de generación y marca cuándo se requiere una decodificación determinista.
Ejercicios
- Fácil. Ejecuta
code/main.pyy verifica que la matriz de atención causal sea triangular inferior después de softmax. Comprobación rápida: la fila 3 debe tener pesos solo en las columnas 0–3. - Medio. Implementa la búsqueda por haz (beam search) para un ancho de 4. Compara la perplejidad de beam-4 frente a greedy en 10 prompts cortos. ¿Siempre gana beam? (Pista: normalmente sí para la traducción, no para el chat abierto).
- Difícil. Implementa la decodificación especulativa: usa un modelo diminuto de 2 capas como borrador (draft) y un modelo de 6 capas como verificador. Mide la aceleración de tiempo real (wall-clock speedup) en 100 completados de longitud 64. Confirma que las salidas coincidan con las de la decodificación greedy del verificador.
Términos Clave
| Término | Lo que la gente dice | Lo que realmente significa |
|---|---|---|
| Máscara causal | "El triángulo" | Matriz triangular superior de -inf añadida a las puntuaciones de atención para que la posición i solo vea las posiciones ≤ i. |
| Predicción del próximo token | "La pérdida (loss)" | Entropía cruzada de la distribución del modelo frente al verdadero siguiente token en cada posición. |
| Autorregresivo | "Generar uno a la vez" | Alimentar la salida de vuelta como entrada; paralelismo solo durante el entrenamiento, no durante la generación. |
| Logits | "Puntuaciones pre-softmax" | Salida bruta del cabezal de LM (LM head) antes de softmax; el muestreo ocurre sobre estos. |
| Temperatura | "Perilla de creatividad" | Divide los logits por T; T→0 = greedy, T→∞ = uniforme. |
| Top-p | "Muestreo de núcleo (nucleus)" | Trunca la distribución al conjunto más pequeño que suma ≥p; realiza el muestreo sobre lo que queda. |
| Min-p | "Mejor que top-p" | Mantiene tokens donde p ≥ min_p × max_p; adapta el límite de corte a la nitidez de la distribución. |
| Decodificación especulativa | "Borrador + verificación" | Un modelo económico propone N tokens; un modelo grande verifica en paralelo. |
| Teacher forcing | "Truque de entrenamiento" | Durante el entrenamiento, alimenta el verdadero token anterior, no la predicción del modelo. Estándar para cada LM seq2seq. |
Lectura Adicional
- Radford et al. (2018). Improving Language Understanding by Generative Pre-Training — GPT-1.
- Radford et al. (2019). Language Models are Unsupervised Multitask Learners — GPT-2.
- Brown et al. (2020). Language Models are Few-Shot Learners — GPT-3 y in-context learning.
- Leviathan, Kalman, Matias (2023). Fast Inference from Transformers via Speculative Decoding — artículo sobre decodificación especulativa.
- HuggingFace
modeling_llama.py— código de referencia canónico de causal-LM.