What a generative model actually is

After thiswhat you will be able to doWrite a working generative model, watch it produce sentences it was never shown, and explain precisely why it is bad.

Questionwhat this lesson answersHow can a word-counting model produce sentences it was never shown, and precisely why is it bad?

Not coveredwhat this lesson leaves outWe do not build a neural network, train anything with gradients, or cover diffusion beyond the caveat in section 9.

Where this lesson is going

By the end of it you will have written a working generative model, watched it produce sentences it was never shown, and understood precisely why it is bad. That last part matters most. The two specific ways this model fails are the two problems that every technique in the next twenty three lessons exists to solve. If you understand the failures clearly now, the rest of the course stops being a list of tricks and becomes a sequence of fixes to problems you have already seen with your own eyes.

No mathematics in this lesson beyond division. Some Python at the end, explained line by line.

1. A model is a function with adjustable numbers inside it

Start with what you already know. Ordinary code looks like this:

def shipping_cost(weight):
    if weight < 1:
        return 5
    return 5 + (weight - 1) * 2

You decided the 5 and the 2. You decided where the threshold sits. Somebody worked out the pricing and you typed it in.

A model looks like this:

def shipping_cost(weight):
    return a * weight + b

Same shape, except nobody typed in a and b. They begin as arbitrary values, maybe 0.3 and -1.7, and then an automatic process adjusts them, over and over, until the function’s answers line up with real examples of weights and costs. Those adjustable values are called parameters, or equivalently weights. Both words mean the same thing and you will see both.

That is the whole idea. A model is a function whose numbers were found rather than written.

When you read that a model has 7 billion parameters, that is a literal count of adjustable numbers inside it. There are 7 billion values like a and b, arranged in a particular structure, and every one of them was set by an automatic adjustment process rather than by a person. Nobody at any company knows what individual parameter number 4,182,663,901 means. It is a number that ended up where it ended up because doing so made the predictions better.

Keep this in mind whenever a model does something impressive or something stupid. There is no hidden rulebook inside it. There is a large pile of numbers and a fixed sequence of arithmetic.

2. Two kinds of model

Discriminative models take data and return a judgement about it.

email text        ->  spam or not spam
photo             ->  cat or dog
transaction       ->  fraudulent or legitimate
x-ray             ->  fracture or no fracture

Generative models produce new data that resembles the data they were trained on.

nothing, or a prompt  ->  a new sentence
nothing, or a prompt  ->  a new image
a few seconds of audio ->  the next few seconds

That is the textbook distinction, and it is useful for about five minutes.

Modern generative models are built almost entirely out of prediction. They are not doing something categorically different from a spam classifier. A spam classifier picks between two options. A language model picks between fifty thousand options, and then does it again, and again, in a loop. The loop is where generation comes from.

Hold onto that, because it explains a great deal of behaviour that otherwise looks mysterious.

3. The trick: produce one small piece at a time

Nobody has worked out how to produce a coherent paragraph in one shot. What works is producing one small piece, then using everything produced so far to decide the next piece, then repeating.

Trace it:

step 1   input:  "The cat sat on the"
         output: "mat"

step 2   input:  "The cat sat on the mat"
         output: "."

step 3   input:  "The cat sat on the mat."
         output: " It"

step 4   input:  "The cat sat on the mat. It"
         output: " was"

Each output gets appended to the input and the whole thing goes back in. This is called autoregressive generation. Auto meaning self, regressive meaning it operates on its own earlier output.

The model never generates a paragraph. The model answers one narrow question, once: given this text, what comes next? A loop wrapped around the model is what produces the paragraph. The loop is about six lines of ordinary code. It contains no intelligence, no parameters, and no learning.

When you watch a chat assistant type out its answer word by word, that is not a typing animation for effect. That is the loop running, one pass through the model per piece of text, in real time.

Several things follow directly from this that are worth having straight now:

4. The output is a probability distribution, not a word

This is the most important idea in the lesson. If you take one thing away, take this.

The model does not output “mat”. It outputs a score for every word it knows, all at once, in a single pass. If its vocabulary has 50,000 entries, the output is 50,000 numbers, and they are arranged to add up to exactly 1.

Given "The cat sat on the", the output might be:

wordprobability
mat0.31
floor0.12
couch0.09
roof0.06
table0.05
grass0.03
… 49,993 more …
bicycle0.0000002
tuesday0.00000004

50,000 possibilities, one total

The visible head is only part of the distribution

total = 1
mat0.31visible total 0.31 of 1
floor0.12visible total 0.43 of 1
couch0.09visible total 0.52 of 1
roof0.06visible total 0.58 of 1
table0.05visible total 0.63 of 1
grass0.03visible total 0.66 of 1
bicycle0.0000002This is one of the values quoted in the lesson.
six visible bars: 0.66tail: 0.34whole: 1

Every word in the vocabulary gets a number, including ridiculous ones. “Tuesday” is not excluded, it is merely given a probability so small it will effectively never be picked. There is no filtering step and no list of allowed words. Everything is possible and almost everything is vanishingly unlikely.

Numbers arranged like this, non-negative and summing to 1, are called a probability distribution. When people say a model is “confident”, they mean the distribution has one large value and the rest are small. When it is “uncertain”, the probability is spread across many words. This is measurable, and in lesson 3 you will measure it.

The choosing step is separate from the model

Something has to turn those 50,000 numbers into one actual word. That something is not part of the model. It is a separate step, usually a few lines of code, and it is called decoding or sampling.

The model itself is completely deterministic. Same input, same parameters, same 50,000 numbers, every single time. There is no randomness inside it.

So where does the variation come from when you ask the same question twice and get different answers? From the decoding step. If that step always takes the highest number, you get the same answer every time. If it picks randomly in proportion to the probabilities, you get variation.

You will see this demonstrated with real output in a moment, and lesson 12 covers the full set of decoding strategies. For now, hold the separation clearly in your head: the model produces possibilities, the decoder chooses among them. Almost every knob you have ever seen exposed in an API, including temperature, belongs to the decoder rather than the model.

5. Building the smallest possible generative model, by hand

Enough description. Build one.

Here is the entire training corpus:

the cat sat on the mat
the cat ate the fish
the dog sat on the rug

The training procedure is: go through the text and count which word follows which.

Do the word “the” by hand. Find every occurrence and write down what came next:

occurrencefollowed by
the cat sat on the matcat
the cat sat on the matmat
the cat ate the fishcat
the cat ate the fishfish
the dog sat on the rugdog
the dog sat on the rugrug

Six occurrences. Turn the counts into probabilities by dividing each by the total:

next wordcountprobability
cat22/6 = 0.333
mat11/6 = 0.167
fish11/6 = 0.167
dog11/6 = 0.167
rug11/6 = 0.167

Train it by counting

Walk through the corpus one word at a time

thecatsatonthemat

thecatatethefish

thedogsatontherug

0 of 17 words

Ready to count what follows the.

What follows the
next wordcountprobability so far
No following words counted yet.

That table is a generative model. It was trained by counting. It takes a word and returns a probability distribution over what comes next, which is exactly the job description from section 4. It is called a bigram model, bigram meaning a pair of adjacent words.

Generating from it

Start at “the”. Look up the distribution. Pick from it at random, weighted by probability. Say you land on “dog”. Now look up what follows “dog”, which in this corpus is always “sat”. Then what follows “sat”, which is always “on”. Then “on”, which is always “the”. And now you are back at “the” with five options again.

One possible run:

the -> dog -> sat -> on -> the -> mat

“the dog sat on the mat” is not in the training text. The corpus has “the dog sat on the rug” and “the cat sat on the mat”, and the model has produced a sentence that is neither, by recombining the patterns. That is generation, in miniature, and the mechanism is not different in kind from what a large model does. It is different in degree by an enormous amount, and the rest of the course is about that degree.

6. The same thing in code

Every line explained. Run it.

text = "the cat sat on the mat the cat ate the fish the dog sat on the rug"
words = text.split()

counts = {}
for i in range(len(words) - 1):
    current = words[i]
    next_word = words[i + 1]
    if current not in counts:
        counts[current] = {}
    counts[current][next_word] = counts[current].get(next_word, 0) + 1

print(counts["the"])

What each part does:

Running it prints:

{'cat': 2, 'mat': 1, 'fish': 1, 'dog': 1, 'rug': 1}

The table you built by hand, produced by six lines of code.

Turning counts into probabilities

def probabilities(word):
    options = counts[word]
    total = sum(options.values())
    return {w: c / total for w, c in options.items()}

print(probabilities("the"))

Output:

{'cat': 0.333, 'mat': 0.167, 'fish': 0.167, 'dog': 0.167, 'rug': 0.167}

options.values() gives the counts, sum adds them up, and the last line builds a new dictionary with each count divided by the total. The {key: value for ...} shape is called a dictionary comprehension, and it is Python’s compact way of building a dictionary from a loop.

Generating

import random

word = "the"
output = [word]

for _ in range(9):
    options = counts.get(word)
    if not options:
        break
    word = random.choices(list(options.keys()), weights=list(options.values()))[0]
    output.append(word)

print(" ".join(output))

Five real runs of that code:

the cat sat on the fish the cat ate the
the mat the cat sat on the cat ate the
the fish the rug
the cat ate the cat sat on the cat sat
the fish the fish the cat sat on the cat

Look at what happened. Some fragments are perfectly reasonable English: “the cat sat on the”, “the cat ate the”. Some are nonsense: “on the fish”, “the fish the fish”. The third run stopped after four words because it hit “rug”, which is the last word in the corpus and therefore has nothing recorded after it.

You have written a generative model. Now find out why it is bad.

7. Demonstrating that decoding is a separate choice

Section 4 claimed that the randomness lives in the decoder rather than the model. Test it. Change one line so that instead of sampling, it always takes the most likely option:

word = max(options, key=options.get)

Same model, same counts, same everything. Only the choosing step changed. The output:

the cat sat on the cat sat on the cat sat on

One model, two decoders

Generate, then inspect every choice

Decoder

The corpus and all of its counts stay fixed.

sampled run

thecatatetherug

Generation stopped at rug because the model has no row for what follows it.

The model distribution and decoder choice at each step
stepgivenmodel distributiondecoder took
1the
cat 2/6 = 0.333mat 1/6 = 0.167fish 1/6 = 0.167dog 1/6 = 0.167rug 1/6 = 0.167
cat
2cat
sat 1/2 = 0.500ate 1/2 = 0.500
ate
3ate
the 1/1 = 1.000
the
4the
cat 2/6 = 0.333mat 1/6 = 0.167fish 1/6 = 0.167dog 1/6 = 0.167rug 1/6 = 0.167
rug
No entry. The corpus records nothing after elephant.

It locks into a loop immediately and stays there forever. Always taking the highest probability is called greedy decoding, and this degenerate repetition is exactly what it produces, in tiny models and in large ones. Real systems repeat in subtler ways, but the cause is the same.

Two decoders, one model, completely different behaviour. That separation is real and it is worth remembering the first time somebody tells you a model is “creative” or “boring”.

8. Why this model is bad, and why every later lesson exists

Two problems. Almost everything in this course is a response to one or the other.

Problem one: it only remembers one word back

The model’s entire knowledge of the situation is the single previous word. When it is sitting at “the”, it has no idea whether the sentence so far was “the dog chased the” or “the chef seasoned the”. Both look identical to it.

The obvious fix is to look further back. Count triples instead of pairs, or count based on the previous ten words. This works a little and then collapses, for a reason worth working out in numbers.

Take a realistic vocabulary of 50,000 words, which is roughly what GPT-2 used.

50,000 choices in every position

Add context and watch the table explode

exact BigInt arithmetic
table checkpoint: 50,0002 entries at 4 bytes each
possible entries2.5 × 1092,500,000,000
storage10 gigabytesfour bytes for every possible entry
decimal digits10storable at laptop scale
seen in this corpus13distinct filled entries at this table order

Almost everything is empty

At most one entry is filled for every 1.923 × 108 possible entries.

This count still fits safely in a JavaScript number.

The picture shows one filled square so it can be seen. The real fraction is much smaller.

Logarithmic comparison ladder

storable at laptop scale

  1. laptop scale
  2. 500 terabytes
  3. astronomical table
  4. atoms in universe
  5. more than the atoms

The entry count is about 71 powers of ten below the estimate of 1080 atoms.

And the storage is not even the real issue. Almost every one of those entries would be empty, because no quantity of text contains most ten word sequences. You would have a gigantic table that is blank nearly everywhere, which is worthless for prediction. This is known as the curse of dimensionality, and it is the reason counting cannot be scaled into a real language model.

Problem two: it cannot generalise at all

The training text never contains “the elephant”. So the model assigns “elephant” a probability of exactly zero after “the”. Not small. Zero. It will never produce it.

That is not a lack of data, it is a structural limitation. To this model, “elephant”, “dog”, and “tuesday” are three unrelated symbols with nothing in common. It has learned that “dog” can follow “the”, and there is no mechanism by which that knowledge transfers to any other animal, or to any other noun, or to anything at all.

Human learning is not like this. You have never read the sentence “the elephant sat on the rug” either, but you know it is fine English, because you know an elephant is the kind of thing that sits and a rug is the kind of thing that gets sat on. The counting model has no representation in which that similarity could exist.

How neural networks fix both

Preview, so you know where the next five lessons are heading.

For problem one, stop storing a table and start computing the answer. A neural network has a fixed number of parameters that does not grow when you feed it longer contexts. A model with 100 million parameters can take 1,000 words of context, and it does not need 50,000¹⁰⁰⁰ of anything. Lessons 4, 5 and 6 cover this.

For problem two, stop treating words as unrelated symbols. Represent each word as a list of numbers, positioned so that words used in similar ways end up with similar lists. Then “elephant” sits near “dog”, and whatever the model learned about how “dog” behaves partly applies to “elephant” automatically, because the model sees similar numbers going in. These lists are called embeddings and they are the entire subject of lesson 2.

Those two fixes, taken seriously and scaled up, get you most of the way to a modern language model. The transformer architecture in Part 2 is a particularly good way of doing the first one.

9. One honest caveat about images

Everything above described autoregressive generation, which is how language models work. Image models mostly do not work this way.

Generating an image one pixel at a time, left to right, was tried and it works badly. A megapixel image would need a million sequential passes, and the result tends to lose coherence across the picture. Image generation is dominated instead by diffusion, which starts from pure random noise and refines the entire image at once, repeatedly, until it becomes a picture.

Different principle, different mathematics, covered properly in Part 5. I am flagging it now so you do not build a mental model where “generative AI” means “predicts the next thing” and then get confused in lesson 22.

Takeaway

A generative model produces one small piece at a time, feeding its own output back in as input. Each step, it outputs a probability across every possible next piece, and a separate decoding step chooses one of them. Counting words gives you a working version of this in six lines of code, and it fails for two reasons: it cannot look back far without the table exploding, and it cannot generalise from one word to a similar one. Everything else in this course exists to solve those two problems.

Exercises

1. Scale it up. Get a large plain text file. Project Gutenberg is the easy source, and any novel will do. Feed it into the counting script, then generate 50 words. Read the output and write down two specific things that are wrong with it. Be concrete. “It does not make sense” is not an answer, “it switches subject halfway through the sentence and never closes a quotation mark” is.

2. Extend to triples. Modify the code so the key is a pair of words rather than one word, and the model predicts the third from the previous two. In Python you can use a tuple as a dictionary key: counts[(word1, word2)]. Generate from it and compare against the bigram output.

Then answer this: it got better, but what did it cost? Print len(counts) for both versions on the same input text and look at the difference. Now imagine going to four words back.

3. Predict the failure. Before running anything, work out what happens if you train on one book and then start generation from a word that appears exactly once in it, as the very last word of the text. Then test whether you were right.

4. Think about the decoder. Modify the sampling so it only ever picks among the top 2 most likely options, ignoring everything else. Run it on the large text. Is the output better or worse than full sampling? There is no single correct answer here, and the tradeoff you are feeling is the subject of lesson 12.

Doorswhat to read next, and why

Symbolswhat each one means, and whether we defined it, measured it, or just started there

Parameter (also: weight)Status: defined
an adjustable number inside a model, set by training rather than written by a programmer.
Discriminative modelStatus: defined
takes data, returns a judgement about it.
Generative modelStatus: defined
produces new data resembling its training data.
Autoregressive generationStatus: defined
producing output one piece at a time, feeding each piece back as input for the next.
Probability distributionStatus: defined
a set of non-negative numbers that sum to 1, giving the likelihood of each possible option.
Decoding (also: sampling)Status: defined
the step that converts the model's probability distribution into one concrete choice. Not part of the model.
Greedy decodingStatus: defined
always choosing the highest probability option. Deterministic, and prone to repetition.
Bigram modelStatus: defined
a model that predicts the next word from the single previous word.
Curse of dimensionalityStatus: empirical
the explosive growth in possible combinations as you add more variables, which makes table-based approaches collapse.
EmbeddingStatus: door
a representation of a word as a list of numbers, arranged so similar words have similar lists. Subject of lesson 2.
What these classifications mean
defined
circular by construction, true because we chose it
empirical
a measured claim about the world that could have come out otherwise
bottoms out
a primitive of the model, with nothing under it here
door
used here, explained elsewhere