Temperature and Token Sampling
The output dimension equals vocab_size. Each logit is a score attached to one vocabulary token, indexed by its position in that final dimension.
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
- Standardize: lowercase and delete punctuation.
- Split on whitespace into tokens.
- Build the vocabulary: 0 = padding, 1 = [UNK], then words by frequency (ties: first appearance), capped at max tokens.
- Map each token to its id (1 if it did not make the vocabulary), then pad with 0 or truncate to the sequence length.
- 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.
Loading the simulation…
Predicting What Temperature Does
A GPT model does not simply announce the next word. It produces a score for every token in its vocabulary, and then a token is chosen from those scores by sampling. The setting that controls how that choice is made is called temperature. This article follows the path from raw token indices to the scores the model produces, and then to the counts that come out of sampling. Work through it in the order given, because each stage consumes the output of the stage before it.
What do you think happens?
The token 'pizza' is sampled many times from the same model. If you repeat the sampling with temperature set to 0 or 0.1, and then again with temperature set to 5, how many times do you expect 'pizza' to be sampled in each case?
Reveal answer
Zero times at temperature 0 or 0.1, and 32 times at temperature 5.
Raising the temperature changes the distribution from which tokens are sampled, so a token that is never picked at low temperature can be picked often at high temperature. Keep this result in mind; the rest of the article explains how it arises.
Three Main Parts of a GPT Model
A GPT model is built from three main parts: an embedding stage, a sequence of transformer blocks run with nn.Sequential, and a linear output head with no bias. The embedding stage turns token indices into vectors. The transformer blocks process those vectors. The output head converts the processed vectors into logits, which are the raw scores for each vocabulary entry. The GPTModel class is a PyTorch module, and all three parts are attributes of it. The diagram below shows how they sit inside the whole model.
The embedding stage has two lookups that are later added together. The token embedding represents which tokens appear. The positional embedding represents where in the sequence they appear. The transformer blocks are not a single layer but a stack of identical-shaped blocks, and the source builds that stack in one line. The output head is the last part, and it is the only part that produces the scores used for sampling.
Building the Transformer Block Stack
The source builds the sequence of transformer blocks in a single expression. It creates one TransformerBlock for each layer, using the count stored under the n_layers key of the configuration dictionary, and wraps the blocks in nn.Sequential. Wrapping them this way means they run one after another, so the output of the first block becomes the input of the second, and so on. You do not need to call each block by hand inside forward; the sequential container handles the ordering.
- The count comes from the
n_layersentry of the configuration dictionary. - One TransformerBlock is created for each layer.
- nn.Sequential runs the blocks in order, each consuming the previous block's output.
Tracing the Forward Method
The forward method is where an input of token indices becomes a set of output scores called logits. Read it as a pipeline. For each stage, ask three questions: what does this line receive, what does it produce, and which part of the GPT model does it belong to. The diagram below traces the input named in_idx from the embedding stage to the logits.
Following the shape of in_idx
Suppose in_idx holds a batch of 2 sequences, each with 4 token indices. Trace what each stage receives and produces.
- 1Read the input
The shape of
in_idxgives batch size 2 and sequence length 4. The input is a grid of token indices, one row per sequence. - 2Token embeddings
self.tok_embis applied toin_idx. Each index is replaced by its embedding vector, so the result has an extra embedding dimension while keeping the batch and sequence structure. - 3Positional embeddings
torch.arange produces the integers from 0 up to the sequence length, which is 4 here.
self.pos_embturns those positions into vectors. This part depends only on the length of the input, not on which tokens appear. - 4Add and drop out
The token and positional results are added together. The sum passes through the embedding dropout layer and then into the transformer blocks.
- 5Normalize and project
After the blocks, the final normalization layer runs, and then the output head projects each embedding to a vector with one entry per vocabulary token. forward returns this as logits.
The logits keep the batch and sequence structure of the input, and the final dimension holds one score per vocabulary entry. Note that this is a generated example illustrating the stated order of stages; the sizes 2 and 4 are chosen for illustration.
Why the Output Head Has No Bias
The phrase with no bias is part of the definition of the output head. The layer is created with bias set to False, so it only applies a weight matrix to its input. It has no added offset term. A learner reading the constructor should note this explicitly, because a bias term would change the arithmetic of every output score. Without a bias, each score is produced purely by the weight matrix acting on the embedding, with nothing added on top.
When you read a layer constructor, check its arguments explicitly. A flag such as bias set to False changes the computation, so treat it as part of the definition of the component rather than a minor setting.
Output Dimension as Vocabulary Scores
The output head maps each embedding to a vector whose size is vocab_size. That means each position in the sequence receives one score per vocabulary entry. The final dimension of the logits is therefore a lookup: position number k in that dimension corresponds to one specific token in the vocabulary, and the value stored there is the score for that token. Reading the logits this way lets you treat each entry as a score for one token, which is exactly what sampling needs.
The output dimension equals vocab_size. Each logit is a score attached to one vocabulary token, indexed by its position in that final dimension.
Estimating Probability from Sample Counts
Once the model has produced scores, a token is chosen by sampling. Each time a token is drawn it adds one to that token's count. If you draw N samples in total and a particular token was drawn c times, then c divided by N is an estimate of that token's probability: $\frac{c}{N}$. The estimate improves as N grows, but it is still an estimate. A count from 1000 draws is a sample-based estimate, and it is not the same thing as reading the probability directly from the distribution. Keeping both numbers in view helps you see the difference between what was sampled and what the distribution holds.
Turning a count into a probability estimate
Suppose 100 draws are taken from the same distribution, and the token 'pizza' appears 32 times. Estimate its probability.
- 1Identify the count
The token was drawn c = 32 times out of N = 100 draws.
- 2Divide by the total
Compute $\frac{32}{100}$, which equals 0.32.
- 3Interpret the estimate
The sampled frequency suggests a probability near 0.32 for this draw. Repeating with more draws would refine the estimate, and a different set of 100 draws could give a somewhat different count.
The estimate is 0.32. This is a generated illustration using hypothetical numbers, not a value taken from the source.
How Temperature Reshapes the Counts
Temperature changes the probability distribution from which tokens are sampled. A higher temperature increases how often certain tokens are sampled. The source makes this concrete with the token 'pizza'. At temperature 0 or 0.1, 'pizza' is sampled zero times. When the temperature is scaled up to 5, it is sampled 32 times. The counts come from the print_sampled_tokens function that the source defines in an earlier section, which is the function to use if you want to reproduce these numbers yourself.
The before and after counts show that a token with no samples under a low temperature can accumulate many samples under a higher one. The source does not give the full distribution at each temperature, so the important lesson is the direction of the change: raising temperature shifts sampling toward tokens that were rarely picked before.
Mistakes Learners Make with Sampling Counts
Common mistake Treating a sampled count as the exact probability
What it looks likeSeeing 32 samples out of 100 and concluding the probability is exactly 32 percent.
Why it failsA count from a finite number of draws is a sample-based estimate. Another run of the same number of draws can give a different count.
Do this insteadDescribe the result as an estimate, and draw more samples if you need a more stable number.
Common mistake Assuming the positional part depends on the token values
What it looks likeExpecting the positional embeddings to change when the same positions hold different tokens.
Why it failsThe source builds the positional embeddings from torch.arange over
seq_len, which is read from the input shape. They depend only on sequence length.Do this insteadAttribute changes in the token part to token identity and changes in the positional part to sequence length.
Common mistake Ignoring the bias argument in the output head
Why it failsWith bias set to False, the layer applies only a weight matrix. Adding a bias would change the arithmetic of every output score.
Do this insteadRead the constructor arguments as part of the definition of the layer.
Common mistake Reading the logits as a list of token names
Why it failsThe logits are numbers. Each position in the final dimension corresponds to one vocabulary token, and the stored value is the score for that token.
Checking Your Reading of forward
Without looking back, write the order of the stages that in_idx passes through inside forward, from the first step to the returned value. Then say which stage is responsible for the positional part and which is responsible for the scores that sampling uses.
Hints
- Start from the token and positional embeddings and their addition.
- The final stage before the return is the output head.
- The output head is the only stage that produces the logits.
Suppose a temperature 5 run shows a token sampled 32 times and a temperature 0.1 run shows the same token sampled 0 times. In one or two sentences, explain why the count changes, referring to the distribution from which tokens are sampled rather than to the token itself.
Hints
- Temperature affects the distribution, not the stored token name.
- Think about which tokens a higher temperature makes more likely to be picked.
Key Takeaways
- A GPT model has three main parts: an embedding stage, a sequence of transformer blocks run with nn.Sequential, and an output head that is a linear layer with no bias.
- The forward method takes
in_idx, adds token and positional embeddings, applies dropout, runs the transformer blocks, normalizes, and projects to logits using the output head. - The output head maps each embedding to a vector of size
vocab_size, so each logit is a score for one vocabulary entry. - A token's probability can be estimated as its sample count divided by the total number of draws, and this is an estimate rather than an exact value.
- Raising temperature changes the sampling distribution; in the source example, 'pizza' goes from 0 samples at temperature 0 or 0.1 to 32 samples at temperature 5.