Text Generation with a GPT Model
Text generation maps input text to token IDs, obtains probability vectors, locates the highest-probability indices, and decodes them back into text.
Putting a Number on Generated Text
A practical question sits at the center of this article: how do you put a number on how good a model's generated text is? Before any number can be computed, the model has to produce its output. The sequence that runs the model on a batch of inputs, converts its raw outputs into probabilities, picks token IDs, and decodes them back into words is the same sequence that generate_text_simple performs internally. Running that sequence on a small batch first lets us see what the model actually produces before we score it.
The batch used here contains two inputs, 'every effort moves' and 'I really like'. Each input has already been converted to token IDs. Each input has three tokens, so the batch holds six token positions in total. Keep that count of six in mind, because it reappears when the loss is averaged.
From Input Tokens to Generated Text
Text generation is a five-step procedure. Each step consumes the output of the step before it, so the stages form a pipeline. The diagram below traces the path from input text to output text, and the explanation after it describes what each stage hands to the next one.
The first step maps the input text to token IDs using a vocabulary. The second step has the model produce a probability score for every token in the vocabulary at every input position. The third step locates, for each position, the index with the highest probability. The fourth step collects those highest-probability indices as the predicted token IDs. The fifth step maps the predicted token IDs back into text using an inverse vocabulary that goes from IDs to words.
These five steps are the same whether the vocabulary is tiny or large. The example diagram uses a seven-word vocabulary so that every probability vector fits on one page. The GPT model used in this work has a far larger vocabulary, and that difference changes how the numbers should be read.
Reading the Probability Tensor
The probability tensor has a shape that encodes three things at once. The first dimension is the batch size, which is the number of input examples. The second dimension is the number of tokens in each input. The last dimension matches the vocabulary size, because each input position gets one probability for every possible next token.
torch.Size([2, 3, 50257])Read that shape as two examples, three positions per example, and one probability per vocabulary entry at each position. The last number, 50257, is the vocabulary size. Token IDs for this model range from 0 to 50,256. The seven-word vocabulary in the pipeline diagram is only a teaching simplification, so its numbers should not be carried over directly to the GPT model.
Scale matters for the starting values. When probability is spread evenly over the vocabulary, each entry is about 1 divided by the vocabulary size. For the seven-word example vocabulary that is about 0.14, while for the 50,257-word vocabulary it is about 0.00002. This is why the starting probabilities look so small. A learner who expects an untrained model to show values like those of a seven-word vocabulary will think something is wrong. Tiny values are the normal starting point for a large vocabulary.
Building Targets by Shifting the Input
The targets are the token IDs the model should produce. They are built from the inputs by shifting every sequence one position forward, so that each input token is paired with the token that follows it. The input 'every effort moves' has the target 'effort moves you'. The input 'I really like' has the target 'really like chocolate'. Each target token is the next word after the corresponding input token.
This shifting is what teaches a language model to predict the next token in a sequence. Without it, the model would be asked to reproduce its input, which is a different task.
Why the Loss Reads Target Probabilities
What do you think happens?
To score a generated token, should the loss look at the single most likely token (the argmax), or at how much probability the model gave to the correct target token?
Reveal answer
The probability given to the correct target token
The loss does not look at the single most likely token. It looks at how much probability the model gave to the correct token at each position.
For every input position, the probability vector has one entry per vocabulary token. The entry at the index of the target token is the value that matters. The training goal is to raise that entry, so that the correct token becomes more likely relative to the others. A model that already picks the right token but gives it only a modest probability still has room to improve, and the loss measures that room.
Before any training, the model's vectors are essentially random. Each input token produces a vector, each vector index corresponds to a vocabulary word, and training is meant to maximize the value at the index of the target token. Because the vectors start random, the values at the target indices are not special yet.
Indexing the probability tensor with the target IDs gives the untrained probabilities assigned to the correct tokens. For the first input, these are roughly 7.45e-05, 3.11e-05, and 1.16e-05. For the second input, they are roughly 1.03e-05, 5.68e-05, and 4.76e-06. Every value is tiny, which matches the expectation for a large vocabulary. These six numbers are the inputs to the loss.
Computing the Loss from Target Probabilities
The loss is computed in three ordered steps that start from the six target probabilities. First, a logarithm is applied to each probability. Logarithms make the values easier to optimize than the raw probabilities. Second, the six log probabilities are averaged into a single number. Third, that average is multiplied by -1. The result is the cross entropy loss, which is the quantity training reduces.
- 1p_i is the probability the model assigned to the correct target token at position i, for the six positions in the batch
- 2The logarithm of each target probability is taken first
- 3The six log values are summed and divided by 6, which gives their average
- 4The negation turns the average, which is negative for probabilities below 1, into a positive loss value
Loss for the untrained two-example batch
Compute the cross entropy loss from the six target probabilities of the untrained batch: 7.45e-05, 3.11e-05, 1.16e-05, 1.03e-05, 5.68e-05, and 4.76e-06.
- 1Take the logarithm of each target probability
Natural logarithms are approximately -9.50, -10.38, -11.36, -11.48, -9.78, and -12.26 for the six values in order.
- 2Sum the six log values
The sum is approximately -64.76.
- 3Average the six log values
Dividing the sum by 6 gives approximately -10.79. The count of six comes from the two inputs times their three positions each.
- 4Negate the average
Multiplying -10.79 by -1 gives approximately 10.79, which is the loss for this untrained batch.
The untrained cross entropy loss is approximately 10.79. Training should drive this value down by raising the probabilities at the target indices.
PyTorch provides a built-in cross entropy function that performs all of these steps at once, so you rarely need to compute them by hand in practice. Doing the steps manually is still valuable because it shows exactly which numbers feed into the loss and why a larger probability on the correct token lowers it. A larger target probability gives a log value closer to zero, which pulls the average toward zero and the negated loss downward.
Mistakes When Scoring Generated Text
Common mistake Scoring the model by its argmax prediction alone
What it looks likeLooking only at the decoded predicted words and deciding the model is wrong at a position where it gave the correct token a moderate probability.
Why it failsThe loss is built from the probabilities assigned to the correct target tokens, not from the argmax prediction. The argmax hides how close the model was.
Do this insteadRead the probability at the target index for each position, and use the logarithm, average, and negation steps to turn those values into one loss.
Common mistake Expecting large starting probabilities
What it looks likeSeeing values around 0.00002 for the correct tokens and concluding that the code has a bug.
Why it failsWith a 50,257-token vocabulary, an evenly spread probability is about 1 divided by 50,257, so tiny values are the normal starting point.
Do this insteadCompare values against the vocabulary size, not against the seven-word teaching vocabulary.
Common mistake Carrying the seven-word vocabulary numbers into the GPT model
Why it failsThe seven-word vocabulary in the pipeline diagram is only a teaching simplification. Token IDs for this model range from 0 to 50,256.
Common mistake Using the input as the target
What it looks likeSetting the target of 'every effort moves' to 'every effort moves' itself.
Why it failsTargets are the inputs shifted one position forward. Without the shift, the model would be asked to reproduce its input, which is a different task.
Do this insteadPair each input token with the token that follows it, so 'effort moves you' is the target for 'every effort moves'.
Finding Where Generated Text Diverges
When generated text is compared with its target, the first useful step is to decode both sides and read them position by position. Decoding the first batch's targets gives ' effort moves you'. Decoding the model's predicted token IDs for the same batch gives ' Armed heNetflix'. The two strings differ throughout, which is consistent with an untrained model.
A divergence report should identify the first position where the predicted token differs from the target, because that is where the sequence departs from what was expected. The loss value for that position is the place to investigate. In this batch, every decoded output differs from its target, so the investigation starts at the first position of each sequence. A trained model would be expected to match the target at more positions, and the first mismatch would move further along the sequence.
Take the untrained batch. Without retraining, a colleague reports that the second input's generated text matches its target at the first position and fails at the second. Using the target probabilities listed for the second input, which index in its three-position sequence would you examine first, and which loss term would you look at to judge how far the model was from the target at that position?
Hints
- Divergence is located by position, and the first mismatch is the place to start.
- The loss for a position is built from the probability at the target index for that position.
Where the Loss Fits in the Chapter
The loss sits between producing text and training the model. Text generation is the first of several stages in the chapter, and the text evaluation stage, where the loss is implemented, comes next. After that come the training and validation stage, the training function, and later stages on text generation strategies and weight handling. The loss serves as the measuring tool that the training function will rely on.
Key Takeaways
- Text generation maps input text to token IDs, produces a probability for every vocabulary token at every position, picks the highest-probability indices, and decodes them back into text.
- Targets are the inputs shifted one position forward, so the model learns to predict the next token.
- The loss is built from the probabilities assigned to the correct target tokens, not from the argmax prediction. It is computed by taking logarithms of those probabilities, averaging them, and negating the result.
- To debug a poor result, decode the targets and the predictions, and locate the first position where they differ.