La tabla bigram es rígida: solo sabe lo que vio. Una red neuronal puede generalizar — predecir combinaciones que nunca vio antes. Eso es lo que hace posible el lenguaje.
Imagina dos cocineros. El primero tiene un libro de recetas con todas las combinaciones exactas de ingredientes que alguna vez funcionaron. Si le pides un plato con un ingrediente nuevo que no está en su libro, responde "no sé" — no puede improvisar.
El segundo cocinero aprendió principios: qué sabores se complementan, cómo afecta la temperatura, cuándo una salsa necesita más acidez. Si le pides algo nuevo, puede razonar desde lo que sabe.
El dataset tiene 32.000 nombres. Pero el número de posibles pares de caracteres es 27 × 27 = 729. La mayoría aparece en el dataset. Sin embargo:
La tabla tiene valores fijos (conteos). La red tiene pesos continuos que se ajustan durante el entrenamiento para minimizar el error.
El modelo train1.py de Karpathy reemplaza la tabla por una red de 3 capas muy simple:
El token de entrada se convierte en un embedding (vector de 16 números), pasa por una capa oculta con ReLU, produce 27 logits (uno por posible siguiente carácter) y softmax convierte los logits en probabilidades.
ReLU (Rectified Linear Unit) es la función de activación más simple que existe. Su regla: si el número es negativo, devuelve cero; si es positivo, lo devuelve igual.
ReLU(x) = max(0, x) Ejemplos: ReLU(-3.5) = 0.0 ← negativo → aplana a cero ReLU(-0.1) = 0.0 ← negativo → aplana a cero ReLU(0.0) = 0.0 ← exactamente cero → cero ReLU(2.7) = 2.7 ← positivo → pasa igual ReLU(8.1) = 8.1 ← positivo → pasa igual ¿Por qué necesitamos ReLU? Sin activación no lineal, apilar capas lineales no sirve de nada: capa2(capa1(x)) = W2(W1·x) = (W2·W1)·x = una sola capa lineal Con ReLU entre capas, la red puede aprender patrones no lineales (como que "k" antes de vocal tiene un patrón distinto a "k" antes de consonante).
Los dos modelos reciben el mismo carácter inicial. El bigram solo mira ese carácter. El MLP usa un embedding de 16 dimensiones que captura más contexto.
* El MLP es simulado con distribuciones entrenadas. En el código real, los pesos se aprenden por gradiente.
train1.py introduce un MLP: token → embedding → capa oculta → logits → softmax.