ap.Abhishek Patel

Search

Search notes, essays, projects, the library and the AI course. Use arrow keys to choose and Enter to open.

Lesson 2 of 7 30 min

Gradient descent

Fit a forecasting line by gradient descent in NumPy, trace updates by hand, and diagnose learning rates that crawl, bounce or explode.

Words in this lessonLoss function · Gradient · Gradient descent · Learning rate · Mini-batch · Parameters
Loss function
A formula that turns “how wrong is the model?” into a single number to minimise. Like a scorecard that gives one total penalty for every mistake made on a tray of pastries.
Gradient
The list of slopes of the loss, one for every parameter, pointing in the direction where the loss rises fastest. Like a compass that always points uphill, so you walk the other way to get down.
Gradient descent
The method training uses to decide which way, and how far, to turn each parameter to reduce the loss. Like walking down a hillside blindfolded, feeling which way the ground slopes and taking a small step that way.
Learning rate
The number that sets how big a step training takes on each update. Like your stride length walking downhill: tiny steps take forever, giant leaps overshoot the valley.
Mini-batch
A small random group of training examples used for one update step. Like tasting one tray of croissants instead of every croissant baked that day.
Parameters
The adjustable numbers inside a model, set during training, that decide what it outputs. Like the knobs on a sound mixing desk: the same desk sounds completely different depending on where the knobs sit.
On this page
  1. The data, and what "a good line" means
  2. Arjun's brute-force idea
  3. A walk in the fog
  4. Following one parameter, step by step
  5. Now take giant strides
  6. Opening the hood: the update rule
  7. Gradient descent in code
  8. Why the standardising mattered
  9. Tasting by the tray: mini-batches
  10. Where gradient descent goes wrong
  11. Try it yourself
  12. Common mistakes
  13. Recap
  14. Go deeper

Crumb sells cold coffee, and cold coffee has a problem: the cold brew has to be made the night before. Last Tuesday, a 31-degree day, the Koregaon Park store prepped 90 cups and sold 70. Twenty cups went down the sink at ₹45 each. On Saturday, at 37 degrees, they prepped 60 and ran out by 2pm. The shift lead counted 28 customers who left without buying anything.

Meera wanted a rule for the evening shift. “The weather app tells us tomorrow’s temperature. Give me a number of cups.”

Arjun had five days of data and a spreadsheet. He typed a formula, cups = 2 × temperature − 10, and compared it to reality. Too low. He tried 3 × temperature − 20. Closer. He nudged the 3 to 2.9, then the 20 to 22, then back. Twenty minutes later he had a decent line and a headache.

Priya leaned over his shoulder. “You’re doing gradient descent. Slowly, by hand, by feel. Let’s give the computer a compass instead.”

Important

The idea in one sentence: gradient descent finds good parameter values by repeatedly measuring how wrong the model is, computing which direction makes it less wrong (the gradient), and taking a small step that way, with the learning rate setting the step size.

The data, and what “a good line” means

Here are Arjun’s five days at Koregaon Park:

Temperature (°C) 25 28 31 34 37
Cold coffees sold 52 61 70 80 88

The model is a straight line with two parameters (the adjustable numbers a model learns): a slope and an intercept .

is the temperature and (“y-hat”) is the predicted number of cups. Arjun’s guess of predicts 55 cups at 25 degrees. Reality was 52, an error of 3.

To judge a line, you need one number for “how wrong is it overall?”. Take each day’s error, square it (so a miss of −3 and a miss of +3 count the same, and big misses count a lot more), then average. That is mean squared error, or MSE, the most common loss function (a formula that boils “how wrong” down to one number) for predicting quantities:

A perfect line has loss 0. The goal is to find the and that make as small as possible.

Arjun’s brute-force idea

Arjun had a better plan than nudging by hand. “Computers are fast. Let me try every combination.”

import numpy as np

temps = np.array([25, 28, 31, 34, 37], dtype=float)
sales = np.array([52, 61, 70, 80, 88], dtype=float)

best = (None, None, float("inf"))
for w in np.arange(0, 20, 0.01):          # 2,000 slopes
    for b in np.arange(-100, 100, 0.1):   # 2,000 intercepts
        loss = ((w * temps + b - sales) ** 2).mean()
        if loss < best[2]:
            best = (w, b, loss)
print(best)

Four million combinations. It ran for about fifteen seconds on his laptop and found , , with a loss of 0.14. He looked pleased.

“Good,” said Priya. “Now do the late-delivery network you’re building this week. It’ll have 241 parameters.”

“Same idea, more loops.”

“Suppose you only try 10 values for each parameter. That’s 10 times 10 times 10, 241 times. combinations. There are about atoms in the observable universe.”

Arjun did not reply. Brute force works for two knobs and is hopeless for anything you would call a neural network. An LLM has billions of knobs. There has to be a way to improve the knobs without trying them all.

A walk in the fog

“Have you been up Sinhagad at dawn in the monsoon?” Priya asked. “Fog so thick you can’t see your own feet. Say you want to get down to the car park. What do you do?”

“Walk downhill?”

“Which way is downhill? You can’t see.”

Arjun thought. “I’d feel it. Whichever way the ground slopes down under my feet, I’d step that way. Then feel again.”

“That’s the whole algorithm.”

  • Where you stand is the current values of the parameters, and .
  • Your height is the loss. Lower is better.
  • The slope under your feet is the gradient (the list of slopes of the loss, one per parameter, pointing in the direction where the loss rises fastest).
  • Your stride is the learning rate (a small number that sets how far you move each step).

You never see the whole mountain. You only feel the local slope, step, and feel again. With two parameters, the “mountain” is a surface you could draw. With 241, or a billion, nobody can picture it, but the procedure is identical, because computing a slope does not care how many directions there are.

ClipGradient descent: walking downhill1/6
Loss (how wrong) = 160knob setting →
Start with random knob settings. The loss is high.

“What if I take giant strides to get down faster?” Arjun asked.

“Try it and see,” Priya said. “On paper first.”

Following one parameter, step by step

To see every number, shrink the problem. One parameter, one data point. The model is (no intercept). The single data point is , . The right answer is obviously , but the algorithm does not know that.

The loss for this one point is:

Its derivative (the slope of the loss as you change , from lesson 1) is:

The update rule says: new = old − learning rate × slope. Start at with a learning rate of 0.05.

Step Slope Change New Loss before
1 0.00 −24.00 +1.20 1.20 36.0
2 1.20 −14.40 +0.72 1.92 12.96
3 1.92 −8.64 +0.43 2.35 4.67
4 2.35 −5.18 +0.26 2.61 1.68
5 2.61 −3.11 +0.16 2.77 0.60

The slope is negative, which means “increasing decreases the loss”, so goes up. It creeps towards 3. Nobody told it the answer; it felt its way there.

Note

Pause and think. The learning rate stayed at 0.05 the whole time, yet the steps shrank: +1.20, +0.72, +0.43, +0.26. Why?

Show the answer

The step is learning rate × slope, and the slope shrinks as you approach the bottom of the valley. At the slope is exactly zero, so the step is zero and the parameter stops moving. Gradient descent slows down automatically as it arrives, like a ball settling in a bowl. That is also why it can be painfully slow near the end: tiny slopes mean tiny steps.

Now take giant strides

Same start, learning rate 0.3:

Step Slope Change New
1 0.00 −24.0 +7.20 7.20
2 7.20 +33.6 −10.08 −2.88
3 −2.88 −47.0 +14.11 11.23

It leaps right over the answer to 7.2, then overcorrects to −2.88, then flies off to 11.23, further away each time. This is divergence. In real training it looks like a loss that climbs and then turns into nan (not a number, which is what a computer prints when values overflow).

There is a neat way to see exactly where the cliff edge is. For this problem, every step multiplies your distance from the answer by , where (“eta”) is the learning rate:

Learning rate Multiplier What happens
0.01 0.92 Shrinks the gap by 8% a step: slow but steady
0.05 0.60 Shrinks by 40% a step: good
0.125 0.00 Lands on 3 in one step: perfect (and lucky)
0.25 −1.00 Bounces between 0 and 6 forever
0.3 −1.40 Each bounce 40% bigger: explodes

The best learning rate depends on how steep the valley is. Steeper valleys need smaller strides. A real network has a different steepness in every direction, which is why choosing the learning rate is part science, part trying a few values.

Opening the hood: the update rule

Back to two parameters and the full dataset. For MSE on a straight line, calculus gives the slope for each parameter:

The curly just means “slope with respect to this one parameter, holding the others still”. You do not need to derive these; read them. The slope for is twice the average error. If the line predicts too high on average, the slope is positive, and stepping against it lowers . The slope for is the same thing, but each error is weighted by its temperature, so hot days have more say over the slope.

Put both slopes in a list, (“nabla L”, the gradient), put both parameters in a list, (“theta”), and the entire algorithm is one line:

New parameters equal old parameters minus learning rate times gradient. The minus sign is “go downhill”. Repeat until the loss stops falling.

Gradient descent in code

Here it is on the cold coffee data. One extra step at the top: the temperatures are standardised (rescaled to mean 0 and standard deviation 1, as in lesson 1). You will see why in a moment.

import numpy as np

temps = np.array([25, 28, 31, 34, 37], dtype=float)
sales = np.array([52, 61, 70, 80, 88], dtype=float)

# Standardise the input so one learning rate suits both parameters
mu, sigma = temps.mean(), temps.std()     # 31.0 and about 4.24
x = (temps - mu) / sigma

w, b = 0.0, 0.0      # start anywhere
lr = 0.1             # the learning rate

for step in range(101):
    pred = w * x + b                 # 1. predict
    error = pred - sales
    loss = (error ** 2).mean()       # 2. measure (MSE)
    dw = 2 * (error * x).mean()      # 3. slope for w
    db = 2 * error.mean()            #    slope for b
    w -= lr * dw                     # 4. step downhill
    b -= lr * db
    if step % 20 == 0:
        print(f"step {step:3d}  loss {loss:8.2f}  w {w:6.2f}  b {b:6.2f}")

t = 30
print(f"Forecast at {t}°C: {w * (t - mu) / sigma + b:.1f} cold coffees")

Line by line, the new parts: error is how far off each day’s prediction is. dw and db are the two slope formulas from above, in NumPy. w -= lr * dw is the update rule. The last line converts 30 degrees into the same standardised units before predicting.

step   0  loss  5093.80  w   2.57  b  14.04
step  20  loss     0.82  w  12.75  b  69.55
step  40  loss     0.14  w  12.87  b  70.19
step  60  loss     0.14  w  12.87  b  70.20
step  80  loss     0.14  w  12.87  b  70.20
step 100  loss     0.14  w  12.87  b  70.20
Forecast at 30°C: 67.2 cold coffees

The loss falls from 5,094 to 0.14 in about forty steps and then stops, because it has reached the bottom. That 0.14 is exactly what Arjun’s four-million-combination search found, in 101 cheap steps instead of four million.

(Why is 12.87 and not 3.03? Because it is the slope per standard deviation of temperature, not per degree. One standard deviation is 4.24 degrees, and . Same line, different units.)

Why the standardising mattered

Arjun tried removing the standardisation, using raw temperatures with the same learning rate of 0.1. The loss went to infinity within a few dozen steps.

Look at the slope formula for : every error is multiplied by . With raw temperatures around 30, the slope for is roughly 30 times bigger than the slope for . A step size that is sensible for is wildly too big for , which overshoots and explodes, exactly like the learning rate 0.3 table. Shrink the learning rate until behaves, and now crawls.

In the fog analogy: the valley is a long, narrow ravine, steep across and nearly flat along. You keep bouncing between the walls while barely moving down the length. Standardising reshapes the ravine into a round bowl, where every direction is about equally steep and one stride length fits all. This is the main reason almost every deep learning pipeline standardises its inputs.

Tasting by the tray: mini-batches

The code above looks at all five days before taking each step. That is called batch gradient descent. Fine for five rows. Hopeless for Crumb’s 50,000 product photos, where computing one exact slope would mean processing every photo before moving once.

Priya’s bakery version: you want to know whether today’s croissant batch needs more butter. You could taste all 400 croissants (accurate, and nobody wants to), taste one random croissant (fast, but it might be the odd one), or taste a tray of 32 (a good estimate, quickly).

  • Stochastic gradient descent (SGD) uses one example per step. Very cheap, very noisy.
  • Mini-batch gradient descent uses a small random group of examples, a mini-batch (usually 32 to 256), per step. This is what everyone actually does. Confusingly, libraries still call it “SGD”.

Each mini-batch gives an estimate of the true slope: right on average, wrong by a bit each time. So the path down the mountain wobbles. That is mostly fine. You get hundreds of slightly wobbly steps in the time one perfect step would take.

Note

Pause and think. If the full dataset gives the exact slope, why not always use it, even if each step is slower? Wouldn’t a perfect path be worth it?

Show the answer

Two reasons. First, cost: with 50,000 photos, one exact step costs as much as about 1,500 mini-batch steps of 32, and those 1,500 noisy steps get you much further downhill than one perfect step. Second, the noise is useful. A slightly jittery path can bounce out of small dips and flat regions that a perfectly smooth path would settle into and get stuck. Many practitioners believe this noise also helps models generalise better to new data, though exactly why is still researched.

Where gradient descent goes wrong

The cold coffee problem is a perfect bowl: one bottom, and every path leads there. Neural networks are not so kind. Here is what goes wrong in practice, in rough order of how often it bites.

The learning rate is wrong. By far the most common problem. Too high and the loss jumps around or becomes nan. Too low and training crawls, and you conclude the model “can’t learn” when it simply has not had time. When anything looks off, try the learning rate 10 times smaller and 3 times larger before changing anything else.

Features are on different scales. As you saw, raw inputs create ravines. Standardise them.

The landscape is bumpy. A neural network’s loss surface is a mountain range of ridges, plateaus and valleys inside valleys. Researchers spent years worrying about local minima (dips that are not the lowest point). It turns out that with millions of parameters, most dips are roughly as good as each other. The bigger practical problems are plateaus (flat regions where the slope is nearly zero and progress stalls) and saddle points (downhill in some directions, uphill in others). The upgrades to gradient descent in two lessons’ time, momentum and Adam, exist largely to push through those.

It finds the best answer for the data you gave it, not for the world. Arjun’s line was trained on days between 25 and 37 degrees. In July, on a 23-degree monsoon day, it predicted 46 cups and the store sold 18, because rainy days have nothing to do with the hot days in the data. Gradient descent did its job perfectly. The data was the problem. You will see this again, and properly, in lesson 5 and in Module 29’s forecasting lesson.

Try it yourself

Run the code above with these learning rates, keeping 100 steps: 0.01, 0.1, 0.5, 1.0, 1.1. Before you run each, write down your prediction: converge, crawl or explode?

Show the answer
  • 0.01: crawls. The loss is still about 93 after 100 steps.
  • 0.1 and 0.5: both reach 0.14, the best a straight line can do on this data.
  • 1.0: stuck. The loss stays at 5,093.8 forever, bouncing between two points, like the 0.25 row in the one-parameter table.
  • 1.1: explodes, reaching around .

Notice the narrow gap between “works well” (0.5) and “broken” (1.0). On real models you find the right learning rate by trying a few values a factor of 3 to 10 apart.

Common mistakes

  • Getting the sign wrong. w += lr * dw climbs instead of descending. If the loss rises steadily from the very first step, check the sign.
  • Treating the learning rate as a one-time choice. It is the most important setting in training. Revisit it whenever anything changes: new data, new model size, new batch size.
  • Skipping input scaling. Unscaled features make one learning rate wrong for every parameter at once.
  • Judging progress by a single step. With mini-batches, the loss jumps around. Look at the trend over many steps.
  • Thinking zero loss is the goal. Zero loss on the training data usually means the model has memorised it, which is a problem you will meet in lesson 5.

Recap

  • A loss function, such as MSE, turns “how wrong is the model?” into one number.
  • The gradient is the slope of the loss for every parameter; stepping against it lowers the loss.
  • Gradient descent repeats: predict, measure, compute the gradient, update .
  • Too small a learning rate crawls; too big overshoots and diverges. Standardising inputs makes one learning rate fit all parameters.
  • Real training uses mini-batches: noisy but cheap estimates of the slope, hundreds of steps for the cost of one exact step.

That evening Arjun explained the cold coffee rule to Meera. “The computer starts with a random line and checks how wrong it is against the last five days. Then it works out which way to tilt and slide the line to be a bit less wrong, and moves it a little. It does that about forty times and the line stops improving. Thirty degrees tomorrow, prep 67 cups.”

The store sold 66. Meera was impressed for about three seconds. “And the photo sorter? That’s going to be millions of these little numbers, isn’t it?”

“Which is why nobody writes the slope formulas by hand,” Priya said. “Arjun, install PyTorch. Tomorrow the computer does the calculus too.”

Go deeper

Video Gradient descent, how neural networks learn · 3Blue1Brown

Check your understanding

3 quick questions
1. Why can’t you train a 241-parameter network by trying every combination of values, as Arjun did for two parameters?
2. For the loss (2w − 6)², each update multiplies the distance to the answer by (1 − 8 × learning rate). What happens with a learning rate of 0.3?
3. Why do practitioners use mini-batches of, say, 32 examples rather than computing the exact gradient over all 50,000 examples for every step?