Prompt20
All posts
neural-networksbackpropagationgradient-descenttrainingdeep-learningfoundationalevergreen

How Neural Networks Learn: Gradient Descent and Backpropagation, Plainly

The 'guess, measure the error, adjust' loop behind every model. Loss functions, gradients, and backpropagation explained as an intuitive feedback process rather than calculus.

By Prompt20 Editorial · 36 min read

A neural network learns the same way you'd tune an old radio with a broken dial: turn a knob a little, notice whether the static got worse or better, and turn it back the other way if you overshot. Do that across millions of knobs, millions of times, and the noise resolves into a signal. That is the entire trick. There is no understanding being poured in, no rules being written down — just a relentless loop of guess, measure the error, nudge everything a hair in the direction that made the error smaller.

The two words people throw around — gradient descent and backpropagation — are not two separate mysteries. Gradient descent is the strategy (roll downhill toward lower error). Backpropagation is the bookkeeping trick that tells you which way is downhill for every single knob at once, cheaply. Once you see that they're the how and the how-do-we-afford-it of the same feedback process, the mystery evaporates. This post explains that process with no calculus notation — just the mechanism.

Table of contents

  1. Key takeaways
  2. What "learning" actually means here
  3. The forward pass: how a prediction is actually computed
  4. The loss function: turning "wrong" into a number
  5. Gradient descent: rolling downhill
  6. The chain rule and the computational graph
  7. Backpropagation: the part everyone finds confusing
  8. A worked backprop example, by hand
  9. Putting the loop together
  10. Stochastic, mini-batch, and full-batch gradient descent
  11. Optimizers: from plain SGD to Adam
  12. Learning-rate schedules and warmup
  13. Vanishing and exploding gradients, and the fixes
  14. Overfitting, regularization, and generalization
  15. Why it works at all: loss landscapes in high dimensions
  16. Common misconceptions
  17. Where this fits in the bigger picture
  18. FAQ

Key takeaways

  • A neural network is a giant pile of adjustable numbers (weights) that transform an input into an output. "Learning" means finding numbers that produce good outputs.
  • A loss function is a single score for how wrong the current guess is. Lower is better. All of training is a search for weights that make this score small.
  • Gradient descent is the search method: figure out which direction reduces the loss, take a small step that way, repeat. The "gradient" is just the direction of steepest increase, so you step the opposite way.
  • Backpropagation is not learning — it's the efficient way to compute the gradient for every weight in one backward sweep, instead of testing each weight one at a time (which would be astronomically slow).
  • The learning rate controls step size. Too big and you bounce around or diverge; too small and training crawls.
  • This loop is dumb but scalable. No step "understands" the task. Capability emerges from repeating a mechanical correction billions of times over enormous data.

What "learning" actually means here

Strip away the biology metaphors. A neural network is a function: numbers go in, numbers come out. In between sits a stack of weights — the adjustable numbers — arranged so that each layer multiplies, adds, and bends its inputs before passing them on. A freshly created network has random weights, so it produces random garbage.

"Learning" is nothing more than changing those weights until the outputs stop being garbage. That's it. There's no separate reasoning module being installed. If a language model eventually predicts the next word well, it's because its weights were nudged, over and over, toward values that happened to make good predictions on the training data. (If you want the bigger picture of how those predictions turn into a chatbot, see how AI chatbots work.)

So the real question — the one this whole post answers — is: how do you know which way to change millions of weights so the output gets better? You can't just guess. You need a signal.

The forward pass: how a prediction is actually computed

Before we can talk about correcting the network, we have to be precise about what it does when it makes a guess. That computation is the forward pass, and it is embarrassingly simple arithmetic repeated at scale.

Take a single artificial neuron. It receives a list of input numbers x₁, x₂, … xₙ. It has a matching list of weights w₁, w₂, … wₙ and one extra number called the bias b. It computes a weighted sum and adds the bias:

z = w₁x₁ + w₂x₂ + … + wₙxₙ + b

That is a dot product plus an offset — nothing more exotic than a spreadsheet formula. If that were the whole story, though, stacking layers would be pointless: a chain of weighted sums collapses algebraically into a single weighted sum, and the entire deep network would be equivalent to one linear layer. That is the reason for the second step.

The neuron passes z through a nonlinear activation function a = f(z). The activation is what lets networks bend, curve, and carve input space into regions. The common choices:

  • ReLUf(z) = max(0, z). Outputs zero for negative inputs, passes positives through unchanged. Cheap, and the default in most modern networks for reasons we'll see when we hit vanishing gradients.
  • Sigmoidf(z) = 1 / (1 + e⁻ᶻ). Squashes any input into the range 0 to 1. Historically dominant, now mostly confined to output layers that need a probability.
  • Tanh — like sigmoid but squashes to the range −1 to 1, and is zero-centered.
  • GELU / SiLU — smooth ReLU-like curves used in transformers; they behave like ReLU for large inputs but have a soft, differentiable elbow near zero.

A layer is just many neurons operating on the same inputs in parallel, so in practice the whole layer is computed as a matrix multiply: the input vector times a weight matrix, plus a bias vector, then the activation applied element-wise — h = f(Wx + b). Stack L of these, feeding each layer's output as the next layer's input, and you have a deep network. The final layer's output is the prediction.

Three things to hold onto, because they all come back during backprop:

  1. The forward pass is a fixed sequence of small, differentiable operations. Multiply, add, apply activation, repeat. Every operation has a known, simple rule for how its output responds to a small change in its input. That is the entire reason backprop is possible.
  2. The network stores intermediate values as it goes. Every z and every activation a computed on the way forward has to be kept in memory, because backprop needs them on the way back. This is why training a network uses far more memory than just running it for inference — you're caching the whole forward trace.
  3. Weights are shared across examples but not across positions. Each weight participates in the prediction for every example in the batch, which is exactly why one gradient can summarize the weight's effect averaged over many examples.

With the forward pass pinned down as "a stack of matrix multiplies interleaved with cheap nonlinearities," the rest of training is about measuring the output error and pushing every one of those W and b numbers in a better direction.

The loss function: turning "wrong" into a number

You can't improve what you can't measure, and "the output feels off" isn't measurable. So the first move is to collapse how wrong the network is into a single number called the loss (or cost, or error — same idea).

The loss function compares the network's guess to the desired answer and returns one score. A few concrete flavors:

  • Predicting a number (like a house price): take the difference between guess and truth, square it so big misses hurt disproportionately, and you have a loss. Square it and it's always positive, and being off by 10 hurts far more than being off by 1.
  • Classifying (cat vs. dog): the network outputs a confidence for each option. If it says "90% cat" and the answer is cat, low loss. If it says "90% cat" and the answer is dog, high loss — and the loss punishes confident wrongness harder than hesitant wrongness.

Those two flavors have names and formulas worth knowing, because which loss you pick shapes the gradient the network feels.

Mean squared error (MSE) for regression. For a prediction ŷ and truth y, the per-example loss is (ŷ − y)², averaged over the batch:

MSE = (1/N) Σ (ŷᵢ − yᵢ)²

Squaring does two jobs: it makes the loss always positive (so overshooting and undershooting both count as error), and it makes large misses dominate — an error of 10 contributes 100, an error of 1 contributes only 1. The gradient of MSE with respect to the prediction is simply proportional to (ŷ − y), the raw residual. That clean form is why MSE is the default for predicting continuous quantities: the correction signal is the mistake, scaled.

Cross-entropy for classification. The network outputs a probability distribution over classes (via a softmax, which exponentiates each score and normalizes so they sum to 1). Cross-entropy loss looks only at the probability the network assigned to the correct class p_correct:

loss = −log(p_correct)

Read the behavior straight off the logarithm. Assign 99% to the right answer and the loss is −log(0.99) ≈ 0.01 — nearly free. Assign 1% to the right answer and the loss is −log(0.01) ≈ 4.6 — a large penalty. As the assigned probability approaches zero, the loss shoots toward infinity. That asymmetry is the whole point: cross-entropy punishes confident wrongness savagely and rewards calibrated confidence, which is exactly what you want from a classifier.

Why not just use MSE for classification too? Because pairing softmax outputs with MSE produces a gradient that goes nearly flat when the network is confidently wrong — precisely when you most need a strong correction. Softmax with cross-entropy, by contrast, has a beautifully simple combined gradient: predicted_probability − true_label. Confidently wrong means a big residual means a big gradient. The choice of loss is not cosmetic; it decides whether the downhill signal is strong where it needs to be.

The crucial property either way: low loss = good, high loss = bad, and it's a single number. That single number is what makes the rest possible. The entire goal of training reduces to one sentence: find the weights that make the loss as small as possible.

Picture the loss as a landscape. Every possible setting of the weights is a location on a vast terrain, and the height at each location is the loss there. Training is the search for a valley.

Gradient descent: rolling downhill

Now the search. You're standing somewhere on that loss landscape (your current random-ish weights), it's pitch dark, and you want to get to a low valley. You can't see the whole map. But you can feel the slope right under your feet.

Gradient descent is exactly that: feel the slope, step downhill, repeat.

The gradient is the technical name for the slope — specifically, the direction in which the loss increases fastest. Since you want the loss to decrease, you step in the opposite direction. Take a small step, you're now at a slightly lower point, re-measure the slope there (it's changed), step again. Thousands or millions of steps later, you've descended into a valley — a set of weights with low loss.

Written out, the entire update rule is one line. For each weight w, with learning rate η (eta) and the gradient of the loss with respect to that weight written ∂L/∂w:

w ← w − η · (∂L/∂w)

That is gradient descent in its entirety. ∂L/∂w answers "if I nudge this one weight up a hair, does the loss go up or down, and how steeply?" A positive gradient means increasing the weight increases loss, so the minus sign pushes the weight down. A large-magnitude gradient means this weight matters a lot right now, so it moves more. The learning rate η scales every step uniformly. Backpropagation, coming up, is nothing but the machine that produces the ∂L/∂w for every weight so this line can be applied to all of them at once.

Two honest caveats that matter:

  • You only ever feel the local slope. Gradient descent doesn't find the lowest possible valley, just a low one it can reach by walking downhill from where it started. In practice, for large networks, the reachable valleys are usually good enough — this is an empirical fact, not a guarantee.
  • The landscape has millions or billions of dimensions, one per weight. "Direction" means a direction in that unimaginably high-dimensional space. The hill metaphor is a 3-D shadow of something far larger, but the logic is identical.

The learning rate is your step size. Get it wrong in either direction and training fails:

Learning rate What happens Analogy
Too large Loss jumps around or blows up; you overshoot valleys Leaping down a hill and launching over the far ridge
Too small Loss creeps down painfully slowly; training costs a fortune Shuffling an inch at a time
About right Steady, efficient descent A confident stride

Much of the practical craft of training — schedules, warmups, optimizers with names like Adam — is really just cleverer ways to choose step size and direction so the descent is faster and more stable. But underneath every one of them is the same feel-the-slope-and-step loop.

The chain rule and the computational graph

To see why backprop works — not just that it does — you need one idea from calculus, and only one: the chain rule. Skip the notation if you like; the sentence version is enough.

The chain rule says: if A affects B and B affects C, then A's effect on C is the product of the two links. If turning a tap changes the water level at 2 units per turn, and water level changes plant growth at 3 units per unit of water, then turning the tap changes growth at 2 × 3 = 6 units per turn. You multiply the sensitivities along the chain.

A neural network is exactly such a chain, just very long. A weight in an early layer affects that layer's output, which affects the next layer's output, which affects the next, all the way to the final prediction, which affects the loss. To know how the early weight affects the loss, you multiply together every local sensitivity along the path from that weight to the loss. In symbols, for a weight w feeding activation a feeding output o feeding loss L:

∂L/∂w = (∂L/∂o) · (∂o/∂a) · (∂a/∂w)

Each factor is a local derivative — how one operation's output responds to a small wiggle in its immediate input. And here is the crucial fact from the forward-pass section: every operation in the network (multiply, add, ReLU, softmax) is simple, so its local derivative is simple and known in closed form. The derivative of Wx with respect to x is W. The derivative of ReLU is 1 where the input was positive and 0 where it was negative. The chain rule just multiplies these easy pieces together.

It helps to picture the network not as layers but as a computational graph: a directed graph where each node is an operation and each edge carries a number forward. The forward pass flows values left to right along the edges. Backprop flows sensitivities right to left along the same edges, and at each node it multiplies the incoming sensitivity by that node's local derivative. Every modern framework — PyTorch, JAX, TensorFlow — builds this graph automatically as your forward code runs and then walks it backward. That machinery is called automatic differentiation, and backpropagation is precisely its reverse mode: start from the single scalar loss at the output and propagate sensitivities back toward the millions of inputs. (There is also forward mode, which goes the other way and is efficient when you have few inputs and many outputs — the opposite of a neural network, which has one loss and billions of weights. That asymmetry is exactly why reverse mode won.)

Backpropagation: the part everyone finds confusing

Here's the problem gradient descent quietly assumes away: how do you actually compute the slope for every weight?

The naive method is brutal. To learn how weight #5,000,000 affects the loss, you could nudge it a tiny bit, run the whole network again, and see how much the loss changed. Now do that separately for all the other weights. A modern network has billions of weights, so one round of learning would require billions of full network runs. That's not slow — it's impossible at scale. Training would take longer than the age of the universe.

Backpropagation is the shortcut that makes it affordable. It computes the effect of every weight on the loss in essentially one backward pass through the network, rather than one pass per weight. That single idea is the reason deep learning is practical at all.

The intuition, told as blame assignment:

  1. Forward pass. Run the input through the network and get an output. Compare to the truth and compute the loss. You now know how wrong the final answer was.
  2. Assign blame at the output. The last layer produced the final numbers, so you can directly ask: how much did each of its inputs contribute to the error? That gives you a little "blame" value for each.
  3. Pass the blame backward. Here's the key move. Each layer knows what it did to its inputs on the way forward (it multiplied and added them in specific ways). So it can take the blame handed to it from the layer ahead and split that blame among its own inputs proportionally to how much each one pushed the output. The blame flows backward, layer by layer, from output toward input.
  4. Read off each weight's responsibility. As the blame reaches each weight, you learn how much that weight contributed to the total error — which is exactly the slope (gradient) for that weight.

The name says it: you propagate the error signal backward. Once every weight has its blame score, gradient descent does its one job — nudge each weight a small step in the direction that reduces its share of the error — and you repeat the whole loop on the next batch of data.

Why is one backward pass enough? Because the blame handed to an early layer already bundles in everything the later layers did with its output. You compute each layer's contribution once and reuse it for everything downstream, instead of recomputing the whole chain for every weight. That reuse is the entire efficiency win. You don't need the calculus to trust the accounting: information about the error flows forward as a prediction and backward as blame, and the backward flow is cheap because each step reuses the step after it.

A worked backprop example, by hand

Abstractions are cheap. Let's run one full backprop step on a network small enough to compute on paper, so you can watch blame actually flow backward and watch the loss actually drop.

Our toy network is a two-layer chain, one neuron per layer, no biases, so every quantity is a single number:

  • Input: x = 1.0
  • Layer 1: weight w₁ = 0.8, then a ReLU activation
  • Layer 2: weight w₂ = 0.5, linear output
  • Target: y = 1.0
  • Loss: L = ½(ŷ − y)² (squared error; the ½ just makes the derivative tidy)

Forward pass. Push the input through:

z₁ = w₁·x  = 0.8 × 1.0 = 0.8
a₁ = ReLU(z₁) = 0.8          (positive, passes through unchanged)
z₂ = w₂·a₁ = 0.5 × 0.8 = 0.4
ŷ  = z₂ = 0.4                (linear output layer)
L  = ½(0.4 − 1.0)² = ½(0.36) = 0.18

The network guessed 0.4; the truth is 1.0; the loss is 0.18. Now assign blame backward.

Backward pass. At each step we multiply the sensitivity handed down from the layer ahead by the local derivative of the current operation — the chain rule, applied node by node.

∂L/∂ŷ  = (ŷ − y)      = 0.4 − 1.0 = −0.60      (slope of the loss at the output)
∂L/∂z₂ = ∂L/∂ŷ × 1    = −0.60                  (output is linear, local deriv = 1)
∂L/∂w₂ = ∂L/∂z₂ × a₁  = −0.60 × 0.8 = −0.48    (local deriv of w₂·a₁ w.r.t. w₂ is a₁)
∂L/∂a₁ = ∂L/∂z₂ × w₂  = −0.60 × 0.5 = −0.30    ← blame passed back to layer 1
∂L/∂z₁ = ∂L/∂a₁ × 1   = −0.30                  (ReLU deriv is 1 because z₁ was positive)
∂L/∂w₁ = ∂L/∂z₁ × x   = −0.30 × 1.0 = −0.30    (local deriv of w₁·x w.r.t. w₁ is x)

Notice the single line that carries the whole idea: ∂L/∂a₁ = −0.30. That is layer 2 handing its blame back to layer 1's output. Layer 1 never has to know anything about the loss or the output layer — it just receives the number −0.30 and continues the chain locally. That is the reuse that makes backprop cheap: everything downstream is already bundled into that one handed-back value.

The update. Both gradients are negative, meaning increasing either weight would lower the loss, so gradient descent will increase both. With learning rate η = 0.1:

w₂ ← 0.5 − 0.1 × (−0.48) = 0.5 + 0.048 = 0.548
w₁ ← 0.8 − 0.1 × (−0.30) = 0.8 + 0.030 = 0.830

Did it work? Run the forward pass again with the new weights:

a₁ = ReLU(0.830 × 1.0) = 0.830
ŷ  = 0.548 × 0.830      = 0.45484
L  = ½(0.45484 − 1.0)²  ≈ 0.1486

The loss fell from 0.18 to 0.1486 after a single step — the prediction moved from 0.4 toward the target of 1.0. Nothing here understood anything. We multiplied a handful of small local derivatives, took one step opposite the gradient, and the error shrank. Repeat this billions of times across billions of weights and a real batch of data and you have the training of every model you've heard of. The arithmetic never gets more sophisticated than what you just did by hand — there is only vastly more of it.

Putting the loop together

Every neural network you've heard of — image models, language models, recommendation engines — is trained by repeating this five-step loop:

  1. Forward: feed in a batch of examples, get predictions.
  2. Measure: compute the loss (how wrong).
  3. Backpropagate: sweep backward to get each weight's blame (the gradient).
  4. Step: nudge every weight a small amount downhill, scaled by the learning rate.
  5. Repeat with the next batch, millions of times.

That's the whole engine. Everything else — architectures, attention, normalization, fancy optimizers — is about making one of these steps richer, faster, or more stable. The skeleton never changes.

Two things people routinely overestimate are worth deflating:

  • No single step is intelligent. Each update is a mechanical correction that shrinks the error on a handful of examples by a hair. There is no moment where the network "gets it." Capability is an emergent statistical average of an astronomical number of tiny, dumb corrections. Skepticism about anthropomorphizing this process is well-earned.
  • Learning is not memorization — usually. Because the network has limited capacity and sees a moving stream of examples, the cheapest way to lower loss across all of them is often to capture general patterns rather than memorize each case. That's why trained models can generalize to inputs they never saw. It's also why they confidently produce wrong answers when the patterns mislead them — the same averaging that yields generalization also yields hallucinations.

Stochastic, mini-batch, and full-batch gradient descent

Step 4 of the loop said "nudge every weight downhill." Downhill according to what? The loss is defined over your whole dataset, so the truest gradient averages the error over every training example. Computing that is called full-batch (or just "batch") gradient descent, and for a dataset of millions of examples it is absurdly expensive: one weight update would require a forward and backward pass over the entire corpus.

The opposite extreme is stochastic gradient descent (SGD) in its original sense: estimate the gradient from a single random example, update, move to the next. Each estimate is noisy — one example is a terrible proxy for the whole dataset — but it is cheap and you get millions of updates for the price of one full-batch step. The noise is not purely a cost, either: the random jitter can knock the trajectory out of shallow bad valleys, acting as a crude form of exploration.

In practice everyone uses the compromise, mini-batch gradient descent: estimate the gradient from a small random batch — typically 32 to a few thousand examples, or millions of tokens for large language models. This is the sweet spot for three reasons:

  • Statistically sane. A batch of a few hundred examples gives a gradient estimate close enough to the true one to head reliably downhill, without the wild variance of a single sample.
  • Hardware-friendly. GPUs and TPUs are matrix-multiply engines; a batch is one big matrix multiply, so processing 256 examples together is nowhere near 256× the cost of one. Idle silicon is wasted money.
  • Enough noise to help. The residual randomness between batches still provides mild regularization and helps escape sharp, brittle minima.

Confusingly, the modern literature calls mini-batch training "SGD" too — the "stochastic" now refers to the random batch rather than a single sample. When someone says "we trained with SGD," they almost always mean mini-batch. One full sweep through the training set is called an epoch; large models are often trained for a single epoch or even less, because with enough data every example is fresh and there is no need to revisit any.

Optimizers: from plain SGD to Adam

Plain gradient descent — w ← w − η·(∂L/∂w) — has a real weakness. It treats every weight identically and reacts only to the current batch's gradient, so it stumbles in common situations: it crawls across long, gently sloped plateaus, and it oscillates wildly across the walls of narrow ravines while barely progressing along the floor. Optimizers are drop-in replacements for that update line that fix these pathologies. They never change backprop; they only change how the computed gradient is turned into a step.

Momentum. Instead of stepping by the current gradient alone, keep a running, decaying average of recent gradients — a "velocity" — and step by that:

v ← β·v + (∂L/∂w)          (β typically 0.9)
w ← w − η·v

The physical analogy is exact: a ball rolling downhill accumulates speed in consistent directions and averages out back-and-forth wobble. Momentum accelerates across plateaus (gradients keep pointing the same way, so velocity builds) and damps oscillation across ravines (opposing gradients cancel). It is the single cheapest upgrade over vanilla SGD.

RMSProp / AdaGrad — per-weight step sizes. These track a running average of each weight's squared gradient and divide the step by its square root. The effect: weights that have consistently seen large gradients get smaller steps; weights with tiny gradients get relatively larger ones. Every parameter effectively gets its own adaptive learning rate, which matters enormously when different weights operate at wildly different scales.

Adam — the default. Adam (Adaptive Moment Estimation) combines both ideas: it keeps a running average of the gradient (first moment, like momentum) and a running average of the squared gradient (second moment, like RMSProp), plus a small bias correction for the fact that both averages start at zero. Schematically:

m ← β₁·m + (1−β₁)·g          (smoothed gradient,   β₁ ≈ 0.9)
v ← β₂·v + (1−β₂)·g²         (smoothed squared,    β₂ ≈ 0.999)
w ← w − η · m̂ / (√v̂ + ε)     (m̂, v̂ are bias-corrected)

Adam and its close cousin AdamW (which handles weight decay more correctly and is the standard for training transformers) dominate deep learning because they are forgiving: they work across a wide range of learning rates, adapt per-weight, and require little tuning. The cost is memory — Adam stores two extra numbers per weight (m and v), so its optimizer state is roughly twice the size of the model itself, which is a serious budget line when training a model with hundreds of billions of parameters. That memory pressure is one reason large-scale training pushes toward lower-precision formats, a tradeoff explored in FP8 and mixed-precision training.

The takeaway: every optimizer is still gradient descent. Backprop produces the gradient; the optimizer just decides, cleverly, how far and how smoothly to move in response to it.

Learning-rate schedules and warmup

A fixed learning rate is rarely optimal for the whole run, because the ideal step size changes as training proceeds. Early on, weights are random and far from any good valley, so large steps make fast progress. Late in training, near the bottom of a valley, large steps just bounce you off the walls and prevent settling. So practitioners schedule the learning rate — vary it over time by a fixed recipe.

Decay schedules. The learning rate starts high and shrinks as training goes on. Common shapes: step decay (drop by 10× at set milestones), cosine decay (smoothly follow a cosine curve down to near zero — the current favorite for large models), and linear decay. The intuition is "take big strides while you're far away, then tiptoe as you close in." Cosine decay in particular spends a long time at a moderate rate and then eases gently to zero, which empirically finds flatter, better-generalizing minima.

Warmup. This one is counterintuitive: for the first few hundred to few thousand steps, the learning rate is ramped up from near zero to its peak, rather than starting at full value. Why deliberately go slow at the start? Because a freshly initialized network produces huge, unreliable gradients, and adaptive optimizers like Adam have not yet accumulated enough gradient history for their per-weight scaling to be trustworthy. Hitting such a network with a full-size learning rate can blow the weights out to garbage in the first handful of steps, from which training never recovers. Warmup lets the optimizer's running averages stabilize and the weights find a sane region before the big steps begin. The now-standard recipe for transformers is linear warmup followed by cosine decay: ramp up, then ease all the way down.

None of this changes the mechanism. Backprop still computes the same gradients; schedules and warmup only modulate the η that multiplies them. But getting the schedule wrong is one of the most common reasons a training run silently underperforms or diverges outright.

Vanishing and exploding gradients, and the fixes

Recall from the worked example that the gradient reaching an early weight is a product of many local derivatives, one per layer between that weight and the loss. Multiplying many numbers together is numerically dangerous. If those local derivatives are consistently a bit less than 1, their product shrinks toward zero as the network gets deeper — the vanishing gradient problem. If they are consistently a bit greater than 1, the product explodes toward infinity — the exploding gradient problem. Either way, the early layers of a deep network get a corrupted or useless learning signal, and the network trains badly or not at all. This is the wall that stopped deep networks from working for decades.

The historical culprit was the sigmoid and tanh activations. Sigmoid's derivative maxes out at 0.25 and is near zero whenever its input is large in magnitude (it "saturates"). Chain twenty of those together and the gradient to the first layer is multiplied by something like 0.25²⁰ — effectively zero. The first layers simply stop learning. The field's escape from this trap came from a stack of specific fixes, each still standard today:

  • ReLU activations. ReLU's derivative is exactly 1 for any positive input — no shrinkage. Chaining many ReLUs does not attenuate the gradient the way chaining sigmoids does. This single change, more than any other, is what made training deep networks feasible. (ReLU has its own failure, "dead neurons" stuck at zero output, which variants like Leaky ReLU and GELU soften.)
  • Careful weight initialization. Schemes like Xavier/Glorot and He initialization set the initial random weights to a scale calculated so that the variance of activations — and of gradients — stays roughly constant from layer to layer at the start of training. Start balanced and you buy yourself a long window before products drift toward zero or infinity.
  • Normalization layers. Batch normalization, and for transformers layer normalization, rescale the activations inside the network to a controlled mean and variance at every layer. This keeps signals in the well-behaved range of the activation functions and dramatically smooths the loss landscape, making gradients far better behaved. Normalization is why very deep networks train stably at all.
  • Residual (skip) connections. The idea behind ResNets, and a load-bearing component of every transformer: add a layer's input directly to its output, output = layer(x) + x. This gives the gradient a "shortcut" path straight back through the addition, unmultiplied by the layer's derivatives. Even if the layer's own contribution to the gradient vanishes, the + x term passes the gradient back intact. Residual connections are the main reason networks can now be hundreds of layers deep without the gradient dying on the way back.
  • Gradient clipping. A blunt but effective guard against explosion: if the total gradient magnitude exceeds a threshold, scale the whole thing down to that threshold before stepping. This caps the damage a single freak batch can do and is standard in training language models and RNNs.

Notice the through-line: every one of these fixes is about keeping that long product of local derivatives from drifting to zero or infinity. Deep learning did not get unlocked by a smarter learning rule — backprop is unchanged since the 1980s. It got unlocked by a collection of tricks that keep the backprop signal healthy as it travels through many layers.

Overfitting, regularization, and generalization

Driving training loss to zero is not the goal. The goal is low loss on data the model has never seen. A network with enough capacity can achieve zero training loss by effectively memorizing every training example — including their noise and quirks — and then fail miserably on new inputs. That gap between excellent training performance and poor real-world performance is overfitting, and fighting it is regularization.

The core tension is the bias-variance tradeoff. Too little capacity (or too much regularization) and the model is too rigid to capture the real pattern — high bias, underfitting. Too much capacity with too little regularization and the model contorts to fit every training-set accident — high variance, overfitting. Generalization lives in the balance between them. The standard tools:

  • Hold out a validation set. Never trust training loss to tell you when to stop. Watch loss on a separate held-out set; when validation loss stops improving (or starts rising) while training loss keeps falling, you are overfitting. Early stopping — halt training at the validation-loss minimum — is the simplest and one of the most effective regularizers there is.
  • L2 regularization / weight decay. Add a penalty proportional to the sum of squared weights to the loss. This nudges every weight toward zero unless the data gives a strong reason to keep it large, favoring simpler, smoother functions. In the update rule it shows up as shrinking each weight slightly on every step (hence "weight decay"), and it is on by default in AdamW.
  • Dropout. During training, randomly zero out a fraction of activations (say 10-50%) on each forward pass. The network can't rely on any single neuron always being present, so it is forced to learn redundant, distributed representations rather than fragile memorized paths. At inference dropout is turned off. It behaves loosely like training an ensemble of many thinned networks and averaging them.
  • Data augmentation. Artificially enlarge the training set by applying label-preserving transformations — flip and crop images, paraphrase text — so the model sees more variety and can't latch onto superficial features. More effective data is the most reliable regularizer of all.
  • Scale. For very large models trained on very large corpora, the cheapest path to generalization is simply more diverse data. When the data is broad enough, memorizing it is a worse strategy for lowering loss than learning the underlying regularities — which is why large models generalize, a point the loop section already flagged.

Regularization is not a bag of unrelated hacks. It is all one principle: constrain the search so that among the many weight settings that fit the training data, the optimizer prefers the simpler ones, because simpler functions are the ones that tend to generalize.

Why it works at all: loss landscapes in high dimensions

Here is a fair objection to everything above. The loss landscape of a deep network is wildly non-convex — a chaotic terrain of countless hills and valleys. Basic calculus says a downhill walk on such a surface should get stuck in the first bad local minimum it stumbles into. So why does dumb gradient descent reliably find good solutions? This is genuinely not fully understood, but the empirical and theoretical picture has sharpened, and honesty requires flagging what is fact versus what is hand-waving.

Local minima are mostly not the problem; saddle points are. In a space of billions of dimensions, a true local minimum requires the surface to curve upward in every one of those billions of directions simultaneously — a statistically rare event. Far more common are saddle points: places that curve up in some directions and down in others, so they look flat but are not trapping. There is almost always some direction that still leads downhill. Gradient descent, with a little help from mini-batch noise and momentum, slides off saddles and keeps descending. High dimensionality, the thing that makes the problem sound impossible, is paradoxically what makes it tractable.

Most reachable minima are about equally good. A robust empirical finding for large overparameterized networks is that the many valleys reachable by gradient descent tend to have similar, low loss. You are not gambling on hitting the one global optimum; a large fraction of the accessible endpoints are good enough. This is why training runs from different random seeds land at different weights but comparable performance.

Flat minima generalize better than sharp ones. Among those good valleys, wide flat basins tend to generalize better than narrow sharp ones — intuitively, a flat minimum means the loss is insensitive to small weight perturbations, so it is also more robust to the small differences between training and test data. Part of why noisy mini-batch SGD and cosine schedules work well is that they are biased toward settling in flatter regions rather than sharp crevices.

The intellectually honest summary: we have strong empirical evidence and partial theory, not a complete proof, for why this works. Gradient descent on a non-convex loss has no general guarantee of finding a good solution. It just does, reliably, for the specific landscapes that real networks and real data produce. Anyone claiming a clean theoretical guarantee for why deep learning optimization succeeds is overselling. What we can say firmly is that it does succeed, that high dimensionality and stochastic noise are central to why, and that this remains an active research frontier rather than settled science.

Common misconceptions

A few beliefs about training are common, sticky, and wrong. Deflating them is a good test of whether the mechanism above actually landed.

  • "Backpropagation is how neural networks learn." No — backpropagation only computes the gradient. The learning, the actual changing of weights, is done by the optimizer applying gradient descent. Backprop is the measurement; gradient descent is the movement. Conflating them is the single most common confusion, and it is why this post keeps them separate.
  • "Backprop is how the brain learns." There is no credible evidence the brain runs backpropagation. Backprop requires a symmetric backward pass with precise access to every forward weight, which biological neurons do not obviously have (the "weight transport problem"). Backprop is an engineering algorithm that works, not a model of neuroscience.
  • "Training finds the best possible weights." It finds a good set of weights reachable by walking downhill from a random start. It makes no claim to global optimality, and as the landscape section covered, global optimality is neither guaranteed nor necessary.
  • "A bigger learning rate means faster learning." Only up to a point. Past a threshold the loss oscillates or diverges and you learn nothing. The relationship between learning rate and speed is not monotonic; there is a stability ceiling, which is exactly why schedules and warmup exist.
  • "Zero training loss means a great model." Often the opposite: zero training loss frequently signals memorization and overfitting. The number that matters is loss on unseen data.
  • "More layers always help." Only if the gradient can survive the trip back through them. Without ReLU, normalization, residual connections, and sane initialization, adding depth makes a network harder to train, not better. Depth is useful because of the tricks that keep gradients healthy, not on its own.
  • "The network understands the features it learns." Each weight update is a mechanical nudge that lowers a number. Useful internal representations emerge as a statistical byproduct of that pressure, but no step contains comprehension. A trained model is a very well-fitted function, not a mind.

Where this fits in the bigger picture

What I've described is the core learning loop, sometimes called pretraining when it runs over a huge unlabeled corpus. It's the foundation, but not the whole story of a modern deployed model.

After the base loop produces a network that's good at raw prediction, teams run additional rounds of the same mechanism with different loss signals to shape behavior — making outputs more helpful, more honest, better at following instructions. That's the domain of post-training with RLHF and DPO, and while the objective changes, the underlying engine is still forward pass, loss, backprop, step. Learning to represent data as searchable meaning — the basis of embeddings and vector search — comes out of the same process too.

The reason it's worth understanding the mechanism rather than the marketing: once you know that a model is a landscape-descent over a loss function, a lot of its behavior stops being magic and starts being predictable. It's great at whatever lowers loss on its training data, and unreliable exactly where the training data was thin, biased, or ambiguous. The mechanism is the explanation. For a wider tour of the foundational ideas worth internalizing, the AI canon is a good next stop.

FAQ

What is the difference between gradient descent and backpropagation? Gradient descent is the overall strategy: repeatedly step the weights in the direction that lowers the loss. Backpropagation is the specific algorithm that computes what that direction is for every weight efficiently, in a single backward pass through the network. Gradient descent is the plan; backpropagation is how you afford to execute it. You need both, and they're often run together, but they solve different parts of the problem.

Does a neural network actually understand what it's learning? No, not in the human sense. Each training step is a mechanical adjustment that reduces a numerical error score on some examples. There is no comprehension inside any step. What looks like understanding is the statistical result of averaging an enormous number of tiny corrections until the network reliably produces useful patterns. It's better to think of a trained model as a very well-fitted function than as a mind.

What is a loss function in simple terms? A loss function is a single number that says how wrong the network's current output is, where lower is better. It compares the network's guess to the correct answer and scores the gap. All of training is a search for weights that push this number as low as possible. Different tasks use different loss functions, but they all share that one job: turn "wrong" into a measurable quantity.

Why is backpropagation such a big deal? Because without it, computing how each weight affects the error would require re-running the entire network once per weight — billions of runs for a large model, which is computationally impossible. Backpropagation gets the same information for every weight in essentially one backward sweep by reusing each layer's contribution for everything downstream. That efficiency is the reason training deep networks is practical at all.

What is the learning rate and why does it matter? The learning rate is the size of each step you take downhill on the loss landscape. Too large and training overshoots valleys, bounces around, or diverges entirely. Too small and it descends so slowly that training becomes needlessly expensive. Choosing and adjusting it well is one of the main practical skills in training, which is why much of modern optimizer design is really about setting step size and direction intelligently.

If the process is so mechanical, why do trained models generalize instead of just memorizing? Because a network has limited capacity and is scored across a huge, varied stream of examples, the cheapest way to lower its loss overall is usually to capture general patterns rather than store each example separately. Generalization emerges as the efficient solution to the optimization, not as a designed feature. The flip side is that where patterns are thin or misleading, the same process produces confident errors.

What is the chain rule and why does backpropagation depend on it? The chain rule is the calculus fact that if a change propagates through a series of steps, its total effect is the product of the effect at each step. A neural network is a long series of steps from each weight to the loss, so the influence of any weight on the loss is the product of the simple, local sensitivities along the path connecting them. Backpropagation is just an organized way of computing all of those products at once, sweeping backward and reusing shared factors. Without the chain rule there would be no principled way to attribute the final error to an individual early weight.

Why does everyone use Adam instead of plain gradient descent? Plain SGD uses one global step size and reacts only to the current gradient, which makes it slow on flat plateaus and jittery in narrow ravines. Adam keeps a smoothed average of past gradients (momentum) and a smoothed average of their squared magnitudes (a per-weight scale), so it moves faster where the signal is consistent and takes gentler, well-sized steps for each individual weight. The result is a much more forgiving optimizer that trains well across a wide range of settings with little tuning. The price is memory: Adam stores two extra numbers per weight, roughly doubling the optimizer's footprint versus the raw model.

What are vanishing and exploding gradients? The gradient reaching an early layer is a product of many per-layer factors. If those factors are consistently below 1, the product shrinks toward zero as the network deepens (vanishing), and early layers stop learning. If they are consistently above 1, the product blows up (exploding) and training destabilizes. Both were major obstacles to deep networks. The standard fixes — ReLU activations, careful initialization, normalization layers, and residual (skip) connections — all work by keeping that long product from drifting to zero or infinity, so the learning signal survives the trip back through many layers.

How is a trained model different from one that just memorized the training data? A memorizing model reaches low loss on the exact examples it saw and fails on anything new, because it stored particulars rather than patterns. A generalizing model reaches low loss on unseen data because it captured the underlying structure. You detect the difference with a held-out validation set: if training loss keeps falling while validation loss rises, the model is memorizing. Regularization techniques — weight decay, dropout, early stopping, data augmentation, and simply training on more diverse data — bias the optimizer toward the generalizing solution over the memorizing one.