3.3.5Deep Learning Frameworks

Training loops from scratch

2,949 words13 min readdifficulty · medium

What is a training loop?

The training loop is the iterative process that transforms random weights into a trained model. At its core, it implements empirical risk minimization: find parameters θ\theta that minimize average loss over training data.

WHY these components? Each step solves a specific problem:

  • Forward pass: "What does my current model predict?"
  • Loss: "How wrong am I?" (scalar measure of error)
  • Backward: "Which weights caused this error?" (gradient flow)
  • Update: "How should I adjust weights to reduce error?"
  • Iteration: "Am I generalizing, or just memorizing?"

Deriving the training loop from first principles

Starting point: The optimization objective

We want to minimize expected risk: R(θ)=E(x,y)D[L(f(x;θ),y)]\mathcal{R}(\theta) = \mathbb{E}_{(x,y) \sim \mathcal{D}}[\mathcal{L}(f(x;\theta), y)]

WHY this form? We care about performance on unseen data from distribution D\mathcal{D}, not just training examples.

Since we don't know D\mathcal{D}, we approximate with empirical risk: R^(θ)=1Ni=1NL(f(xi;θ),yi)\hat{\mathcal{R}}(\theta) = \frac{1}{N}\sum_{i=1}^{N} \mathcal{L}(f(x_i;\theta), y_i)

WHY the average? Raw sum grows with dataset size; averaging makes loss magnitude dataset-independent.

From objective to iterative updates

Direct minimization is intractable for neural networks (non-convex, millions of parameters). Instead, we use gradient descent:

θt+1=θtηθR^(θt)\theta_{t+1} = \theta_t - \eta \nabla_\theta \hat{\mathcal{R}}(\theta_t)

WHY this works: Gradient θR^\nabla_\theta \hat{\mathcal{R}} points toward stepest increase in loss; moving opposite (negative gradient) decreases loss locally.

The problem: Computing θR^\nabla_\theta \hat{\mathcal{R}} requires full-dataset pass—expensive!

The solution: Stochastic Gradient Descent (SGD) approximates the gradient using a mini-batch:

θR^1BibatchθL(f(xi;θ),yi)\nabla_\theta \hat{\mathcal{R}} \approx \frac{1}{B}\sum_{i \in \text{batch}} \nabla_\theta \mathcal{L}(f(x_i;\theta), y_i)

WHY batches? Single examples are too noisy; full dataset is too slow; mini-batches balance variance and computation.

Implementation from scratch: Step-by-step

Common mistakes and fixes

Advanced: Learning rate scheduling and early stopping

A fixed learning rate often underperforms. Learning rate scheduling adapts η\eta during training.

WHY schedule? Early training needs large steps to escape initialization; late training needs small steps to settle into minima.

Early stopping prevents overfitting by monitoring validation loss:

best_val_loss = float('inf')
patience = 10  # Epochs to wait for improvement
patience_counter = 0
 
for epoch in range(max_epochs):
    train_loss = train_one_epoch(model, train_loader, optimizer)
    val_loss = evaluate(model, val_loader)
    if val_loss < best_val_loss:
        best_val_loss = val_loss
        save_checkpoint(model, 'best_model.pth')
        patience_counter = 0
    else:
        patience_counter += 1
    if patience_counter >= patience:
        print(f"Early stopping at epoch {epoch}")
        break

WHY this works: Validation loss increases when model starts memorizing training noise → stop before overfitting worsens.

Diagram: Training loop flow

Figure — Training loops from scratch
Recall Explain to a 12-year-old

Imagine you're learning to shoot basketball free throws, but you're blindfolded and can only feel how far you missed.

Training loop is like this practice routine:

  1. Shoot the ball (forward pass) - you take a shot with your current technique
  2. Feel where it landed (compute loss) - did you miss left, right, short, or long?
  3. Figure out what went wrong (backward pass) - was your elbow too high? Did you use too much power?
  4. Adjust your form (update parameters) - bend your elbow a little less, ease up on the power
  5. Shoot again (next iteration) - try with your adjusted technique

Each shot teaches you something small. After hundreds of shots (epochs), your muscle memory (weights) gets really good at hitting the basket. The "learning rate" is like how much you adjust each time - big changes early when you're way off, tiny tweaks later when you're close. The magic is that you never need to see the basket - just feeling the error and adjusting step-by-step eventually makes you a great shooter!

Connections

  • 3.1.02-Backpropagation-algorithm - How gradients flow backward (the math behind loss.backward())
  • 3.3.01-PyTorch-fundamentals - Tensors and autograd that power training loops
  • 3.3.06-Custom-loss-functions - What goes into the loss computation step
  • 3.4.03-Learning-rate-schedules - Advanced strategies for the update step
  • 3.4.01-Batch-normalization - Layers that behave differently in train vs eval mode
  • 3.5.02-Data-loaders-and-batching - How batches are prepared for the loop
  • 4.2.01-Gradient-descent-variants - SGD, Adam, RMSprop - different update rules
  • 5.1.01-Overfitting-and-underfitting - Why we monitor train vs validation loss

#flashcards/ai-ml

What are the five core components of a training loop? :: 1. Forward pass (compute predictions), 2. Loss computation (measure error), 3. Backward pass (compute gradients), 4. Parameter update (apply optimizer), 5. Iteration (repeat over batches/epochs)

Why do we use mini-batch SGD instead of full-batch gradient descent?
Full-batch requires computing gradients over entire dataset (slow and memory-intensive). Mini-batches approximate the gradient with much less computation while providing less noisy updates than single-example SGD. Balances variance and efficiency.
What is empirical risk minimization?
Minimizing the average loss over training data as a proxy for minimizing expected risk over the true data distribution. Formula: R^(θ)=1Ni=1NL(f(xi;θ),yi)\hat{\mathcal{R}}(\theta) = \frac{1}{N}\sum_{i=1}^{N} \mathcal{L}(f(x_i;\theta), y_i)
Why must you call optimizer.zero_grad() before backward()?
PyTorch accumulates gradients by default. Without zeroing, gradients from previous batches add to current gradients, causing incorrect gradient magnitudes and exploding gradients. Only intentionally skip when implementing gradient accumulation.
What happens if you forget model.eval() during validation?
Layers like Dropout and BatchNorm use training-mode behavior (random drops, batch statistics instead of running statistics), giving incorrect and typically pessimistic evaluation metrics. Always call model.eval() before validation and model.train() before training.
What is the update rule for SGD with mini-batches?
θt+1=θtηBt(x,y)BtθL(f(x;θt),y)\theta_{t+1} = \theta_t - \frac{\eta}{|\mathcal{B}_t|} \sum_{(x,y) \in \mathcal{B}_t} \nabla_\theta \mathcal{L}(f(x;\theta_t), y) where Bt\mathcal{B}_t is the mini-batch, η\eta is learning rate, and we average the gradient over the batch.
Why do we shuffle training data each epoch?
Prevents model from learning batch order artifacts and correlations between consecutive batches. Without shuffling, corelated samples bias gradient estimates and the model may learn the sequence pattern instead of true underlying patterns.
What is early stopping and why does it work?
Monitoring validation loss and stopping training when it stops improving (after patience period). Works because validation loss increases when model starts overfitting (memorizing training noise), so stopping before this point preserves generalization.
How do you implement gradient accumulation correctly?
Divide loss by accumulation_steps before backward(), accumulate gradients over multiple batches without zero_grad(), then call optimizer.step() and zero_grad() after accumulation_steps batches. This simulates a larger effective batch size.
What is the purpose of learning rate scheduling?
Adapts learning rate during training - large steps early to escape initialization quickly, small steps later to settle into minima without overshooting. Common schedules: step decay, exponential decay, cosine annealing, reduce on plateau.

Concept Map

unknown D, approximate

intractable to minimize

full pass too slow

mini-batch estimate

step 1

feeds

measure error

gradients guide

theta update rule

repeat

Expected Risk objective

Empirical Risk average loss

Gradient Descent

Stochastic Gradient Descent

Training Loop

Forward Pass predictions

Loss computation

Backward Pass gradients

Parameter Update

Iteration batches x epochs

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Training loop deep learning ka dil hai, dost. Socho tumhare pas ek model hai jo bilkul nayi hai, kuch nahi janta. Training loop woh process hai jisse model seekhta hai data se.

Pehle forward pass hota hai - matlab model apna current guess deta hai (prediction). Fir loss function bata hai kitna galat tha (error). Ab magic shuru hoti hai: backpropagation se har weight ko pata chalta hai ki usne kitna contribution diya is error mein. Yeh gradients hain. Phir optimizer (jaise SGD ya Adam) un gradients ka use karke weights ko thoda adjust karta hai, taki agle baar error kam ho.

Yeh sab ek batch ke liye hota hai (32-256 examples). Pura dataset khatam hone tak yeh repeat karta rehta hai - iskoek epoch kehte hain. Kai epochs ke bad model expert ban jata hai. Lekin dhyaan rakho - agar validation loss badhne lage toh early stopping lagao, warna overfitting ho

Go deeper — visual, from zero

Test yourself — Deep Learning Frameworks

Connections