Training Loops
Um loop de treinamento repete a passagem forward, o cálculo da perda, a passagem backward e o passo do otimizador entre batches e épocas. Schedulers ajustam a taxa de aprendizado; checkpoints preservam o progresso para retomada e implantação.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
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()Quando usar isso:
- Todo modelo PyTorch precisa de um loop de treinamento (a menos que use Lightning).
- Implementando passes de validação, early stopping e checkpointing.
- Ajustando schedules de taxa de aprendizado e gradient clipping.
- Registrando métricas por época ou por passo.
Exemplo Funcional
"""training_loops.py - loop completo de treino/val com checkpointing."""
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")O que isso demonstra:
- Fases separadas de treino e validação com troca de modo correta.
- Otimizador
AdamWcom weight decay e schedule de LR cosseno. - Gradient clipping para estabilidade de treinamento.
- Salvamento de checkpoint quando a perda de validação melhora.
Mergulho Profundo
Como Funciona
- Passagem forward calcula predições e perda.
- Passagem backward calcula gradientes via autograd.
- Passo do otimizador atualiza parâmetros usando gradientes e taxa de aprendizado.
- Scheduler modifica LR com base na contagem de época ou passo.
- Validação executa em
inference_modesem rastreamento de gradiente.
Seleção de Otimizador
| Otimizador | Usar Quando | Notas |
|---|---|---|
| AdamW | Padrão para a maioria dos modelos | Weight decay desacoplado |
| SGD + momentum | CNNs com ajuste cuidadoso | Frequentemente melhor com schedule de LR |
| Adam | Prototipagem rápida | Weight decay interage com LR adaptativo |
| Lion | Pesquisa/experimentação | Alternativa eficiente em memória |
Notas Python
# Acumulação de gradiente para tamanho de batch efetivo 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)Armadilhas
- Não chamar model.eval() para validação - dropout randomiza e batch norm usa estatísticas do batch. Correção:
model.eval()antes da validação;model.train()antes do treino. - Registrar perda sem média - perdas de batch brutas são ruidosas. Correção: acumular
loss.item() * batch_sizee dividir pelo tamanho do dataset. - Chamar scheduler a cada batch vs época - forma incorreta do schedule. Correção: corresponder ao tipo de scheduler (
step()por época para CosineAnnealingLR). - Sem checkpoint na melhor validação - perde o melhor modelo se o treinamento continuar e ocorrer overfitting. Correção: salvar na melhoria da validação.
- Taxa de aprendizado muito alta - perda NaNs ou diverge. Correção: começar com 1e-3 para Adam, 0.1 para SGD; usar warmup.
- Esquecer de mover dados para o dispositivo - erros de incompatibilidade CPU/GPU. Correção:
x.to(device, non_blocking=True)no loop.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Loop manual | Aprendizado, controle total | Boilerplate repetitivo entre projetos |
| PyTorch Lightning | Estrutura de treinamento de produção | Depuração de fundamentos de autograd |
| HuggingFace Trainer | Fine-tuning de Transformers | Arquiteturas CNN customizadas |
torch.compile | Acelerar forward/backward | Depuração de instabilidade de treinamento |
FAQs
Qual função de perda para classificação?
CrossEntropyLosspara multi-classe (inclui softmax).BCEWithLogitsLosspara binário multi-label.- Passe logits brutos, não saídas softmax.
Quantas épocas devo treinar?
- Até a métrica de validação estabilizar (early stopping).
- 10-100 para datasets pequenos; monitore a perda de validação a cada época.
O que é weight decay?
- Regularização L2 aplicada aos pesos no AdamW.
weight_decay=0.01é um bom ponto de partida.- Reduz overfitting em datasets pequenos.
Quando devo usar acumulação de gradiente?
- Quando a memória da GPU limita o tamanho do batch, mas você precisa de um batch efetivo maior.
- Divida a perda por passos de acumulação antes do backward.
- Use o otimizador a cada N batches.
Como retomar de um checkpoint?
ckpt = torch.load("best.pt", weights_only=True)
model.load_state_dict(ckpt["model"])
optimizer.load_state_dict(ckpt["optimizer"])
start_epoch = ckpt["epoch"] + 1Qual scheduler de taxa de aprendizado devo usar?
CosineAnnealingLR- decaimento suave, padrão popular.OneCycleLR- convergência rápida com warmup.ReduceLROnPlateau- reduz quando a métrica de validação estagna.
Como detectar overfitting?
- Perda de treinamento diminui enquanto a perda de validação aumenta.
- Adicione dropout, weight decay, data augmentation ou early stopping.
Devo embaralhar a cada época?
- Sim para treinamento (
shuffle=Trueno DataLoader). - Embaralhar impede que o modelo aprenda artefatos da ordem do batch.
O que é early stopping?
- Para o treinamento quando a métrica de validação não melhora por N épocas.
- Restaura os pesos do melhor checkpoint.
Como registrar métricas de treinamento?
- Imprima por época para scripts simples.
- Use TensorBoard (
torch.utils.tensorboard), W&B ou MLflow para produção.
O que é warmup?
- Aumenta gradualmente o LR de perto de zero para os primeiros N passos.
- Estabiliza o treinamento para transformers e tamanhos de batch grandes.
- Implementado em
OneCycleLRou schedulers customizados.
Posso treinar na CPU?
- Sim para modelos pequenos e depuração.
- GPU é essencial para tempo de treinamento razoável em imagens ou dados grandes.
Relacionados
- Autograd - mecânica da passagem backward
- Datasets & DataLoaders - entrada em batch
- GPUs & Mixed Precision - treinamento mais rápido
- PyTorch Lightning - loops estruturados
- Saving, Loading & Export - formato de checkpoint
Versões da Stack: Esta página foi escrita para Python 3.14.0 (stable 3.14, maintenance 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+, e uv 0.6+.