Fit a line with gradient descent
Now put two earlier ideas together, the linear model and gradient descent, and let the model learn. Start with a line that is wrong: weight 0 and bias 0. Measure how far its predictions are from the true values. Work out which way to move the weight and the bias to shrink that error, and move both a little. Each round the line fits the points better. This is training, in its smallest form.
Learn it
Words to know
- mean squared error
- A loss for predicting numbers: the average of the squared differences between predictions and true values.
- gradient
- The slope of the loss for one number in the model: which way the loss moves, and how fast, when that number goes up a little.
- learning rate
- How far to move against the gradient on each update. Too small is slow; too large overshoots.
How it works
- Predict
w * x + bfor every point, and take the errorprediction - yfor each. The loss is the mean of the squared errors. - The slope for
wis2 * mean(error * x). A point with a largexmoves the weight more. - The slope for
bis2 * mean(error). - Update both together:
w = w - rate * dwandb = b - rate * db. Both slopes come from the same errors, worked out before either number changes.
Worked example
Input xs = [1, 2] ys = [2, 4] rate = 0.1 steps = 1 Output [1, 0.6]
| What | Calculation | Value |
|---|---|---|
| Predictions | w and b are 0 | 0 and 0 |
| Errors | 0 - 2 and 0 - 4 | -2 and -4 |
| Slope for w | 2 × ((-2×1) + (-4×2)) / 2 | -10 |
| Slope for b | 2 × (-2 + -4) / 2 | -6 |
| New w | 0 - 0.1 × (-10) | 1 |
| New b | 0 - 0.1 × (-6) | 0.6 |
- Start
- After 1 step
- After 2 steps
y = 2x.The true line is y = 2x. After one step the model already says 1.6 and 2.6 for the two points, much closer than 0 and 0.
Why it matters
Chapter 4 runs this same loop in PyTorch, where the slopes are worked out for you. Knowing what happens by hand makes that code readable.
Your turn
Fit a line w * x + b to some points with gradient descent on the mean squared error. Start from w = 0 and b = 0.
xs- the x value of each point; at least one
ys- the y value of each point, in the same order
rate- the learning rate
steps- how many updates to make; 0 or more
- Returns
- The list
[w, b]after the last update.
Example 1
Input xs = [1, 2] ys = [2, 4] rate = 0.1 steps = 1 Output [1, 0.6]
One update moves w from 0 to 1 and b from 0 to 0.6, as in the worked example.
Example 2
Input xs = [1, 2] ys = [2, 4] rate = 0.1 steps = 2 Output [1.32, 0.78]
A second update starts from w = 1 and b = 0.6. The errors are smaller now, so the step is smaller too.
Example 3
Input xs = [0, 1, 2, 3] ys = [1, 3, 5, 7] rate = 0.1 steps = 1 Output [1.7, 0.8]
Four points on the line y = 2x + 1. The errors are -1, -3, -5 and -7, so the slopes are 2 × (-34) / 4 = -17 and 2 × (-16) / 4 = -8.
Example 4
Input xs = [1] ys = [2] rate = 0.1 steps = 0 Output [0, 0]
With zero steps the line stays where it started.
Hints
Each hint gives away a little more. Open one only when you need it.
Hint 1: Where to start
One update needs three things in order: the error of every point, the two slopes, and then the two new values.
Hint 2: The key step
Work out all the errors with the current
wandbfirst, and keep them in a list. Use that one list for both slopes.Hint 3: The outline
Set
ntolen(xs). Repeatstepstimes: builderrorsasw * x + b - yfor each point; setdwto2 * sum(e * x for e, x in zip(errors, xs)) / nanddbto2 * sum(errors) / n; then subtractrate * dwfromwandrate * dbfromb. Return[w, b].
Solution
From here on the page gives the method away. If you are still solving, go back to the hints.
Step by step
- How far each prediction is from its true value. The errors are stored once, so both slopes are measured against the same line.
- The slope of the loss for w and for b. Each error is multiplied by
xfor the weight, because the weight's effect on a prediction grows withx. The bias affects every prediction equally. - Move both against their slopes. Both slopes were worked out before this point, so changing
wfirst does not disturb the update ofb.
The same numbered steps are the comments in the solution.
Python
def solve(xs, ys, rate, steps):
w = 0.0
b = 0.0
n = len(xs)
for _ in range(steps):
# 1. How far each prediction is from its true value
errors = [w * x + b - y for x, y in zip(xs, ys)]
# 2. The slope of the loss for w and for b
dw = 2 * sum(error * x for error, x in zip(errors, xs)) / n
db = 2 * sum(errors) / n
# 3. Move both against their slopes
w = w - rate * dw
b = b - rate * db
return [w, b]Watch out
- Do not update
wand then work out the errors again forb. Both slopes must come from the line as it was at the start of the step. - Divide by the number of points. Without it the slopes grow with the size of the data, and a rate that worked for 2 points fails for 200.
Check yourself
Why is each error multiplied by x in the slope for the weight?
Changing the weight changes a prediction by x times as much. So points with a large x say more about which way the weight should move.
Why must both slopes be worked out before either value changes?
They describe the same line. If w moved first, the slope for b would be measured on a different line.