Pytorch training loop
Production-grade Machine Learning, Data Science & MLOps skills for AI coding agents (Codex, Claude Code, Cursor, OpenCode). One npx command to install.
npx -y skills add param087/agent-ml-skills --skill pytorch-training-loopAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use when writing or reviewing a PyTorch training loop. Covers correct train/eval modes, gradient handling, mixed precision, checkpointing, reproducibility, and device management.
SKILL.md
3.3 KB, as published. Nobody here has run it
PyTorch Training Loop
Overview
A correct PyTorch loop has a precise sequence of operations. Getting the order or the modes wrong produces silent bugs (no gradients, dropout active at eval, leaked compute graphs). This skill encodes the canonical, production-ready loop.
When to use
- Writing a training loop from scratch.
- Debugging a model that won't learn or OOMs.
- Reviewing PyTorch training code.
Canonical loop
import torch
from torch.amp import autocast, GradScaler
device = "cuda" if torch.cuda.is_available() else "cpu"
model.to(device)
optimizer = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.01)
scaler = GradScaler(enabled=(device == "cuda"))
best_val = float("inf")
for epoch in range(num_epochs):
# ---- TRAIN ----
model.train()
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)
with autocast(device_type=device, enabled=(device == "cuda")):
out = model(x)
loss = criterion(out, y)
scaler.scale(loss).backward()
scaler.unscale_(optimizer)
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
scaler.step(optimizer)
scaler.update()
# ---- VALIDATE ----
model.eval()
val_loss = 0.0
with torch.no_grad():
for x, y in val_loader:
x, y = x.to(device), y.to(device)
val_loss += criterion(model(x), y).item() * x.size(0)
val_loss /= len(val_loader.dataset)
# ---- CHECKPOINT BEST ----
if val_loss < best_val:
best_val = val_loss
torch.save({"model": model.state_dict(),
"optimizer": optimizer.state_dict(),
"epoch": epoch}, "best.pt")
Non-negotiable rules
model.train()before training,model.eval()before validation/inference (toggles dropout & batchnorm).optimizer.zero_grad()every step — gradients accumulate otherwise.- Wrap validation/inference in
torch.no_grad()(orinference_mode()) to save memory. - Detach when logging:
loss.item(), notloss— keeping tensors leaks the graph and OOMs. - Clip gradients for RNNs/transformers to prevent explosions.
Reproducibility header
import torch, numpy as np, random
def seed_everything(seed=42):
random.seed(seed); np.random.seed(seed)
torch.manual_seed(seed); torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
Pitfalls
- Forgetting
zero_grad→ gradients pile up, training diverges. eval()never called → dropout/batchnorm corrupt validation metrics.- Accumulating
total_loss += loss(tensor, not.item()) → memory explosion. - DataLoader with
num_workers=0on large data → CPU-bound; raise workers +pin_memory=True. - LR too high → NaN loss; see the
ml-debuggingskill.
Hand-off
A checkpointed model + seed config that experiment-tracking logs and model-serving loads for inference.