AI from scratch

Module 01 · ML Foundations

The bedrock: how machines actually learn

What machine learning really is, how industry teams train and judge models, and the trap that quietly breaks almost every first attempt — overfitting.

The core mental flip

In traditional programming, you write the rules. if temperature > 38: print("fever") — you, the human, know the rule and type it out.

In machine learning, you show examples and the machine finds the rules. You hand it 10,000 patient records labelled "fever / no fever" and it works out the threshold itself. You're not programming the logic — you're programming a process that learns the logic from data.

Industry framing: an ML system has three ingredients — data (examples), a model (a flexible function with knobs called parameters), and a learning algorithm (how those knobs get tuned). Change the data and the “program” changes. That is the whole job.

An LLM is the extreme version of this: nobody wrote rules for grammar or facts. It learned patterns from billions of text examples. Same mental flip — just more data, more parameters, more compute.

When not to use ML

If a clear rule already works, write the rule. ML earns its keep when patterns are fuzzy, high-dimensional, or change faster than humans can hand-tune — spam, ranking, fraud, speech, vision, language. Interviews love this honesty: strong engineers know when ML is the wrong hammer.

How machines learn (the map interviewers use)

Supervised learning — every example comes with the right answer (a label). “Here are emails marked spam / not-spam; learn to predict.” Most production ML starts here. Regression predicts a number (fare, price). Classification predicts a category (spam / not spam). LLM supervised fine-tuning (SFT) is supervised learning on instruction → response pairs.

Unsupervised learning — no labels; find structure yourself. Clustering customers, compressing data, spotting anomalies. Useful for exploration and features — rarely the whole product by itself.

Self-supervised learning — the industry’s favourite trick: hide part of the input and predict it from the rest. The “label” is free because it was already in the data. LLM pretraining (predict the next token) is self-supervised. Say this in interviews; it shows you know how modern AI is actually trained.

Reinforcement learning — learn by trial and reward, not a fixed labelled dataset. An agent acts, gets a score, updates. The “RL” in RLHF rewards answers humans prefer. Harder to get right; powerful when the goal is a behaviour, not a single label.

Cheat-sheet: supervised = labelled answers, self-supervised = labels from the data itself, RL = reward signal. GenAI systems often use all three across pretrain → SFT → preference tuning.

The production mental model: data → model → eval → ship

Every serious ML project — from a taxi-fare model to GPT fine-tuning — follows the same skeleton:

1. Problem & metric     what does “good” mean in business terms?
2. Data                   collect, clean, label, check leakage
3. Split                  train / validation / test (or time-based)
4. Baseline               always ship a simple model first
5. Train & tune           fit on train; choose knobs on validation
6. Evaluate               report test metrics once; don’t peek repeatedly
7. Ship & monitor         latency, drift, failures, cost

Juniors jump to step 5. Seniors obsess over steps 1–3 and 7. If the metric is wrong or the split leaks the future, the fanciest model is theatre.

Train / validation / test (and why splits lie)

The load-bearing idea: never judge a model on data it learned from. That’s grading students on the exact questions they studied.

Training set — the model studies this; parameters get updated here.

Validation set — your scratchpad for decisions: which model, which hyperparameters, when to stop training. You are allowed to look, repeatedly. That’s why validation scores slowly become optimistic.

Test set — locked box. Open it once (or rarely) for the number you report. Touching it while tuning is cheating; interviewers will ask.

Cross-validation

When data is scarce, k-fold cross-validation rotates which slice is held out, averages the scores, and gives a stabler estimate than one lucky split. Costly on huge datasets or deep nets; still standard for classic ML on medium tabular data.

Split gotchas industry hits constantly

LLM parallel: “data contamination” in benchmarks is the same sin — if test questions leaked into training data, the scores mean nothing. Same principle, billion-dollar stakes.

Metrics: pick the score that matches the business

Accuracy is the default people reach for — and often the wrong one.

Classification

Regression

Interview move: state the metric, then state the cost of each error type. That is what separates a tutorial answer from a production answer.

Overfitting: the central trap

A model can get better and better on training data while getting worse on new data. That gap is overfitting — memorising noise instead of learning the pattern.

Underfitting is the opposite: too simple to capture the real pattern (high bias). Overfitting is too flexible (high variance). The craft is finding the sweet spot.

Live experiment — NYC taxi fares

Predict a ride’s fare from distance and passenger count, using decision trees that get steadily more complex (max_depth). Score with R² on train and on held-out test rides.

depth | train R² | test R²
  1   |  0.586   |  0.601   underfit — too simple
  2   |  0.759   |  0.787
  3   |  0.840   |  0.836
  5   |  0.884   |  0.875   ← test peaks: the sweet spot
  8   |  0.913   |  0.826   overfitting begins
 12   |  0.928   |  0.773
 none |  0.932   |  0.769   train high, test sagging
▶ Run this yourself in Colab

No setup — opens in your browser. Fixed seed → same numbers.

import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor

df = sns.load_dataset("taxis").dropna(subset=["distance", "passengers", "fare"])
X = df[["distance", "passengers"]]
y = df["fare"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

for depth in [1, 2, 3, 5, 8, 12, None]:
    m = DecisionTreeRegressor(max_depth=depth, random_state=42).fit(X_train, y_train)
    print(depth, m.score(X_train, y_train), m.score(X_test, y_test))

Shallow (depth 1–2): underfit — pattern not captured yet.
Middle (~5): test peaks — general pattern learned.
Deep (8+): train keeps rising, test falls — memorising individual rides.

The best model isn’t the most complex one — it’s the one at the peak of the test (or validation) score. Past that point, complexity is vanity.

How industry fights overfitting

Want drama? In the notebook change y = df["fare"] to y = df["tip"]. Tips are noisy human generosity — deep trees can go negative R² on test (worse than guessing the average).

One sentence to memorise: too simple is high bias, too complex is high variance, and the job is balancing the two.

Data leakage: the silent interview killer

Leakage means information that would not be available at prediction time somehow helped training — so your metrics look heroic and production falls over.

Defence: split first, fit preprocessing on train only, transform val/test with those same statistics. Draw the timeline of what is known when a prediction is made.

Interview questions

Also in the full interview bank.

Difference between supervised and unsupervised learning?

Supervised uses labelled data to learn input→output mappings; unsupervised finds structure in unlabelled data. Strong answer: LLM pretraining is self-supervised — the data labels itself using the next token as the target.

Your model gets 99% on training but 80% on test. What’s happening?

Overfitting — it memorised noise. Fixes: simplify the model, add regularisation, get more data, early stopping, or use cross-validation. Naming several fixes is what separates a strong answer.

Why do we need a test set at all?

To estimate performance on data the model has never seen — the only thing that matters in production. Scoring on training data is dishonestly optimistic. Validation is for tuning; test is for the final report.

What’s the bias-variance tradeoff?

High bias = too simple, underfits. High variance = too complex, overfits. Total error ≈ bias² + variance + irreducible noise; you tune complexity to minimise the sum.

When is accuracy a bad metric?

Class imbalance. Prefer precision/recall/F1 or PR-AUC, and tie the metric to the cost of false positives vs false negatives.

Give an example of data leakage.

Fitting a scaler on train+test before splitting, or using a feature only known after the event you’re predicting. Fix: split first; fit transforms on train only; respect time.