Linear Regression with Gradient Descent
Watch how Gradient Descent iteratively minimizes the Mean Squared Error (MSE) to find the best-fit line. Adjust the learning rate or take manual steps to see the weights update.
Watch how Gradient Descent iteratively minimizes the Mean Squared Error (MSE) to find the best-fit line. Adjust the learning rate or take manual steps to see the weights update.
You are fitting y = mx + c by minimising mean squared error. The partial derivatives are:
∂L/∂m = −(2/n) Σ x(y − ŷ)
∂L/∂c = −(2/n) Σ (y − ŷ)
and each step is m ← m − η · ∂L/∂m, likewise for c. That is the same update rule a network with millions of params uses. The learning rate η controls the step size: too large and the params overshoot the min and diverge, too small and convergence takes thousands of iterations. For this two-param problem the loss surface is a paraboloid (a bowl). So there is just one min and gradient descent finds it no matter the starting point — a luxury that disappears in deeper networks where the surface has saddle points and local minima. The closed-form solution (the normal equation) computes the best m and c in one matrix step. And for linear regression it is faster and exact. Gradient descent turns needed when the net is nonlinear, the dataset is too large to invert a matrix. Or the loss function has no closed form. Stochastic gradient descent computes the gradient on a random subset (a mini-batch) rather than the full dataset, trading noise for speed. This page runs gradient descent step by step, plots the trajectory on the loss surface, and shows how the learning rate changes the path.
Watch how Gradient Descent iteratively minimizes the Mean Squared Error (MSE) to find the best-fit line.
Fitting a straight line is the smallest problem that still uses the real training loop. Two parameters, a real loss, real gradients — everything a deep network does, at a scale you can follow by hand.
You are fitting y = mx + c by minimising mean squared error. The partial derivatives are:
∂L/∂m = −(2/n) Σ x(y − ŷ)
∂L/∂c = −(2/n) Σ (y − ŷ)
and each step is m ← m − η · ∂L/∂m, likewise for c. That is the same update rule a network with millions of params uses. The learning rate η controls the step size: too large and the params overshoot the min and diverge, too small and convergence takes thousands of iterations. For this two-param problem the loss surface is a paraboloid (a bowl). So there is just one min and gradient descent finds it no matter the starting point — a luxury that disappears in deeper networks where the surface has saddle points and local minima. The closed-form solution (the normal equation) computes the best m and c in one matrix step. And for linear regression it is faster and exact. Gradient descent turns needed when the net is nonlinear, the dataset is too large to invert a matrix. Or the loss function has no closed form. Stochastic gradient descent computes the gradient on a random subset (a mini-batch) rather than the full dataset, trading noise for speed. This page runs gradient descent step by step, plots the trajectory on the loss surface, and shows how the learning rate changes the path.
Three points: (1, 2), (2, 4), (3, 6). The answer is obviously m = 2, c = 0. But start from m = 0, c = 0 and let the maths find it.
With m = c = 0 each prediction is 0. So the residuals are 2, 4 and 6.
∂L/∂m = −(2/3)[(1×2) + (2×4) + (3×6)] = −(2/3)(28) = −18.67
∂L/∂c = −(2/3)(2 + 4 + 6) = −8.00
At a learning rate of 0.01: m ← 0 + 0.187 and c ← 0 + 0.08. The line has tilted slightly toward the data. Repeat a few hundred times and it lands on m = 2, c = 0.
Fit a line, y = wx + b, by iteratively adjusting w and b to reduce the squared error. It is the smallest complete case of all training does, with two params instead of millions.
The loss is mean squared error:
L = (1/n) Σ (ŷᵢ − yᵢ)² where ŷ. = wx + b
Its two gradients, from the chain rule:
∂L/∂w = (2/n) Σ (ŷᵢ − yᵢ) xᵢ ∂L/∂b = (2/n) Σ (ŷᵢ − yᵢ)
Read those two expressions and the algorithm turns intuitive. Both are driven by the error (ŷ − y). The weight's gradient is also multiplied by x. So points far from the origin push the slope harder. The bias's gradient is just the average error. So the bias tracks the total offset.
Data: (1, 2), (2, 4), (3, 6) — the true line is y = 2x. Start at w = 0, b = 0, learning rate 0.1.
Step 1. Predictions are 0, 0, 0. Errors −2, −4, −6.
Step 2. Predictions are 2.67, 4.53, 6.40. Errors +0.67, +0.53, +0.40 — now overshooting slightly. And much less.
Step 3 onwards. The corrections keep shrinking. After a few hundred steps w ways 2 and b ways 0.
Two lessons visible in three steps. The first step is enormous since the error is enormous. And the steps shrink automatically as the fit improves — no schedule needed for that. And the loss overshot from negative to positive error: gradient descent oscillates towards a solution rather than approaching monotonically.
Ordinary least squares has an exact closed-form solution — the normal equation — so iterating towards the answer looks like a step backwards. Three reasons it is not:
Scale. The closed form needs inverting a matrix whose size is the count of features, at roughly cubic cost. And it needs the whole dataset in memory. Gradient descent works on mini-batches and scales to any size.
Generality. Change the loss to absolute error. Or add a non-linear activation, and the closed form disappears. Gradient descent needs just a derivative.
It is the same algorithm. This is the point of the exercise: what happens here is just what happens in a network with a billion params. Same loss, same chain rule, same update rule — just the count of params differs.
Divergence from too high a learning rate is the classic failure. And its signature is unmistakable: the loss raises each step, often to infinity within a dozen iterations. If you see that, the fix is almost always η, not the net.Unscaled x vals cause a subtler problem. If x is in the thousands, ∂L/∂m is thousands of times more than ∂L/∂c. So a learning rate that suits one wrecks the other and the path zig-zags down a narrow valley.
Two params, the same optimiser as a deep network. And slow enough to watch each step.
With two params the effect of the learning rate is easy to see right.
| Learning rate | Behaviour on the example above |
|---|---|
| 0.001 | Converges, very slowly — thousands of steps |
| 0.1 | Converges smoothly in a few hundred steps |
| 0.5 | Oscillates around the answer before settling |
| 1.5 | Diverges — the loss grows until it overflows |
The divergence case is worth grasp: if the step overshoots far enough that the new error is more than the old one, the next step is more still. And the process runs away. That is the same mechanism behind NaN losses in deep networks, visible here in two dimensions.
Feature scaling matters for the same reason as in networks. With x vals in the thousands, the gradient with respect to w is thousands of times more than the gradient with respect to b. So the loss surface turns a narrow ravine and no single learning rate suits both params.
import numpy as np
x = np.array([1, 2, 3], dtype=float)
y = np.array([2, 4, 6], dtype=float)
w, b, lr = 0.0, 0.0, 0.1
for step in range(500):
pred = w * x + b
err = pred - y
w -= lr * (2 / len(x)) * (err * x).sum()
b -= lr * (2 / len(x)) * err.sum()
print(w, b) # ~2.0, ~0.0
Three additions turn the code above into a network. And nothing else changes conceptually.
More params. Replace the scalar w with a matrix. And the multiplication with a matrix product. The gradient formula generalises right.
An activation function. Wrap the output in a non-linearity and the net can fit curves. The chain rule gains one factor per activation.
Layers. Feed one layer's output into the next. Backpropagation is the bookkeeping that computes all the gradients well rather than recomputing shared factors.
That is genuinely all of it. All else — Adam, batch normalisation, dropout, schedules — is a refinement of the same loop: predict, measure error, compute gradients, step.
One weight, one bias, and a loop -- then the same problem solved just. So you can watch gradient descent arrive at an answer you now know.
Building on the same setup, the next block shows the left cases.
The next block covers the left steps.
Why the factor of 2 in the gradients? It comes from differentiating the square. Some texts use 1/(2n) in the loss so it cancels. It just rescales the effective learning rate.
Does it always converge? For linear regression the loss is convex. So with a small enough learning rate it converges to the unique global min. Networks are not convex, and there is no such guarantee.
How many iterations? Until the loss stops improving. For this problem, hundreds. For networks, thousands to millions of steps.
Do I need to scale the inputs? For gradient descent, yes — unscaled features create a ravine. The closed-form solution is unaffected.
What if I use absolute error instead? The gradient turns the sign of the error. So each step is the same size no matter how wrong you are. It is more reliable to outliers and slower to settle.
Is this how scikit-learn's LinearRegression works? No — it uses the closed form. SGDRegressor is the gradient-descent version.
y = wx + b by stepping both params against the gradient of squared error.Say the answer out loud before you reveal it — recalling it is what makes it stick, and rereading it is not.
Without scrolling back — what is the one-line takeaway from this module?
What does this module say about “The two gradients”?
What does this module say about “One step, worked out”?
Take gradient descent one step at a time and watch the best-fit line and its mean squared error converge together.