PyTorch autograd
Every loss.backward() call runs reverse-mode AD over the computation graph PyTorch built during the forward pass.
loss = criterion(model(x), y)
loss.backward()
optim.step()Name things for the reader, not the writer.
Name things for the reader, not the writer.
Deep Learning Foundations
Training a neural network is just gradient descent on a very deeply nested function. The miracle is that the gradient — through possibly hundreds of layers and billions of parameters — can be computed in time *linear* in the size of the network, using the chain rule applied in reverse. That algorith
Backprop is the chain rule applied in reverse — every layer contributes a transpose-weight matvec and a non-linearity-gradient elementwise multiply.
Without backprop, neural networks past 2-3 layers are untrainable in practice.
Training a neural network is just gradient descent on a very deeply nested function. The miracle is that the gradient — through possibly hundreds of layers and billions of parameters — can be computed in time *linear* in the size of the network, using the chain rule applied in reverse. That algorithm is backpropagation, and understanding it is the difference between using deep learning and *engineering* deep learning.
A feed-forward network is a composition: , where each layer takes the previous activation, applies a linear map , and a non-linearity . The loss at the end is a scalar function of all the parameters , and we want .
The chain rule says . Define the upstream gradient . Then the entire backward pass is two recursions: and the parameter gradients .
The genius of backprop is that we never form a giant Jacobian. We only ever multiply a *vector* by a Jacobian — a vector-Jacobian product (VJP) — which is cheap because each layer's Jacobian has known structure (diagonal for elementwise non-linearities, for linear layers). This is the reverse-mode autodiff that PyTorch, JAX, and TensorFlow all implement.
Two failure modes haunt backprop in deep networks. Vanishing gradients: if every layer's Jacobian shrinks magnitudes by , exponentially decays going backward, and early layers stop learning. Sigmoid and tanh activations cause this. Exploding gradients: the opposite. Cure: ReLU activations, residual connections, batch normalization, careful initialization, gradient clipping. These tricks are why we can now train 100-layer networks.
Python (in browser)
Expected: Loss prints; gradient norms finite and non-zero
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Every loss.backward() call runs reverse-mode AD over the computation graph PyTorch built during the forward pass.
loss = criterion(model(x), y)
loss.backward()
optim.step()jax.grad differentiates a Python function; jax.jit compiles it to XLA for GPU/TPU. Together they give numpy-style code that runs at compiled speed.
from jax import grad, jit
grad_fn = jit(grad(loss_fn))Save activations only at every k-th layer; recompute the rest during backward. Trades 2× compute for O(sqrt(L)) memory — what lets LLaMA-70B training fit.
Forward in fp16/bf16, gradients accumulated in fp32. Cuts memory and accelerates training on Tensor Cores by 2-4× with minimal accuracy loss.
Put your understanding to the test. Score + streak + speed all count.
3 quick questions. Get 2 right to mark this lesson complete.