BetweenTokens

Transformer Math

The transformer is a learned probability model

A joint probability over sequences is impossible to store. The chain rule turns it into one function you can learn.

Part 1 of 3

Helloo,

Transformer is the model architecture used by Large Language Models. It was introduced by the Google Brain team in 2017 in the famous research paper — “Attention is all you need”.

The latest trillion parameter models trained by frontier labs, that feel like magic, out of a science fiction book, are scaled up versions of this architecture. There have been a few tweaks to the architecture over the years but the core is still the same.

In this blog we’ll go over high level Math behind the transformer architecture. Let’s Go!

Transformers are from the class of autoregressive models. Which means you generate tokens one by one. Each new token depends on the previous tokens.

The tokens 'you can just do' feeding up into a box labelled transformer, which emits 'can just do things' — each output position predicting the token after the one below it.

The first step is, to convert raw input text into tokens. This step is called Tokenization. It is the process of breaking down Raw Text into chunks.

The words 'you can just do' feeding down into a box labelled tokenizer, which outputs the token id list 13320, 665, 1327, 621, 3283.
GPT-5 tokenizer

There are multiple ways to build the Tokenizer algorithm. It could be as simple as tokenizing on characters, tokenizing on whitespaces (words), but currently the most widely used technique is BPE Tokenizer. Check out Andrej Karpathy’s video on Tokenization for a deep dive. We are moving forward, as this step is comparatively trivial and we have a lot to cover.

The token is the smallest unit a model sees. Tokens have a fixed vocabulary size VV. Current state of the art models (GPT-5, Opus) have a vocab size of 100K-200K tokens.

When we say training a model, it means learning the underlying probability distribution of the sequence of tokens. This sequence of tokens can be anything — code, essays, images, music…

And then inference simply becomes sampling from this learned probability distribution given a sequence of input tokens.

The question is how do we make the model learn this probability distribution?

If PP^* is the real world probability distribution of human generated text. We have to learn a model that approximates human text generation. We’ll call this PθP_\theta

If we have 3 human generated sentences —

  1. the cat sat on the mat
  2. the cat sat zx oj squid
  3. Paris is the capital of France

In real world the probability of seeing a sentence like 2 is near zero, no human will write like that. So PP^* will give it near 0 prob. and we expect PθP_\theta to do the same.

PP^* can be defined as

P=P(x1,x2,,xT)P^* = P(x_1, x_2, \dots, x_T)

where P(x1,x2,,xT)P(x_1, x_2, \dots, x_T) is the joint probability over the sequence of input tokens of length TT. What we’re saying is — I want to know the probability of seeing a particular sequence (x1,x2,,xT)(x_1, x_2, \dots, x_T). On each position I have VV options, so for the sequence of length TT the number of options to choose from becomes VTV^T

The naive way to learn this joint probability is:

  1. Build a giant lookup table: one row for every possible sequence of length TT, which is VTV^T rows. Where we store the occurrence of each sequence, count how often each appears and normalize to get probabilities. This approach is not feasible.
    1. Even with a moderate size of V=50000V = 50000 vocab and just T=100T = 100 sequence length. Since we can have 50000 choices at each position the size of the table becomes 5000010050000^{100} which is larger than the number of atoms in the universe. And the T=100T = 100 sequence length is nothing compared to real world sequences.
    2. Second, if this model sees a sequence it has not seen before it will assign it a score of zero. This table will be incredibly sparse.

We tackle this problem by using the chain rule.

The chain rule states that the joint probability of a sequence of events can be expressed as the product of conditional probabilities of each event, given the events that came before it.

Mathematically, it can be expressed as:

P=P(x1,x2,,xT)=P(x1)P(x2x1)P(x3x1,x2)P(xTx1,x2,,xT1)\begin{aligned} P^* &= P(x_1, x_2, \dots, x_T) \\ &= P(x_1) \cdot P(x_2 \mid x_1) \cdot P(x_3 \mid x_1, x_2) \\ &\quad \cdots P(x_T \mid x_1, x_2, \dots, x_{T-1}) \end{aligned}

This is amazing. The joint probability P(x1,x2,,xT)P(x_1, x_2, \dots, x_T), which was impossible to compute, now breaks into TT smaller problems that all look exactly the same — given the tokens so far, what is the next token?

Each of these smaller problems is a function. It takes the previous sequence as input, and outputs a probability distribution over the next token. That distribution is always a vector of size VV, one probability for every token in the vocabulary, no matter how long the input sequence is. And we don’t memorize a 5000010050000^{100} lookup anymore — we learn the weights of this one function, and the same weights serve every position and every sequence length.

Let’s call this function PθP_\theta, where θ\theta are the learned weights.

Pθ(next tokenprevious sequence)P_\theta(\text{next token} \mid \text{previous sequence})

And we can stack this up. PθP_\theta gives us a distribution over the next token, we pick a token from it, append it to the sequence, and call PθP_\theta again on the longer sequence to get the token after that. Keep going till we reach the end of the sequence. Multiply the PθP_\theta’s along the way and we get back the probability of the whole sequence.

The transformer is this function PθP_\theta — given an input sequence, it predicts the probability distribution of the next token. Training a transformer means learning the weights θ\theta.

One small note on notation before we go further. To keep every step uniform we add a special start token x0x_0 at the front of the sequence. This way even the very first token is a conditional — P(x1)P(x_1) is really P(x1x0)P(x_1 \mid x_0) — and every step looks the same.

Let’s see how this unfolds.

So after converting, raw text —> tokens

Each token is represented by a numerical id in a fixed vocabulary. Each token is depicted by a vector of raw numbers called embedding. The embedding encodes the semantic meaning of the token in a numerical format. You can imagine it being like a dictionary of token_id and embedding vector —

A table with three columns: the tokens hello, you, can, just, do, things; their ids 123, 13320, 665, 1327, 621, 3283; and an embedding vector of decimals for each, labelled e0 through e5.

We’ll denote embedding vectors by ete_t

The tokens are converted into embeddings, which we get by just a lookup in the embedding matrix. The embedding matrix is learned at training time and fixed during inference.

Here is what each symbol in the diagram means —

xtx_t — the token at position tt. The input sequence is X=(x0,x1,,xT1)X = (x_0, x_1, \dots, x_{T-1})

ete_t — the embedding vector of xtx_t. This is what actually goes into the transformer, the transformer never sees the raw token id.

utu_t — the output at position tt. Before we can say what’s in it, we need a name for the tokens in the vocabulary. The vocabulary is a fixed list of VV tokens, we’ll call them v1,v2,,vVv_1, v_2, \dots, v_V. Now, utu_t is a vector of VV raw scores, one for each vocabulary token. The kk-th entry is a score for how likely vkv_k is to be the next token xtx_t, given everything that came before it, x0,x1,,xt1x_0, x_1, \dots, x_{t-1}. Higher score means more likely. These raw scores are called logits.

There is one uu vector at every position. u1u_1 sits above x0x_0 and scores what comes after x0x_0. u2u_2 sits above x1x_1 and scores what comes after x0,x1x_0, x_1. And so on. That’s why in the diagram the xx’s start at 0 and the uu’s start at 1 — utu_t is always the prediction for xtx_t, computed from everything before xtx_t.

We view the whole mapping from xx’s to uu’s as a black box in this section and call it a Transformer.

We call the transformer a function ff with parameters θ\theta. Given the input tokens x0,x1,,xt1x_0, x_1, \dots, x_{t-1} it produces the logit vector utu_t.

ut=fθ(x0,x1,,xt1)u_t = f_\theta(x_0, x_1, \dots, x_{t-1})

utu_t only depends upon x0,x1,,xt1x_0, x_1, \dots, x_{t-1}

Logits are not probabilities yet — they can be negative, and they don’t sum to 1. To turn them into a probability distribution we do a softmax over them.

It looks something like this —

Pθ(xtx0,x1,,xt1)=softmax(ut)=softmax(fθ(x0,x1,,xt1))\begin{aligned} &P_\theta(x_t \mid x_0, x_1, \dots, x_{t-1}) \\ &\qquad = \mathrm{softmax}(u_t) \\ &\qquad = \mathrm{softmax}\big(f_\theta(x_0, x_1, \dots, x_{t-1})\big) \end{aligned}

fθf_\theta is the transformer, PθP_\theta is the distribution we set out to learn. The only gap between them is the softmax — ff gives us the raw scores, PθP_\theta gives us probabilities.

So the output vector has one entry per vocabulary token, where Pθ(xt=v1x0,x1,,xt1)P_\theta(x_t = v_1 \mid x_0, x_1, \dots, x_{t-1}) is the probability of seeing v1v_1 as the next token when given the input sequence x0,x1,,xt1x_0, x_1, \dots, x_{t-1} and so on and so forth.

Autoregressive Inference§

Given an autoregressive transformer we sample tokens from it sequentially, and the next token generated is used as an input for the next generation phase.

Three copies of the transformer in sequence. The first takes x0, x1, x2 and produces u3; the highest probability token from u3 is appended to the input of the second, which produces u4; that in turn is appended for the third, which produces u5.

xt+1softmax(fθ(x0,x1,,xt))xt+2softmax(fθ(x0,x1,,xt+1)) xTsoftmax(fθ(x0,x1,,xT1))\begin{aligned} x_{t+1} &\sim \mathrm{softmax}\big(f_\theta(x_0, x_1, \dots, x_t)\big) \\ x_{t+2} &\sim \mathrm{softmax}\big(f_\theta(x_0, x_1, \dots, x_{t+1})\big) \\ &\quad\ \vdots \\ x_T &\sim \mathrm{softmax}\big(f_\theta(x_0, x_1, \dots, x_{T-1})\big) \end{aligned}

Each generated token is used as the input to the model when generating the following tokens. This is the high level math of a transformer. Keeping it as a black box.

In Part 2, we will look under the hood of a transformer and see how we get the logit vector uu and how each step works.