LECCIÓN 10

Red en PyTorch

El cierre. Todo lo que aprendiste a mano, ahora en su forma profesional: definir la red con nn.Module, elegir un optimizador y entrenar XOR en unas pocas líneas hasta resolverlo.

1. Definir la red con nn.Module

En vez de manejar W₁, b₁, W₂, b₂ a mano, los empaquetamos en capas nn.Linear. Cada nn.Linear(entradas, salidas) contiene su matriz de pesos y su bias, y los inicializa al azar por ti.

import torch
import torch.nn as nn

class XORNet(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(2, 2)   # capa oculta: 2 → 2
        self.fc2 = nn.Linear(2, 1)   # capa salida:  2 → 1

    def forward(self, x):
        h = torch.sigmoid(self.fc1(x))   # oculta + activación
        y = torch.sigmoid(self.fc2(h))   # salida + activación
        return y

net = XORNet()
Es la misma arquitectura 2-2-1 de todo el curso. nn.Linear(2,2) es literalmente la operación x @ W + b de la lección 3. Solo que ahora PyTorch guarda y actualiza los pesos por ti.

2. Los datos, la pérdida y el optimizador

# Las 4 filas de la tabla de verdad de XOR
X = torch.tensor([[0.,0.],[0.,1.],[1.,0.],[1.,1.]])
Y = torch.tensor([[0.],   [1.],   [1.],   [0.]])

loss_fn = nn.MSELoss()                              # pérdida (lección 5)
optim   = torch.optim.Adam(net.parameters(), lr=0.1) # el que da los pasos

El optimizador automatiza la regla w = w − lr·gradiente de la lección 6. Usamos Adam en vez del descenso simple: ajusta el paso solo y converge mucho más rápido (recuerda la meseta lenta de la lección 8).

3. El bucle de entrenamiento (el ciclo de la lección 8, en código)

torch.manual_seed(1)   # para reproducir este resultado exacto

for epoca in range(2001):
    optim.zero_grad()         # 0. limpiar gradientes anteriores
    pred = net(X)             # 1. forward  → predicciones
    loss = loss_fn(pred, Y)   # 2. pérdida
    loss.backward()           # 3. backward → gradientes (autograd)
    optim.step()              # 4. actualizar pesos

¿Reconoces los 4 pasos? Son exactamente el ciclo de la lección 8. Esto imprime:

época    0: loss=0.25477
época  100: loss=0.20232
época  250: loss=0.00071
época  500: loss=0.00023
época 1000: loss=0.00007
época 2000: loss=0.00002  ← resuelto ✅

4. El resultado: XOR resuelto

print(net(X))   # predicciones finales
x₁x₂XOR (target)predicción de la red
0000.006
0110.996
1010.996
1100.004
🎲 Honestidad sobre XOR: con una red tan pequeña (2 neuronas ocultas), el resultado depende de la inicialización aleatoria. Con algunas semillas la red queda atascada en un mínimo local (pérdida ≈ 0.167, no aprende). Por eso fijamos seed=1. En redes reales esto se mitiga con más neuronas y mejores inicializaciones — pero es bueno que sepas que el entrenamiento no siempre es mágico al primer intento.

5. 🎓 Lo que aprendiste en todo el curso

LecciónConcepto
1La neurona: suma ponderada (w·x + b)
2Activación: la chispa no-lineal (sigmoid)
3Capa = multiplicación de matrices
4Forward pass: el viaje completo del dato
5Pérdida: medir el error con un número
6Gradiente: la pendiente que indica por dónde bajar
7Backpropagation: la regla de la cadena hacia atrás
8Entrenamiento: repetir el ciclo miles de veces
9Autograd: PyTorch reproduce tu backprop, automático
10nn.Module: la red completa, lista para escalar
¡Completaste el curso! Empezaste con una sola neurona y terminaste entrenando una red que resuelve XOR en PyTorch — entendiendo cada número del camino, sin gaps. Y lo mejor: estas mismas piezas (sumas ponderadas, activaciones, backprop, autograd) son exactamente las que construyen un Transformer. Ahora tienes la base para entenderlo todo. 🚀