We track training and validation loss to see how well our model learns and if it works well on new data.
Training and validation loss tracking in PyTorch
for epoch in range(num_epochs): model.train() train_loss = 0 for inputs, targets in train_loader: optimizer.zero_grad() outputs = model(inputs) loss = loss_function(outputs, targets) loss.backward() optimizer.step() train_loss += loss.item() train_loss /= len(train_loader) model.eval() val_loss = 0 with torch.no_grad(): for inputs, targets in val_loader: outputs = model(inputs) loss = loss_function(outputs, targets) val_loss += loss.item() val_loss /= len(val_loader) print(f"Epoch {epoch+1}, Training Loss: {train_loss:.4f}, Validation Loss: {val_loss:.4f}")
Use model.train() before training and model.eval() before validation to set correct modes.
Use torch.no_grad() during validation to save memory and computation.
train_loss = 0 for inputs, targets in train_loader: optimizer.zero_grad() outputs = model(inputs) loss = loss_function(outputs, targets) loss.backward() optimizer.step() train_loss += loss.item() train_loss /= len(train_loader)
val_loss = 0 with torch.no_grad(): for inputs, targets in val_loader: outputs = model(inputs) loss = loss_function(outputs, targets) val_loss += loss.item() val_loss /= len(val_loader)
This program trains a simple linear model to fit y = 2x + 1 with some noise. It prints training and validation loss for 5 epochs.
import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import DataLoader, TensorDataset # Simple dataset: y = 2x + 1 x_train = torch.linspace(0, 1, 100).unsqueeze(1) y_train = 2 * x_train + 1 + 0.1 * torch.randn_like(x_train) x_val = torch.linspace(0, 1, 20).unsqueeze(1) y_val = 2 * x_val + 1 + 0.1 * torch.randn_like(x_val) train_dataset = TensorDataset(x_train, y_train) val_dataset = TensorDataset(x_val, y_val) train_loader = DataLoader(train_dataset, batch_size=10) val_loader = DataLoader(val_dataset, batch_size=5) # Simple linear model model = nn.Linear(1, 1) loss_function = nn.MSELoss() optimizer = optim.SGD(model.parameters(), lr=0.1) num_epochs = 5 for epoch in range(num_epochs): model.train() train_loss = 0 for inputs, targets in train_loader: optimizer.zero_grad() outputs = model(inputs) loss = loss_function(outputs, targets) loss.backward() optimizer.step() train_loss += loss.item() train_loss /= len(train_loader) model.eval() val_loss = 0 with torch.no_grad(): for inputs, targets in val_loader: outputs = model(inputs) loss = loss_function(outputs, targets) val_loss += loss.item() val_loss /= len(val_loader) print(f"Epoch {epoch+1}, Training Loss: {train_loss:.4f}, Validation Loss: {val_loss:.4f}")
Training loss usually decreases every epoch.
If validation loss starts increasing while training loss decreases, the model may be overfitting.
Use small batches to get smoother loss estimates.
Track training and validation loss to monitor model learning and generalization.
Use model.train() and model.eval() to switch modes correctly.
Calculate average loss over batches for clear progress tracking.
Practice
Solution
Step 1: Understand the purpose of training loss
Training loss shows how well the model fits the training data during learning.Step 2: Understand the purpose of validation loss
Validation loss shows how well the model performs on unseen data, indicating generalization.Final Answer:
To monitor if the model is learning and generalizing well to new data -> Option CQuick Check:
Training and validation loss track learning and generalization [OK]
- Thinking validation loss speeds up training
- Confusing loss tracking with batch size changes
- Assuming loss tracking reduces parameters
Solution
Step 1: Recall PyTorch modes
model.train() sets the model to training mode, enabling dropout and batch norm updates.Step 2: Identify validation mode
model.eval() sets the model to evaluation mode, disabling dropout and batch norm updates for stable validation.Final Answer:
model.eval() -> Option BQuick Check:
Use model.eval() before validation [OK]
- Using model.train() during validation
- Assuming model.validate() exists
- Confusing freeze() with eval()
train_losses = []
for inputs, targets in train_loader:
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, targets)
loss.backward()
optimizer.step()
train_losses.append(loss.item())
avg_train_loss = sum(train_losses) / len(train_losses)
print(f"Average training loss: {avg_train_loss:.4f}")
Assuming losses per batch are [0.8, 0.6, 0.4], what is the output?Solution
Step 1: Sum the batch losses
Sum = 0.8 + 0.6 + 0.4 = 1.8Step 2: Calculate average loss
Average = 1.8 / 3 = 0.6Final Answer:
Average training loss: 0.6000 -> Option DQuick Check:
Sum 1.8 / 3 batches = 0.6 [OK]
- Printing sum instead of average
- Dividing by wrong number of batches
- Using loss tensor instead of loss.item()
model.eval()
val_losses = []
for inputs, targets in val_loader:
outputs = model(inputs)
loss = criterion(outputs, targets)
val_losses.append(loss)
avg_val_loss = sum(val_losses) / len(val_losses)
print(f"Validation loss: {avg_val_loss:.4f}")Solution
Step 1: Check what is appended to val_losses
The code appends loss tensors, not scalar values.Step 2: Understand sum behavior on tensors list
Summing loss tensors retains computation graphs from each forward pass, preventing memory release and causing high memory usage over multiple epochs.Final Answer:
Appending loss tensor instead of loss.item() -> Option AQuick Check:
Use loss.item() to get scalar loss [OK]
- Appending loss tensor directly
- Confusing model.train() and model.eval() roles
- Expecting loss calculation to stop in eval mode
Solution
Step 1: Understand loss tracking per epoch
We need to store average losses per epoch separately for training and validation.Step 2: Use separate lists and append averages
Appending average loss per epoch to separate lists allows clear plotting and comparison.Final Answer:
Use separate lists for training and validation losses, append average loss each epoch, then plot both lists -> Option AQuick Check:
Track average losses per epoch separately [OK]
- Mixing batch losses in one list
- Ignoring validation loss tracking
- Using model.train() during validation
Ready to prove it?
Pass the test and this pattern moves unknown
