Before you read on
Think about this for a minute.
You write a program that converts miles to kilometers. You run it a thousand times. Is it any better at the job than it was on the first run?
Almost certainly not. It does exactly what it did the first time, no faster and no more accurately. Running a program does not improve it. So what would have to change for a program to genuinely get better at something?
Two ways to write the converter
The normal way is that you already know the rule. One mile is 1.609 kilometers, so you write:
function milesToKm(miles) {
return miles * 1.609;
}
You supplied the 1.609. The program contributes nothing except multiplication.
Now suppose you did not know the number. You have never seen a conversion table. All you have is a handful of measurements someone recorded:
const examples = [
[1, 1.609],
[2, 3.218],
[5, 8.045],
];
Could you write a program that works out the 1.609 by itself, using only those examples? That is a different kind of program, and it is the kind this whole course is about.
A program that improves
Here is one. It is short enough to read in full, and every line is explained underneath.
const examples = [[1, 1.609], [2, 3.218], [5, 8.045]];
let factor = 0; // the program starts out knowing nothing
for (let step = 0; step < 200; step++) {
for (const [miles, km] of examples) {
const guess = miles * factor; // what we currently predict
const error = km - guess; // how far off we are
factor = factor + 0.01 * error * miles; // nudge in the right direction
}
}
console.log(factor); // 1.609...
Read it once more before the explanation. The whole idea of machine learning is in those few lines.
factorstarts at 0. The program has no knowledge at the start. Its first prediction for any distance is zero kilometers, which is badly wrong.guessis the prediction it would make right now.erroris the gap between the correct answer and the guess. If the guess is too low, the error is positive. If it is too high, the error is negative.- The last line moves
factora small amount in whichever direction reduces the error. Positive error pushes it up, negative error pushes it down. - The
0.01controls how big each nudge is. Try changing it and see what happens.
Nobody told this program that the answer was 1.609. It found the number from the examples alone.
Watch it happen
Print the value on every pass instead of only at the end:
for (let step = 0; step < 200; step++) {
for (const [miles, km] of examples) {
const guess = miles * factor;
const error = km - guess;
factor = factor + 0.01 * error * miles;
}
if (step % 20 === 0) console.log(step, factor.toFixed(4));
}
You will see it climb quickly at first, then slow down as the error shrinks, and settle near 1.609. Later in this course we will draw that curve on a canvas rather than reading numbers, because the shape tells you a great deal about whether learning is going well.
So, the answer
Yes, a program can get better at a task, but only if three things are true. It has to have something adjustable inside it. It has to have a way of measuring how wrong it currently is. And it has to have a rule for changing itself in response to that measurement.
Our converter had all three: factor was adjustable, error measured the wrongness, and the last line was the rule for changing. Every model in this course, up to and including neural networks, has exactly these three parts. Only the details grow.
Try this before the next lesson
- Set the starting
factorto 100 instead of 0. Does it still reach 1.609? - Change
0.01to0.1. Then to0.5. What breaks, and can you say why? - Add a fourth example with a deliberately wrong value, such as
[10, 50]. What happens to the answer, and is that behavior reasonable?
The second question is the one worth sitting with. We come back to it properly in the section on gradient descent.