How Large Language Models Work
A large language model does one thing: given some text, it predicts what comes next. Everything it appears to do, from answering questions to writing code, comes from doing that very well, over and over.
Step 1: text becomes tokens
A tokeniser splits text into tokens and replaces each with a number. Tokens are pieces of words. Common words are a single token, and rare words are split into several.
vocabulary = ["un", "believ", "able", "happi", "ness", "the", "cat", " "]
def tokenise(text):
tokens = []
while text:
match = max((v for v in vocabulary if text.startswith(v)), key=len, default=None)
if match is None:
match = text[0] # unknown character becomes its own token
tokens.append(match)
text = text[len(match):]
return tokens
for word in ["unbelievable", "unhappiness", "the cat"]:
tokens = tokenise(word)
print(word, "->", tokens, "->", [vocabulary.index(t) if t in vocabulary else -1 for t in tokens])
Real tokenisers have vocabularies of tens of thousands of pieces, learned from data with algorithms such as byte-pair encoding. The principle is the same: any text can be written as a sequence of known pieces.
Step 2: tokens become vectors
Each token number is looked up in a table of embeddings, which gives a vector of several hundred or several thousand numbers. Information about each token’s position in the text is added.
Step 3: the transformer layers
The vectors pass through a stack of transformer layers. In each layer, attention lets every token draw information from the tokens before it, and a feed-forward network processes the result. After many layers, the vector at the last position encodes what the model needs to predict the next token.
Step 4: a probability for every token
The final vector is turned into a score for every token in the vocabulary, and the scores are turned into probabilities.
Step 5: choose a token and repeat
One token is chosen, added to the text, and the whole process runs again. This is called autoregressive generation.
import numpy as np
rng = np.random.default_rng(0)
# a toy "model": for each word, the probability of the next word
next_word = {
"the": {"cat": 0.5, "dog": 0.3, "sun": 0.2},
"cat": {"sat": 0.6, "ran": 0.4},
"dog": {"ran": 0.7, "sat": 0.3},
"sun": {"rose": 1.0},
"sat": {"down": 1.0},
"ran": {"away": 1.0},
}
def generate(start, steps=3):
words = [start]
for _ in range(steps):
options = next_word.get(words[-1])
if not options:
break
words.append(rng.choice(list(options), p=list(options.values())))
return " ".join(words)
for _ in range(4):
print(generate("the"))
Run it several times. The outputs differ because a token is sampled, not simply picked. A real model does the same with a vocabulary of tens of thousands of tokens and probabilities calculated from the entire preceding text.
Sampling settings
- Temperature flattens or sharpens the probabilities. Low values give focused, repeatable output. High values give more varied output.
- Top-p restricts the choice to the most likely tokens whose probabilities add up to p.
- Maximum tokens limits the length of the output.
- Stop sequences end generation when a given piece of text appears.
How a model is trained
Pretraining. The model reads an enormous amount of text and is trained to predict the next token. No labels are needed, because the text supplies its own answers. To predict well, the model has to pick up grammar, facts, styles and patterns of reasoning. This stage needs very large amounts of computing power.
Fine-tuning for conversation. The pretrained model is trained further on examples of instructions and good responses, so that it behaves as an assistant.
Alignment with human preferences. People, or models trained on human ratings, score outputs, and the model is adjusted towards responses that are helpful, accurate and safe.
What follows from this
| Fact about the mechanism | Consequence |
|---|---|
| It predicts likely text | It can produce fluent text that is false |
| It sees only the context window | It knows nothing you did not put there, beyond its training |
| It works on tokens | It can miscount letters and mishandle long numbers |
| It samples | Output varies from run to run |
| It was trained up to a cut-off date | It lacks recent information |
| Generation is one token at a time | Giving it room to reason before answering helps |
Parameters and context size
Two numbers describe a model. The parameter count is the number of learned weights. The context window is the number of tokens it can take in at once. A larger context window lets you supply more material, at higher cost and with slower responses.
Practice
Change the probabilities in the toy model so that “the” is followed by “cat” 95% of the time. Generate ten sentences and count how many start with “the cat”.