🔁 Backpropagation
Interactive backpropagation simulator: watch deltas pulse backward through a small MLP and gradients update each weight as the decision boundary morphs.
About Backpropagation in Neural Networks
Backpropagation (Rumelhart, Hinton & Williams, 1986) is the algorithm that makes training deep neural networks practical. It applies the chain rule of calculus to efficiently compute the gradient of the loss function with respect to every weight in the network in a single backward pass — compared with the naïve approach of perturbing each weight individually, which would cost O(W) forward passes for W weights. The insight is that gradients can be propagated backwards layer by layer, each layer reusing the δ-signals (error terms) computed by the layer above. Backpropagation is the foundation of virtually every modern deep-learning system, from image classifiers to large language models.
This simulation visualises a multilayer perceptron (MLP) with an input layer, two hidden layers of adjustable width H, and a two-class output. You can step through the forward pass (watching activations flow left to right) and the backward pass (watching δ-signals and weight gradients flow right to left), choose between ReLU, tanh, and sigmoid activations, switch between classification (softmax) and regression (linear) output modes, and paint your own dataset on the canvas with several presets including XOR, spirals, and two-moon datasets.
Frequently Asked Questions
What problem does backpropagation solve?
Training a neural network means finding weights W that minimise a loss function L(W) — for example, cross-entropy for classification or mean squared error for regression. Gradient descent requires computing ∂L/∂w for every weight w. A network with W weights would naively need W + 1 forward passes to estimate all gradients by finite differences. Backpropagation uses the chain rule to compute the exact gradient of L with respect to all W weights in just one forward pass and one backward pass — reducing computation from O(W²) to O(W).
How does the chain rule make backprop work?
The chain rule states that if z = f(y) and y = g(x), then dz/dx = (dz/dy)(dy/dx). In a network with layers l = 1, …, L, the loss L depends on the output ŷ which depends on activations in layer L–1, which depend on layer L–2, and so on. The backward pass computes δ^(l) = (∂L/∂a^(l)), the "error signal" at layer l, recursively: δ^(l) = (W^(l+1))ᵀ δ^(l+1) ⊙ σ'(z^(l)), where σ' is the derivative of the activation function. The weight gradient is then ∂L/∂W^(l) = δ^(l) (a^(l-1))ᵀ.
What is the vanishing gradient problem?
With sigmoid or tanh activations, the derivative σ'(z) is at most 0.25 (sigmoid) or 1 (tanh at z = 0) and shrinks towards zero for large |z|. Multiplying many such derivatives through the chain rule across L layers causes gradients in early layers to shrink exponentially — a factor of (0.25)^L per step for sigmoid. With 10 layers this means gradients shrink by a factor of about 10⁻⁶, making weights in early layers nearly impossible to train. ReLU (σ'(z) = 1 for z > 0) avoids this in the forward pass but can suffer "dead neurons" where z is always negative.
What is the difference between SGD, mini-batch GD, and full-batch GD?
Stochastic gradient descent (SGD) updates weights after each single training example — fast but noisy. Full-batch gradient descent computes the exact gradient over the entire dataset before updating — stable but slow for large datasets. Mini-batch gradient descent (the standard in deep learning) uses a random subset of B examples per update, averaging the gradient over the batch. Mini-batch balances noise (which helps escape local minima) with computational efficiency (matrix operations over batches parallelise well on GPUs). This simulation runs single-sample SGD to show individual weight updates clearly.
What are the differences between ReLU, tanh, and sigmoid activations?
Sigmoid σ(z) = 1/(1 + e^(–z)) squashes outputs to (0, 1) and was the original choice; it suffers from vanishing gradients for large |z|. Tanh(z) = (e^z – e^(–z))/(e^z + e^(–z)) maps to (–1, 1) and has stronger gradients near zero than sigmoid, making it better for hidden layers. ReLU(z) = max(0, z) is the most popular modern choice: it has a constant gradient of 1 for z > 0 (no vanishing), is computationally cheap, and produces sparse activations. Leaky ReLU and GELU are common variants that fix the "dying ReLU" problem.
What is the learning rate and how does it affect training?
The learning rate η scales each gradient step: W ← W – η ∂L/∂W. Too large an η causes the loss to oscillate or diverge (overshooting the minimum); too small an η leads to extremely slow convergence. Typical values range from η = 10⁻⁴ to 10⁻¹. The learning rate slider in this simulation uses a log scale (10^x where x goes from –3 to 0). Modern optimisers like Adam adapt η per-parameter using moment estimates, effectively setting a good η automatically and often requiring much less tuning.
What do the glowing edges during the backward pass represent?
Edge brightness during the backward pass is proportional to |∂L/∂w|, the absolute value of the gradient for that weight. Brightly glowing edges are learning fast — their weights are being updated by a large step. Dark edges correspond to nearly zero gradient, meaning those weights are barely changing. In deep networks with sigmoid activations you can often see that early layers have dim edges (vanishing gradient) while later layers glow brightly — illustrating exactly why deep networks were hard to train before ReLU and batch normalisation.
How is the decision boundary visualised?
The canvas background is colour-coded by the network's current class prediction at every point: red regions are predicted as class 0, blue as class 1, with saturation indicating confidence. After each weight update this background is re-rendered by running a forward pass at every pixel — which is computationally expensive for large networks, so it is sampled on a coarser grid and upscaled. As training progresses you can watch the decision boundary contort and sharpen to separate the two classes, sometimes getting stuck in a local minimum.
What datasets are available and why are they chosen?
The five presets test different aspects of network expressiveness: "2 Gauss" (linearly separable blobs) can be solved even without hidden layers; "XOR" requires at least one hidden layer because the classes are not linearly separable; "Moons" and "Spirals" require the network to learn a curved, non-convex boundary; "3 Cluster" tests multi-class separation with a softmax output. Spirals are a classic benchmark — a fully connected net with only two hidden units of tanh can solve them, while a linear classifier cannot.
What is the gradient norm |∇| in the stats panel?
The gradient norm |∇| = √(Σ (∂L/∂w)²) is the Euclidean length of the entire gradient vector concatenated across all weights. A large gradient norm means the loss surface is steep and the network is far from a minimum; a very small norm suggests convergence or a plateau. Monitoring |∇| is useful for detecting exploding gradients (|∇| suddenly very large) and vanishing gradients (|∇| near zero early in training). Gradient clipping sets a maximum allowed |∇| to stabilise training of recurrent networks.
Can this network learn the XOR function?
Yes — XOR is not linearly separable, meaning no single line can separate the four input combinations, so a perceptron (no hidden layers) fails completely. A network with at least one hidden neuron using a nonlinear activation can learn XOR exactly. Rumelhart et al.'s 1986 paper used XOR as the key demonstration that backprop enables hidden units to develop useful internal representations rather than just being intermediaries. With η = 0.1 and tanh activations, the network here typically solves XOR in a few hundred SGD steps.
δ pulses flow backward through a small MLP: gradients highlight edges, weights update, and the decision boundary morphs to fit the data.
3D · Three.js / WebGL renderer · 60 FPS target · runs fully client-side, no install