Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Module 2.4 — PyTorch in Depth

Mode: curated breadth Gate: build gate Est. effort: 8–12 focused hours

You used PyTorch in Module 2.1 to get a network running, and you built the engine underneath it in Modules 2.2 and 2.3. Now you connect the two: you will understand exactly what PyTorch is doing, because you have done it by hand, and you will learn to wield it well. This is the framework you will use for the rest of the curriculum.

Why this matters

You now know what an autograd engine and a training loop really are, because you built them. That puts you in the best possible position to learn PyTorch properly: not as magic, but as a fast, well-engineered version of the machinery you already understand. The goal of this module is fluency. You should be able to reach for the right PyTorch construct without friction, read other people’s PyTorch, and know which part of the framework maps to which part of your from-scratch code.

The payoff is leverage. Every later module (CNNs, transformers, fine-tuning) is written in PyTorch. Time spent now becoming genuinely comfortable with tensors, autograd, nn.Module, and the data pipeline pays back many times over.

What you will be able to do

By the end of this module you will be able to:

Prerequisites

PyTorch: the essentials

Here is the mental map, so the tutorials below have somewhere to land. PyTorch is your from-scratch engine, scaled and hardened:

The canonical training loop, which you will write a hundred times:

for epoch in range(epochs):
    for xb, yb in train_loader:
        optimizer.zero_grad()          # clear old gradients
        preds = model(xb)              # forward
        loss = loss_fn(preds, yb)      # compute loss
        loss.backward()                # backward (autograd)
        optimizer.step()               # update weights

That loop is the entire heart of deep learning in PyTorch. Everything else is variations on it.

Curated path

  1. PyTorch, “Learn the Basics,” in full. You skimmed this in Module 2.1; now work it thoroughly, especially the tensors, autograd, build_model, and optimization sections. https://pytorch.org/tutorials/beginner/basics/intro.html

  2. The autograd mechanics explainer. Read the official “A Gentle Introduction to torch.autograd” and notice how grad_fn is exactly the _backward closures from your own engine. https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html

  3. Karpathy makemore, the PyTorch-ification parts. Watching Karpathy move the same model from raw tensors into clean PyTorch modules reinforces the mapping between your code and the framework. https://github.com/karpathy/nn-zero-to-hero

Deliberately skip for now: distributed training, mixed precision, and custom CUDA. Those are Phase 4. Here, master single-device PyTorch.

Knowledge check

  1. What two things does a PyTorch tensor track that a NumPy array does not?

  2. Walk through what loss.backward() does, in terms of the engine you built in Module 2.2.

  3. Why must you call optimizer.zero_grad() each iteration? What bug appears if you forget?

  4. What is the role of nn.Module, and what goes in __init__ versus forward?

  5. What do Dataset and DataLoader each do for you?

  6. In the standard training loop, what is the precise order of the four key calls, and why does the order matter?

Build gate

Reimplement your Module 2.3 MLP in idiomatic PyTorch and confirm parity.

Specification:

Tests it must pass:

Project

Package it and write a short comparison (reuse your template):

Definition of done: the PyTorch MLP matching your from-scratch accuracy, plus the mapping write-up.

The workshop: ship it

Build this in its own repository, modelwright-pytorch-mlp, using the project habits from Module 0.2.

  1. Set up the project:

mkdir modelwright-pytorch-mlp && cd modelwright-pytorch-mlp
uv init && uv add torch torchvision matplotlib && mkdir src
  1. Write the nn.Module model, the DataLoader pipeline, and the training loop in src/.

  2. Commit at checkpoints: “Model and data pipeline”, then “Training loop and curves”, then “Parity with from-scratch MLP”.

  3. Add a README with your curves and the from-scratch-to-PyTorch mapping note.

  4. Ship it:

gh repo create modelwright-pytorch-mlp --public --source=. --push

(No gh? Create an empty public repo, then git remote add origin <url> and git push -u origin main.)

Done when: modelwright-pytorch-mlp is on GitHub, matches your from-scratch accuracy, and the README explains how the framework maps to what you built by hand.

Going deeper (optional)

Canonical references