Building LLMs — Lecture deep-dive
When to use
You are about to design, evaluate, or steer a Large Language Model product and keep hitting buzzwords like perplexity, BPE tokenization, RLHF, DPO, Chinchilla, HNSW. Skim this page when you need a one-stop, beginner-friendly walkthrough of how LLMs are actually built and evaluated.
Analogy
Think of an LLM as a language factory. The factory has four rooms:
- Data room (raw internet + filter + dedupe + balance).
- Pretraining room (a giant transformer that tries to predict the next token in every sequence).
- Post-training room (a smaller team that turns the raw language model into an assistant that follows instructions).
- Systems room (the GPU plumbing that keeps the lights on).
Each room has its own tools, costs, and failure modes. Forget one and the whole factory grinds to a halt.
Data-flow diagram
internet (250 B pages ~ 1 PB)
|
crawl -> extract text -> filter PII / dedupe / heuristic quality
|
Common Crawl ~ 100 B cleaned tokens
|
pretrain (transformer, next-token cross-entropy)
|
base model (e.g. Llama-3 405 B, 15.6 T tokens)
|
supervised fine tuning (SFT, ~10-50 K examples)
|
assistant model that follows instructions
|
RLHF / DPO (preferences over pairs, ~1 M labels)
|
shipped model (e.g. ChatGPT)
Deep explanation
A modern LLM is built in two phases: pretraining (a self-supervised exercise on a huge corpus) and post-training (supervised + preference fine-tuning that turns a language modeler into an assistant). Pretraining costs millions of dollars and trains on trillions of tokens; post-training costs a fraction but changes how the model behaves.
The whole pipeline:
- Tokeniser (BPE) cuts text into sub-word units (≈ 3–4 letters each) so the model sees a fixed vocabulary instead of a never-ending list of typos.
- Pretraining runs cross-entropy loss: given tokens 1..t, predict token t+1. The architecture is one transformer; the magic is scale (parameters × data × compute).
- Evaluation uses perplexity in development and aggregate benchmark suites (MMLU, HELM, ChatBotArena) for academic comparison.
- SFT trains the model on a small set of “good answers” written by humans (or by another LLM).
- RLHF/DPO trains the model on human preference pairs — “is A better than B for this prompt?” — so the model learns what users actually want, not just what is grammatically likely.
- Systems carries the whole thing on GPU clusters: low precision, operator fusion, sharding — all to keep Model FLOPs Utilization (MFU) as high as possible.
Pretraining — what are we actually fitting?
Definitions in one line each
- Language model: a probability distribution over token sequences.
- Autoregressive:
$p(x_1,\dots,x_L) = \prod_t p(x_t \mid x_{<t})$.
- Token: the atomic unit the model reads; usually a sub-word byte pair.
- Vocabulary: the set of all tokens (e.g. 100 K for GPT-style models).
- Cross-entropy loss:
$-\sum_t \log p(x_t^\* \mid x_{<t})$ — the negative log-probability of the real next token.
- Perplexity:
$\exp(\text{loss per token})$. Lower = better. Range: 1..vocab size.
- Embedding model, transformer, softmax: read the architecture primer elsewhere; they are not the focus today.
Simple worked example
The sentence “the mouse ate the cheese” becomes five token IDs [t_1, t_2, t_3, t_4, t_5]. The model predicts a probability distribution over the 100 K vocabulary for what follows t_1..t_4; if the real answer is t_5, the cross-entropy contribution is $-\log p(t_5)$. Average over millions of sentences and minimise the total — that is what training does.
Why we use cross-entropy
Cross-entropy between the predicted distribution and the one-hot “real answer” distribution is mathematically identical to maximising the log-likelihood of the corpus. One function fits both views.
The bitter lesson, in one sentence
Architectures matter less than you think; scale + data + systems matter more. Always-on scaling laws predict loss from compute / data / params, so we tune on small models before training a big one.
Tokenisation — Byte-Pair Encoding (BPE)
One-line summary
Start with characters; repeatedly merge the most frequent adjacent pair into a new token. After ~100k merges you have a vocabulary of frequent chunks, slightly bigger than a character.
Worked example
Start: each character is its own token. After merges:
t + o -> to
t + o + k -> tok
t + o + k + e -> toke
t + o + k + e + n -> token
e + x -> ex (and many more merges)
A real GPT-3 tokenizer splits tokenizer into [token, izer]. The vocabulary size is the size of the output dimensionality, so changing the tokenizer mid-project is very painful.
Three gotchas
- Typos: tokenisers pre-merge so a typo doesn’t become
<unk>. They still degrade quality.
- Numbers:
327 may be a single token, so the model is bad at multi-digit arithmetic. Companies now treat numbers specially.
- Code whitespace: 4-space indents deserve their own token; GPT-4 fixed this and code generation improved.
Evaluation
Perplexity
- Defined as
$\exp(\text{avg per-token loss})$.
- Range: 1 (perfect) to vocabulary size (uniform random).
- Standard benchmark perplexity dropped from ~70 in 2017 to <10 in 2023 — the same architecture, scaled.
Aggregated benchmarks
- MMLU: many choice questions across college domains. Often evaluated by logit comparison — look at
$p(\text{A}), p(\text{B}), p(\text{C}), p(\text{D})$ and pick the highest; no sampling required.
- HELM, HuggingFace Open LLM Leaderboard, ChatBotArena: aggregate scores from many tasks with many question types.
Two specific evaluation gotchas
- Methodology drift: Llama-65B scored 63.7 on HELM and 48.8 on a different benchmark for the same task. Pick one benchmark and stick with it.
- Train/test contamination: the test set might already be in pre-training data. People detect this by comparing the model’s likelihood of the test items in the canonical order vs shuffled (it shouldn’t matter unless the model memorised them).
Data
The recipe at a glance
- Crawl the open web (Common Crawl gives ~250 B pages / 1 PB).
- Extract text from HTML (very fiddly for math, code, tables).
- Filter:
- blacklist of undesirable domains
- heuristics (length, ratio of symbols, language)
- model-based filtering (train a classifier that learns “Wikipedia-like” vs random)
- De-duplicate exact and fuzzy (MinHash) — 30-50% of crawl is repeated headers/footers.
- Domain-mix: up-weight code, books, math, QA; down-weight entertainment.
- High-quality tail: at the end of training, anneal the learning rate and over-fit on Wikipedia + curated data.
Why data is the secret
The same architecture trained on the same compute budget with better data beats a bigger architecture with worse data. In the Llama-2/3 team of ~70 researchers, ~15 worked on data. The rest did modelling + systems.
Scaling Laws
Three lawyers: compute, data, parameters
If you plot loss vs log(compute) / log(data) / log(params) you get a straight line. That means you can extrapolate from a small model how loss will scale at 10× or 100× the compute.
Chinchilla / Inference-aware
For a fixed compute budget, the optimal models follow:
- Chinchilla (training-optimal): ~20 tokens per parameter.
- Inference-aware (production-optimal): ~150 tokens per parameter; smaller models are cheaper per query and dominate total cost over time.
Why you bother
Old workflow: train 30 models for 1 day each, pick the best. New workflow: train many small models (1 day × ~3 sizes), fit a scaling law, extrapolate, then train one final huge model for ~27 days. Predictability replaces brute force.
Back-of-the-envelope cost of a frontier model
For Llama-3-405B trained on 15.6 T tokens:
- Flops ≈
$6 \times N \times D$ ≈ $3.8 \times 10^{25}$.
- 16 000 H100 × 70 days ≈ 26 M GPU-hours.
- At $2/hour H100 rental: ≈ $52 M.
- Carbon: ~4 000 t CO₂ (≈ 2 000 NY-London return flights).
- Plus ~50 employees × $0.5 M salary ≈ $25 M.
- Round number: ~$75 M to train a frontier open model.
Post-training: from “internet autocomplete” to assistant
SFT — Supervised Fine-Tuning
- Take the pretrained model.
- Fine-tune on a small set of
(prompt, ideal_response) pairs written by humans (or another LLM).
- Same loss as pretraining — next-token cross-entropy on the desired answer.
- Surprising fact: only 2 000 high-quality examples (LIMA) does most of the work. Scaling beyond ~30 K gave no extra returns. The pretraining is the knowledge; the SFT picks a “voice”.
Why SFT alone isn’t enough
- Bound by human ability: people can rank answers better than they can write them.
- Hallucinations: SFT can teach the model to make up plausible-but-false references by rewarding wrong answers in a domain it had never seen during pretraining.
- Price: writing ideal answers is slow and expensive.
RLHF (Reward model + PPO)
- For each prompt, generate two answers (A, B).
- Human raters pick the better.
- Train a reward model to predict the human’s choice (Bradley-Terry logits).
- PPO adjusts the LM to maximise the reward model — with a KL penalty against the original model to avoid “reward hack” mode collapse.
DPO — Direct Preference Optimisation
- Skip the reward model. Skip RL.
- Loss: maximise the log-prob of the preferred answer, minimise the log-prob of the rejected one.
- Under some assumptions, the global minimum of DPO equals the global minimum of PPO.
- Same performance, vastly simpler implementation. Standard in open-source fine-tuning today.
Why RLHF can produce rambling answers
Human raters prefer longer text. The model learns: “be longer”. This is a measurable bias in ChatBotArena logs and is fixed in modern eval suites with length regression.
Systems — keeping the factory alive
The constraints
- GPUs are scarce and expensive. Even with $10 M you cannot buy them instantly.
- Communication is the bottleneck: data movement between cores and between GPUs is much slower than compute. The metric is MFU — observed throughput / theoretical peak. Top labs run at 40-50 %; 50 % is excellent.
Two tricks that buy you 2-4×
- Low precision: store weights in 32-bit floats, compute in 16-bit (or 8-bit with care). Memory traffic halves; throughput doubles. Training uses automatic mixed precision: weights saved at 32-bit, activations at 16-bit.
- Operator fusion: every
x = cos(x); x = exp(x); x = sin(x) round-trips to global memory. torch.compile rewrites PyTorch into one fused CUDA kernel; one round-trip, 2× faster.
MFU (Model FLOPs Utilization) and why labs obsess over it
The exact formula:
MFU = observed_FLOPs_per_sec / theoretical_peak_FLOPs_per_sec
In words: divide the FLOPs you actually ran per second by the FLOPs the silicon could run in a perfect world. Range = [0, 1]. Real labs run at 0.40–0.50; 0.50 is excellent; > 0.60 is world-class, usually only inside a single tightly-tuned kernel. The gap to 1.0 mostly comes from communication (data hops between cores / nodes). If your code does 1 matmul then 1 softmax then 1 sigmoid, each line waits for an HBM round-trip — that gap is exactly what MFU measures.
3D parallelism at a glance (DP × TP × PP)
Most frontier runs combine three parallelisms on the same cluster. Picture 8 nodes × 8 GPUs = 64 GPUs in total:
DP=4 (replicate model 4× across nodes, split data)
┌─────────────────────────────────────────────────────────────┐
│ ├── DP-rank 0 ──┐ │
│ ├── DP-rank 1 ──┤ TP=2 (split each weight matrix │
│ ├── DP-rank 2 ──┤ across 2 GPUs within one node) │
│ └── DP-rank 3 ──┘ │
│ │
│ PP=4 stages along the depth direction: │
│ stage 0 ▓▓▓ .. .. ▓▓▓ bubble at warm-up / drain │
│ stage 1 .. ▓▓▓ .. ▓▓ bubble same problem │
│ stage 2 .. .. ▓▓▓ ▓▓ bubble same problem │
│ stage 3 ▓▓ .. .. ▓▓▓ bubble same problem │
│ (▓ = real work, .. = idle GPU — that's the bubble) │
└─────────────────────────────────────────────────────────────┘
The bubble is the fraction of the timeline when a pipeline-parallel stage is waiting on its neighbour. Shrink the bubble by either (a) more micro-batches in flight, or (b) fewer PP stages (which pushes more work onto tensor-parallel, which costs more all-reduce). Every frontier lab tunes this DP × TP × PP grid per workload — there is no single best answer.
Tiling: keep matrices resident on a single core’s high-bandwidth SRAM
Big matrices don’t fit in on-chip SRAM (a few tens of MB). Cube cores load a TILE — say 128 × 128 — into shared SRAM, do all the work locally, write back. Tiling is how 24× faster is reached on memory-bound kernels without changing the algorithm.
Parallelism: three flavours, three trade-offs
- Data parallel (DDP): copy the model to N GPUs, split batches. Sync gradients every step. Easiest to add; works when the model fits on one GPU.
- Tensor / model parallel: split one weight matrix across GPUs (row-wise or column-wise); each step needs an all-reduce. Required when the model is bigger than one GPU; communication overhead is high.
- Pipeline parallel: split LAYERS across GPUs; stages run micro-batches in a staggered pipeline. Idle “bubble” GPUs are inevitable; the trick is keeping the bubble small relative to the work.
- Mixture of Experts (MoE): split FEED-FORWARD layers into 8–64 “experts”, only a few per token. Looks bigger (8× params) but FLOPs-per-token barely change. Llama-4 MoE uses 16 experts with top-2 routing.
When you pick which
- Model fits on one node + you only want more throughput -> DDP.
- Model doesn’t fit -> tensor parallel within a node; pipeline across nodes.
- Want bigger looking-model without bigger compute cost -> MoE.
Production failure playbook
Failure scenario 1: a great model ships and forgets everything about itself
- Symptom: Users report the assistant contradicts itself across turns; chat history appears lost.
- Detection: Maintain a fixed multi-turn golden set; p95 “divergence” between expected reply N and actual reply N+1.
- Root cause: SFT overwrote parts of the pretraining. RLHF in PPO mode can collapse the model’s distribution to one preferred token (its KL drift is unconstrained).
- Mitigation: KL anchor in PPO; for DPO, mix some pretraining data into each fine-tune batch.
- Prevention: ADR every fine-tune — KL anchor mandatory; bake 5 % pretraining data into SFT.
Failure scenario 2a: offline scaling plateau
- Symptom: Loss curves flatten on internal benchmarks after a compute bump; the next 2× compute gives < 0.5 % loss improvement.
- Detection: Plot loss vs
$\log(\text{compute})$ each run; compute the slope. Slope dropping below an agreed threshold = plateau.
- Root cause: Data-quality ceiling, not tokens, not parameters, not tokenizer. Adding more compute does not help when data is the bottleneck.
- Mitigation: Audit the data mix; upgrade quality before adding more compute; stop throwing GPUs at the problem.
- Prevention: Internal compute-vs-loss slope ADR per training run; if the slope drops, fix data first.
Failure scenario 2b: online A/B rubric drift
- Symptom: Production thumbs-down rate climbs while offline metrics hold flat.
- Detection: A/B vs prior model; cross-task benchmark; ChatBotArena weekly deltas; length-regressed quality (see Why RLHF can produce rambling answers).
- Root cause: The labelling rubric drifted; synthetic data added during fine-tuning encoded the reward model’s biases.
- Mitigation: Pause; reset the rubric to last known good; re-label 1 K examples; re-run preference training.
- Prevention: Freeze the rubric per release and re-audit quarterly so the team can rotate labels without breaking comparability.
Failure scenario 3: a “perfect” benchmark score is a train/test leak
- Symptom: MMLU 88 % vs competitors’ 70 %.
- Detection: Run the canonical-order / shuffled-order recall test on the test set; if shuffled hurts, the test set leaked during pretraining.
- Root cause: Test data was in Common Crawl.
- Mitigation: Drop the leaked rows; retrain; re-report.
- Prevention: Maintain a decontaminated subset of MMLU with strict membership checks.
Common mistake
- Treating every architecture change as the next big thing. Architecture nudges the intercept of the loss curve; data nudges the slope. Optimise the slope.
- Computing FLOPS as if every operation counted. The real signal is MFU. Buy GPUs that hit 50 % MFU and the rest is software.
Key takeaway
A frontier LLM is a 4-stage factory: collect clean data, pretrain a transformer, fine-tune it to follow instructions, prefer the answers humans actually want. Each stage has its own failure mode (data drift, eval contamination, KL collapse, RL alignment). Knowing the factory by heart beats knowing the arXiv paper of the week.
Topics in this lecture
- When to use (where this page fits)
- Autoregressive language modelling
- Tokenisation (BPE)
- Perplexity + MMLU
- Data recipe
- Chinchilla + scaling laws
- SFT
- RLHF + DPO
- Systems (precision + fusion)
- Production failure playbook