Tres herramientas que separan un entrenamiento amateur de uno profesional: ajustar el learning rate sobre la marcha, controlar gradientes que explotan, y crear tus propias capas.
Un learning rate fijo es un compromiso: grande al principio (avanzar rápido) pero pequeño al final
(afinar sin pasarse). Un scheduler lo reduce automáticamente durante el
entrenamiento. StepLR lo multiplica por gamma cada step_size
épocas:
opt = torch.optim.SGD(params, lr=0.1)
sched = torch.optim.lr_scheduler.StepLR(opt, step_size=2, gamma=0.5)
for epoca in range(6):
# ... entrenar una época ...
opt.step()
sched.step() ← actualizar el learning rate
sched.step()
una vez por época, después de opt.step().
A veces los gradientes se vuelven gigantescos y un solo paso destroza el entrenamiento (típico en redes profundas o recurrentes). El clipping los recorta a un tamaño máximo, conservando su dirección:
w = torch.tensor([3.0, 4.0], requires_grad=True)
(w.sum() * 100).backward() # gradiente enorme
torch.nn.utils.clip_grad_norm_([w], max_norm=1.0)
1) norma del gradiente (longitud del vector):
√(100² + 100²) = √(10000 + 10000) = √20000 = 141.42
2) como 141.42 > max_norm (1.0), se reduce por el factor:
factor = max_norm / norma = 1.0 / 141.42 = 0.007071
3) multiplicar cada componente por el factor:
100 · 0.007071 = 0.7071
100 · 0.007071 = 0.7071
→ misma dirección (ambos iguales), pero norma ahora = 1.0 ✓
El gradiente se redujo para que su "longitud" (norma) no pase de 1, pero mantiene su dirección
(ambos componentes iguales). Va en el bucle entre backward() y
step().
Ya sabes crear modelos con nn.Module. La misma idea sirve para inventar tu propia
capa: hereda de nn.Module y define su forward. Por ejemplo,
una capa que aplica una transformación lineal y le suma la entrada (una "conexión residual", como en
el Transformer):
class BloqueResidual(nn.Module):
def __init__(self, dim):
super().__init__()
self.lin = nn.Linear(dim, dim)
def forward(self, x):
return x + torch.relu(self.lin(x)) # salida + entrada (residual)
nn.Module con un forward,
puedes componer y crear arquitecturas arbitrarias. Las capas que ya viste (Linear,
Conv2d…) son justo esto, escritas por el equipo de PyTorch.