ML · Week 1 · Note 1 of 15

What machine learning is: data, model, loss, optimizer

Machine learning is programming by example: instead of writing the rules, you show the computer data and let it find rules that fit. Every ML system, from a line through three points to GPT, has the same four parts. This note names them, builds the smallest possible one by hand, and gives you the vocabulary for the rest of the track.

Why this note matters

Interviewers for AI roles ask the big-picture question more often than juniors expect, because it reveals whether you have a mental model or a pile of memorized terms. “Explain machine learning to someone non-technical.” “What is the difference between supervised and unsupervised learning?” “What are the parts of a training loop?” “What is a hyperparameter?” These are easy marks if you have one clear picture, and that picture is the four-part loop on this page. Every later note, including the ones on transformers, is a specialization of it.

Questions that are really this note:

  • “How is machine learning different from ordinary programming?”
  • “Walk me through what happens when a model trains.”
  • “Parameters versus hyperparameters?”
  • “Is training a language model supervised or unsupervised?”
  • “Why do we split data into train and test sets?”

In plain words

Everyday ideaTechnical termSymbol
The examples you learn fromtraining data(xi,yi)(\mathbf{x}_i, y_i) pairs
The facts about one examplefeatures (inputs)x\mathbf{x}
The right answer for one examplelabel (target)yy
The recipe with adjustable amountsmodelfθ(x)f_\theta(\mathbf{x})
The adjustable amountsparameters (weights)θ\theta
The recipe’s guesspredictiony^\hat{y} (“y hat”)
The taste test: how wrong is the guess?loss functionL(y^,y)L(\hat{y}, y)
“Less salt next time”optimizergradient descent
Cooking it again with the new amountstraining step (iteration)
Serving the dish to a guestinference (prediction on new data)

The four parts of every ML system

data features x model f(x; θ), the knobs loss how wrong is ŷ? optimizer turn the knobs label y the right answer prediction ŷ update θ the data also carries the labels
Fig. 1. The training loop. Data goes in, the model guesses, the loss compares the guess with the label, and the optimizer nudges the model’s parameters. Repeat thousands of times.

Take the parts one at a time, with the example this track will use for the next two weeks: predicting a house’s price from its size.

Data. A set of examples, each with features and, for supervised learning, a label. Here each example is one house: the feature is its size, the label is the price it sold for. The data is usually written as a matrix XX with one row per example (the data matrix from the matrices note) and a vector y\mathbf{y} of labels. Data is the part people underestimate: in practice, more and cleaner data beats a cleverer model far more often than the other way round.

Model. A function with adjustable parameters that turns features into a prediction. The simplest one for house prices is a line, y^=w⋅size+b\hat{y} = w \cdot \text{size} + b, with two parameters. A neural network (week 5) is the same idea with millions of parameters and a more flexible shape. Choosing the form of the model (line? tree? network? how big?) is your job; choosing the parameter values is the optimizer’s.

Loss. A single number that says how wrong the model’s predictions are on the data, with zero meaning perfect. For prices, the standard choice is the mean squared error: take each prediction minus its label, square it so that over- and under-predictions both count as bad, and average. The loss turns the vague goal “predict well” into a precise target: make this number small.

Optimizer. The procedure that changes the parameters to reduce the loss. The one everyone uses is gradient descent: compute which way each parameter should move to reduce the loss by a little, move all of them that way, repeat. Week 2 is about exactly how. For now the key insight is that the optimizer never sees the problem; it only sees the loss number and the knobs, and it turns knobs to push the number down.

Run the loop: predict on the data, compute the loss, update the parameters, predict again. Each pass through the whole dataset is an epoch. Stop when the loss stops improving, or when a clock runs out. The parameters at the end are the trained model; “saving a model” means saving those numbers.

Watch StatQuest: A Gentle Introduction to Machine Learning About 12 minutes. The whole picture, with the point that testing on new data is what makes a method good, which the next section is about.

A first model, by hand

Write size in thousands of square feet, so the data is x=(1,1.5,2)x = (1, 1.5, 2) and the prices are y=(200,300,380)y = (200, 300, 380). The model is a line with two knobs:

y^=w x+b\hat{y} = w\,x + b

The loss is the mean squared error over the three houses:

L(w,b)=13∑i=13(y^i−yi)2=13∑i=13(wxi+b−yi)2L(w, b) = \frac{1}{3}\sum_{i=1}^{3} (\hat{y}_i - y_i)^2 = \frac{1}{3}\sum_{i=1}^{3} (w x_i + b - y_i)^2

Now play optimizer. Try three settings of the knobs and score each one:

KnobsPredictions for x = 1, 1.5, 2Errors (prediction − price)SquaredLoss (mean)
w=180, b=0w = 180,\ b = 0180, 270, 360−20, −30, −20400, 900, 400566.7
w=200, b=0w = 200,\ b = 0200, 300, 4000, 0, +200, 0, 400133.3
w=190, b=10w = 190,\ b = 10200, 295, 3900, −5, +100, 25, 10041.7
(1, 200)(1.5, 300)(2, 380) size (thousand sq ft) price w = 180, b = 0: loss 567w = 200, b = 0: loss 133w = 190, b = 10: loss 42 red ticks = the errors loss = mean of their squares
Fig. 2. Three candidate lines through three houses. The loss is the average squared vertical gap between the line and the dots. The red line has the smallest gaps.

The third setting is best of the three, and you found it the way every optimizer does: by looking at how wrong the current guess was and moving the knobs in the direction that reduces the error. The second row was too high for the big house, so you lowered the slope a little and lifted the intercept to keep the small houses right. Gradient descent will do exactly this reasoning with calculus instead of intuition, and the code section does it with brute force. The best line of all turns out to be w=180, b≈23.3w = 180,\ b \approx 23.3, with a loss of about 22.2; you will derive that in the linear regression note.

Notice what “learning” meant here. Nothing mystical: a model shape, a score, and a search over the knobs. The model never “understood” houses. It found two numbers that make a score small. Keep this deflationary picture; it is accurate all the way up to the largest language model, and it is what interviewers want to hear.

The real goal: new data

memorized: training loss 0 learned: training loss small, not 0 new point new point
Fig. 3. Two models fit to the same nine points. Left: a wiggly curve passing through every point has zero training loss and predicts the new point (open circle) badly. Right: a straight line misses the training points slightly and predicts the new point well.

The ability to do well on unseen data is called generalization, and it is the actual objective of machine learning. The training loss is only a proxy for it. A model that drives training loss to zero by memorizing the examples, like the wiggly curve, has overfit: it learned the noise along with the pattern. A model too simple to capture the pattern at all has underfit. The whole craft of ML sits between those two failures, and the overfitting note next week gives it a full treatment.

The practical rule follows immediately. Before you train anything, split the data: a training set the model learns from and a test set it never sees until the very end, when you measure it once. Most projects add a third validation set for making choices during development, so that the test set stays untouched. Any number you report from data the model trained on is not evidence of anything. The data splits note in week 3 has the details and the traps.

Read Google Machine Learning Crash Course: Generalization A short page with the same picture as Fig. 3 and a clear statement of the train/test rule. Five minutes.

Kinds of learning

machine learning supervised unsupervised self-supervised reinforcement labels given by people regression: a number classification: a category no labels clustering (k-means) dimensionality reduction (PCA) labels made from the data predict the next word how language models learn rewards, not labels games, robots teaching chat models manners
Fig. 4. The kinds of learning, split by where the label comes from. Interviews mostly ask about the first two; the way language models are trained is the third.
KindWhat the data looks likeTypical tasksIn these notes
Supervised Features plus a human-provided label for each example Regression predicts a number (price, temperature). Classification predicts a category (spam or not, which digit). Linear and logistic regression, trees, most of weeks 1–3
Unsupervised Features only, no labels Clustering groups similar examples. Dimensionality reduction compresses features while keeping structure. k-means and PCA, week 4
Self-supervised Raw data, with labels manufactured from it Predict a hidden part from the visible part: the next word, a hidden word, a missing patch of an image. How language models are trained, weeks 7–9
Reinforcement An agent acting in an environment, receiving rewards Learn behaviour that collects the most reward over time: games, robots, and teaching chat models which answers people prefer. Preference tuning of chat models, week 10, at the depth interviews need

Two clarifications that interviewers like. First, regression and classification differ only in the type of the label, and that changes the loss: squared error for numbers, and a different loss for categories that you meet next week (the log loss ). The rest of the loop is identical. Second, a word you will hear constantly: a language model is a model whose only job is to guess the next piece of text given the text so far, and the pieces of text it works with, usually words or parts of words, are called tokens. “Large language model” (LLM) just means one with billions of parameters. So the question “is training an LLM supervised?” has a precise answer: the mechanics are supervised (there is a label and a loss at every position), but the labels cost nothing because they are the next tokens of the text itself. That is what “self-supervised” means, and it is why LLMs could be trained on the whole internet without anyone labelling it.

Read Google Machine Learning Glossary Bookmark it. When any term in these notes is unclear, its entry here is short, correct and has an example. Look up “supervised”, “unsupervised” and “self-supervised” now.

The workflow around the loop

define taskget + split databaselinetrainevaluateiteratedeploy + monitor and the metric train / val / test the dumb model the loop of Fig. 1 on held-out data change one thing, train again
Fig. 5. The standard workflow. The training loop of Fig. 1 is only the fourth box. Evaluation always uses data that was set aside before training began.
  1. Define the task and the metric. What is the input, what is the output, and what single number will tell you the model is good enough? The metric is what the business cares about (accuracy, revenue, time saved) and is often different from the loss the optimizer minimizes. Decide it first, or you will decide it after seeing results, which is cheating.
  2. Get the data and split it. Training, validation and test sets, separated before you look too closely. Clean it, and look at examples by hand; most project-ending bugs live in the data.
  3. Build a baseline. The simplest thing that could work: predict the average, predict the most common class, or use a rule of thumb. Every real model must beat the baseline on the validation set, and the margin by which it does so is the honest measure of what you have gained. The next section works this out in full.
  4. Train. The loop of Fig. 1.
  5. Evaluate on held-out data. The validation set during development. The test set once, at the end, for the number you report.
  6. Iterate. Change one thing at a time: a feature, a model size, a hyperparameter. Measure again. Keep a log; the log is where the interview stories come from.
  7. Deploy and monitor. The world changes after you ship, and so does the data. A model that was good in March can be bad in September. Monitoring is part of the job, and the production track in week 15 is about it.

This is also the structure of Project 0 and of every project after it. Projects that follow this shape produce numbers you can defend; projects that skip the baseline and the split produce numbers nobody should believe, including you.

Read Kaggle Learn: Intro to Machine Learning A free, short, hands-on course that walks this exact workflow on a housing dataset in a notebook. About three hours in total; do the first four lessons this week.

Baselines: is the model any good?

A baseline is the simplest predictor that could reasonably be used, usually one that ignores the features entirely, against which every real model is compared. It turns a raw number (“MSE 3424”) into a meaningful one (“a third less error than guessing the average”). It also catches bugs: a model that does worse than the baseline is broken, not just weak.

The three houses, by hand

Go back to the three houses: sizes 1, 1.5 and 2 (thousand square feet), prices 200, 300 and 380. The baseline ignores the sizes and guesses the average price for every house:

guess=200+300+3803=293.3\text{guess} = \frac{200 + 300 + 380}{3} = 293.3
HousePriceBaseline guessErrorSquared
1,000 sq ft200293.3+93.38,711
1,500 sq ft300293.3−6.744
2,000 sq ft380293.3−86.77,511
Mean squared error5,422

The best line, which does use the size, had a mean squared error of 22.2. Now the number means something: using the size removed almost all of the error the lazy guess made.

guess 293 for all baseline: MSE 5,422 best line: MSE 22.2 price price
Fig. 6. Left: the baseline is a flat line. It gives every house the same price, so the errors (red) are large. Right: the best line uses the size and the errors almost vanish. The baseline is what the model has to beat.

One number for “how much better”

Compare the two errors with one ratio. The model’s error divided by the baseline’s error says what fraction of the lazy guess’s error is left. One minus that is the fraction the model removed:

skill=1−model errorbaseline error=1−22.25,422=0.996\text{skill} = 1 - \frac{\text{model error}}{\text{baseline error}} = 1 - \frac{22.2}{5{,}422} = 0.996

Read it as “the model removes 99.6% of the error you would make by guessing the average”. Three things to know:

  • 1 (100%) means a perfect model. 0 means no better than the baseline.
  • Below 0 means worse than guessing the average. That is a bug or a badly broken model.
  • When the error is mean squared error and the baseline is the mean, this number has a famous name, R² (“R-squared”). You will meet it properly in the linear regression note. It is nothing more than “improvement over the mean baseline”.

Why the average, and not some other number?

If you must guess one number for everyone, which number is best depends on how mistakes are scored. There are two common ways. Mean squared error squares each miss and averages, as before. Mean absolute error (MAE) just averages the sizes of the misses, ignoring whether each was too high or too low: misses of −20 and +10 give (20 + 10) / 2 = 15. Try four guesses on the three house prices, scored both ways:

Guess for every houseMean squared errorMean absolute error
2507,30076.7
293.3 (the mean)5,422 (smallest)62.2
300 (the median)5,46760.0 (smallest)
3508,63376.7

Squared error punishes big misses heavily, so the best single guess is pulled toward the far-away prices: that is the mean. Absolute error treats every unit of miss the same, so the best single guess is the middle value: the median. So the right baseline matches the metric: mean for squared error, median for absolute error. This is also why a single huge price in the data drags a mean-based model around while a median barely moves.

The usual baselines

TaskBaselineWhy it is the right one
Predict a number, scored by squared errorThe training meanThe best single guess under squared error, as above.
Predict a number, scored by absolute errorThe training medianThe best single guess under absolute error.
Pick a categoryThe most common class (the “majority class”)The best single guess when you score by accuracy.
Predict tomorrow from the past (a time series)“Same as yesterday”, or same as this day last weekHard to beat for things that change slowly, such as weather or daily sales.
Any task with a model already runningThe current production modelA new model must beat what is already there, not just the lazy guess.
Any taskA simple rule a person would write, such as “flag emails containing ‘lottery’”If machine learning cannot beat the obvious rule, it is not worth its cost.

Always compare against the strongest simple baseline, not the weakest. Guessing zero for every patient is technically a baseline, and any model beats it by miles, which proves nothing. The code below shows exactly this trap.

Code: the three houses

import numpy as np

# the three houses from earlier
prices = np.array([200.0, 300.0, 380.0])

# The baseline ignores the sizes and guesses the same price for every house.
guess = prices.mean()                            # 293.33
baseline = np.full_like(prices, guess)           # [293.33 293.33 293.33]
baseline_mse = np.mean((baseline - prices) ** 2)
print(round(guess, 2), round(baseline_mse, 1))   # 293.33 5422.2

# The best line from earlier uses the sizes.
sizes = np.array([1.0, 1.5, 2.0])
model_mse = np.mean((180 * sizes + 23.33 - prices) ** 2)
print(round(model_mse, 1))                       # 22.2

# How much of the baseline's error did the sizes remove?
skill = 1 - model_mse / baseline_mse
print(f"{skill:.1%}")                            # 99.6%

# Why the mean? Try other constant guesses and score each one two ways.
for c in [250, prices.mean(), np.median(prices), 350]:
    mse = np.mean((c - prices) ** 2)             # mean squared error
    mae = np.mean(np.abs(c - prices))            # mean absolute error
    print(f"guess {c:6.1f}   MSE {mse:7.1f}   MAE {mae:5.1f}")
# guess  250.0   MSE  7300.0   MAE  76.7
# guess  293.3   MSE  5422.2   MAE  62.2    <- the mean wins on squared error
# guess  300.0   MSE  5466.7   MAE  60.0    <- the median wins on absolute error
# guess  350.0   MSE  8633.3   MAE  76.7

Code: a real dataset, three baselines and a model

The diabetes dataset has 442 patients. For each one there are 10 measurements (age, body mass index, blood pressure and six blood tests) and a score for how much the disease progressed one year later, between 25 and 346. The code splits off 89 patients as a test set, scores three baselines and a linear model on them, and reports the skill.

import numpy as np
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, mean_absolute_error

# 442 patients, 10 measurements each; y = disease progression score (25 to 346)
X, y = load_diabetes(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=0)

# Step 1: the baselines. Each is ONE number, computed from the TRAINING
# answers only, then guessed for every one of the 89 test patients.
guesses = {"mean": y_train.mean(), "median": np.median(y_train), "zero": 0.0}
for name, value in guesses.items():
    pred = np.full_like(y_test, value)
    mse = mean_squared_error(y_test, pred)
    mae = mean_absolute_error(y_test, pred)
    print(f"{name:>6} baseline   guess {value:6.1f}   MSE {mse:6.0f}   MAE {mae:5.1f}")

# Step 2: the real model, which reads the 10 measurements.
model = LinearRegression().fit(X_train, y_train)
pred = model.predict(X_test)
model_mse = mean_squared_error(y_test, pred)
model_mae = mean_absolute_error(y_test, pred)
print(f"linear regression                MSE {model_mse:6.0f}   MAE {model_mae:5.1f}")

# Step 3: report the model against the strongest honest baseline.
baseline = np.full_like(y_test, y_train.mean())
baseline_mse = mean_squared_error(y_test, baseline)
skill = 1 - model_mse / baseline_mse
print(f"skill over the mean baseline: {skill:.0%}")

# The square root of an MSE is back in the score's own units: a typical
# miss, in points.
baseline_miss = np.sqrt(baseline_mse)
model_miss = np.sqrt(model_mse)
print(f"typical miss: baseline {baseline_miss:.0f} points, model {model_miss:.0f} points")

# Output:
#   mean baseline   guess  151.6   MSE   5135   MAE  59.2
# median baseline   guess  139.0   MSE   5360   MAE  59.0
#   zero baseline   guess    0.0   MSE  28913   MAE 154.2
# linear regression                MSE   3424   MAE  46.2
# skill over the mean baseline: 33%
# typical miss: baseline 72 points, model 59 points

How to read the output:

  • The mean baseline is the bar to clear. Guessing 151.6 for everyone gives a mean squared error of 5,135, a typical miss of about 72 points.
  • The median wins on absolute error and loses on squared error, exactly as in the house table. The theory shows up even on real data.
  • The zero baseline is the trap. Against an error of 28,913, the model looks like a miracle. It is not; zero is just a silly guess.
  • The model removes about a third of the baseline’s error (skill 33%), cutting the typical miss from about 72 to about 59 points. That is real but modest, and saying so honestly is what an interviewer wants to hear.
  • The baseline’s guess comes from the training answers (y_train.mean()), never the test answers. Using the test answers would let the baseline peek at the exam, the same cheating the test set exists to prevent.

scikit-learn ships the lazy guess as a model of its own, so it slots into any pipeline:

from sklearn.dummy import DummyRegressor
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

X, y = load_diabetes(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=0)

# A baseline packaged as a model: same fit / predict as every other model.
# strategy can be "mean", "median" or "constant".
dummy = DummyRegressor(strategy="mean").fit(X_train, y_train)
# same as by hand
print(mean_squared_error(y_test, dummy.predict(X_test)))
# prints 5134.78...

# For categories: DummyClassifier(strategy="most_frequent")
# always predicts the majority class.

Code: when the baseline is already “95% accurate”

For categories the trap is sharper. When one class is rare, always guessing the common one already scores a high accuracy while doing nothing useful:

import numpy as np

# 1,000 emails, about 5% of them spam (1 = spam, 0 = not spam).
rng = np.random.default_rng(0)
# 1,000 random numbers between 0 and 1
draws = rng.random(1000)
# True for about 5% of them, then True/False -> 1/0
is_spam = (draws < 0.05).astype(int)
print(is_spam.sum(), "spam emails")                       # 45 spam emails

# The majority-class baseline: always say "not spam".
baseline = np.zeros_like(is_spam)
# True where the guess matches the truth
right = baseline == is_spam
# True counts as 1, False as 0
accuracy = np.mean(right)
# sounds great
print(f"accuracy {accuracy:.1%}")
# prints 95.5%
# & means "both true", email by email
caught = np.sum((baseline == 1) & (is_spam == 1))
# catches nothing
print("spam caught:", caught)
# prints 0

# So a spam filter with 95% accuracy may have learned nothing at all.
# On lopsided data, compare against this baseline, and use a metric
# that looks at the rare class.

So “our spam filter is 95% accurate” means nothing until you know the majority-class baseline is also about 95%. Week 3 covers the metrics that look at the rare class directly, called precision and recall .

Read scikit-learn user guide: Dummy estimators A short section on DummyRegressor and DummyClassifier and their strategies. Five minutes.

The vocabulary, in one table

These are the words that will appear on every page from here on. Most confusion in interviews comes from using two of them interchangeably when they are not, so the right-hand column gives the pairs to keep apart.

TermMeaningDo not confuse with
Example (sample, instance, row)One data point: one house, one email, one image.A feature, which is one column, one fact about every example.
FeatureOne measured input: size, word count, pixel value.The label, which is the output we want to predict.
Label (target, ground truth)The correct answer for an example, used only in training and evaluation.The prediction, which is the model’s guess at it.
Parameters (weights)Numbers inside the model that training changes.Hyperparameters: settings you choose before training (model size, learning rate, number of epochs). Training never changes them; you tune them on the validation set.
LossThe number the optimizer minimizes during training; must be smooth enough to optimize.The metric: what you actually care about, often not smooth (accuracy, F1). You optimize the loss and report the metric.
Training (fitting)Running the loop to set the parameters.Inference: using the trained model to predict on new inputs. Different cost, different code path.
EpochOne full pass over the training data.A step (iteration), one parameter update, usually on one batch of examples. An epoch is many steps.
BaselineThe simplest reference model, or a previous model, that a new one must beat.A benchmark, which is a standard dataset and metric used to compare methods across papers.
GeneralizationPerformance on data not seen in training.Training performance, which is only evidence of fitting, not of learning.
Language model (LLM)A model whose job is to guess the next piece of text. “Large” means billions of parameters.A chat assistant, which is a language model plus extra training and a product around it.
TokenOne piece of text as the model sees it: usually a word or part of a word.A word: long or rare words are several tokens; “unbelievable” might be “un”, “believ”, “able”.

AI, ML, deep learning, LLMs

artificial intelligence includes hand-written rules, search, planning machine learning rules learned from data: this track deep learning multi-layer neural networks: weeks 5–6 large language models huge networks trained on text: weeks 7+
Fig. 6. Nested boxes. Everything in this track lives in the machine learning box; the deep learning and LLM tracks go deeper into the inner boxes. The four-part loop is the same in all of them.

The reason to be precise about the boxes is that interviewers use them to probe depth. “Deep learning” is not a different kind of learning; it is machine learning with a particular, very flexible model and the same four parts. “Classical” machine learning, the subject of this track, refers to the models that are not deep networks: linear models, trees, nearest neighbours, clustering. They still win on most tabular business data, they train in seconds on a laptop, and they are what interviewers reach for when they want to check that you understand the fundamentals rather than only the fashion.

Code

Type these out. The three programs are the same loop at three levels of automation.

The four parts, by brute force

import numpy as np

# Three houses: size in thousands of square feet, price in thousands.
sizes = np.array([1.0, 1.5, 2.0])
prices = np.array([200.0, 300.0, 380.0])

def predict(w, b, x):              # the MODEL: a line with two knobs
    return w * x + b

# the LOSS: mean squared error over the data
def loss(w, b):
    errors = predict(w, b, sizes) - prices
    return np.mean(errors ** 2)

print(loss(180, 0), loss(200, 0), loss(190, 10))
# 566.666... 133.333... 41.666...   (matches the table)

# The dumbest OPTIMIZER: try every knob setting on a grid and keep the best
# one.
best_loss = None
for w in range(150, 251, 2):       # slopes 150, 152, ..., 250
    for b in range(-50, 51, 2):    # intercepts -50, -48, ..., 50
        current = loss(w, b)
        if best_loss is None or current < best_loss:
            best_loss = current
            best_w = w
            best_b = b
# -> price ~ 180 * size + 24 on this coarse grid
print(best_w, best_b, round(best_loss, 2))
# prints 180 24 22.67

# That is machine learning in miniature: data, a model with knobs, a loss,
# and a search over the knobs.
# Gradient descent (week 2) replaces the grid with a smarter search;
# everything else stays the same.

The same model with scikit-learn

import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

# scikit-learn wants 2-D: one row per house, one column per feature
sizes = np.array([[1.0], [1.5], [2.0]])
prices = np.array([200.0, 300.0, 380.0])

# the model: y = w x + b, knobs not yet set
model = LinearRegression()
# the optimizer: finds the best w and b for the data
model.fit(sizes, prices)
print(model.coef_)                # [180.]   the slope w the model learned
print(round(model.intercept_, 2))  # 23.33    the intercept b: the exact best line; the grid got close

new_house = np.array([[1.8]])     # a house of 1,800 sq ft we have not seen
# inference: the predicted price
print(model.predict(new_house).round(2))
# prints [347.33]

predictions = model.predict(sizes)
# the loss at the best knobs
print(round(mean_squared_error(prices, predictions), 2))
# prints 22.22

A real dataset, a split and a baseline

import numpy as np
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

# 442 patients, 10 features, target = disease progression
X, y = load_diabetes(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=0)
# (89, 10)   rows, columns of each part
print(X_train.shape, X_test.shape)
# prints (353, 10)

# Baseline first: always predict the training mean. Any real model must beat
# this (see Baselines above).
baseline = np.full_like(y_test, y_train.mean())
baseline_mse = mean_squared_error(y_test, baseline)
print("baseline test MSE:", round(baseline_mse))     # 5135

# make the model and train it in one line
model = LinearRegression().fit(X_train, y_train)
train_mse = mean_squared_error(y_train, model.predict(X_train))
test_mse = mean_squared_error(y_test, model.predict(X_test))
print("train MSE:", round(train_mse))                # 2735
print("test  MSE:", round(test_mse))                 # 3424

# The test number is the one that matters: it estimates performance on
# patients we have never seen.
# It is a little worse than train, which is normal. If it were much worse,
# we would suspect overfitting.
Read scikit-learn documentation: LinearRegression Read the Parameters, Attributes and Methods sections. Every scikit-learn model follows this same fit / predict pattern, so learning it once pays for the whole track. Code Raschka, Machine Learning with PyTorch and Scikit-Learn, chapter 2 code A tiny classifier trained from scratch on the iris flower dataset: the four parts with no library hiding any of them. Read along with the chapter.

Where you will meet this again

  • Data. About 40 GB of web text. Each training example is a window of 1,024 tokens, and the label at each position is simply the next token. No human labelled anything: self-supervised.
  • Model. A particular kind of neural network called a transformer , with 124 million parameters (small) up to 1.5 billion (large). A function from a token sequence to a probability for each possible next token, with knobs.
  • Loss. The log loss : minus the logarithm of the probability the model gave to the token that actually came next, averaged over all positions. The next note builds it; week 4 gives it its grown-up name, cross-entropy .
  • Optimizer. A polished variant of gradient descent called Adam (week 6), run for hundreds of thousands of steps, each on a batch of sequences.
  • Hyperparameters. Number of layers, width, learning rate, batch size, how many tokens the model sees at once. Chosen by people, before training, and reported in the paper.
  • Inference. Run the trained model on a prompt, get a probability for each next token, pick one, append it, repeat. That is “generation”.
  • Generalization. Measured as loss on held-out text the model never trained on; a model that memorized its training set would have low training loss and useless outputs on anything new, exactly the wiggly curve of Fig. 3.

Fine-tuning, RAG and agents, the subjects of the later tracks, are ways of adapting or wrapping this one trained function. Keep locating the four parts and none of it will feel like magic.

The full interview answer

The question usually comes as “explain machine learning to me as if I were not technical, then as if I were”. Here is both, in about ninety seconds.

If they push further, be ready for:

  • “Give an example of a hyperparameter and how you would choose it.” Learning rate; try several values, pick the one with the best validation loss, never the test loss.
  • “Loss versus metric?” Loss is what you can optimize (smooth); the metric is what you report (accuracy, F1). They should agree in direction, but they are different numbers.
  • “Why not evaluate on the training data?” It measures memorization, not learning. The wiggly curve has zero training error and is useless.
  • “Is deep learning a different kind of ML?” No; same four parts with a neural network as the model.
  • “What would you do first on a new problem?” Define the metric, split the data, build the dumbest baseline, then try the simplest model that could work.

Practice questions

Answer each one out loud before opening it.

What are the four parts of every machine-learning system, and what does each do?

Data (examples to learn from), model (a parameterized function from features to predictions), loss (a number measuring how wrong the predictions are), optimizer (adjusts the parameters to reduce the loss). Training iterates the loop.

What is the difference between a parameter and a hyperparameter? Give two examples of each.

Parameters are learned by the optimizer from data: the slope and intercept of a line, the weights of a network. Hyperparameters are chosen before training and tuned on validation data: learning rate, number of layers, number of epochs, regularization strength.

Why is the training loss not the goal?

The goal is generalization: good predictions on unseen data. Training loss can be driven to zero by memorizing, which does not generalize. Held-out data is the only honest measure.

Define regression and classification in one sentence each. What changes in the training loop between them?

Regression predicts a continuous number; classification predicts a category. Only the model’s last step and the loss change: squared error for regression, the log loss for classification. Data, optimizer and loop are the same.

Is training a language model supervised or unsupervised?

Self-supervised: the mechanics are supervised (a label and a loss at every position) but the labels are the next tokens of the text itself, so no human labelling is needed.

What is a baseline and why do you build one first?

The simplest reference predictor, such as the training mean or the majority class. Without it you cannot tell whether a model’s score is good; the gain over the baseline is the real measure of what the model learned.

Three apartments rent for 10, 12 and 20 (thousand a year). Compute the mean baseline and its mean squared error, and the median baseline and its mean absolute error.

Mean = 14. Errors −4, −2, +6; squared 16, 4, 36; MSE = 56/3 ≈ 18.7. Median = 12. Absolute errors 2, 0, 8; MAE = 10/3 ≈ 3.3. (The mean’s MAE would be 12/3 = 4, worse; the median’s MSE would be 68/3 ≈ 22.7, worse.)

A model has test MSE 400; the mean baseline has 500. What is its skill? Another model has MSE 550. What does that tell you?

Skill = 1 − 400/500 = 0.2: it removes 20% of the baseline’s error. The second model has skill 1 − 550/500 = −0.1, worse than guessing the average: something is broken (a bug, a leak in reverse, a bad feature scale), not merely weak.

What is the difference between the loss and the metric?

The loss is the smooth quantity the optimizer minimizes (MSE, cross-entropy). The metric is what the task cares about and what you report (accuracy, F1, revenue), often not differentiable. You optimize the loss and monitor the metric.

What are the training, validation and test sets for?

Training: fitting parameters. Validation: choosing hyperparameters and models during development. Test: one final, untouched estimate of generalization. Tuning on the test set makes its number meaningless.

What is an epoch? How does it differ from a step?

An epoch is one full pass over the training data. A step is one parameter update, usually on one batch. An epoch of 10,000 examples with batch size 100 is 100 steps.

Name a task for each: supervised regression, supervised classification, unsupervised learning, self-supervised learning, reinforcement learning.

House price prediction; spam detection; customer clustering with k-means; next-token prediction for an LLM; learning to play a game from win/loss rewards (or RLHF for a chat model).

Explain the relationship between AI, machine learning, deep learning and LLMs.

Nested subsets: ML is the part of AI where behaviour is learned from data; deep learning is ML with multi-layer neural networks; LLMs are large transformers trained self-supervised on text. All share the four-part loop.

A model has training MSE 10 and test MSE 400. What do you suspect, and what is one thing you would try?

Overfitting: it fits the training data far better than new data. Try more data, a simpler model, regularization, or check for a data leak between the sets. The overfitting note covers the options.

Practice problems

Paper first, then check. Solutions are hidden under each problem.

By hand

1. For the three houses (1, 200), (1.5, 300), (2, 380), compute the MSE of the line ŷ = 160x + 60 and of ŷ = 180x + 20. Which is better?

First: predictions 220, 300, 380; errors 20, 0, 0; MSE 400/3 = 133.3. Second: 200, 290, 380; errors 0, −10, 0; MSE 100/3 = 33.3. The second. Neither is the least-squares optimum, which is w=180,b=23.3w = 180, b = 23.3 with MSE 22.2; the linear regression note derives it.

2. Classify each as a parameter or a hyperparameter: the slope of a regression line; the number of trees in a ‘random forest’ model (week 4); the learning rate; the intercept b of a line; the number of layers in a network; the entries of a model’s lookup table of word vectors.

Parameter, hyperparameter, hyperparameter, parameter, hyperparameter, parameter.

3. Classify each task: predicting tomorrow’s temperature; deciding whether a transaction is fraud; grouping news articles by topic with no labels; predicting the masked word in a sentence; choosing ad placements to maximize clicks over time.

Supervised regression; supervised classification; unsupervised clustering; self-supervised; reinforcement learning (a bandit problem).

4. A dataset has 1,000 rows and 12 columns, one of which is the label. How many examples, how many features? If the training set is 80% and batch size is 50, how many steps per epoch?

1,000 examples, 11 features. 800 training examples / 50 = 16 steps per epoch.

5. Write down a sensible baseline for each: house prices; spam detection where 5% of email is spam; next-token prediction.

Predict the mean (or median) training price. Predict “not spam” for everything (95% accuracy, which shows why accuracy is a poor metric here). Predict the most frequent token, or a unigram frequency model.

6. You tuned the learning rate by trying ten values and picking the one with the best test accuracy. What is wrong, and what should you have done?

The test set has been used for a choice, so its accuracy is now optimistically biased and no longer an honest estimate. Tune on a validation set (or cross-validation) and touch the test set once at the end.

7. Describe the four parts for a spam filter that outputs a probability of spam.

Data: emails with spam/not-spam labels, turned into feature lists (word counts). Model: a weighted sum of the word counts, squashed into a probability between 0 and 1 (week 3 calls this logistic regression). Loss: the log loss, which charges a lot for being confidently wrong (next note). Optimizer: gradient descent on the weights and the bias.

8. Describe the four parts for training a language model such as GPT-2.

Data: web text cut into 1,024-token windows, label = the next token at every position. Model: a very large neural network (124 million parameters) that outputs a probability for each possible next token. Loss: the log loss of the true next token, averaged over positions. Optimizer: a variant of gradient descent. Self-supervised because the labels come from the data.

9. Explain, in two sentences a product manager would accept, why the model that scored 99% on the training data might be worthless.

It may have memorized the training examples instead of learning the pattern, like a student who memorized last year’s exam. The only score that counts is on examples it has never seen, and we have not measured that yet.

10. Sketch the training loop of Fig. 1 from memory and label which arrow carries the gradient.

Data → model → prediction → loss (with the label entering the loss); loss → optimizer → model. The arrow from the optimizer back to the model carries the update, computed from the gradient of the loss with respect to the parameters.

Code

11. Extend the brute-force search to a finer grid (step 0.5 for w and b) and report the best (w, b) and loss. Then plot the loss as a function of w with b fixed at 20. What shape is it?
import numpy as np
import matplotlib.pyplot as plt

sizes = np.array([1.0, 1.5, 2.0])
prices = np.array([200.0, 300.0, 380.0])

def loss(w, b):
    return np.mean((w * sizes + b - prices) ** 2)

# A finer grid: steps of 0.5 instead of 2.
ws = np.arange(150, 251, 0.5)      # 150.0, 150.5, ..., 250.0
bs = np.arange(-50, 51, 0.5)       # -50.0, -49.5, ..., 50.0
best_loss = None
for w in ws:
    for b in bs:
        current = loss(w, b)
        if best_loss is None or current < best_loss:
            best_loss = current
            best_w = w
            best_b = b
# (exact optimum: b = 23.33, MSE 22.22)
print(best_w, best_b, round(best_loss, 2))
# prints 180.0 23.5 22.25

# The loss as a function of w alone, with b held at its best value.
losses = []
for w in ws:
    losses.append(loss(w, 23.33))
plt.plot(ws, losses)
plt.xlabel("w (with b = 23.33)")
plt.ylabel("MSE")
plt.title("a bowl: one minimum, no traps")
plt.show()
# The loss of a linear model under MSE is a parabola in each parameter (a
# bowl in both).
# That is why gradient descent works so cleanly for it: roll downhill and
# you reach the bottom.
12. On the diabetes dataset, compare three baselines on the test set: predict the mean, predict the median, predict zero. Then fit LinearRegression and report how much of the gap it closes. (Read the Baselines section first; this is a shorter version of its code.)
import numpy as np
from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

X, y = load_diabetes(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=0)

guesses = {"mean": y_train.mean(), "median": np.median(y_train), "zero": 0.0}
for name, value in guesses.items():
    # the same guess for every test patient
    baseline = np.full_like(y_test, value)
    error = mean_squared_error(y_test, baseline)
    print(f"{name:>6} baseline MSE: {error:8.0f}")

model = LinearRegression().fit(X_train, y_train)
model_mse = mean_squared_error(y_test, model.predict(X_test))
print(f"linear regression MSE: {model_mse:8.0f}")

mean_baseline = np.full_like(y_test, y_train.mean())
mean_mse = mean_squared_error(y_test, mean_baseline)
improvement = 1 - model_mse / mean_mse
print(f"improvement over mean baseline: {improvement:.0%}")
#   mean baseline MSE:     5135
# median baseline MSE:     5360
#   zero baseline MSE:    28913
# linear regression MSE:     3424
# improvement over mean baseline: 33%
# "The gap" is the distance from the baseline's error down to a perfect 0. The model closes a third of it.
# Always report the improvement over the baseline, not the raw number: raw
# MSE means nothing on its own.
13. Show overfitting in one experiment: fit polynomials of degree 1, 3 and 12 to 15 noisy points and print train and test MSE for each.
import numpy as np

# 30 noisy points around the straight line y = 0.8 x + 1.
rng = np.random.default_rng(0)
# 30 random x values between 0 and 10, in order
x = np.sort(rng.uniform(0, 10, 30))
# random wobble, typically between -1 and +1
noise = rng.normal(0, 1, 30)
y = 0.8 * x + 1 + noise

# Every second point for training, the points in between for testing.
x_train = x[::2]
y_train = y[::2]
x_test = x[1::2]
y_test = y[1::2]
print(len(x_train), len(x_test))             # 15 15

for degree in [1, 3, 12]:
    # fit a curve of this degree to the training points
    coeffs = np.polyfit(x_train, y_train, degree)
    train_mse = np.mean((np.polyval(coeffs, x_train) - y_train) ** 2)
    test_mse = np.mean((np.polyval(coeffs, x_test) - y_test) ** 2)
    print(f"degree {degree:>2}: train MSE {train_mse:6.2f}   test MSE {test_mse:8.2f}")
# degree  1: train MSE   0.94   test MSE     0.89    the straight line fits the pattern
# degree  3: train MSE   0.62   test MSE     0.86    a gentle curve: about the same on test
# degree 12: train MSE   0.15   test MSE     4.74    hugs the training points, five times worse on test:
# it memorized the noise (Fig. 3, left panel)
14. Write a function train_val_test_split(X, train=0.7, val=0.15, seed=0) by hand with NumPy that returns the row numbers of a 70/15/15 split. Assert the three parts are disjoint and cover every row.
import numpy as np

def train_val_test_split(X, train=0.7, val=0.15, seed=0):
    # The test share is whatever is left: 1 - 0.7 - 0.15 = 0.15.
    n = len(X)
    rng = np.random.default_rng(seed)
    # the row numbers 0..n-1 in a random order
    order = rng.permutation(n)
    n_train = int(n * train)
    n_val = int(n * val)
    # the first 70% of the shuffled order
    train_rows = order[:n_train]
    val_rows = order[n_train:n_train + n_val]       # the next 15%
    test_rows = order[n_train + n_val:]             # the rest
    return train_rows, val_rows, test_rows

X = np.arange(200).reshape(100, 2)      # 100 rows, 2 features
train_rows, val_rows, test_rows = train_val_test_split(X)
X_train = X[train_rows]                 # pick those rows out of X
print(len(train_rows), len(val_rows), len(test_rows), X_train.shape)
# prints 70 15 15 (70, 2)

# Self-checks: no row is in two parts, and together the parts cover every
# row.
# & on two sets keeps what they share
assert len(set(train_rows) & set(val_rows)) == 0
assert len(set(train_rows) & set(test_rows)) == 0
assert len(set(val_rows) & set(test_rows)) == 0
all_rows = np.concatenate([train_rows, val_rows, test_rows])
assert sorted(all_rows) == list(range(100))
print("all checks passed")              # all checks passed
# Shuffling before cutting matters: if the rows were sorted by label, an
# unshuffled split would be useless.

Common mistakes

All sources

Everything linked above, in the order to use it, plus the two books for the track.

  1. StatQuest, “A Gentle Introduction to Machine Learning” (video, 12 min). Start here.
  2. Andrew Ng, Supervised Machine Learning: Regression and Classification (Coursera, course 1 of the Machine Learning Specialization; free to audit). Week 1 of the course matches this note and the next two.
  3. Google ML Crash Course, Generalization and the ML Glossary.
  4. Kaggle Learn, Intro to Machine Learning (hands-on, about 3 hours).
  5. scikit-learn, LinearRegression and load_diabetes (documentation).
  6. Raschka, Machine Learning with PyTorch and Scikit-Learn, chapter 2 code. Chapters 1–2 of the book are the reading for this note.
  7. James, Witten, Hastie and Tibshirani, An Introduction to Statistical Learning (free PDF), chapter 2: “Statistical Learning”. The careful version of generalization, with the bias-variance picture you will meet next week.

One-minute revision