srinivas raghav blog's

how does a gpt learn ?

begin with one unfinished sentence

Consider the short unfinished sentence

the cat sat on the ?

It looks simple to us because we read it almost in a single go. A language model does not begin with that understanding. It does not receive the sentence as meaning; it receives a sequence of token IDs.

A tokenizer first breaks the text into tokens and maps each token to an integer. The model then turns those integers into vectors, lets the vectors exchange information under a rule that hides the future, and asks the same question at every position:

What token should come next?

That one question connects the forward pass, the loss, backpropagation, and text generation. The aim of this blog is to follow that thread from beginning to end.

We will use a deliberately small example so that every object, equation, and shape remains visible.

build a tiny vocabulary

Assume the vocabulary contains the following seven tokens:

𝒱={[BOS],the,cat,sat,on,mat,[EOS]}

A vocabulary is like a dictionary: it maps each token to a unique integer ID. For this example, let

[BOS]0,the1,cat2,sat3,on4,mat5,[EOS]6

The vocabulary size is therefore

V=7

The IDs are only labels. Token ID (2) is not mathematically closer to token ID (3) than it is to token ID (6). The model must learn useful vector representations for these IDs.

For the main example, let the model dimension be

d=4

This means that the model represents every token position using a vector with four real-valued components.

Real language models use much larger vocabularies, sequence lengths, and model dimensions, but the same equations and tensor shapes still apply.

one sentence creates five prediction positions

Suppose the training text contains

the cat sat on the mat

Using our token-ID map, the sentence becomes

[123415]

The sentence contains six tokens:

thecatsatonthemat

To create a next-token target, every input position needs a token immediately after it. The final token has no later token inside this six-token example, so the six tokens create five prediction positions:

N=61=5

The input sequence contains the first five tokens, and the target sequence contains the final five tokens:

𝐱=[12341],𝐲=[23415]

More precisely,

𝐱,𝐲{0,1,,V1}NN,

where

0={0,1,2,}

For this example,

𝐱,𝐲{0,1,,6}5

At position (t), the target is the token one position to the right:

yt=st+1,

where (s1,,s6) denotes the original six-token sequence. Equivalently,

𝐱=[s1s2s3s4s5],𝐲=[s2s3s4s5s6]

The text creates its own labels. No separate answer file is required: the token after each prefix becomes the correct target for that prefix.

In words, the five training relationships are

available prefixcorrect next tokenthecatthe catsatthe cat satonthe cat sat onthethe cat sat on themat

Using token IDs, the same relationships are

[1]2[4pt][1,2]3[4pt][1,2,3]4[4pt][1,2,3,4]1[4pt][1,2,3,4,1]5

These are not five independent word-pair examples. They are five causal views of one sequence.

pass the whole sequence through the model at once

During training, the entire input sequence

𝐱=[12341]

is passed through the Transformer in one forward pass.

The model is causal, so the representation at each position may use only that position and the positions before it. It may not use any future position. The whole sequence is physically present in the input matrix, but every row has a different visibility pattern.

A simple binary visibility matrix makes this clear:

C=[1000011000111001111011111]

Here,

Ct,j={1,jt,0,j>t

A (1) means that position (t) is allowed to use position (j), while a (0) means that position (j) is hidden from it.

With token labels and targets attached, the same structure is

the(1)cat(2)sat(3)on(4)the(5)target110000cat211000sat311100on411110the511111mat

The first output position can use only the and predicts cat. The second can use the cat and predicts sat. The final position can use the full input prefix the cat sat on the and predicts mat.

The model therefore performs all five prefix predictions together:

one sequence+different causal visibility at each row=[4pt]all next-token predictions in one pass

The matrix (C) is only a conceptual visibility matrix. The actual Transformer uses an additive causal mask inside attention, which we will write explicitly later.

turn token ids into vectors

The model cannot do useful geometry directly with arbitrary integer IDs, so it stores a learned embedding matrix

EV×d

With (V=7) and (d=4),

E7×4

Each row belongs to one vocabulary token, and each row contains four learned real numbers. For illustration, imagine

E=[0.080.110.200.040.120.340.560.780.910.230.450.670.330.880.120.560.450.670.340.110.220.550.780.330.140.290.410.62]

These numbers are illustrative. In a real model, they are learned during training.

Looking up the rows indexed by

𝐱=[12341]

gives

Xtok=E[𝐱]=[0.120.340.560.780.910.230.450.670.330.880.120.560.450.670.340.110.120.340.560.78]

Its shape is

XtokN×d=5×4

There is one row for every token position and one column for every learned feature. The rows have not been merged into one sentence vector. The model carries all five positions at the same time.

The token the occurs twice, so its raw token-embedding row appears twice. The model must still distinguish the first occurrence from the second. Position information is therefore added or otherwise introduced.

In a simple additive description,

X(0)=Xtok+P,

where

PN×d

Because both matrices have the same shape,

(N,d)+(N,d)=(N,d)

and therefore

X(0)N×d

Position information changes the values, not the shape. Modern models may use learned positions, sinusoidal positions, rotary position embeddings, or relative-position methods. The central fact remains the same: there is one (d)-dimensional state for each of the (N) positions.

one sequence, many changing viewpoints

The hidden-state shape stays the same through the Transformer.

If (X()) enters block (), then the block returns another matrix with the same shape:

X()N×dX(+1)N×d

A common pre-normalization block can be written schematically as

U()&=X()+MHA(LN(X())),X(+1)&=U()+MLP(LN(U()))

Exact normalization details vary across architectures, but every residual addition requires matching shapes. Both the attention branch and the feature-processing branch therefore return (N×d) matrices.

If the shape does not change, what does change?

The meaning carried by each row changes.

At the beginning, a row mostly represents one token at one position. After many Transformer blocks, the same row can represent that token together with information gathered from its permitted prefix.

After (L) blocks, let

H=X(L)=[h1h2h3h4h5]5×d

Conceptually, the rows are allowed to encode

h1the,h2the cat,h3the cat sat,h4the cat sat on,h5the cat sat on the

The vectors do not literally contain those strings. This notation describes the information each row is permitted to depend on.

how the future stays hidden

If all five positions are present in the same matrix, why can the row for cat not look ahead and copy information from sat?

This is the purpose of causal self-attention.

For one attention head, start with

XN×d

The model forms queries, keys, and values:

Q=XWQ,K=XWK,Va=XWV,

where

WQ,WK,WVd×dh

The symbol (V_{!a}) denotes the attention-value matrix. It is different from the vocabulary size (V).

The projected matrices have shape

Q,K,VaN×dh

A useful interpretation is

All pairwise attention scores are computed together:

S=QKdh

The shape calculation is

(N,dh)(dh,N)=(N,N),

so

SN×N

Entry (S_{t,j}) measures how strongly position (t) matches position (j) before masking and normalization.

The additive causal mask is

Mt,j={0,jt,,j>t

For five positions,

M=[000000000000000]

The attention weights are computed row by row:

A=softmax(QKdh+M)

Because

e=0,

every forbidden future position receives exactly zero attention weight. The resulting pattern is

A=[*0000**000***00****0*****],

where every (*) is a nonnegative value and every row sums to (1).

The attention output is

Za=AVa

For row (t),

za,t=j=1tAt,jvj

The upper limit is (t), not (N). Future positions do not appear in the sum. This is the precise mathematical statement that the future is hidden.

The sequence length does not grow inside the forward pass. The model already has a fixed (N\times N) attention grid. What changes from row to row is the amount of context that is visible.

In short,

(N,d)(N,N) attention relations(N,d)

Real Transformers use multiple heads, allowing different relationships to be represented in parallel. After the heads are joined and projected, the output returns to shape (N\times d).

from hidden states to next-token probabilities

After the final Transformer block, we have

HN×d

Each row must now become a score for every vocabulary token. The model uses an output projection

WUd×V

and usually a bias

bUV

For each position,

zt=htWU+bU,ztV

Applying the same projection to all rows gives

Z=HWU+bU,

where the bias is broadcast across the (N) rows.

The shape calculation is

(N,d)(d,V)=(N,V)

With (N=5), (d=4), and (V=7),

(5,4)(4,7)=(5,7)

so

Z5×7

There are five input positions, and every position receives seven vocabulary scores.

Suppose the logits are

Z=[1.20.32.00.10.50.41.00.80.30.52.50.70.11.21.50.20.10.43.00.21.02.02.80.10.30.50.51.22.00.50.10.30.52.81.0]

with columns ordered as

[[BOS],the,cat,sat,on,mat,[EOS]]

A logit is an unrestricted real-valued score. Softmax converts each row into a probability distribution:

pt,v=ezt,vu=0V1ezt,u

Softmax is applied separately to every row, so

v=0V1pt,v=1for every position t

For the logits above, the approximate probability matrix is

P[0.02390.10700.58590.08760.04810.11830.02920.02440.04020.08940.66060.10920.05990.01630.00890.04860.03600.05940.79980.03260.01460.00640.78370.05270.03530.07860.02890.01440.00640.02880.05250.03520.07830.78130.0175]

The bold entries are the probabilities assigned to the correct next tokens:

pθ(catthe)&0.5859,pθ(satthe cat)&0.6606,pθ(onthe cat sat)&0.7998,pθ(thethe cat sat on)&0.7837,pθ(matthe cat sat on the)&0.7813

The network has produced five different next-token distributions in one pass. Row (1) answers “what follows the?” Row (5) answers “what follows the cat sat on the?”

During generation, only the newest row is needed. During training, every row has a known target, so every row can contribute to the loss.

why cross-entropy is the right loss

At position (t), let

pt=[pt,0pt,1pt,V1]

be the model's predicted distribution over the vocabulary.

Let (y_t) be the correct token ID, and let (q_t) be its one-hot target distribution:

qt,v={1,v=yt,0,vyt

The categorical cross-entropy is

t=v=0V1qt,vlogpt,v

Because every incorrect entry of (q_t) is zero, all terms disappear except the correct one:

t=logpt,yt.

This gives a simple interpretation:

cross-entropy loss=surprise assigned to the correct token

A high probability for the correct token gives a small loss:

log(1)=0.

A low probability gives a large loss:

limp0+logp=+

Some reference values make the scale intuitive:

pcorrectlogpcorrect0.900.1050.500.6930.102.3030.014.605

The function (-\log p) decreases continuously as (p) increases. Therefore, for a one-hot target, minimizing cross-entropy is exactly the same as pushing the probability of the correct token upward.

There is also a sequence-level reason for the logarithm.

The causal model assigns the correct continuation the probability

&pθ(cat sat on the matthe)[4pt]&=pθ(catthe)·pθ(satthe cat)·pθ(onthe cat sat)&·pθ(thethe cat sat on)·pθ(matthe cat sat on the)

This is the chain rule of probability. The capital pi notation is a compact way to write the same product. If the original sequence is

𝐬=[s1s2sN+1],

then

pθ(s2,,sN+1s1)=t=1Npθ(st+1st)=t=1Npθ(ytxt)

Here,

t=1Nat=a1a2aN

Taking the negative logarithm turns the product into a sum:

logpθ(𝐲𝐱)&=logt=1Npθ(ytxt)[4pt]&=t=1Nlogpθ(ytxt)[4pt]&=t=1Nt

Therefore,

sum of token cross-entropies=negative log-probability of the correct continuation.

This is the key intuitive proof.

The model is not being trained on unrelated word pairs. Maximizing the probability of the entire correct continuation is equivalent to minimizing the sum of its next-token cross-entropies.

The mean training loss is usually

=1Nt=1Nt

Dividing by (N) changes the scale but not the best model parameters for a fixed sequence length. It also makes losses and gradient magnitudes more comparable across examples containing different numbers of valid target tokens.

For the five correct probabilities above,

1&=log(0.5859)0.5346,2&=log(0.6606)0.4146,3&=log(0.7998)0.2234,4&=log(0.7837)0.2437,5&=log(0.7813)0.2469

The per-token loss vector is

[0.53460.41460.22340.24370.2469]5

The mean is

=0.5346+0.4146+0.2234+0.2437+0.246950.3326

The product of the five correct probabilities is approximately

psequence0.1895,

and indeed,

log(0.1895)1.6632=t=15t.

Dividing by five gives the same mean:

1.663250.3326

For a more general target distribution (q), cross-entropy also has the identity

H(q,p)=H(q)+DKL(qp)

Because

DKL(qp)0,

cross-entropy is minimized when the predicted distribution (p) matches the target distribution (q). For ordinary next-token training, (q) is one-hot, so this reduces to assigning as much probability as possible to the correct token.

In practice, software computes cross-entropy directly from logits using a numerically stable log-softmax operation:

t=zt,yt+log(v=0V1ezt,v)

This is algebraically equal to (-\log p_{t,y_t}), but it avoids numerical problems caused by explicitly exponentiating very large or very small values.

how one scalar changes every weight

The scalar loss was produced through a chain of differentiable operations:

token IDsembeddingshidden stateslogitscross-entropy

Every learnable parameter that influenced the logits also influenced the loss. Autograd records these operations and applies the chain rule backward through the graph.

For a parameter (\theta_i), the gradient

θi

answers the local question

How would the loss change if θi changed slightly?

Softmax cross-entropy has a particularly clear gradient. If (e_{y_t}) is the one-hot vector for the correct token, then

tzt=pteyt

For the correct token,

tzt,yt=pt,yt1,

which is negative unless the correct probability is already (1). Gradient descent subtracts the gradient, so it tends to increase the correct token's logit.

For an incorrect token (v),

tzt,v=pt,v>0

Gradient descent therefore tends to decrease that incorrect logit. An incorrect token that received more probability receives a stronger downward correction.

All positions use the same model parameters. If

=1Nt=1Nt,

then differentiation is linear:

θ=1Nt=1Nθt

This is why the model does not need one backward pass per token. We compute all token losses, reduce them to one scalar, and call backward once. The resulting gradient already contains the contribution from every supervised position.

A basic gradient-descent update is

θk+1=θkηθ(θk),

where (\eta) is the learning rate.

Modern optimizers such as Adam use additional state and rescaling, but the central action is the same: change the parameters in a direction expected to reduce future loss.

One training step is therefore

forward passscalar lossbackward passparameter update

Repeated over many sequences, this process changes the embedding table, attention projections, MLP weights, normalization parameters, and output projection so that correct continuations receive more probability.

why training is parallel but generation is sequential

Training and generation use the same causal next-token model, but they use its output differently.

during training

The correct continuation is already known.

For the input

[the,cat,sat,on,the]

the shifted target is

[cat,sat,on,the,mat]

The causal mask prevents each row from seeing future input tokens, while the target sequence provides the correct answer for every output row. All five positions can therefore be trained together:

ZN×VN supervised next-token decisions

This is commonly called teacher forcing: every position receives the true earlier tokens from the dataset rather than earlier tokens sampled from the model.

during generation

Suppose the prompt is

[the,cat]

A forward pass produces one logit row per prompt position:

Z2×V

The first row predicts what follows the, but the prompt already contains cat. Only the final row predicts the next unseen token. Generation therefore uses

zN,:

The next token may be chosen greedily,

x^N+1=\argmaxv𝒱zN,v.

or sampled from a temperature-scaled distribution,

x^N+1~Categorical(softmax(zNτ)),

where (τ>0) is the temperature.

If the model chooses sat, it appends that token:

[the,cat][the,cat,sat]

The process then repeats:

[the,cat]sat[4pt][the,cat,sat]on[4pt][the,cat,sat,on]the[4pt][the,cat,sat,on,the]mat

Generation is sequential because the next prediction depends on the token just generated:

x^t+1~pθ(·xt)

Before (x^t+1) exists, it cannot be part of the context used to produce (x^t+2).

A key-value cache can reuse attention keys and values computed for earlier tokens, making generation much faster. It does not remove the one-new-token-at-a-time dependency.

beginning and end tokens

The main example treats the first the as given context and predicts the five tokens after it.

To assign a probability to the first token too, place [BOS] before the sentence. To teach the model when to stop, place [EOS] after it:

[BOS] the cat sat on the mat [EOS]

Then the input and target could be

𝐱boundary=[0123415]𝐲boundary=[1234156]

This version has seven prediction positions. It includes both

pθ(the[BOS)

and

pθ([EOS]the cat sat on the mat)

The earlier (N=5) example is still correct; it simply studies the continuation after the initial the and stops at mat.

attention masks and loss masks are different

A causal attention mask answers

Which input positions may influence this hidden state?

A loss mask answers

Which output positions count toward the training objective?

These are different operations.

For ordinary language-model pretraining, most real token positions contribute to the loss. Padding positions are normally excluded.

In supervised fine-tuning, the entire prompt and response may enter the model, while only response positions contribute directly to the loss. If (mt{0,1}) marks supervised positions, then

masked=tmtttmt

A prompt token with (mt=0) is still present and can influence later answer states through attention. It is merely excluded from the final loss average.

the whole picture without the clutter

For one sequence, the complete path is

𝐱{0,,V1}Nembedding and positionX(0)N×dTransformer blocksHN×d

followed by

Houtput projectionZN×Vcross-entropyNmean

With a batch of (B) sequences, a head count of (Hheads), and a common stored sequence length (N),

token IDs{0,,V1}B×N,hidden statesB×N×d,attention scoresB×Hheads×N×N,logitsB×N×V,token lossesB×N,reduced loss.

If (mb,t) marks valid supervised targets, the batch loss is

=b=1Bt=1Nmb,tb,tb=1Bt=1Nmb,t

The central facts are now compact:

  1. The model keeps one hidden row per token position:

    (N,d)(N,d)

  2. The whole input is processed at once, but causal masking hides future columns from every row:

Mt,j={0,jt,,j>t.
  1. Every final hidden row becomes a complete vocabulary distribution:

    (N,d)(d,V)=(N,V)

  2. The target sequence is the original sequence shifted by one token:

    yt=st+1

  3. Token cross-entropies are the additive pieces of one continuation-level negative log-probability:

t=1Nt=logt=1Npθ(ytxt).
  1. One backward pass includes the learning signal from every supervised position:
θ=1Nt=1Nθt
  1. Training uses every valid output row because every target is known. Generation uses the newest row because only the next unseen token matters.

As one story, the process is very orderly. The model keeps one evolving vector for every position. Each vector may gather information only from its past. Each final vector proposes a distribution over what should come next. The correct next tokens are scored with cross-entropy, the token losses become one scalar, and that scalar sends a learning signal backward through the entire network.