Concepts / Postprocessing Logits into Token IDs

Postprocessing Logits into Token IDs

The logits tensor is the point at which the shape is fully visible, and the postprocessing step is where it is turned into token IDs.

  • 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…

Starting From a Real Model Run

This article begins with code that is already running rather than with a list of definitions. A 124-million-parameter DummyGPTModel is created and fed a batch of tokenized text. The result that comes back is called the model output, and in this context it is commonly referred to as logits. Your job is to watch what the code produces and then work out why the result has the shape it has. Once you can read that shape, the rest of the printed output becomes much easier to interpret.

The run you will trace feeds the model two text samples, and each sample contains four tokens. Everything in this article is built around one question: when the model finishes, what exactly is the structure of the result it hands back?

What do you think happens?

The input is a batch of two text samples with four tokens each. For each token, does the model produce a single number, a list of numbers, or something else? Make your prediction before reading on.

Reveal answer
Answer:

For each token, the model produces a list of numbers, one entry per token in the vocabulary, so the result is a vector per token position rather than a single number.

The source describes each token's output as a 50,257-dimensional vector that matches the size of the tokenizer's vocabulary. Each grid cell holds a whole vector, not a single value.

Tracing the Printed Output Shape

Two things are printed when the run is shown: the shape, and the values that follow it. The shape tells you how the output is organized. The values are the numbers the model produced, and they only make sense once you know what organization they belong to. So read the shape first.

Output
torch.Size([2, 4, 50257])

The shape has three numbers, and they are not interchangeable. Each one answers a different question about the output. Before you can explain any value in the printed tensor, you need to know which question each number answers, so the next section takes the three axes one at a time.

Reading the Three Axes

A tensor is easiest to read one axis at a time. The output of this model has three axes, and each one answers a different question. The first axis asks which text sample a result belongs to. The second asks which token position inside that sample it belongs to. The third asks which vocabulary entry that particular number is scored against.

2text samples (batch axis)4token positions within eachsample50257vocabulary entries (one pertoken)thenthen
Which axis is the batch of text samples, which is the token position within each sample, and which is the vocabulary dimension?

Read in order, the first axis groups the results by text sample, so the 2 tells you there are two rows, one per sample. The second axis, with size 4, gives the token position inside a sample, so each sample has four positions. The third axis, with size 50257, is the vocabulary dimension. The source describes the result as a grid of samples and token positions in which every grid cell holds a whole vocabulary-sized vector rather than a single value.

Why Each Slot Is a Vocabulary Entry

The reason the vector at each position has 50,257 entries is that each entry corresponds to one unique token in the vocabulary. This is the key to reading the output. The model is not handing back a single guessed word. For each position, it gives a set of numbers spread across the entire vocabulary, and the position of a number inside that vector is what links it to a specific token.

slot 0one specific vocabularytokenslot 1one specific vocabularytokenslot 2one specific vocabularytoken...slot 50256one specific vocabularytoken
How does one token position map to a 50257-long vector, and how does each slot correspond to a specific vocabulary token?

The diagram shows a single token position. Its output is one row of 50,257 slots, and each slot is tied to one token in the vocabulary. The vocabulary therefore sets the width of every vector, and every position in the vector is a slot for one specific token. The same two-way correspondence governs how tokens are represented in general: each token is a high-dimensional vector whose size matches the tokenizer's vocabulary, so a token can be thought of as a position in a space with one dimension for every token the tokenizer knows.

Where Logits Go Next

The source also explains what happens after the model returns. The 50,257-dimensional vectors are converted back into token IDs, and those IDs can then be decoded into words. The flow below shows the order of steps from input token IDs, through the model, to the logits tensor, then through postprocessing, and finally to words.

Input token IDs2 samples, 4 tokens eachGPT modelplaceholder components inthis runLogitsshape [2, 4, 50257]Postprocessingconverts vectors to tokenIDsToken IDsdecoded laterWordsdecoded in a later step
What is the order of steps from input token IDs to the logits tensor to the final predicted token IDs, and where does the shape change?

The logits tensor is the point at which the shape is fully visible, and the postprocessing step is where it is turned into token IDs. The source places the placeholder model between the input and the output you studied here. Layer normalization is the next placeholder the source plans to replace, and it sits inside the model in the same position. Its details are outside the scope of this article.

Predicting the Shape After a Change

Now test the reading you have built. Suppose the input changes from two samples of four tokens to three samples of six tokens. This example is generated for practice and is not a result taken from the source. It uses the same reasoning the source applies: the first axis corresponds to text samples, the second to tokens, and the last to vocabulary entries.

Worked example

Predicting the new output shape

The original run produced torch.Size([2, 4, 50257]). The input now has 3 text samples with 6 tokens each. What is the new output shape?

  1. 1
    Identify the sample axis

    The first axis counts text samples, so it changes from 2 to 3.

  2. 2
    Identify the token axis

    The second axis counts token positions per sample, so it changes from 4 to 6.

  3. 3
    Identify the vocabulary axis

    The third axis is the vocabulary dimension, which is set by the tokenizer. It does not depend on how many samples or tokens are in the input, so it stays at 50257.

Result

The new output shape is torch.Size([3, 6, 50257]).

2 samples3 samples4 tokens6 tokens50257 vocabulary50257 vocabulary
If I add a sample or lengthen the input, which dimension of the output grows, and which stays fixed at 50257?

The before and after columns show the rule. The sample count and the token count are the two dimensions that grow when you change the input, while the vocabulary dimension remains 50257 in both runs. This is the stable part of the shape, and it is the part you can rely on when you read any logits output from this model.

Mistakes Beginners Make When Reading Logits

  • Common mistake

    Assuming the output has one number per token

    What it looks like

    Expecting a shape like [2, 4] for two samples of four tokens.

    Why it fails

    Each token position holds a whole vocabulary-sized vector, so the output has a third axis.

    Do this instead

    Read the output as [samples, token positions, vocabulary entries], which gives [2, 4, 50257] for this run.

  • Common mistake

    Treating the last axis as something that depends on the input

    What it looks like

    Thinking that a longer input should make the vocabulary dimension grow.

    Why it fails

    The source ties the vocabulary dimension to the tokenizer's vocabulary, which does not change when the input changes.

    Do this instead

    Expect the sample and token axes to change with the input, and expect the 50257 axis to stay fixed.

  • Common mistake

    Reading a logit as a finished word

    What it looks like

    Looking at one number in the vector and assuming it names a word directly.

    Why it fails

    Logits are an intermediate stage. They must still be converted to token IDs and then decoded.

    Do this instead

    Follow the pipeline: logits, then postprocessing into token IDs, then decoding into words.

  • Common mistake

    Swapping the sample and token axes when reading the shape

Finding Where the Shape Surprises You

MEDIUM

A run prints torch.Size([4, 2, 50257]) for an input of four text samples with two tokens each. Is this output consistent with the reading in this article? Identify which step in the run you would check first if the printed shape did not match what you predicted.

Hints
  • Start by reading the first axis: which quantity does it count?
  • Compare the first two numbers with the sample count and token count of the input, and check whether the vocabulary dimension is still 50257.
  • If the sample and token numbers are swapped relative to the input, look at how the input batch was shaped before the model received it.

Closing the Loop on Logits

The model output for this run is called logits, and its shape torch.Size([2, 4, 50257]) encodes three facts: two text samples, four tokens per sample, and one slot for each of the 50,257 vocabulary entries. Each slot is tied to one specific token, and the logits are converted into token IDs in postprocessing before being decoded into words later.

Key Takeaways

  • The output shape torch.Size([2, 4, 50257]) has three axes: text samples, token positions within each sample, and vocabulary entries.
  • Each token position yields a 50,257-dimensional vector with one slot per unique vocabulary token, and this output is called logits.
  • Changing the number of samples or tokens changes the first two axes, while the vocabulary axis stays fixed at 50257.
  • Logits are an intermediate stage: postprocessing converts them into token IDs, which are then decoded into words.
  • When a printed shape surprises you, check each stage of the pipeline to find where the mismatch begins.

Related concepts

More concepts starting with P