5.6.8 · D2Machine Learning (Aerospace Applications)

Visual walkthrough — Backpropagation — chain rule, gradient computation

2,016 words9 min readBack to topic

We use exactly the network from the parent, all numbers scalar so nothing hides:

Before any calculus, meet the cast.


Step 1 — Draw the computation as a chain of boxes

WHAT. A neural net is not a mysterious blob — it is a sequence of small operations, each one taking a number in and pushing a number out. We draw it as a computational graph: every box is one operation, every wire carries one number.

WHY. If we can see which number flows into which box, we can later see which box is to blame when the answer is wrong. Backprop is nothing but reading this same picture right-to-left.

PICTURE. Read the arrows left→right. The input enters, gets scaled by and shifted by to make (the "pre-activation"). The nonlinearity squashes into (the "activation"). Layer 2 repeats the pattern to make (our prediction). Finally compares to the target .


Step 2 — Forward pass: fill every wire with a number, and remember it

WHAT. Run the graph left→right with concrete numbers and store every value on every wire. Using the parent's numbers: , and ReLU (ReLU means "keep positives, zero out negatives").

WHY store them? The backward step will need (the input to layer 2) and the slope . Both depend on numbers we compute now. Throwing them away means recomputing later — wasteful. Caching is the trick that makes backprop cheap.

PICTURE. Same graph, now every wire wears its numeric tag. The little "cache" tray under the graph holds the two values ( and ) the backward pass will come back for.


Step 3 — Seed the error at the very end

WHAT. Start the backward journey by asking one question at the output: if nudged up a little, how much does change? That number is .

WHY here? Only the final box, the loss, directly knows "how wrong" we are. So the blame originates at the end and travels backward. Differentiating :

The and the power conspire: , so the messy square becomes a clean . If we predicted too high, this is positive (push down); too low, negative.

PICTURE. A single red arrow appears at the far right, pointing backward out of , carrying the value . This is the "error signal" born at the output.


Step 4 — Cross layer 2's linear box: split the error into three

WHAT. The pre-activation is built from three ingredients: . Define the error at as . Since exactly, . Now hand this error to each ingredient.

WHY three arrows? The chain rule says: to get 's sensitivity to any ingredient, multiply the incoming error by how that ingredient affects .

Read each term-by-term:

  • Weight gets its input. because multiplies . So a weight's gradient is error out × signal in.
  • Bias gets a plain 1. is just added, so nudging it moves one-for-one.
  • The activation gets . The error keeps travelling backward through the weight — this is the wire that reaches earlier layers.

PICTURE. The red error arrow hits the layer-2 box and forks into three: a pink branch down to (labelled ), a pink branch down to (labelled ), and a blue branch continuing left toward (labelled ).


Step 5 — Cross the nonlinearity: multiply by the local slope

WHAT. We have the error arriving at (). But we want the error at , i.e. before the squash. Recall , so:

WHY the slope? is how steeply the activation responds right where we are sitting. If the unit is in a flat region (), a nudge to barely changes , so almost no blame passes through — this is exactly the seed of vanishing gradients. For ReLU with , the slope is (ReLU is a straight line of slope 1 on the positive side), so:

PICTURE. A small ReLU graph shows the kink at ; a dot sits at on the slope-1 arm. The blue error arrow passes through a "gate" labelled and comes out the other side still carrying .


Step 6 — Finish at layer 1: same rule, one layer earlier

WHAT. We now have , the error at . The last box, , has the same shape as layer 2, so the same rule applies:

WHY this matters. Notice we did not re-run the network. The whole backward pass reused , then , then multiplied by cached inputs. That reuse is the reason backprop costs one backward sweep, not one sweep per weight — the recursion just repeats "error out × signal in" at each stage.

PICTURE. The graph now has all gradients written under their weights and biases in yellow, with the red→blue error arrow shown sweeping fully from right to left across the network.


Step 7 — The degenerate case: a "dead" ReLU unit

WHAT. Everything above assumed . What if the same input had produced ? Then ReLU outputs and its slope is .

WHY it's worth its own step. Look at Step 5's gate: multiplying by kills the error. Then

So and receive zero gradient this step — they don't learn from this example at all. The downstream weight still gets a gradient (its input though, so too here!). This is the "dying ReLU" phenomenon and the exact mechanism behind vanishing gradients.

PICTURE. The same ReLU graph, but the dot now sits on the flat left arm (). The gate reads , and the error arrow stops dead at the gate — no blue arrow continues to layer 1.


Step 8 — Why this scales: fan-in nodes sum their arrows

WHAT. Our toy had one wire per layer. Real nets have a unit's output feeding many downstream units. When error comes back along several paths into the same node, we add them.

WHY add? Each downstream path is an independent way depends on that node. The multivariable chain rule says total sensitivity = sum of path sensitivities:

In matrix form this sum is the of the parent's boxed equation — each output row of dots against all downstream errors, i.e. it sums the paths automatically. (Computing these products efficiently and correctly at scale is what automatic differentiation libraries do for you.)

PICTURE. A node splits forward into two units; two blue error arrows return and merge at with a "" symbol, showing the fan-in sum.


The one-picture summary

Everything above compressed: the forward pass (yellow, left→right) fills the wires; the backward pass (red seed → blue error → pink weight/bias gradients, right→left) is one sweep. Each weight's gradient is error out × signal in; each nonlinearity multiplies the error by its local slope; fan-ins sum.

Recall Feynman: retell the whole walkthrough

I drew the network as a line of boxes and ran a real number through it, writing the number on every wire and keeping two of them in my pocket (the input and the slope). At the end the loss told me how wrong I was — that's the error, a single red number. I walked that number backwards. At each box I handed it to the box's dials: a weight's blame is the error times the number that flowed into it; a bias's blame is just the error; and to keep travelling I pushed the error back through the weight and shrank it by how steep the squash was right there. If a unit was asleep (flat slope), the blame died at its door and that piece didn't learn. Where one unit fed several others, I added up all the blame coming back. One walk forward, one walk back — and now every dial knows exactly which way to turn. That single backward walk is backpropagation, and it hands its numbers straight to gradient descent.

Connections

  • Chain Rule — the single rule every step above secretly uses.
  • Computational Graphs — the box picture we drew in Step 1.
  • Activation Functions — where the slope in Steps 5 & 7 comes from.
  • Vanishing Gradients — the dead-unit degenerate case of Step 7.
  • Automatic Differentiation — how Step 8's sums are done at scale.
  • Neural Network Surrogate Models (CFD) — the aerospace payoff of cheap gradients.
  • Gradient Descent — consumes the gradients this walk produces.