SIMULATED

Backpropagation Visualizer

A 2-2-1 network as a computational graph. Every node shows its forward value and its backward gradient; the backward pass is the forward order walked in reverse, one local derivative at a time. Take one training step and watch the weights move — or a hundred, and watch XOR get learned.

ProblemTargetDataRepresentationSplitModelTrainingEvaluationValidationDeploymentInferenceMonitoringDriftRetraining

A framework hides this, which is fine until it is not. Backpropagation is not a formula for the gradient of a network; it is a bookkeeping rule — every node knows its own local derivative, and the loss's gradient flows backwards through the graph by multiplying those together along each path. Watch the gradient on x₁ after the backward pass: nothing wrote it down, it accumulated. Then look for a hidden unit whose z is negative. Its ReLU outputs zero and passes zero gradient back, so nothing upstream of it will ever change. That is a dead unit, and in a network with two of them it is the difference between learning XOR and never learning it.

The sample and the step

Dataset
Sample (x₁, x₂) → y
Learning rate

The graph

Values flow left to right: inputs → pre-activations → ReLU → output logit → sigmoid → loss.

x₁inputv 0.000∂ -0.299x₂inputv 1.000∂ -0.337z₁w1[0]·x + b…v 0.600∂ -0.374z₂w1[1]·x + b…v -0.500∂ 0.000h₁relu(z₁)v 0.600∂ -0.374h₂relu(z₂)v 0.000∂ 0.499z₃w2·h + b2v 0.340∂ -0.416ŷsigmoid(z₃)v 0.584∂ -1.712LBCE(ŷ, y)v 0.538∂ 1.000
v forward value ∂loss/∂node — positive in swap, negative in sorteddashed border = ReLU is off for this input
Forward order
  1. 1x₁= 0.000
  2. 2x₂= 1.000
  3. 3z₁= 0.600
  4. 4z₂= -0.500
  5. 5h₁= 0.600
  6. 6h₂= 0.000
  7. 7z₃= 0.340
  8. 8ŷ= 0.584
  9. 9L= 0.538

What the network knows right now

loss on this sample
0.538
prediction ŷ
0.584
mean loss on XOR
0.724
accuracy on XOR
3 / 4
Parameters and their gradients on this sample
w1[0][0]0.800∂ 0.000→ 0.800
w1[0][1]0.900∂ -0.374→ 1.087
b1[0]-0.300∂ -0.374→ -0.113
w1[1][0]0.700∂ 0.000→ 0.700
w1[1][1]0.600∂ 0.000→ 0.600
b1[1]-1.100∂ 0.000→ -1.100
w2[0]0.900∂ -0.249→ 1.025
w2[1]-1.200∂ 0.000→ -1.200
b2-0.200∂ -0.416→ 0.008

The last column is where one step at lr = 0.5 on this sample would put each parameter. Gradients are checked against finite differences in the tests — the analytic and numerical values agree to 1e-5, which is the only proof the graph is wired correctly.

Loss over training

Press “Train 100 epochs” to run full-batch gradient descent over the 4 samples and draw the loss. One training step updates on the selected sample only, which is what stochastic descent does one sample at a time.

A hidden unit is off for this input
Its pre-activation is negative, ReLU outputs zero, and the gradient it passes back is zero — read the dashed node. For this sample nothing upstream of it will change. That is normal for one input; a unit that is off for every input is dead, and a 2-2-1 network with a dead unit has one unit left, which is a linear model, which cannot learn XOR. Reset and train the AND set to see the case where that never matters.

How to read this page honestly

What the model is, and what it deliberately refuses to be.

  • SIMULATEDA 2-input, 2-hidden (ReLU), 1-output (sigmoid) network with binary cross-entropy loss, built as an explicit computational graph. The backward pass is a literal reverse traversal of the forward order — each node hands grad × local derivative to its inputs. There is no closed-form gradient for the network anywhere in the code; ∂L/∂w₁ falls out of the chain rule one edge at a time.
  • SIMULATEDThe analytic gradients are checked against central finite differences — every parameter perturbed by ±1e-6 and the forward pass re-run — and the test pins agreement to 1e-5. That check is the only proof the graph is wired correctly, and it is the check a framework runs for you and you should still know exists.
  • SIMPLIFIEDThe network is small enough to fail. A 2-2-1 ReLU network has exactly enough capacity for XOR and no spare; from a poor initialisation one hidden unit dies (z < 0 for every input, so its gradient is zero forever) and it never trains. The starting weights here were chosen so that XOR *does* train — and the AND set is the linearly separable case that trains from almost anywhere. The difference is the lesson on capacity and initialisation, and it does not scale up: a 2-2-1 network says nothing about a transformer's optimisation.

Take it further