Part 01 · Mathematics for AI

Optimization

Loss functionGradient descentLearning rateLocal minima

Training is walking downhill in the fog. Loss functions, gradient descent step by step, picking a learning rate, and why the walk sometimes gets stuck.

⏱ 1-2 hours · Station 4 of 92

What it is and why it matters

You're on a hill in thick fog and want to reach the bottom of the valley. You can't see the valley. You can only feel the ground under your feet: which way slopes down, and how steeply. So you take a step downhill, feel again, take another step. That's gradient descent, and it's how nearly every model in this course is trained, from a two-number line fit to an LLM with billions of weights.

Three things decide whether the walk works:

  • The loss function: the height of the hill, a single number that says how wrong the model is.
  • The gradient: the slope under your feet (last lesson).
  • The learning rate: how big a step you take.

How it works

The loss function turns "how wrong" into one number. For predicting numbers, the usual one is mean squared error, the average of (prediction − answer)². For picking classes you'll use cross-entropy (Part 2). Training means: find the weights that make this number small.

The update rule. Repeat:

w = w − learning_rate × gradient(w)

The minus sign walks against the slope, so downhill. Where the hill is steep, the gradient is big and the step is big. Near the bottom the gradient shrinks, so the steps shrink by themselves.

The learning rate is the one knob you set by hand:

  • Too small: every step is tiny, and training takes forever.
  • Right: the loss drops fast and settles.
  • Too big: each step overshoots the bottom and lands higher on the other side. The loss zig-zags or explodes to infinity.

Local minima. A real loss surface isn't a clean bowl. It can have several valleys, and gradient descent stops in whichever one it rolls into first. Where you start (the initial weights) can change where you end. In huge neural networks this matters less than you'd fear: most valleys they find are about equally good. Saddle points and flat regions, where the slope is nearly zero but you're not at the bottom, slow training down more often.

Predict first

You train a model and print the loss every 100 steps: 2.31, 1.40, 3.95, 18.2, 1.4e6, nan. What's the most likely cause?

Visual

w = 5 (lowest loss)w = 0w = 10●●learning rate 0.1: big steps on the steep part, tiny ones near the bottomlearning rate too big: it jumps across the valley every stepeach step: w = w − learning rate × slope
The loss curve for the one-weight model, lowest at w = 5. With learning rate 0.1 the ball takes a big step on the steep side, then smaller and smaller ones, and stops at the bottom. With a learning rate that's too big, it jumps from one side of the valley to the other on every step.

Practical example

The same one-weight model from the last lesson, trained from w = 0 with three learning rates. Then a bumpy loss with two valleys, started from two different places.

# Gradient descent on loss(w) = (w*2 - 10)^2, the one-weight model from the last lesson.
# The best w is 5. Watch three learning rates.
def loss(w):
    return (2 * w - 10) ** 2

def grad(w):
    return 2 * (2 * w - 10) * 2

for lr in [0.01, 0.1, 0.3]:
    w = 0.0
    trail = []
    for step in range(1, 21):
        w = w - lr * grad(w)  # the whole algorithm is this line
        if step in (1, 2, 5, 10, 20):
            trail.append(f"{step}:{w:.2f}")
    print(f"lr={lr:<4} w after steps {'  '.join(trail)}  final loss {loss(w):.4f}")

# A bumpy loss with two valleys: where you start decides where you end.
def bumpy(w):
    return w**4 - 3 * w**2 + w

def bumpy_grad(w):
    return 4 * w**3 - 6 * w + 1

for start in [2.0, -2.0]:
    w = start
    for _ in range(200):
        w -= 0.01 * bumpy_grad(w)
    print(f"start {start:+.1f} -> w {w:+.3f}, loss {bumpy(w):+.3f}")

Output:

lr=0.01 w after steps 1:0.40  2:0.77  5:1.70  10:2.83  20:4.06  final loss 3.5605
lr=0.1  w after steps 1:4.00  2:4.80  5:5.00  10:5.00  20:5.00  final loss 0.0000
lr=0.3  w after steps 1:12.00  2:-4.80  5:31.89  10:-139.63  20:-4178.41  final loss 70003769.6591
start +2.0 -> w +1.131, loss -1.070
start -2.0 -> w -1.301, loss -3.514

Reading it:

  • lr = 0.01 is crawling. After 20 steps w is only 4.06 and the loss is still 3.56.
  • lr = 0.1 reaches w = 4.00 in one step and 5.00 by step 5. The loss is 0.
  • lr = 0.3 overshoots to 12, then −4.8, then 31.89, and by step 20 the loss is seventy million. Same model, same data, same code: only the step size changed.
  • On the bumpy loss, starting at +2 settles at w = 1.131 (loss −1.07), and starting at −2 settles at w = −1.301 (loss −3.51). Both runs stopped where the slope is zero, but only one found the deeper valley.

In production

  • The learning rate is the first thing to tune. If training misbehaves, try 3x and 10x smaller and larger before changing anything else. Most frameworks also use a schedule: a short warm-up, then a slowly shrinking rate.
  • Use better optimisers. Plain gradient descent is the base. Momentum and Adam (Part 3) keep a running memory of past gradients, so they roll through flat spots and handle weights that need very different step sizes. Adam is the default for transformers.
  • Watch the loss curve. Log the loss at every step. A curve that falls then rises, a nan, or a curve that never moves tells you more than any single number.
  • Each step costs a full pass over the data's gradient. Computing it on all the data is too slow, so real training uses small random batches (mini-batch SGD), which also adds a bit of useful noise that helps escape bad spots.
  • Guard against nan. One overflow poisons every weight. Clip gradients to a maximum size, and stop the run automatically if the loss becomes nan or infinite, so you don't burn GPU hours on garbage.

Key takeaway

Training is walking downhill on the loss: w = w − learning_rate × gradient, repeated. The learning rate decides everything: too small is slow, too big explodes, and where you start decides which valley you end in.

Practice

Run the example with learning rates 0.2 and 0.24. For each, does the loss go to 0, zig-zag, or explode? Then find the learning rate above which this model always explodes. Hint: one step multiplies the distance from w = 5 by (1 − 8 × lr).

Answer

The update is w − 5 → (1 − 8·lr)(w − 5). With lr = 0.2 the factor is −0.6: w jumps across the bottom each step but the distance shrinks, so it converges with a zig-zag. With lr = 0.24 the factor is −0.92: it still converges, but slowly, bouncing side to side (that's the red ball in the diagram). It explodes when |1 − 8·lr| > 1, so for lr above 0.25. lr = 0.125 is the perfect step: factor 0, it lands on w = 5 in one step.

Station stamp

Finish the chapter

Done reading? Press Complete to save your progress. XP is Pro-only — on Pro this chapter is worth +10 XP.

Go Pro to earn XP →