Bucles de Entrenamiento
Un bucle de entrenamiento repite el pase hacia adelante, el cálculo de la pérdida, el pase hacia atrás y el paso del optimizador a través de lotes y épocas. Los planificadores ajustan la tasa de aprendizaje; los puntos de control preservan el progreso para la reanudación y el despliegue.
Receta
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
for epoch in range(num_epochs):
model.train()
for x, y in train_loader:
x, y = x.to(device), y.to(device)
optimizer.zero_grad(set_to_none=True)
loss = loss_fn(model(x), y)
loss.backward()
optimizer.step()
scheduler.step()Cuándo usar esto:
- Cada modelo de PyTorch necesita un bucle de entrenamiento (a menos que se use Lightning).
- Implementar pases de validación, parada temprana y guardado de puntos de control.
- Ajustar los planes de tasa de aprendizaje y el recorte de gradientes.
- Registrar métricas por época o por paso.
Ejemplo Funcional
"""training_loops.py - bucle completo de entrenamiento/validación con guardado de puntos de control."""
from __future__ import annotations
import torch
import torch.nn as nn
from torch.optim.lr_scheduler import CosineAnnealingLR
from torchvision import datasets, transforms
from torch.utils.data import DataLoader, random_split
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
dataset = datasets.FashionMNIST(root="./data", train=True, download=True, transform=transform)
train_ds, val_ds = random_split(dataset, [50_000, 10_000])
train_loader = DataLoader(train_ds, batch_size=128, shuffle=True, num_workers=2, pin_memory=True)
val_loader = DataLoader(val_ds, batch_size=256, shuffle=False, num_workers=2)
model = nn.Sequential(nn.Flatten(), nn.Linear(784, 256), nn.ReLU(), nn.Linear(256, 10)).to(device)
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=0.01)
scheduler = CosineAnnealingLR(optimizer, T_max=10)
loss_fn = nn.CrossEntropyLoss()
best_val_loss = float("inf")
for epoch in range(10):
model.train()
train_loss = 0.0
for x, y in train_loader:
x, y = x.to(device, non_blocking=True), y.to(device, non_blocking=True)
optimizer.zero_grad(set_to_none=True)
loss = loss_fn(model(x), y)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
optimizer.step()
train_loss += loss.item() * x.size(0)
scheduler.step()
model.eval()
val_loss = 0.0
correct = 0
with torch.inference_mode():
for x, y in val_loader:
x, y = x.to(device), y.to(device)
logits = model(x)
val_loss += loss_fn(logits, y).item() * x.size(0)
correct += (logits.argmax(1) == y).sum().item()
val_loss /= len(val_ds)
acc = correct / len(val_ds)
print(f"epoch {epoch+1}: val_loss={val_loss:.4f} acc={acc:.3f} lr={scheduler.get_last_lr()[0]:.6f}")
if val_loss < best_val_loss:
best_val_loss = val_loss
torch.save({"epoch": epoch, "model": model.state_dict(), "optimizer": optimizer.state_dict()}, "best.pt")Lo que esto demuestra:
- Fases de entrenamiento y validación separadas con cambio de modo correcto.
- Optimizador
AdamWcon decaimiento de peso y planificador de LR cosenoidal. - Recorte de gradientes para estabilidad del entrenamiento.
- Guardado de puntos de control cuando la pérdida de validación mejora.
Inmersión Profunda
Cómo Funciona
- Pase hacia adelante calcula las predicciones y la pérdida.
- Pase hacia atrás calcula los gradientes mediante autograd.
- Paso del optimizador actualiza los parámetros usando gradientes y la tasa de aprendizaje.
- Planificador modifica la LR basándose en el recuento de épocas o pasos.
- Validación se ejecuta en
inference_modesin seguimiento de gradientes.
Selección de Optimizador
| Optimizador | Usar Cuándo | Notas |
|---|---|---|
| AdamW | Por defecto para la mayoría de los modelos | Decaimiento de peso desacoplado |
| SGD + momentum | CNNs con ajuste cuidadoso | A menudo el mejor con planificador de LR |
| Adam | Prototipado rápido | El decaimiento de peso interactúa con la LR adaptativa |
| Lion | Investigación/experimentación | Alternativa eficiente en memoria |
Notas de Python
# Acumulación de gradientes para un tamaño de lote efectivo grande
accum_steps = 4
for i, (x, y) in enumerate(train_loader):
loss = loss_fn(model(x), y) / accum_steps
loss.backward()
if (i + 1) % accum_steps == 0:
optimizer.step()
optimizer.zero_grad(set_to_none=True)Errores Comunes
- No llamar a
model.eval()para la validación - dropout aleatoriza y batch norm usa estadísticas del lote. Solución:model.eval()antes de la validación;model.train()antes del entrenamiento. - Registrar la pérdida sin promediar - las pérdidas de lote crudas son ruidosas. Solución: acumular
loss.item() * batch_sizey dividir por el tamaño del conjunto de datos. - Pasar el planificador cada lote vs época - forma de planificador incorrecta. Solución: hacer coincidir el tipo de planificador (
step()por época paraCosineAnnealingLR). - Sin punto de control en la mejor validación - se pierde el mejor modelo si el entrenamiento continúa y se sobreajusta. Solución: guardar al mejorar la validación.
- Tasa de aprendizaje demasiado alta - la pérdida se convierte en NaN o diverge. Solución: empezar con 1e-3 para Adam, 0.1 para SGD; usar calentamiento (warmup).
- Olvidar mover los datos al dispositivo - errores de discrepancia CPU/GPU. Solución:
x.to(device, non_blocking=True)en el bucle.
Alternativas
| Alternativa | Usar Cuándo | No Usar Cuándo |
|---|---|---|
| Bucle manual | Aprendizaje, control total | Boilerplate repetitivo entre proyectos |
| PyTorch Lightning | Estructura de entrenamiento de producción | Depuración de los fundamentos de autograd |
| HuggingFace Trainer | Ajuste fino de Transformers | Arquitecturas CNN personalizadas |
torch.compile | Acelerar el pase hacia adelante/atrás | Depuración de inestabilidad en el entrenamiento |
Preguntas Frecuentes
¿Qué función de pérdida para clasificación?
CrossEntropyLosspara multiclase (incluye softmax).BCEWithLogitsLosspara binario multietiqueta.- Pasar logits crudos, no salidas softmax.
¿Cuántas épocas debo entrenar?
- Hasta que la métrica de validación se estabilice (parada temprana).
- 10-100 para conjuntos de datos pequeños; monitorizar la pérdida de validación cada época.
¿Qué es el decaimiento de peso?
- Regularización L2 aplicada a los pesos en AdamW.
weight_decay=0.01es un punto de partida común.- Reduce el sobreajuste en conjuntos de datos pequeños.
¿Cuándo debo usar acumulación de gradientes?
- Cuando la memoria de la GPU limita el tamaño del lote pero necesitas un lote efectivo más grande.
- Dividir la pérdida por los pasos de acumulación antes de backward.
- Avanzar el optimizador cada N lotes.
¿Cómo reanudo desde un punto de control?
ckpt = torch.load("best.pt", weights_only=True)
model.load_state_dict(ckpt["model"])
optimizer.load_state_dict(ckpt["optimizer"])
start_epoch = ckpt["epoch"] + 1¿Qué planificador de tasa de aprendizaje debo usar?
CosineAnnealingLR- decaimiento suave, popular por defecto.OneCycleLR- convergencia rápida con calentamiento.ReduceLROnPlateau- reducir cuando la métrica de validación se estanca.
¿Cómo detecto el sobreajuste?
- La pérdida de entrenamiento disminuye mientras la pérdida de validación aumenta.
- Añadir dropout, decaimiento de peso, aumento de datos o parada temprana.
¿Debo barajar cada época?
- Sí para el entrenamiento (
shuffle=Trueen DataLoader). - Barajar evita que el modelo aprenda artefactos del orden de los lotes.
¿Qué es la parada temprana?
- Detener el entrenamiento cuando la métrica de validación no mejora durante N épocas.
- Restaurar los pesos del mejor punto de control.
¿Cómo registro las métricas de entrenamiento?
- Imprimir por época para scripts simples.
- Usar TensorBoard (
torch.utils.tensorboard), W&B o MLflow para producción.
¿Qué es el calentamiento (warmup)?
- Incrementar gradualmente la LR desde casi cero durante los primeros N pasos.
- Estabiliza el entrenamiento para transformers y tamaños de lote grandes.
- Implementado en
OneCycleLRo planificadores personalizados.
¿Puedo entrenar en CPU?
- Sí para modelos pequeños y depuración.
- La GPU es esencial para un tiempo de entrenamiento razonable en imágenes o datos grandes.
Relacionado
- Autograd - mecánica del pase backward
- Datasets & DataLoaders - entrada por lotes
- GPUs & Mixed Precision - entrenamiento más rápido
- PyTorch Lightning - bucles estructurados
- Saving, Loading & Export - formato de punto de control
Versiones de la Pila: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, y uv 0.6+.