PyTorch Essentials — Tensors, Autograd & Training Loop
Tensores, gradientes automáticos y el ciclo de entrenamiento
Un tensor en PyTorch es un array multidimensional que vive en CPU o GPU y puede registrar operaciones para calcular gradientes automáticamente. Es el bloque fundamental de todo en deep learning: imágenes, texto, audio y pesos de modelos son tensores.
Autograd es el motor de diferenciación automática de PyTorch. Cuando creas un tensor con requires_grad=True, cada operación sobre él construye un grafo computacional. Llamar .backward() en el loss recorre ese grafo hacia atrás y deposita los gradientes en el atributo .grad de cada tensor hoja.
nn.Module es la clase base de todos los modelos en PyTorch. Define la arquitectura en __init__ (capas, pesos) y la lógica de forward en forward(). El framework se encarga del backward automáticamente. Piénsalo como un plano arquitectónico: __init__ describe qué materiales tienes, forward describe cómo ensamblarlos.
El ciclo de entrenamiento siempre sigue el mismo patrón: zero_grad → forward → loss → backward → step. Saltarse zero_grad es el bug más frecuente en PyTorch porque los gradientes se acumulan entre iteraciones y las actualizaciones de pesos se vuelven incorrectas.
Los dispositivos (CPU/CUDA/MPS) deben ser consistentes: modelo y datos deben vivir en el mismo device. Un mismatch produce un RuntimeError inmediato. La práctica estándar es definir device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') y mover modelo y tensores con .to(device).
Los optimizadores (Adam, SGD, AdamW) consumen los gradientes calculados por autograd y actualizan los parámetros del modelo. Adam es el punto de partida habitual: adapta el learning rate por parámetro y converge rápido en la mayoría de arquitecturas.
TENSOR CREATION
x = torch.tensor([1.0, 2.0], requires_grad=True)
x = torch.zeros(3, 4) # shape (3, 4), CPU
x = torch.randn(8, 512).to(device)
NN.MODULE TEMPLATE
class MyModel(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(128, 64)
self.fc2 = nn.Linear(64, 10)
def forward(self, x):
x = torch.relu(self.fc1(x))
return self.fc2(x) # raw logits
TRAINING LOOP
model.train()
for batch_x, batch_y in dataloader:
batch_x, batch_y = batch_x.to(device), batch_y.to(device)
optimizer.zero_grad()
logits = model(batch_x)
loss = criterion(logits, batch_y)
loss.backward()
optimizer.step()
INFERENCE
model.eval()
with torch.no_grad():
preds = model(test_x.to(device))Debugging lab
Detecta y corrige el error en el código.
- 3.2.5.1
for batch_x, batch_y in dataloader: logits = model(batch_x) loss = criterion(logits, batch_y) loss.backward() optimizer.step()
- 3.2.5.2
loss = criterion(logits, batch_y) optimizer.step() loss.backward()
- 3.2.5.3
model = MyModel() batch_x = batch_x.to('cuda') logits = model(batch_x)
- 3.2.5.4
model.eval() preds = model(test_x)
- 3.2.5.5
# saving model torch.save(model, 'model.pt') # loading model = torch.load('model.pt')