1. One step downhill
Picture the MSE as a valley. Every (m, c) is a spot on the hillside; the best line is at the bottom. Blindfolded, you can still feel which way the ground slopes — so take a small step downhill. Repeat. That is gradient descent, the engine behind almost all modern AI.
The slope (gradient) of the MSE for a line:
err = (m × x + c) − y for each pointdm = average of 2 × err × xdc = average of 2 × err
Then step against the slope: m = m − lr × dm and c = c − lr × dc.
lr (learning rate) is the step size. Too small: slow. Too big: you leap over the valley and the error explodes.
Challenge: One gradient-descent step
Write gdStep(m, c, xs, ys, lr) that returns a new object { m, c } after one step. With n points: err = (m * x + c) - y; dm is the average of 2 * err * x; dc is the average of 2 * err; then m - lr * dm and c - lr * dc.
2. The training loop
Training is just taking many small steps:
- start with a silly line: m = 0, c = 0
- take one
gdStep - repeat a few thousand times
Each step the line tilts and lifts a little closer to the dots. After enough steps it settles at the bottom of the valley — the best-fit line. Real neural networks do exactly this, only with millions of numbers instead of two.
Challenge: Train the line
gdStep is ready. Write trainLine(xs, ys, lr, steps): start with m = 0 and c = 0, call gdStep steps times (each time using the new m and c), and return { m, c }.
3. Draw what the model learned
Numbers like m = 6.69 are hard to feel. A picture shows at once whether the line follows the dots.
On a canvas, y grows downwards, so toPixel(hours, marks) flips marks for you: 0 marks sits at the bottom. To draw the line, find the pixels of two points on it — at hours 0 and hours 7 — and join them with moveTo, lineTo and stroke.
Challenge: Plot the dots and the line
The model is trained for you (model.m, model.c). Complete the TODOs:
- Draw every student as a dot:
beginPath, arc at toPixel(HOURS[i], MARKS[i]) with radius 4, then fill. - Draw the line from hours 0 to hours 7:
beginPath, moveTo, lineTo, stroke. - Put the equation in
#eq exactly as marks ≈ M × hours + C, with M and C from toFixed(1) (e.g. marks ≈ 6.7 × hours + 31.6).