Index Ai Academy
Phase 6 · Modern LLM engineering · Adapting models

Distillation

Train a small model to imitate a large one.

About 35 minutes · A free account opens the whole lesson

Create a free account Try part of it here

Already have an account? Sign in to open this lesson

Why it matters

Many of the fast, cheap models you use learned partly by copying bigger ones. This copying is called distillation. It's how a lab turns an expensive model into an affordable one. It's how reasoning skills passed from DeepSeek-R1 to much smaller models. And it's how a company can turn a prompted frontier model into a small model that does one job well. It also shows that a model's outputs are valuable training data in their own right, and that has legal consequences.

What you'll be able to do

  • Explain knowledge distillation: training a small student on a large teacher's outputs
  • Use temperature to expose the information in a teacher's full probability distribution
  • Train a student with soft targets and compare it with training on hard labels
  • Distinguish logit distillation from training on generated text, and know the legal limits

What it covers

  1. More than the right answer
  2. Turning up the temperature
  3. How the student is scored
  4. Worked example: scoring one student guess
  5. Distilling a smaller GPT
  6. Distillation for language models in practice

More than the right answer

Picture two teachers marking the same quiz question. The first writes "wrong, the answer is B." The second writes "B is right. C was a fair guess, almost as good. D makes no sense at all." Both give you the right answer. The second also tells you how close the other options were, so you learn more from one question.

Training a language model normally works like the first teacher. Each example says only which token came next in the text. That single right answer is called a hard label.

A trained model can act like the second teacher. Its prediction is a full list of chances, one for every token in its vocabulary. It says which other tokens were plausible, and how plausible.

Distillation uses that richer signal. Two models are involved:

  • The teacher: a large, trained model.
  • The student: a smaller model you want to train.

The student learns to match the teacher's full list of chances. Those lists are called soft targets. Geoffrey Hinton and colleagues (2015) called the extra information in them "dark knowledge." They showed that a small student learns better from a big teacher's soft targets than from hard labels alone.

Quick check
Why does a soft target carry more information than a hard label?
  1. It always picks the correct token
  2. It uses more tokens per example
  3. It gives a probability for every option, including how plausible the wrong-but-close ones are
  4. It removes rare words from the vocabulary
Show the answer

It gives a probability for every option, including how plausible the wrong-but-close ones are

A hard label names one token. A full list of chances holds the teacher's judgment of every alternative, like the second teacher's notes on options C and D.

Turning up the temperature

A confident teacher has a problem. It might give the top token 99% and spread the last 1% thinly over everything else. Those tiny chances still hold knowledge, but they're too small for the student to notice.

Temperature fixes this. You met it in the sampling lesson. A model's raw scores, before they become chances, are called logits. Divide every logit by a number TT, the temperature, before the softmax. When TT is bigger than 1, the scores move closer together. So the chances come out flatter, and the small ones grow big enough to learn from.

Here is the softmax with a temperature. Number the options 1, 2, 3 and so on. Write ziz_i for the logit of option number i, and pip_i for the chance it ends up with:

pi=ezi/T∑jezj/Tp_i = \frac{e^{z_i / T}}{\sum_j e^{z_j / T}}

The top line raises ee (about 2.718) to the power of one option's scaled logit. The bottom line does the same for every option jj and adds them all up. The sign ∑\sum means "add up."

In plain words: shrink every score by dividing it by T. Then turn the scores into chances that add up to 1, as the softmax always does. A bigger T gives a flatter, less certain list. The order of the options never changes.

A worked example. Take three logits: 3, 1 and 0.

  • At T=1T = 1, the chances are about 0.84, 0.11 and 0.04.
  • At T=2T = 2, the logits become 1.5, 0.5 and 0. The chances are about 0.63, 0.23 and 0.14.

The top option is still on top. But the last option's share more than triples, from 4% to 14%. (The first row adds up to 0.99 only because of rounding.) The same sum as a loop:

import math

logits = [3.0, 1.0, 0.0]
for T in (1, 2):
    exps = [math.exp(z / T) for z in logits]
    total = sum(exps)
    print(T, [round(e / total, 2) for e in exps])
It runs right here in your browser, with nothing to install.

It prints 1 [0.84, 0.11, 0.04] and then 2 [0.63, 0.23, 0.14].

Now try it on a real teacher. The cell below loads the course's pretrained tiny GPT. It shows the teacher's top five next tokens for two prompts, at T=1T = 1 and at T=2T = 2:

import torch
from tinygpt import load_pretrained

teacher, tok = load_pretrained("tiny-gpt")                 # the base model, as a teacher
for prompt in ["Our Kestrel tent is made from", "It is light and"]:
    with torch.no_grad():
        logits = teacher(torch.tensor([tok.encode(prompt)]))[0, -1]
    print(prompt)
    for T in (1, 2):
        top = torch.softmax(logits / T, dim=-1).topk(5)
        print(f"  T={T}: " + ", ".join(f"{tok.vocab[i]} {p:.2f}" for p, i in zip(top.values.tolist(), top.indices.tolist())))

In the catalog text, "Our Kestrel tent is made from" has exactly one next word. But the teacher knows that tents come in silnylon and recycled ripstop nylon, nearly 50/50. A hard label teaches half of that. The soft target teaches all of it. At T=2T = 2, the teacher's small chances become visible too, such as waxed canvas at 3%.

Quick check
What does this print?
import math
def soft(a, b, t):
    ea, eb = math.exp(a / t), math.exp(b / t)
    return round(ea / (ea + eb), 2)
print(soft(2, 0, 1) > soft(2, 0, 4))
  1. None
  2. 0.88
  3. True
  4. False
Show the answer

True

At temperature 1, soft gives about 0.88, and at temperature 4, about 0.62. 0.88 is larger, so it prints True. A higher temperature evens out the probabilities, which reveals what the teacher thinks of the runners-up.

Try it now

At temperature 1, the teacher looks certain. Raise the temperature and its hidden knowledge appears: a cat is much more like a dog than like a car.

Quick check
A teacher gives two tokens the logits 4 and 2. You distill at T = 2. Which logits go into the softmax?
  1. 2 and 0
  2. 2 and 1
  3. 8 and 4
  4. 4 and 1
Show the answer

2 and 1

Each logit is divided by T: 4 / 2 = 2 and 2 / 2 = 1. The gap shrinks from 2 to 1, so the two chances come out closer together. The first token is still on top.

How the student is scored

The student also produces logits, and they're softened with the same temperature. Training then compares two lists of chances: the teacher's and the student's. The score is the cross-entropy you met in Phase 2, with the teacher's list in place of a single right answer.

Write qiq_i for the teacher's softened chance for option ii. Write pip_i for the student's softened chance for the same option. The loss for one position is:

loss=−T2∑iqilog⁡pi\text{loss} = -T^2 \sum_i q_i \log p_i

Here log⁡\log is the natural log, as in the cross-entropy lesson. The factor T2T^2 is the temperature times itself.

In plain words: for every option, take the log of the student's chance and weight it by the teacher's chance. Add those up and flip the sign. The loss is small when the student puts high chances where the teacher does. Then multiply by T times T. In training, this is averaged over every position in the batch.

With a hard label, the teacher's list is 1 for the true token and 0 for the rest. Then the sum keeps only one term. At T=1T = 1, that's ordinary cross-entropy again.

Go deeper Why multiply by T squared?

Softening makes both lists flatter, so the student's mistakes look smaller. Hinton's team showed that the push the student gets from soft targets shrinks by about 1/T21/T^2. Multiplying the loss by T2T^2 undoes that. So the training signal keeps a similar strength whichever temperature you choose. This matters when you mix the soft loss with an ordinary hard-label loss, as many recipes do.

Worked example

Worked example: scoring one student guess

Three possible next words: silnylon, ripstop and canvas. The teacher's softened list is 0.5, 0.4 and 0.1. The student's softened guess is 0.8, 0.1 and 0.1. The true word in the text was silnylon, and T=2T = 2. Compare the hard-label loss with the soft loss. To keep the numbers small, use the same student guess for both. (In real training, the hard-label loss uses the student's unsoftened chances.)

import math

teacher = [0.5, 0.4, 0.1]    # silnylon, ripstop, canvas: the softened target
student = [0.8, 0.1, 0.1]    # the student's softened guess
T = 2

hard = -math.log(student[0])                                  # the true word was silnylon
soft = -sum(q * math.log(p) for q, p in zip(teacher, student))
print(round(hard, 3), round(soft, 3), round(soft * T * T, 3))

copy = -sum(q * math.log(q) for q in teacher)                 # a student that matches the teacher
print(round(copy, 3))
In the lesson you can change this and run it.

It prints 0.223, 1.263 and 5.051, then 0.943. The hard label calls the student nearly right: it gave silnylon 80%, so the loss is only 0.223. The soft loss is much bigger, 1.263. It notices that the student gave ripstop only 10% when the teacher gave it 40%. Times T2=4T^2 = 4, that's 5.051.

The last line scores a student whose guess matches the teacher exactly. Its soft loss is 0.943, not 0. That's the teacher's own entropy, the lowest the soft loss can go. Training pushes the student toward that floor.

Quick check
A student's softened guess matches the teacher's softened list exactly. What is its soft loss, before multiplying by T²?
  1. The entropy of the teacher's list, the lowest value the loss can reach
  2. Exactly 0
  3. ln 2 ≈ 0.693, whatever the lists are
  4. It can't be computed
Show the answer

The entropy of the teacher's list, the lowest value the loss can reach

Cross-entropy is smallest when the two lists match, and then it equals the entropy of the target list. In the worked example that was 0.943, not 0.

Distilling a smaller GPT

Now the real experiment. The teacher is the course's tiny GPT. The student has about a quarter of the teacher's parameters. It has one layer of width 16 instead of two layers of width 32. (Width is the length of the list of numbers that stands for each token inside the model.)

The student sees only 800 tokens of catalog text, about 25 product descriptions. Two students train on that same text:

  • One trains on the hard labels: the true next token.
  • One trains on the teacher's soft targets, at temperature 2.

The teacher's soft targets are computed once, up front. Offline distillation usually works this way: run the teacher over the data first, store its outputs, then train the student.

Both students are then tested on descriptions they never saw. The test uses ordinary cross-entropy against the true next tokens, and lower is better. The cell takes a while to run. The Run button counts the seconds.

import requests
import torch
import torch.nn.functional as F
from tinygpt import GPT, load_pretrained

teacher, tok = load_pretrained("tiny-gpt")
data = torch.tensor(tok.encode(requests.get("https://api.gradient.test/v1/corpus").json()["text"]))
train, held_out = data[:800], data[int(0.9 * len(data)):]       # the student sees 800 tokens
V, T = len(tok), 2.0

windows = torch.stack([train[i:i + 33] for i in range(len(train) - 33)])   # every 32-token window + next token
with torch.no_grad():
    soft_targets = torch.softmax(teacher(windows[:, :-1]) / T, dim=-1)    # the teacher's view, computed once

@torch.no_grad()
def held_out_loss(model):
    torch.manual_seed(123)
    losses = []
    for _ in range(8):
        starts = torch.randint(0, len(held_out) - 33, (32,)).tolist()
        x = torch.stack([held_out[i:i + 32] for i in starts])
        y = torch.stack([held_out[i + 1:i + 33] for i in starts])
        losses.append(F.cross_entropy(model(x).reshape(-1, V), y.reshape(-1)).item())
    return sum(losses) / len(losses)

def train_student(soft, steps=300):
    torch.manual_seed(0)
    student = GPT(V, context=64, d=16, n_layers=1, n_heads=2)
    opt = torch.optim.AdamW(student.parameters(), lr=3e-3, weight_decay=0.01)
    torch.manual_seed(1)
    for step in range(steps):
        b = torch.randint(0, len(windows), (16,))
        logits = student(windows[b, :-1])
        if soft:                                              # match the teacher's softened distribution
            loss = -(soft_targets[b] * torch.log_softmax(logits / T, dim=-1)).sum(dim=-1).mean() * T * T
        else:                                                 # match the one true next token
            loss = F.cross_entropy(logits.reshape(-1, V), windows[b, 1:].reshape(-1))
        opt.zero_grad()
        loss.backward()
        opt.step()
    return student

count = lambda m: sum(p.numel() for p in m.parameters())
hard, soft = train_student(soft=False), train_student(soft=True)
print(f"teacher: {count(teacher):,} parameters; each student: {count(hard):,}")
print(f"student trained on hard labels:    held-out loss {held_out_loss(hard):.3f}")
print(f"student trained on teacher (T=2):  held-out loss {held_out_loss(soft):.3f}")

The line starting loss = -(soft_targets[b] ... is the formula from above, written in PyTorch.

From the same 800 tokens, the distilled student does noticeably better on new text. Each example carries the teacher's view of what else could have come next, and the teacher learned that view from the whole catalog.

With plenty of data, the gap narrows. In testing, with nearly ten times as much text, the two students were nearly tied. That matches practice: distillation helps most when the student can't see everything the teacher learned from. (torch here is the course's in-browser PyTorch subset.)

Distillation for language models in practice

There are two main kinds, and they need different access to the teacher.

  • Logit distillation is what the cell did. It needs the teacher's full lists of chances, and both models must use the same tokenizer. So it's used when one organization owns both models. Google, for example, trained its smaller Gemma 2 models with distillation from a larger model. DistilBERT (2019) kept about 97% of BERT's performance while being 40% smaller and 60% faster.
  • Sequence-level distillation trains the student with SFT on text the teacher generated. You ask the big model thousands of questions and fine-tune the small one on its answers. This needs no access to the chances, only the teacher's text. Stanford's Alpaca (2023) did this with 52,000 answers from an OpenAI model. DeepSeek fine-tuned small Qwen and Llama models on about 800,000 samples from R1, and got strong small reasoning models.
Quick check
Why can't you use logit distillation on a model behind a text-only API?
  1. The student must be bigger than the teacher
  2. Text can't be tokenized
  3. It needs the teacher's full lists of chances, and the API only returns text
  4. APIs are too slow
Show the answer

It needs the teacher's full lists of chances, and the API only returns text

With only the text, you can still train on the outputs, but that's the other kind of distillation.

A common business pattern works like this:

  1. Prototype with a frontier model and a careful prompt.
  2. Collect its outputs on real inputs, and have people review them.
  3. Fine-tune a small model on the approved outputs for the high-volume job.
  4. Keep evaluating the small model against the big one.

Know the terms. Many commercial providers' terms of service ban using their models' outputs to build competing models. They generally allow narrower internal uses. Open-model licenses vary too. Check the teacher's terms before you distill. Also check the license of any dataset that was itself generated by a model.

Know the limits. In general, a student can't beat its teacher on the teacher's own tasks. It copies the teacher's mistakes along with its skills. And a small model distilled on a narrow task can lose general abilities it had before.

For marketers: say a big model writes good product descriptions, but it costs too much at catalog scale. Generate a few thousand, have editors approve them, and fine-tune a small model on the approved set. Check first that your provider's terms allow it.

Quick check
Your teacher model often gets one product's price wrong in its answers. You fine-tune a student on those answers without reviewing them. What should you expect?
  1. The student repeats the same mistake
  2. The student fixes the mistake, because it's smaller
  3. The student refuses to mention prices
  4. Nothing, because distillation only copies style
Show the answer

The student repeats the same mistake

A student copies its teacher's mistakes along with its skills. That's why the business pattern has people review the teacher's outputs before training.

Practice what you just read

  • 4 code examples you can edit and run
  • a practice exercise that checks your code
  • a 5-question quiz
  • 5 review cards for spaced repetition

Create a free account

Try a quiz question

What does raising the distillation temperature T do to the teacher's distribution?

  1. Flattens it, making the relative probabilities of less likely tokens visible to the student
  2. Makes it more confident in the top token, so the student gets a clearer answer to copy
  3. Removes the top token, so that the student has to learn from the runners-up on their own
  4. Changes which token is most likely, so the student sees answers that the teacher wouldn't give

Answer it at the end of the lesson to see if you're right, and why.

Before this lesson