Build Deep Learning From Scratch

View on GitHub

A project-based curriculum that teaches how PyTorch works internally by reimplementing it from the ground up. You start with scalar backpropagation, build a reverse-mode autodiff engine, grow it into an N-dimensional Tensor, then stack neural-network layers, optimizers, training loops, CNNs, attention, a full Transformer, a Vision Transformer, a small but real PyTorch-like framework, and finally capstone projects. The philosophy: you are the autodiff library. Nothing is imported that you haven't already built by hand, so every gradient and every chain-rule accumulation is code you wrote and understand.

The scalar autodiff engine in stages 01-05 is a from-scratch reimplementation of Andrej Karpathy's micrograd: Value(data) (stage 01) → computational graph (stage 02) → per-op _backward closures (stage 03) → the backward() reverse pass (stage 04) → the remaining ops tanh/exp/relu (stage 05). The same engine micrograd packs into one file, built up one concept per stage. Everything afterward generalizes it to tensors.

Tool restriction

The only permitted packages are NumPy (forward array math only — never to compute a derivative for you), Matplotlib (visualization), and pytest (tests). No torch, tensorflow, jax, autograd, tinygrad, micrograd, or any library that does autodiff/backprop for you — until you've built that concept by hand in an earlier stage. See requirements.txt.

How a stage works

Each stage_xx/ directory contains three source files:

  • README.md — context, background (intuition + key equations/gradients), watch (videos), and a zero-ambiguity exercise.
  • code.py — skeleton only: interfaces, signatures, docstrings, and TODOs. No working bodies.
  • test.py — pytest tests, including numerical gradient checks (central differences) wherever gradients exist.

Implement code.py until the tests pass:

pytest stage_xx/test.py

Each stage builds on the code from prior stages (e.g. Value from stage_05, Tensor from stage_08).

One import convention to know: a later stage pulls a symbol from the latest stage that extended it, not from the stage that first created it. Tensor is created in stage_08 but extended in stage_11 (broadcasting) and stage_12 (sum/mean reductions), so stages 13+ do stage_import("stage_12", "Tensor"); likewise Dense is created in stage_10 but extended in stage_11, so later stages import it from stage_11.

Solutions

Reference implementations live on the solutions branch (currently solved through stage 17; later stages are being added as the course is finalized). Check it out (git checkout solutions) only after you've attempted a stage yourself — the whole point is that you write every gradient. The main branch ships skeletons only.

The 35 stages

#StageWhat you build
01Scalar ValuesValue: wrap one number; forward arithmetic via operator overloading.
02Computational GraphRecord each result's parents (_prev set), op (_op), and a no-op _backward hook.
03Local DerivativesInstall per-op _backward closures (the local-derivative push).
04Chain Rulebackward(): topological sort + seed grad=1 + reverse-walk the closures.
05Backprop EngineAdd tanh, exp, relu on the scalar Value; the complete micrograd engine.
06Vector OperationsA Vec container of Values: elementwise ops, dot, sum.
07Matrix OperationsA Mat of Values: matmul/@, transpose, reshape, sum, mean.
08Tensor EngineCollapse scalar graphs onto one N-dim NumPy-backed autodiff Tensor.
09NeuronA single learnable neuron y = phi(x @ w + b) on the Tensor.
10Dense LayerVectorized fully-connected layer Z = X @ W + b.
11MLPStack Dense layers with activations between them.
12Loss FunctionsSingle-example MSE/MAE/cross-entropy (+ stable softmax) and sum/mean reductions.
13Loss Functions (Batched)Lift softmax/cross-entropy to a (B, C) batch; mean over the batch.
14SGD OptimizerThe Optimizer/SGD update step abstraction.
15First Training LoopWire MLP + loss + SGD into the canonical learn loop.
16Weight InitializationXavier/Glorot and He/Kaiming init, and why scale matters.
17MomentumSGD with momentum.
18AdamRMSProp/Adam with bias correction and weight decay.
19Batch TrainingMinibatching, epochs, shuffling; gradient-variance intuition.
20DataLoaderDataset/DataLoader batching abstraction.
21RegularizationL2 / weight decay; train vs eval mode.
22DropoutDropout forward + backward; inverted scaling.
23BatchNormBatch normalization forward + backward by hand.
24Conv2D MathConvolution arithmetic and gradients via im2col.
25Conv2D ImplementationConv2D/pooling/flatten as Tensor layers.
26CNN ProjectStack conv/pool/linear; train on image data.
27Attention MathScaled dot-product attention forward + backward (pure NumPy).
28Self-AttentionSelf-attention on the Tensor autodiff engine.
29Multi-Head AttentionSplit/concat heads; the full MHA module.
30TransformerResiduals + LayerNorm + FFN; a full Transformer block.
31Vision TransformerPatch embeddings + Transformer for image classification.
32Framework RefactorPackage it all into a clean PyTorch-like Module/Parameter API.
33Capstone: MNISTEnd-to-end MNIST classifier.
34Capstone: CIFAR-10End-to-end CIFAR-10 classifier.
35Capstone: TransformerEnd-to-end Transformer language model.

Expected effort

Roughly 150-250 hours end to end, depending on background.

AI / Agent setup

This repo ships a tutor prompt at tutor_skill.md — a Socratic study partner that guides your thinking with hints and questions but won't hand you the solution (the point is that you write every gradient). It asks which stage you're on, reads that stage's files, and helps you reason to the answer.

Works with any AI coding agent (Cursor, Copilot, Codex, Claude, Gemini, local models, …): give the agent tutor_skill.md as its system prompt / custom instructions, then tell it which stage you're stuck on. (For Claude Code, drop tutor_skill.md into .claude/skills/tutor/SKILL.md to run it as the /tutor slash command.)

Community

Questions, help, and updates: r/pytorch_from_scratch.