Concepts / Softmax and Probability Distributions over a Vocabulary

Softmax and Probability Distributions over a Vocabulary

Text generation maps input text to token IDs, obtains probability vectors, locates the highest-probability indices, and decodes them back into text.

  • Programming
Interactive lab

Try it: Text Vectorization: Tokens to Vectors

The text-to-tensor pipeline: standardize, split into tokens, build a frequency-ranked vocabulary with padding and [UNK], map tokens to integer ids, pad or truncate, then one-hot or multi-hot encode and look the ids up in an embedding table.

How it works

  1. Standardize: lowercase and delete punctuation.
  2. Split on whitespace into tokens.
  3. Build the vocabulary: 0 = padding, 1 = [UNK], then words by frequency (ties: first appearance), capped at max tokens.
  4. Map each token to its id (1 if it did not make the vocabulary), then pad with 0 or truncate to the sequence length.
  5. Encode: one-hot rows per position or one multi-hot row per text; embed: id k selects row k of the embedding table.

Default run (18 steps): Raw text (59 characters): "The movie was great. The plot was great, the acting wasn't!". A model cannot read strings, so it is turned into numbers step by step. … Embedding lookup: id k selects row k of a fixed 8 x 3 table, giving a (8, 3) dense matrix instead of (8, 8) sparse one-hots. Row 0 (padding) is looked up too; a trained Embedding layer would learn these rows.

Simplified: Bounded ASCII text (up to 200 characters, 40 tokens), whitespace splitting only, and a small FIXED embedding table (a real Embedding layer learns its rows). The multi-hot vector keeps the padding slot (always 0) so its positions line up with the ids.

Educational simulation

Loading the simulation…

Putting a Number on Generated Text

A practical question comes up as soon as a language model produces text: how do you put a number on how good that text is? The answer is a loss value, but a loss can only be computed after the model has produced its output. So the first job is to run the model on a small batch and look closely at what it actually generates. Doing this on a small batch makes every step visible before any scoring happens.

The sequence that runs the model, converts its raw outputs into probabilities, picks token IDs, and decodes them back into words is the same sequence that the generate_text_simple function performs internally. This article walks through that sequence on a concrete batch, then shows how the loss is built from the probabilities the model assigned to the correct tokens.

The running batch contains two inputs, 'every effort moves' and 'I really like'. Each has already been converted to token IDs. Each input has three tokens, so the batch holds six token positions in total. That count of six comes back later when the loss is averaged.

Tracing the Generation Pipeline

Text generation is a five-step procedure. First, the input text is mapped to token IDs using a vocabulary. Second, the model produces a probability score for every token in the vocabulary at every input position. Third, for each position, the index with the highest probability is located. Fourth, those highest-probability indices are collected as the predicted token IDs. Fifth, the predicted token IDs are mapped back into text using an inverse vocabulary that goes from IDs to words.

Input texttwo sentences in the batchToken IDsvia the vocabularyProbability vectorsone score per vocabularytokenPredicted token IDshighest-probability indexper positionGenerated textvia the inverse vocabularyvocabulary lookupmodel forward passpick highest indexinverse vocabulary
What happens to the data at each step, and in what order: text to token IDs, IDs to probability vectors, probability vectors to argmax IDs, and IDs back to text?

The same five steps apply whether the vocabulary is tiny or large. The pipeline 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 matters when you interpret the numbers, as the next section explains.

Probability Vectors Indexed by Vocabulary

The output of the model is a probability tensor, and its shape 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 receives one probability for every possible next token. With the two-example batch here and a vocabulary of 50,257 tokens, the probability tensor has shape torch.Size([2, 3, 50257]).

Index 0probability for token ID 0Index 1probability for token ID 1Index 2probability for token ID 2Index 50256probability for token ID50256
How does each position in the output vector correspond to a specific vocabulary token ID, and how is the highest-probability index selected from that vector?

Read the diagram as a lookup table. Each slot in one probability vector is an index, and each index corresponds to a vocabulary token ID. Token IDs for this model range from 0 to 50,256. To choose the predicted token at a position, the third step of the pipeline locates the index whose probability is highest in that vector. The index itself is the token ID, which is why the predicted IDs can be decoded back into words through the inverse vocabulary.

Targets as Shifted Inputs

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

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.

QuestionArgmax predictionTarget-token probability
What it readsThe single index with the highest probabilityThe value at the index of the correct target token
What it tells the learnerWhich token the model would pickHow much probability the model gave to the right answer
Changes smoothly when training nudges valuesNot necessarily; the winning index can stay the same while the correct one gains groundYes; raising the correct entry raises this value directly
Role in the lossNot used to compute the lossThe values that the logarithm, averaging, and negation are applied to

Argmax versus target-token probability

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.

Applied to the two-example batch, 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.

Computing the Loss Step by Step

The loss is computed in a fixed sequence that starts from the six target probabilities collected above. First, a logarithm is applied to each probability, which makes 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.

Targetprobabilitiessix values, one perpositionLogarithmapplied to each valueAveragemean of six log valuesNegatemultiply by -1Cross entropy lossthe quantity trainingreduceslogsum then divide by 6multiply by -1result
What sequence of operations turns the per-position target probabilities into a single loss value, and how does each step change the numbers?
Rule

In the formula, $p_{i}$ is the probability the model assigned to the correct target token at position $i$, and $n$ is the number of positions, which is six for this batch. The source does not fix a base for the logarithm, so the worked numbers below use the natural logarithm.

Worked example

Loss for the Two-Example Batch

Using the six untrained target probabilities for the batch (7.45e-05, 3.11e-05, 1.16e-05, 1.03e-05, 5.68e-05, 4.76e-06), compute the cross entropy loss.

  1. 1
    Take the logarithm of each value

    Natural logs are approximately -9.505, -10.378, -11.365, -11.483, -9.776, and -12.255.

  2. 2
    Sum the six log values

    The sum is approximately -64.762.

  3. 3
    Average over six positions

    Dividing the sum by 6 gives approximately -10.794.

  4. 4
    Negate the average

    Multiplying by -1 gives a loss of approximately 10.79.

Result

The untrained loss is approximately 10.79. Exact digits depend on how the listed probabilities are rounded.

Notice how the steps respond to the numbers. Every target probability is far below 1, so every logarithm is strongly negative. Averaging and negating turn those negative values into a positive loss. A larger probability on the correct token pulls its logarithm toward zero, which lowers the loss. That is the direction training pushes.

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 then 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. Finding that point is the debugging step: it tells you where the model's behaviour first breaks from the target.

Mistakes Beginners Make With This Pipeline

  • Common mistake

    Scoring the model with the argmax prediction only

    What it looks like

    Checking whether the highest-probability index equals the target and stopping there.

    Why it fails

    The loss is built from the probability at the target index, so a near miss and a far miss look identical to an argmax check.

    Do this instead

    Read the probability assigned to the target token at each position and compute the loss from those values.

  • Common mistake

    Expecting large starting probabilities

    What it looks like

    Thinking an untrained model with values near 0.00002 is broken.

    Why it fails

    Tiny values are the normal starting point when the vocabulary has about 50,257 entries.

    Do this instead

    Compare against 1 divided by the vocabulary size, not against the seven-word teaching example.

  • Common mistake

    Forgetting the shift between inputs and targets

    What it looks like

    Using the input 'every effort moves' as its own target.

    Why it fails

    Without the one-position shift, the model is asked to reproduce its input instead of predicting the next token.

    Do this instead

    Pair each input token with the token that follows it, giving 'effort moves you' for the first input.

  • Common mistake

    Comparing whole strings instead of positions

    Why it fails

    Two strings can look different overall while the first mismatch sits at an early position that deserves investigation.

Practice Locating the First Divergence

EASY

Given the aligned target token IDs [5, 9, 2, 7] and predicted token IDs [5, 9, 4, 7], identify the first position where the generated output diverges from the target, and say which loss value you would inspect first.

Hints
  • Compare the two lists one position at a time, starting from position 0.
  • The first position where the two values differ is the divergence point.

What do you think happens?

Before reading on, predict the first divergence position for the lists above, counting positions from 0.

Reveal answer
Answer:

Position 2. The target has 2 and the prediction has 4 there, while positions 0, 1, and 3 match.

The loss value at position 2 is the one to inspect first, since that is where the generated sequence departs from the target.

Key Takeaways

  • Text generation maps input text to token IDs, computes a probability for every vocabulary token at each position, selects 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.
  • The cross entropy loss takes the logarithm of each target probability, averages the results, and negates the average.
  • When debugging, decode both sequences and locate the first position where the predicted token differs from the target.

Related concepts

More concepts starting with S