Type at least 2 letters. Enter opens the first result, Esc closes.

    ML Interview Prep · Lesson 11 · ML breadth

    Breadth: LLM pretraining, scaling laws, fine-tuning with LoRA, RLHF, DPO and evals

    Advanced 90 min 5 interactive figures 5 videos Colab notebook

    Before this lesson: lesson 07 (the training step, the 16 bytes per parameter of mixed-precision Adam, BPE) and lesson 08 (the decoder and its sampling). Background: KL divergence and cross-entropy in the Information Theory track, LoRA as low rank in the Linear Algebra track, and policy gradients and PPO in the Reinforcement Learning track. A full LLM course (see the resources) treats every topic here in full depth. Time: about 90 minutes, plus the notebook.


    Why this matters #

    LLM questions are now standard breadth in ML engineer, research engineer and research scientist interviews, not a specialty. A common opening is "Walk me through how a chat model is trained." A strong answer names the stages in order, gives one equation and one trade-off per stage, and uses numbers: tokens, FLOPs, GPU-hours. A weak answer lists method names. The same questions come back in daily work and in ML for science: how large should a foundation model be for my data and my compute? Should I fine-tune on labels or with a reward from a checker? Is the new model better, or did the number only move inside its error bar?

    1. Predict first #

    2. The picture #

    Start with the simplest model. A language model gives a probability to each possible next token. A model that knows nothing spreads the probability evenly over the vocabulary of VV tokens. Its loss per token is then −ln⁡(1/V)=ln⁡V-\ln(1/V) = \ln V, which is 10.810.8 nats for V=50,000V = 50{,}000. The perplexity is exp⁡(loss)\exp(\text{loss}), here exactly VV: the model is as unsure as a choice among VV equal options. Every stage of training removes uncertainty in a different way.

    Stage Data Training signal What it adds
    Pretraining 101210^{12}–101310^{13} tokens of filtered, deduplicated web text, code, books next-token cross-entropy knowledge, language, in-context learning
    Mid-training a smaller high-quality mix (math, code, long documents) while the learning rate decays the same loss quality, skills, long context
    SFT 10410^4–10610^6 (prompt, response) demonstrations cross-entropy on response tokens only the format: follow instructions, chat template, tool calls
    Preference tuning pairs (chosen, rejected) reward model + PPO, or DPO which of the possible answers people prefer
    RL with verifiable rewards prompts with a checker (a math answer, unit tests) reward 1 if correct, else 0 reasoning: longer, self-checking solutions
    Evaluation held-out benchmarks, human or model judges — the decision whether a change helped

    In one line: pretraining makes the model know; SFT makes it answer in the right form; preference tuning chooses among good answers; RL with a checker makes it search for correct answers. Evaluation decides at every step.

    Scaling in one picture. For a fixed compute budget, model size and data trade against each other. You can train a big model on few tokens, or a small model on many tokens. Along this line of equal compute (an iso-FLOP curve) the final loss is U-shaped. The bottom of the U is the compute-optimal model. The bottom is flat: a model 2× smaller or larger loses very little.

    Interactive figure: loading…

    Move the model size NN along one budget. The blue curve is the Chinchilla loss fit L(N,D)L(N, D) with D=C/(6N)D = C/(6N) tokens, so every point costs the same compute CC. The orange dot is the minimum of the fit, and the aqua dot is the "20 tokens per parameter" rule. The preset is predict question 1: 10 B parameters on 20 B tokens. Notice how far up the U it sits, and how flat the bottom is.

    Quick check

    A model with N=1N = 1 B parameters is trained on D=100D = 100 B tokens. About how many FLOPs does training cost?

    Post-training in one picture: the KL leash. Take one prompt with two possible answers. The SFT model πref\pi_{\text{ref}} gives each answer probability 0.50.5. A reward model scores them 11 and 00. We want a new policy π\pi with a high expected reward, but every nat of KL divergence from πref\pi_{\text{ref}} costs β\beta. For β=1\beta = 1 the best policy is (0.73,0.27)(0.73, 0.27) (section 3.6 derives it). As β→0\beta \to 0 it puts all mass on the higher reward; as β→∞\beta \to \infty it stays at (0.5,0.5)(0.5, 0.5). So β\beta is the length of the leash that ties the policy to πref\pi_{\text{ref}}.

    Interactive figure: loading…

    Shorten and lengthen the leash with β\beta. Faint blue bars are the reference policy πref\pi_{\text{ref}}; solid orange bars are the optimal policy π∗∝πref er/β\pi^* \propto \pi_{\text{ref}}\, e^{r/\beta}. Edit the rewards and the reference probabilities. Try "reward hack": one answer has a high proxy reward but a tiny reference probability. Watch how small β\beta must be before π∗\pi^* moves to it, and how large the KL becomes.

    Quick check

    In the two-answer toy (πref=(0.5,0.5)\pi_{\text{ref}} = (0.5, 0.5), rewards (1,0)(1, 0)), you halve β\beta from 11 to 0.50.5. What is the new probability of the better answer?

    3. Definitions and main results #

    Notation. NN is the number of parameters, DD the number of training tokens, CC the training compute in FLOPs, VV the vocabulary size, TT the sequence length. πθ(y∣x)\pi_\theta(y \mid x) is the probability that the model with parameters θ\theta gives the response yy to the prompt xx.

    3.1 Pretraining loss, perplexity, bits per byte #

    The text is a sequence of tokens x1,…,xTx_1, \dots, x_T. The pretraining loss is the average negative log-probability of each token given the tokens before it:

    L(θ)=−1T∑t=1Tlog⁡pθ(xt∣x<t).\mathcal{L}(\theta) = -\frac{1}{T} \sum_{t=1}^{T} \log p_\theta(x_t \mid x_{<t}).

    Minimizing it is maximum likelihood. It is the cross-entropy between the text and the model. In expectation it equals the entropy rate of the text plus a KL divergence, which is never negative. So the loss cannot go below the entropy of the text.

    • Perplexity is PPL=eL\mathrm{PPL} = e^{\mathcal{L}} (with L\mathcal{L} in nats). It depends on the tokenizer: a tokenizer with longer tokens has fewer, harder predictions. So perplexity compares only models with the same tokenizer.
    • Bits per byte divides the total loss by the number of bytes of the text: bpb=T Lnbytesln⁡2\text{bpb} = \dfrac{T\, \mathcal{L}}{n_{\text{bytes}} \ln 2}. It does not depend on the tokenizer, so it compares models with different tokenizers.

    The data pipeline matters as much as the model: extract text from HTML, keep the wanted languages, filter by quality (rules and a classifier), remove exact and near duplicates (MinHash), choose a mixture weight for each source, and remove benchmark test items (decontamination).

    3.2 Compute: C≈6NDC \approx 6ND #

    Claim. Training a dense transformer with NN parameters on DD tokens costs about C≈6NDC \approx 6ND floating-point operations (FLOPs).

    1. Almost all FLOPs are products with weight matrices. A weight matrix of size m×nm \times n applied to one token's vector costs mnmn multiplications and mnmn additions: 2mn2mn FLOPs. Summed over all matrices: 2N2N FLOPs per token in the forward pass.
    2. For y=Wxy = Wx the backward pass computes two products of the same size: the gradient for the input, W⊤∂L∂yW^\top \frac{\partial \mathcal{L}}{\partial y} (2mn2mn FLOPs), and the gradient for the weights, ∂L∂y x⊤\frac{\partial \mathcal{L}}{\partial y}\, x^\top (2mn2mn FLOPs). So 4N4N per token.
    3. Total 6N6N per token, so C≈6NDC \approx 6ND. ■\blacksquare

    What the count leaves out: the attention scores and their weighted sums (Kaplan et al. show that this extra cost is small while the context length is below about 12 dmodel12\, d_{\text{model}}), activation recomputation (it repeats the forward pass: 8N8N instead of 6N6N per token), and the embedding lookup (no matrix product). Inference costs about 2N2N FLOPs per generated token.

    From FLOPs to time. Time =C/(nGPU⋅F⋅MFU)= C / (n_{\text{GPU}} \cdot F \cdot \text{MFU}), with FF the peak FLOP/s of one GPU. MFU (model FLOPs utilization) is the fraction of the peak that the model's FLOPs really use. Large tuned runs reach about 40%: the Llama 3 report gives 38–43% bf16 MFU.

    Memory. Mixed-precision training with Adam stores about 16 bytes per parameter: bf16 weights (2) and gradients (2), plus fp32 master weights, first moment and second moment (12). This is the count of the ZeRO paper (lesson 07). Activations come on top. A 7 B model needs 16⋅7⋅109=11216 \cdot 7 \cdot 10^9 = 112 GB for these states alone, more than one 80 GB GPU, so the states must be sharded (lesson 12).

    3.3 Scaling laws #

    Kaplan et al. (2020) found smooth power laws of the loss in NN, DD and CC. Their compute-optimal model size grew as Nopt∝C0.73N_{\text{opt}} \propto C^{0.73}: "make models bigger, and train them on relatively few tokens".

    Chinchilla (Hoffmann et al., 2022) fitted a different form:

    L(N,D)=E+ANα+BDβ,E=1.69, A=406.4, B=410.7, α=0.34, β=0.28.L(N, D) = E + \frac{A}{N^\alpha} + \frac{B}{D^\beta}, \qquad E = 1.69,\ A = 406.4,\ B = 410.7,\ \alpha = 0.34,\ \beta = 0.28.

    EE is the irreducible loss (the entropy of text), A/NαA/N^\alpha is the cost of a finite model, and B/DβB/D^\beta is the cost of finite data. (Here β\beta is an exponent; it is not the β\beta of RLHF.)

    Theorem (compute-optimal allocation). Minimize L(N,D)L(N, D) subject to 6ND=C6ND = C. The minimum is at

    Nopt=G(C6)a,Dopt=G−1(C6)b,a=βα+β,  b=αα+β,  G=(αAβB)1α+β.N_{\text{opt}} = G \left(\frac{C}{6}\right)^{a},\quad D_{\text{opt}} = G^{-1} \left(\frac{C}{6}\right)^{b},\qquad a = \frac{\beta}{\alpha+\beta},\ \ b = \frac{\alpha}{\alpha+\beta},\ \ G = \left(\frac{\alpha A}{\beta B}\right)^{\frac{1}{\alpha+\beta}}.

    Why this is true, in one sentence. Growing NN lowers the model term but, at fixed compute, shrinks DD and raises the data term; the best point balances the two rates of change.

    1. Substitute D=C/(6N)D = C/(6N):  L(N)=E+AN−α+B(C/6)−βNβ\ L(N) = E + A N^{-\alpha} + B (C/6)^{-\beta} N^{\beta}.
    2. Set the derivative to zero: −αAN−α−1+βB(C/6)−βNβ−1=0-\alpha A N^{-\alpha-1} + \beta B (C/6)^{-\beta} N^{\beta-1} = 0.
    3. Multiply by NN and use (C/6)−βNβ=D−β(C/6)^{-\beta} N^{\beta} = D^{-\beta}:  αAN−α=βBD−β\ \alpha A N^{-\alpha} = \beta B D^{-\beta}. At the optimum the model term and the data term are in the fixed ratio β:α\beta : \alpha.
    4. From step 2, Nα+β=αAβB(C/6)βN^{\alpha+\beta} = \frac{\alpha A}{\beta B} (C/6)^{\beta}. Take the power 1/(α+β)1/(\alpha+\beta) to get NoptN_{\text{opt}}; then Dopt=(C/6)/NoptD_{\text{opt}} = (C/6)/N_{\text{opt}} gives the second formula.
    5. It is a minimum: with u=ln⁡Nu = \ln N, the two terms Ae−αuA e^{-\alpha u} and B(C/6)−βeβuB (C/6)^{-\beta} e^{\beta u} are convex in uu, so their sum has exactly one stationary point, and it is the minimum. ■\blacksquare

    Because α≈β\alpha \approx \beta, both exponents are near 0.50.5: grow NN and DD by the same factor. The paper's three methods give a=0.46a = 0.46–0.500.50; the rounded constants above give a=0.45a = 0.45. The practical rule is about 20 tokens per parameter. Chinchilla itself (70 B parameters, 1.4 T tokens) used about the compute of Gopher (280 B parameters, 300 B tokens) and beat it. With D=20ND = 20N we get C=6N⋅20N=120N2C = 6N \cdot 20N = 120 N^2, so N=C/120N = \sqrt{C/120}.

    Why Kaplan differs (Chinchilla §2): Kaplan used one learning-rate schedule and one token count for all runs. The losses of shorter runs were read from checkpoints of a long cosine schedule, so they were too high. This undervalued data. Most of Kaplan's models were also small.

    Why practice "over-trains". Chinchilla minimizes training compute only. Serving costs 2N2N FLOPs per generated token, for the whole life of the model. So a smaller model trained on many more tokens is cheaper overall. Llama 3 8B saw about 15 T tokens: about 1,900 tokens per parameter. The flat bottom of the iso-FLOP curve makes this cheap (section 4).

    3.4 Supervised fine-tuning (SFT) #

    Each example is a prompt xx and a response yy, written into one token sequence zz by a chat template (special tokens mark the roles and the end of a turn). With a mask mt=1m_t = 1 on response tokens and mt=0m_t = 0 on prompt tokens:

    LSFT=−∑tmtlog⁡πθ(zt∣z<t)∑tmt.\mathcal{L}_{\text{SFT}} = -\frac{\sum_t m_t \log \pi_\theta(z_t \mid z_{<t})}{\sum_t m_t}.

    Trade-offs. SFT is cheap, stable, and uses the same code as pretraining. But it only imitates. The model cannot beat its demonstrations, and it never sees what not to do. Demonstrations of facts the model does not know can teach it to make things up (Gekhman et al., 2024).

    3.5 LoRA: fine-tuning a low-rank correction #

    Full fine-tuning changes a weight matrix W0W_0 into W0+ΔWW_0 + \Delta W, and it needs gradients and Adam states for every weight. LoRA (Hu et al., 2021) assumes that a useful ΔW\Delta W has low rank.

    Definition. A frozen pretrained weight W0∈Rd×kW_0 \in \mathbb{R}^{d \times k} maps an input x∈Rkx \in \mathbb{R}^k to W0x∈RdW_0 x \in \mathbb{R}^d. LoRA adds a trainable low-rank path:

    h=W0x+s BAx,s=αr,B∈Rd×r,A∈Rr×k,r≪min⁡(d,k).h = W_0 x + s\, B A x, \qquad s = \frac{\alpha}{r}, \quad B \in \mathbb{R}^{d \times r}, \quad A \in \mathbb{R}^{r \times k}, \quad r \ll \min(d, k).

    The input is squeezed to rr numbers (AxAx) and expanded back (B(Ax)B(Ax)). The update ΔW=sBA\Delta W = sBA is a sum of rr rank-1 matrices, so its rank is at most rr (Linear Algebra lesson 15).

    • Parameters: r(d+k)r(d + k) instead of dkdk. For d=k=4096d = k = 4096 and r=8r = 8: 65,53665{,}536 instead of 16,777,21616{,}777{,}216, which is 0.39%0.39\%.
    • Initialization: AA random (Gaussian), B=0B = 0. So ΔW=0\Delta W = 0, and training starts exactly at the pretrained model.
    • Scale: α/r\alpha/r lets you change rr without retuning the learning rate much. (rsLoRA uses α/r\alpha/\sqrt{r} for large rr.)
    • Merge for inference: W=W0+sBAW = W_0 + sBA is one matrix again, so a merged LoRA adds no latency.
    • In code, compute (xA⊤)B⊤(xA^\top)B^\top for a batch of row vectors. Never build the d×kd \times k matrix BABA in the training forward pass.
    Interactive figure: loading…

    Choose the rank budget rr. The target update ΔW\Delta W (left) and its best rank-rr approximation BABA. Move rr and watch the error and the parameter count 2dr2dr against d2d^2. When the singular values decay fast, a small rr already captures most of ΔW\Delta W; this is the bet that LoRA makes.

    Theorem (LoRA gradients). Let u=Ax∈Rru = Ax \in \mathbb{R}^r and let g=∂L/∂h∈Rdg = \partial \mathcal{L} / \partial h \in \mathbb{R}^d be the gradient that arrives from the layers above. Then

    ∂L∂B=s g u⊤,∂L∂A=s B⊤g x⊤.\frac{\partial \mathcal{L}}{\partial B} = s\, g\, u^\top, \qquad \frac{\partial \mathcal{L}}{\partial A} = s\, B^\top g\, x^\top .
    1. h=W0x+sBuh = W_0 x + s B u. W0W_0 is frozen, so only the term sBusBu depends on AA and BB.
    2. For fixed uu, hh is linear in BB: ∂hi/∂Bij=s uj\partial h_i / \partial B_{ij} = s\, u_j. So ∂L/∂Bij=s giuj\partial \mathcal{L} / \partial B_{ij} = s\, g_i u_j, which is the matrix s gu⊤s\, g u^\top.
    3. The gradient with respect to uu is ∂L/∂u=sB⊤g\partial \mathcal{L} / \partial u = s B^\top g (the transpose of the linear map u↦sBuu \mapsto sBu, applied to gg).
    4. u=Axu = Ax is linear in AA, so by the argument of step 2, ∂L/∂A=(∂L/∂u) x⊤=sB⊤g x⊤\partial \mathcal{L} / \partial A = (\partial \mathcal{L} / \partial u)\, x^\top = s B^\top g\, x^\top. ■\blacksquare

    Consequences for the initialization.

    • With B=0B = 0: ∂L/∂A=0\partial \mathcal{L} / \partial A = 0, but ∂L/∂B=s g(Ax)⊤≠0\partial \mathcal{L} / \partial B = s\, g (Ax)^\top \ne 0. So BB moves first. After one step B≠0B \ne 0, and then AA moves too.
    • With A=B=0A = B = 0: both gradients are zero at every step. Nothing trains.
    • With both random: ΔW≠0\Delta W \ne 0 at step 0. Training starts from a changed, worse model.
    • A=0A = 0 with BB random also works (the mirror case). What matters is ΔW=0\Delta W = 0 with not both factors zero.

    What LoRA saves, and what it does not.

    • Saves: the gradients and optimizer states of W0W_0. Full fine-tuning with Adam needs about 16 bytes per parameter. LoRA needs the frozen weights (2 bytes per parameter in bf16) plus about 16 bytes per adapter parameter. Hu et al. report 1.2 TB → 350 GB of GPU memory for GPT-3 175B, and a checkpoint of 35 MB instead of 350 GB (r=4r = 4, query and value projections only).
    • Does not save: activations. Backpropagation still needs the stored inputs of every adapted layer, and the gradient must still flow through every frozen W0W_0 to the layers below. The backward pass skips only the weight gradient of W0W_0 (the paper reports a 25% speed-up).
    • Capacity: each adapted matrix can change only by a matrix of rank at most rr. For a large domain shift (a new language, continued pretraining) LoRA can fall short of full fine-tuning; it also forgets less of what the base model knew (Biderman et al., 2024).
    • QLoRA (Dettmers et al., 2023) stores the frozen base in 4-bit NF4 and puts adapters on all linear layers; this fine-tunes a 65 B model on one 48 GB GPU.
    Quick check

    A colleague initializes a LoRA layer with A=0A = 0 and B=0B = 0 "to start exactly at the pretrained model". What happens in training?

    3.6 Reward model and RLHF with PPO #

    Reward model. Labelers choose the better of two responses: ywy_w (winner) and yly_l (loser). The Bradley–Terry model says

    P(yw≻yl∣x)=σ(rϕ(x,yw)−rϕ(x,yl)),P(y_w \succ y_l \mid x) = \sigma\big(r_\phi(x, y_w) - r_\phi(x, y_l)\big),

    with σ\sigma the logistic function and rϕr_\phi a scalar head on an LLM. The loss is −log⁡σ(rϕ(x,yw)−rϕ(x,yl))-\log \sigma(r_\phi(x, y_w) - r_\phi(x, y_l)): logistic regression on the difference of two scores. Only differences matter, so rϕr_\phi is fixed only up to a constant for each prompt.

    RL objective. With πref\pi_{\text{ref}} the SFT model and β>0\beta > 0:

    max⁡π Ex, y∼π(⋅∣x)[r(x,y)]−β KL(π(⋅∣x) ∥ πref(⋅∣x)).\max_\pi\ \mathbb{E}_{x,\ y \sim \pi(\cdot \mid x)}\big[r(x, y)\big] - \beta\, \mathrm{KL}\big(\pi(\cdot \mid x) \,\|\, \pi_{\text{ref}}(\cdot \mid x)\big).

    Theorem (optimal policy). For each prompt xx the maximizer is

    π∗(y∣x)=1Z(x) πref(y∣x) er(x,y)/β,Z(x)=∑yπref(y∣x) er(x,y)/β.\pi^*(y \mid x) = \frac{1}{Z(x)}\, \pi_{\text{ref}}(y \mid x)\, e^{r(x, y)/\beta}, \qquad Z(x) = \sum_y \pi_{\text{ref}}(y \mid x)\, e^{r(x, y)/\beta}.

    Why this is true, in one sentence. The objective is, up to a constant, minus β\beta times the KL divergence from π\pi to π∗\pi^*, and a KL divergence is smallest (zero) when the two distributions are equal.

    1. Fix xx and drop it from the notation. The objective is J(π)=∑yπ(y)r(y)−β∑yπ(y)log⁡π(y)πref(y)J(\pi) = \sum_y \pi(y) r(y) - \beta \sum_y \pi(y) \log \frac{\pi(y)}{\pi_{\text{ref}}(y)}.
    2. Take the log of the definition of π∗\pi^* and solve for the reward: r(y)=βlog⁡π∗(y)πref(y)+βlog⁡Zr(y) = \beta \log \frac{\pi^*(y)}{\pi_{\text{ref}}(y)} + \beta \log Z.
    3. Substitute this into JJ. The two πref\pi_{\text{ref}} terms cancel, and ∑yπ(y)=1\sum_y \pi(y) = 1: J(π)=∑yπ(y) βlog⁡π∗(y)π(y)+βlog⁡Z=−β KL(π ∥ π∗)+βlog⁡ZJ(\pi) = \sum_y \pi(y)\, \beta \log \frac{\pi^*(y)}{\pi(y)} + \beta \log Z = -\beta\, \mathrm{KL}(\pi \,\|\, \pi^*) + \beta \log Z.
    4. ZZ does not depend on π\pi, and KL(π ∥ π∗)≥0\mathrm{KL}(\pi \,\|\, \pi^*) \ge 0 with equality only at π=π∗\pi = \pi^*. So π∗\pi^* is the unique maximizer, and the maximum value is βlog⁡Z\beta \log Z. ■\blacksquare

    In the toy of section 2: π∗∝(0.5e1,0.5e0)\pi^* \propto (0.5 e^{1}, 0.5 e^{0}), so π∗=(0.731,0.269)\pi^* = (0.731, 0.269).

    PPO in practice (InstructGPT): sample responses from the policy, score them with rϕr_\phi, add a KL penalty per token, estimate advantages with a value model and GAE, and update with the clipped probability ratio. Four models are in memory: policy, reference, reward model, value model.

    Trade-offs. PPO learns from its own samples, so it can improve beyond the data. But it is expensive (generation inside the training loop), has many hyperparameters, and can be unstable. And the reward model is only a proxy. Gao et al. (2022) showed that the true reward first rises and then falls as the policy moves further (in KL) from πref\pi_{\text{ref}}. This is reward over-optimization (also called reward hacking).

    3.7 DPO: the reward model inside the policy #

    Step 2 of the proof writes the reward through the optimal policy. DPO (Rafailov et al., 2023) puts this expression into the Bradley–Terry model:

    1. r(x,yw)−r(x,yl)=βlog⁡π∗(yw∣x)πref(yw∣x)−βlog⁡π∗(yl∣x)πref(yl∣x)r(x, y_w) - r(x, y_l) = \beta \log \frac{\pi^*(y_w \mid x)}{\pi_{\text{ref}}(y_w \mid x)} - \beta \log \frac{\pi^*(y_l \mid x)}{\pi_{\text{ref}}(y_l \mid x)}. The term βlog⁡Z(x)\beta \log Z(x) cancels, because both responses answer the same prompt xx.
    2. Replace the unknown π∗\pi^* by the trained policy πθ\pi_\theta, and minimize the Bradley–Terry loss on the preference pairs:
    LDPO=−log⁡σ(βlog⁡πθ(yw∣x)πref(yw∣x)−βlog⁡πθ(yl∣x)πref(yl∣x)).\mathcal{L}_{\text{DPO}} = -\log \sigma\Big(\beta \log \frac{\pi_\theta(y_w \mid x)}{\pi_{\text{ref}}(y_w \mid x)} - \beta \log \frac{\pi_\theta(y_l \mid x)}{\pi_{\text{ref}}(y_l \mid x)}\Big).

    The implicit reward is r^θ(x,y)=βlog⁡πθ(y∣x)πref(y∣x)\hat r_\theta(x, y) = \beta \log \frac{\pi_\theta(y \mid x)}{\pi_{\text{ref}}(y \mid x)}. The gradient is

    ∇θLDPO=−β σ(r^θ(x,yl)−r^θ(x,yw))[∇θlog⁡πθ(yw∣x)−∇θlog⁡πθ(yl∣x)].\nabla_\theta \mathcal{L}_{\text{DPO}} = -\beta\, \sigma\big(\hat r_\theta(x, y_l) - \hat r_\theta(x, y_w)\big)\big[\nabla_\theta \log \pi_\theta(y_w \mid x) - \nabla_\theta \log \pi_\theta(y_l \mid x)\big].

    It raises the log-probability of the winner, lowers that of the loser, and the weight σ(r^l−r^w)\sigma(\hat r_l - \hat r_w) is large when the model still ranks the pair wrongly.

    DPO needs two models (the policy and the frozen reference), no sampling, and the training loop of SFT. Trade-offs: it is offline. It learns only from the fixed pairs, often sampled from other models, so it cannot explore or get feedback on its own new answers. It can overfit the pairs, and it can lower the likelihood of both responses. Variants: IPO (a squared loss against overfitting), KTO (unpaired thumbs up or down; still uses πref\pi_{\text{ref}}), SimPO and ORPO (no reference model).

    3.8 RL with verifiable rewards and GRPO #

    For math and code, a program can check the answer. The reward is 11 if the final answer matches or the unit tests pass, else 00 (sometimes plus a small format reward). GRPO (DeepSeekMath, 2024) samples a group of GG responses for each prompt and gives every token of response ii the advantage

    Ai=ri−mean⁡(r1,…,rG)std⁡(r1,…,rG).A_i = \frac{r_i - \operatorname{mean}(r_1, \dots, r_G)}{\operatorname{std}(r_1, \dots, r_G)}.

    The group mean replaces the value model as the baseline: an answer is good if it beats the other answers to the same prompt. The update is a PPO-style clipped ratio per token, plus a KL term to πref\pi_{\text{ref}}. DeepSeek-R1-Zero ran this on a base model with only accuracy and format rewards; its responses grew longer, and it learned to re-check its own steps.

    Interactive figure: loading…

    Click an answer to flip its reward between 1 (correct) and 0 (wrong). The bars are the advantages: blue pushes the answer up, orange pushes it down. Make all answers correct (or all wrong): every advantage becomes 0, and the prompt gives no learning signal. Switch to "no std" (Dr. GRPO) to see that only the scale changes.

    Trade-offs. It works only where a checker exists. Generation dominates the cost. A group where all answers get the same reward has zero advantage and gives no signal (DAPO filters such groups and samples new prompts). The checker can be gamed. Variants: Dr. GRPO removes the length and std normalizations, because they bias the update; DAPO drops the KL term. It is still debated whether this RL teaches new abilities or mainly makes the model sample its best answers more often (higher pass@1, similar pass@kk for large kk).

    Other tools of the same stack: rejection-sampling fine-tuning (sample many answers, keep the best, run SFT on them), distillation (SFT on a stronger model's outputs), and RLAIF (AI feedback instead of human labels).

    Method Data Models in memory Online Strength Main failure mode
    SFT demonstrations 1 no simple, stable; sets the format imitation only; no negative signal
    RLHF (PPO) pairs → reward model; prompts 4: policy, reference, reward, value yes can go beyond the data; any learned reward cost, instability, reward hacking
    DPO pairs 2: policy, reference no as simple as SFT; no reward model off-policy; overfits; no exploration
    GRPO + checker prompts + a checker policy + reference (1 without the KL term) yes strong for math and code reasoning only checkable tasks; zero-signal groups
    Quick check

    Your team has 50,000 preference pairs, little GPU budget, and wants simple, stable code. Which method fits, and what is its main limit?

    3.9 Evaluation #

    • Perplexity and bits per byte measure language-modeling quality, not usefulness. Compare perplexity only between models with the same tokenizer.
    • Benchmarks: multiple choice (MMLU), scored by the log-likelihood of each option or by the generated letter; generative tasks (GSM8K, HumanEval), scored by a checker. An accuracy p^\hat p on nn independent questions has standard error p^(1−p^)/n\sqrt{\hat p(1-\hat p)/n}.
    • pass@kk (Chen et al., 2021) is the probability that at least one of kk samples is correct.
    • LLM-as-judge is cheap and scales, but it prefers the first position, longer answers, and its own outputs (Zheng et al., 2023). Mitigate: swap the order and average, control for length, use a judge from a different model family, and check agreement with human labels.
    • Contamination: test items inside the training data inflate scores. Detect it with nn-gram overlap (GPT-3 used 13-grams), report results on a clean subset, and prefer new or private test sets.

    Theorem (unbiased pass@kk). Draw n≥kn \ge k independent samples for one problem, and let cc of them be correct. Then

    pass@k^=1−(n−ck)(nk)\widehat{\text{pass@}k} = 1 - \frac{\binom{n-c}{k}}{\binom{n}{k}}

    is unbiased for pass@k=1−(1−p)k\text{pass@}k = 1 - (1-p)^k, where pp is the probability that one sample is correct. The plug-in estimate 1−(1−c/n)k1 - (1 - c/n)^k is biased low.

    1. (n−ck)/(nk)\binom{n-c}{k}/\binom{n}{k} is the probability that a random subset of kk of the nn samples contains no correct sample.
    2. Average this over the random samples. A random kk-subset of nn independent samples is itself kk independent samples, so its chance to be all wrong is (1−p)k(1-p)^k. Hence E[(n−ck)/(nk)]=(1−p)k\mathbb{E}\big[\binom{n-c}{k}/\binom{n}{k}\big] = (1-p)^k, and the estimator is unbiased.
    3. The plug-in uses f(p^)=1−(1−p^)kf(\hat p) = 1 - (1 - \hat p)^k with p^=c/n\hat p = c/n. The function ff is concave, so by Jensen's inequality E[f(p^)]≤f(Ep^)=f(p)\mathbb{E}[f(\hat p)] \le f(\mathbb{E}\hat p) = f(p): it is too low on average. ■\blacksquare
    Interactive figure: loading…

    Change nn, cc and kk. The blue curve is the unbiased estimator 1−(n−ck)/(nk)1 - \binom{n-c}{k}/\binom{n}{k} for every k≤nk \le n, and the orange curve is the plug-in 1−(1−c/n)k1 - (1 - c/n)^k. At k=1k = 1 they agree. For larger kk the plug-in is lower, and at k=nk = n the unbiased estimator is exactly 1 whenever c≥1c \ge 1.

    Quick check

    A model scores 70% on a benchmark of 1,000 independent questions. What is the standard error of this accuracy, in percentage points?

    Answers to section 1. (1) It is 2 tokens per parameter, far from about 20. The budget is C=6⋅1010⋅2⋅1010=1.2⋅1021C = 6 \cdot 10^{10} \cdot 2 \cdot 10^{10} = 1.2 \cdot 10^{21} FLOPs. With D=20ND = 20N: N=C/120=1019≈3.2N = \sqrt{C/120} = \sqrt{10^{19}} \approx 3.2 B and D≈63D \approx 63 B tokens. The Chinchilla fit gives a loss of 2.3882.388 for the plan and 2.3182.318 for the 20-tokens choice (its own minimum, 2.3112.311, is at 2.0 B parameters on 101 B tokens). If the model will serve many tokens, go even smaller and train longer. (2) DPO learns only from a fixed set of pairs. Online RL samples from the current policy and gets a reward for exactly those samples. So it can explore, it can improve beyond the data, and it can use a checker. The price is cost and instability.

    4. Worked example #

    A. Plan a small pretraining run. The budget is 8 H100 GPUs for 24 hours. Peak dense bf16 throughput is F=989F = 989 TFLOP/s per GPU. Assume 40% MFU, so each GPU gives 0.4⋅989⋅1012=3.96⋅10140.4 \cdot 989 \cdot 10^{12} = 3.96 \cdot 10^{14} useful FLOP/s.

    1. Compute: C=8⋅86,400 s⋅3.96⋅1014 FLOP/s=2.73⋅1020C = 8 \cdot 86{,}400\ \text{s} \cdot 3.96 \cdot 10^{14}\ \text{FLOP/s} = 2.73 \cdot 10^{20} FLOPs.
    2. Chinchilla rule: N=C/120=2.28⋅1018=1.5⋅109N = \sqrt{C/120} = \sqrt{2.28 \cdot 10^{18}} = 1.5 \cdot 10^9 parameters, and D=20N=30D = 20N = 30 B tokens.
    3. Memory: 16⋅1.5⋅109=2416 \cdot 1.5 \cdot 10^9 = 24 GB for weights, gradients and Adam states. It fits on one 80 GB GPU with room for activations, so plain data parallelism works.
    4. Serving cost: 2N=3.02N = 3.0 GFLOP per generated token.
    5. Over-trained option: N=0.5N = 0.5 B on D=C/(6N)=91D = C/(6N) = 91 B tokens (182 tokens per parameter). With the Chinchilla fit, the loss rises only from 2.4752.475 to 2.4892.489 nats (+0.6%+0.6\%), and every generated token costs 3× less.

    B. One DPO pair. β=0.1\beta = 0.1. The sequence log-probabilities are log⁡πθ(yw∣x)=−10\log \pi_\theta(y_w \mid x) = -10, log⁡πref(yw∣x)=−12\log \pi_{\text{ref}}(y_w \mid x) = -12, log⁡πθ(yl∣x)=−15\log \pi_\theta(y_l \mid x) = -15, log⁡πref(yl∣x)=−14\log \pi_{\text{ref}}(y_l \mid x) = -14.

    1. Implicit rewards: r^w=0.1⋅(−10+12)=0.2\hat r_w = 0.1 \cdot (-10 + 12) = 0.2 and r^l=0.1⋅(−15+14)=−0.1\hat r_l = 0.1 \cdot (-15 + 14) = -0.1.
    2. Margin: r^w−r^l=0.3\hat r_w - \hat r_l = 0.3.
    3. Loss: −log⁡σ(0.3)=−log⁡0.574=0.554-\log \sigma(0.3) = -\log 0.574 = 0.554.
    4. Gradient weight: σ(r^l−r^w)=σ(−0.3)=0.426\sigma(\hat r_l - \hat r_w) = \sigma(-0.3) = 0.426. The pair still gets a large update, because the policy separates the two responses only a little.

    C. One GRPO group. G=8G = 8 answers to one math prompt, with rewards (1,0,0,1,1,0,0,0)(1, 0, 0, 1, 1, 0, 0, 0).

    1. Mean: 3/8=0.3753/8 = 0.375.
    2. Standard deviation (population, divide by GG): 0.375⋅0.625=0.484\sqrt{0.375 \cdot 0.625} = 0.484. (For 0/1 rewards with mean rˉ\bar r, the variance is rˉ(1−rˉ)\bar r(1 - \bar r).)
    3. Advantages: (1−0.375)/0.484=+1.29(1 - 0.375)/0.484 = +1.29 for each correct answer and (0−0.375)/0.484=−0.77(0 - 0.375)/0.484 = -0.77 for each wrong one.
    4. If all 8 were correct, every ri−meanr_i - \text{mean} would be 00: no signal. Implementations add a small ε\varepsilon to the std to avoid 0/00/0. Some libraries divide by G−1G - 1 in the std; this multiplies all advantages by the same factor (G−1)/G\sqrt{(G-1)/G}.

    D. Is model B better? Model A scores 71.0% and model B 72.5% on the same 1,000 questions.

    1. Each standard error is about 0.72⋅0.28/1000=1.4\sqrt{0.72 \cdot 0.28 / 1000} = 1.4 points.
    2. If we treat the two scores as independent, the difference has standard error 1.432+1.412=2.0\sqrt{1.43^2 + 1.41^2} = 2.0 points, so the 95% interval is 1.5±3.91.5 \pm 3.9 points. Not significant.
    3. A paired test on the same questions is tighter, because it removes the variation in question difficulty. Report the interval either way.

    E. pass@kk. n=10n = 10 samples, c=3c = 3 correct.

    1. pass@1 =1−(71)/(101)=1−7/10=0.30= 1 - \binom{7}{1}/\binom{10}{1} = 1 - 7/10 = 0.30.
    2. pass@5 =1−(75)/(105)=1−21/252=0.917= 1 - \binom{7}{5}/\binom{10}{5} = 1 - 21/252 = 0.917.
    3. The plug-in gives 1−0.75=0.8321 - 0.7^5 = 0.832: too low.

    F. LoRA on a 7 B model. A Llama-2-7B-shaped model has 32 layers, width d=4096d = 4096 and full multi-head attention, so Wq,Wk,Wv,WoW_q, W_k, W_v, W_o are all 4096×40964096 \times 4096. LoRA with r=8r = 8 on these four:

    1. Per matrix: 8⋅(4096+4096)=65,5368 \cdot (4096 + 4096) = 65{,}536. Per layer: 4⋅65,536=262,1444 \cdot 65{,}536 = 262{,}144.
    2. All layers: 32⋅262,144=8,388,60832 \cdot 262{,}144 = 8{,}388{,}608 trainable parameters, about 0.12%0.12\% of 7 B.
    3. Their training states: 16⋅8.39M≈13416 \cdot 8.39\text{M} \approx 134 MB. The frozen base: 2⋅7B=142 \cdot 7\text{B} = 14 GB in bf16.
    4. Full fine-tuning would need 16⋅7B=11216 \cdot 7\text{B} = 112 GB for the same states.

    5. In code #

    First, a check of 2N2N forward and 4N4N backward FLOPs per token, with PyTorch's FLOP counter on a stack of bias-free linear layers (as in modern LLMs):

    import torch
    from torch.utils.flop_counter import FlopCounterMode
    
    torch.manual_seed(0)
    d, T = 64, 128                       # width, tokens in the batch
    model = torch.nn.Sequential(         # 4 bias-free linear layers
        torch.nn.Linear(d, 4 * d, bias=False), torch.nn.GELU(),
        torch.nn.Linear(4 * d, d, bias=False),
        torch.nn.Linear(d, 4 * d, bias=False), torch.nn.GELU(),
        torch.nn.Linear(4 * d, d, bias=False),
    )
    N = sum(p.numel() for p in model.parameters())
    x = torch.randn(T, d, requires_grad=True)   # as for a layer deep inside a network
    
    with FlopCounterMode(display=False) as fwd:
        y = model(x)
    with FlopCounterMode(display=False) as bwd:
        y.square().mean().backward()
    
    print(N, fwd.get_total_flops() / (N * T), bwd.get_total_flops() / (N * T))   # 65536 2.0 4.0
    

    With requires_grad=False on x, the backward ratio drops to 3.5: the first layer needs no gradient for its input.

    Second, the closed form of section 3.3 against a numerical minimizer, and the other numbers of section 4, in NumPy:

    import numpy as np
    from math import comb
    from scipy.optimize import minimize_scalar
    
    E, A, B, alpha, beta = 1.69, 406.4, 410.7, 0.34, 0.28   # Hoffmann et al. (2022), approach 3
    C = 2.73e20                                              # the budget of section 4A
    
    def loss_on_isoflop(logN):                               # D is fixed by C = 6ND
        N = np.exp(logN)
        return E + A / N**alpha + B / (C / (6 * N))**beta
    
    res = minimize_scalar(loss_on_isoflop, bounds=(np.log(1e7), np.log(1e12)), method="bounded")
    G = (alpha * A / (beta * B)) ** (1 / (alpha + beta))
    print(f"{np.exp(res.x):.3e} {G * (C / 6) ** (beta / (alpha + beta)):.3e}")
    # 1.016e+09 1.016e+09
    for N in [0.5e9, 1e9, 1.5e9]:
        print(f"N = {N:.1e}  D/N = {C / (6 * N) / N:5.1f}  L = {loss_on_isoflop(np.log(N)):.3f}")
    # N = 5.0e+08  D/N = 182.3  L = 2.489
    # N = 1.0e+09  D/N =  45.6  L = 2.470
    # N = 1.5e+09  D/N =  20.3  L = 2.475
    
    p = np.array([0.5, 0.5]) * np.exp(np.array([1.0, 0.0]) / 1.0)   # KL leash, beta = 1
    print((p / p.sum()).round(3))                                      # [0.731 0.269]
    
    sig = lambda z: 1 / (1 + np.exp(-z))                               # DPO pair of section 4B
    rw, rl = 0.1 * (-10 + 12), 0.1 * (-15 + 14)
    print(round(-np.log(sig(rw - rl)), 3), round(sig(rl - rw), 3))     # 0.554 0.426
    
    r = np.array([1, 0, 0, 1, 1, 0, 0, 0], float)                      # GRPO group of section 4C
    print(((r - r.mean()) / r.std()).round(2))
    # [ 1.29 -0.77 -0.77  1.29  1.29 -0.77 -0.77 -0.77]
    
    n, c, k = 10, 3, 5                                                 # pass@k of section 4E
    print(round(1 - comb(n - c, k) / comb(n, k), 3), round(1 - (1 - c / n) ** k, 3))
    # 0.917 0.832
    

    The fit puts the optimum at 1.01.0 B parameters (45 tokens per parameter); the 20-tokens rule gives 1.51.5 B. Inside a factor of 3 in NN, the loss changes by less than 1%. This flatness is why the exact ratio matters less than the inference cost.

    6. Where it shows up #

    • LLM work in industry. Every team that adapts an open model chooses SFT, DPO or RL by the data it has: demonstrations, preference pairs, or a checker. LoRA adapters let one server keep one base model and many small task adapters (lesson 13).
    • Scientific foundation models. The same accounting sizes a weather or Earth-system model: a "token" is a patch of a field at one time step, and 6ND6ND still counts the matrix FLOPs. The rule of 20 tokens per parameter was measured on web text; measure your own exponents with small runs before you spend the big budget. LoRA adapts a pretrained weather or protein model to a new region, variable or small assay data set, with a few MB per task.
    • Rewards from physics. A simulator or a conservation check is a verifiable reward, so the ideas of section 3.8 carry over to generative models of physical fields. So does the risk: a field can conserve mass and still be wrong.
    • Reading papers. Ask: is the gain larger than about 2 standard errors? Is the benchmark contaminated? Is perplexity compared across tokenizers?

    7. Common mistakes #

    • Treating 20 tokens per parameter as a law. It is the training-compute optimum of one fit on one data mix. Inference cost and data quality move the best choice.
    • Forgetting what 6ND6ND leaves out. Attention FLOPs at long context, recomputation, and the gap between peak and achieved FLOP/s (MFU).
    • Comparing perplexities of models with different tokenizers. Use bits per byte.
    • Computing the SFT loss on prompt tokens. The model then spends capacity on predicting user prompts. Mask them.
    • Initializing both LoRA factors to zero (nothing trains) or both at random (the wrong starting model). Forgetting to freeze W0W_0 also removes all the memory savings.
    • Saying "DPO has no reference model". It has one (frozen). SimPO and ORPO remove it.
    • Saying "the reward went up, so the model is better". The reward model is a proxy. Watch the KL and a held-out gold evaluation.
    • Using 1−(1−c/n)k1 - (1 - c/n)^k for pass@kk, and reporting differences smaller than their standard error.

    8. Check yourself #

    1. How many H100 GPU-days does it take to train a 7 B model on 2 T tokens at 40% MFU?
      AnswerC=6⋅7⋅109⋅2⋅1012=8.4⋅1022C = 6 \cdot 7 \cdot 10^9 \cdot 2 \cdot 10^{12} = 8.4 \cdot 10^{22} FLOPs. One GPU gives 0.4⋅989⋅1012=3.96⋅10140.4 \cdot 989 \cdot 10^{12} = 3.96 \cdot 10^{14} FLOP/s, so 2.12⋅1082.12 \cdot 10^8 GPU-seconds, about 2,4602{,}460 GPU-days (about 10 days on 256 GPUs).
    2. Why is the KL penalty in RLHF needed, and what happens as β→0\beta \to 0?
      AnswerIt keeps the policy near πref\pi_{\text{ref}}, where the reward model was trained and is reliable, and it keeps the text fluent. As β→0\beta \to 0 the optimum π∗∝πref er/β\pi^* \propto \pi_{\text{ref}}\, e^{r/\beta} puts all mass on the highest proxy reward: reward hacking.
    3. In DPO, why does the partition function Z(x)Z(x) disappear?
      AnswerThe reward is βlog⁡(π∗/πref)+βlog⁡Z(x)\beta \log(\pi^*/\pi_{\text{ref}}) + \beta \log Z(x). Bradley–Terry uses only the difference of the rewards of two responses to the same prompt, so βlog⁡Z(x)\beta \log Z(x) cancels.
    4. A GRPO group of 4 answers is all correct. What is the policy-gradient signal from it, and what can you do?
      AnswerZero: every ri−mean=0r_i - \text{mean} = 0, so all advantages are 0 (only the KL term acts). Filter such prompts and sample new ones (DAPO's dynamic sampling), or choose prompts of medium difficulty for the current model.
    5. A 4096×40964096 \times 4096 projection gets LoRA with rank 16. How many trainable parameters, and what fraction of the matrix?
      Answer16⋅(4096+4096)=131,07216 \cdot (4096 + 4096) = 131{,}072, which is 131,072/16,777,216=0.78%131{,}072 / 16{,}777{,}216 = 0.78\%.
    6. When would you choose DPO over PPO, and when the other way round?
      AnswerDPO: you have good preference pairs, limited compute, and want stability and simple code. PPO or GRPO: you need on-policy improvement beyond the data, you have a reliable reward model or a checker (math, code), and you can pay for generation in the loop.
    Recall cardsAnswer in your head first, then reveal. Add the cards to your review deck to see them again just before you would forget.
    1. About how many FLOPs does it take to train a dense transformer with NN parameters on DD tokens, and why that factor?

    2. What is the loss and the perplexity of a model that predicts uniformly over VV tokens?

    3. What is the Chinchilla rule for a compute-optimal model?

    4. Why do labs train far past 20 tokens per parameter?

    5. What is the optimal policy of max⁡πEπ[r]−β KL(π∥πref)\max_\pi \mathbb{E}_\pi[r] - \beta\, \mathrm{KL}(\pi \| \pi_{\text{ref}})?

    6. Write the DPO loss for one pair (yw,yl)(y_w, y_l).

    7. What is the GRPO advantage of answer ii in a group of GG answers?

    8. How many trainable parameters does LoRA of rank rr add to a d×kd \times k matrix?

    9. Why does LoRA start with B=0B = 0 and AA random, and not both zero?

    10. What does pass@kk measure, and what is its unbiased estimator from nn samples with cc correct?

    Open the review →

    9. Interview angle #

    Recognize the question from the wording.

    The question says Start with
    "how is a chat model trained", "walk me through the pipeline" the stage table of section 2; one equation and one number per stage
    "how big a model for this budget", "how long will it train" C≈6NDC \approx 6ND, N≈C/120N \approx \sqrt{C/120}, time =C/(nGPUF MFU)= C/(n_{\text{GPU}} F\, \text{MFU})
    "Kaplan vs Chinchilla", "why does Llama train so long" the schedule flaw; inference cost; the flat iso-FLOP curve
    "derive DPO", "why no reward model" the optimal-policy proof, then log⁡Z\log Z cancels
    "we only have a unit-test checker", "reasoning" RL with verifiable rewards, GRPO advantage, zero-signal groups
    "fine-tune on one GPU", "many customers, one base model" LoRA (and QLoRA): r(d+k)r(d + k) parameters, memory, merge
    "is model B better?" standard error, paired test, contamination, judge biases

    The routine to say aloud for any breadth question (60–90 seconds): give the one-sentence answer first; then one equation or one number; then one trade-off ("it costs …, it fails when …"); then stop and let the interviewer choose the follow-up.

    Typical questions and short model answers.

    1. "Walk me through how a chat model is trained." — "Pretraining on about 101310^{13} tokens with the next-token loss; that gives knowledge. Then mid-training on a cleaner mix while the learning rate decays. Then SFT on prompt–response pairs, with the loss only on response tokens; that gives the format. Then preference tuning, with a reward model and PPO or with DPO; that picks the answers people prefer. For math and code, RL with a checker, for example GRPO, which improves reasoning. Compute is about 6ND6ND, so a 7 B model on 2 T tokens is about 8⋅10228 \cdot 10^{22} FLOPs."
    2. "Chinchilla vs Kaplan. Why does Llama train far past 20 tokens per parameter?" — "Chinchilla fitted L=E+A/Nα+B/DβL = E + A/N^\alpha + B/D^\beta and found that at fixed compute NN and DD should grow together, about 20 tokens per parameter. Kaplan used one schedule for all runs, so short runs looked worse than they were, and data was undervalued. Llama trains longer because Chinchilla counts only training compute. Inference costs 2N2N per token forever, and the loss is flat near the optimum, so a smaller model trained longer is cheaper overall."
    3. "Derive DPO." — "Start from max⁡πE[r]−β KL(π∥πref)\max_\pi \mathbb{E}[r] - \beta\,\mathrm{KL}(\pi\|\pi_{\text{ref}}). Its solution is π∗∝πrefer/β\pi^* \propto \pi_{\text{ref}} e^{r/\beta}, because the objective equals −β KL(π∥π∗)-\beta\,\mathrm{KL}(\pi\|\pi^*) plus a constant. Invert it: r=βlog⁡(π∗/πref)+βlog⁡Zr = \beta \log(\pi^*/\pi_{\text{ref}}) + \beta\log Z. Put this into Bradley–Terry; log⁡Z\log Z cancels because both answers share the prompt. Replace π∗\pi^* by πθ\pi_\theta and minimize the logistic loss on the pairs."
    4. "Why does GRPO need no value model? What can go wrong?" — "It samples a group of answers per prompt and uses the group mean as the baseline, normalized by the group std. That removes the value model and its memory. Problems: a group where all answers get the same reward gives zero signal; the std and length normalizations bias the update (Dr. GRPO removes them); and the checker can be gamed."
    5. "How do you know model B is better than model A?" — "Report the standard error: on 1,000 questions at 70% it is 1.4 points, so a 1.5-point gain is not significant. Use a paired test on the same questions, several seeds, and a check for contamination. If a model judges, swap the order and control for length."
    6. "LoRA or full fine-tuning?" — "LoRA trains r(d+k)r(d+k) parameters per matrix, so it saves the gradients and Adam states, gives small checkpoints, and lets one base serve many adapters; it also forgets less. It does not save activations. For a large domain shift, full fine-tuning has more capacity."

    Typical follow-ups. "What does 6ND6ND leave out?" (attention at long context, recomputation, MFU). "What happens if β\beta is too small?" (reward hacking; the KL grows). "Why does DPO lower the likelihood of both answers sometimes?" (it only needs the margin to grow). "What is pass@kk and why not 1−(1−p^)k1 - (1-\hat p)^k?" (biased low, by Jensen). "Where do you put LoRA adapters?" (all linear layers when quality matters, as in QLoRA).

    10. Practice #

    The notebook for this lesson runs in Colab, in NumPy. Each exercise has a check cell and a folded solution:

    1. chinchilla_optimum(C): the closed form of section 3.3, checked against a grid search on the iso-FLOP curve.
    2. kl_regularized_policy(pi_ref, r, beta): the optimal policy, checked to beat many random policies on the objective.
    3. dpo_loss and its gradient with respect to the two policy log-probabilities, checked by finite differences.
    4. grpo_advantages(rewards): the group-normalized advantages, with the zero-signal case.
    5. pass_at_k(n, c, k): the unbiased estimator, checked against a simulation.

    The notebook also has a LoRA layer in NumPy: the output equals the base at the start, the gradients follow the theorem, and the merged weight gives the same output.

    Timed practice (25 minutes each, talking aloud): derive C≈6NDC \approx 6ND on a blank page; derive the compute-optimal NoptN_{\text{opt}} and DoptD_{\text{opt}}; derive π∗∝πref er/β\pi^* \propto \pi_{\text{ref}}\, e^{r/\beta} and the DPO loss; implement a LoRA linear layer with merge and unmerge; implement the DPO loss for a batch of sequence log-probabilities.

    Say it aloud drill. Start a 2-minute timer and answer "walk me through how a chat model is trained" aloud. Record yourself and compare with the stage table: did you give one equation and one number per stage? Then do the same for "derive DPO" in 3 minutes.

    11. Watch and read #

    The pipeline from pretraining to the assistant, and scaling, at the level of a clear interview answer.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    Pretraining data and tokenization, SFT, and RL including RLHF and reasoning models, step by step.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    The Bradley–Terry model, the optimal KL-regularized policy, and the DPO derivation of section 3.7.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    Why a low-rank update is enough, and what LoRA saves, from the first author.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    The DeepSeekMath paper, with GRPO and its group baseline explained.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play