Self-Attention, Transformers, NLP y LLMs
Guía completa en 4 niveles: desde cero hasta arquitecturas avanzadas. Elige tu punto de entrada y sube de nivel a tu ritmo.
NLP (Natural Language Processing) es la rama de la IA que enseña a las máquinas a leer, escribir y entender lenguaje humano.
Cuando Siri pone una canción, Gmail detecta spam o ChatGPT responde una pregunta — todo eso es NLP.
- Clasificación: ¿spam o no spam?
- Sentimiento: ¿reseña positiva o negativa?
- Traducción: español → inglés.
- Resumen: noticia larga → titular.
- Q&A: "¿Quién fundó Google?" → respuesta.
- Generación: crear texto nuevo (ChatGPT).
Un token es la pieza mínima en que se divide el texto. Puede ser una palabra, parte de una palabra o un carácter.
El modelo no ve palabras: ve tokens convertidos en números.
Un embedding es un vector (lista de números) que representa una palabra. Palabras con significado parecido quedan cerca en ese espacio.
| Término | Significado |
|---|---|
| Token | Unidad mínima de texto |
| Embedding | Vector que representa una palabra |
| Prompt | Lo que tú escribes al modelo |
| Contexto | Todo lo que el modelo puede "ver" |
| LLM | Modelo de lenguaje grande (GPT, Claude…) |
| Alucinación | Cuando el modelo inventa datos falsos |
Self-Attention permite que cada palabra "mire" a todas las demás y decida cuáles son importantes para entenderla.
Ejemplo:
"Banco" es ambiguo. Self-Attention lo conecta con "río" para desambiguar.
Cada token se transforma en tres vectores:
- Query (Q): "¿Qué estoy buscando?"
- Key (K): "¿Qué información ofrezco?"
- Value (V): "¿Qué contenido aporto?"
import torch
import torch.nn as nn
d_model = 512
x = torch.randn(1, 10, d_model)
W_q = nn.Linear(d_model, d_model)
W_k = nn.Linear(d_model, d_model)
W_v = nn.Linear(d_model, d_model)
Q = W_q(x)
K = W_k(x)
V = W_v(x)
- Q·Kᵀ: similitud entre tokens.
- /√dₖ: escalado para estabilidad.
- softmax: convierte en pesos (suman 1).
- ·V: pondera los values.
Varias "cabezas" en paralelo. Cada una aprende a fijarse en relaciones distintas.
Self-Attention no tiene noción de orden. Se añade información posicional con senos y cosenos:
PE(pos, 2i+1) = cos(pos / 100002i/d)
class TransformerBlock(nn.Module):
def __init__(self, d_model, n_heads, d_ff):
super().__init__()
self.attn = MultiHeadAttention(d_model, n_heads)
self.norm1 = nn.LayerNorm(d_model)
self.norm2 = nn.LayerNorm(d_model)
self.ff = nn.Sequential(
nn.Linear(d_model, d_ff),
nn.GELU(),
nn.Linear(d_ff, d_model)
)
def forward(self, x, mask=None):
x = x + self.attn(self.norm1(x), mask)
x = x + self.ff(self.norm2(x))
return x
Un LLM (Large Language Model) es un Transformer gigante entrenado para predecir el siguiente token.
- Preentrenamiento: lee billones de palabras.
- Instruction Tuning: se ajusta con pares instrucción-respuesta.
- RLHF / DPO: alineación con preferencias humanas.
- Despliegue: inferencia con prompts.
- Fine-tuning / LoRA: adaptación a dominios.
| Parámetro | Qué hace |
|---|---|
temperature | Aleatoriedad (0 = determinista, 1.5 = caótico) |
top_k | Elegir entre los k más probables |
top_p | Elegir entre los que sumen p de probabilidad |
max_tokens | Límite de tokens a generar |
RAG combina el LLM con una base de conocimiento externa.
pregunta = "¿Capital de Australia?"
embedding = embed(pregunta)
docs = vector_db.search(embedding, top_k=3)
prompt = f"Contexto: {docs}\nPregunta: {pregunta}"
respuesta = llm.generate(prompt)
- Zero-shot: sin ejemplos.
- Few-shot: con ejemplos.
- Chain of Thought: "piensa paso a paso".
- Role prompting: "actúa como experto en…".
| Componente | Tiempo | Espacio |
|---|---|---|
| Self-Attention | O(n² · d) | O(n² + n·d) |
| Feed-Forward | O(n · d²) | O(n · d) |
| Multi-Head | O(n² · d + n · d²) | O(n² · h + n · d) |
FlashAttention
Reordena los cálculos para minimizar accesos a memoria HBM. Acelera 2–4× en GPU.
Sparse Attention (Longformer, BigBird)
Solo se calcula atención entre tokens cercanos o seleccionados. O(n · √n).
Linear Attention (Performer)
Aproxima el softmax con kernels. Complejidad O(n · d²).
Sliding Window (Mistral)
Cada token atiende solo a los w anteriores. Muy eficiente en práctica.
RoPE (Rotary Position Embedding)
Rota Q y K en el plano complejo. Usado en Llama, Qwen.
GQA / MQA
Comparten K y V entre varias cabezas Q. Reduce el KV-cache. Usado en Llama 3.
Con B ∈ ℝd×r, A ∈ ℝr×k, r ≪ d. Solo se entrenan A y B (<1% de parámetros).
from peft import LoraConfig, get_peft_model
config = LoraConfig(
r=8,
lora_alpha=16,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05
)
model = get_peft_model(base_model, config)
RLHF: reward model + PPO.
DPO: optimización directa de preferencias sin RL.
Chinchilla (2022): óptimo N ≈ D/20. Más datos, menos parámetros.
class MiniGPT(nn.Module):
def __init__(self, vocab_size, d_model=256,
n_heads=8, n_layers=6, d_ff=1024):
super().__init__()
self.token_emb = nn.Embedding(vocab_size, d_model)
self.pos_emb = nn.Embedding(512, d_model)
self.blocks = nn.ModuleList([
TransformerBlock(d_model, n_heads, d_ff)
for _ in range(n_layers)
])
self.norm = nn.LayerNorm(d_model)
self.head = nn.Linear(d_model, vocab_size, bias=False)
def forward(self, idx, mask=None):
B, T = idx.shape
pos = torch.arange(T, device=idx.device).unsqueeze(0)
x = self.token_emb(idx) + self.pos_emb(pos)
for block in self.blocks:
x = block(x, mask)
x = self.norm(x)
return self.head(x)
- 📄 Attention Is All You Need (Vaswani et al., 2017)
- 📄 Chinchilla (Hoffmann et al., 2022)
- 📄 LoRA (Hu et al., 2021)
- 📄 FlashAttention (Dao et al., 2022)
- 📄 DPO (Rafailov et al., 2023)
- 🎥 CS224n (Stanford), CS25 (Transformers)
- 🛠️ Hugging Face, nanoGPT (Karpathy)
