Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Token embedding

In the previous part, we used a recurrent neural network (RNN) to let a model read Shakespeare for the first time. But an RNN has two inherent flaws:

  • Limited memory: all the history has to be compressed into a hidden state of fixed length. The more information is stuffed in, the sooner the early content is squeezed out;

  • No parallelism: tokens must be processed one by one in order, and the next cannot start before the previous one has finished. With massive amounts of text, training speed becomes an insurmountable bottleneck.

In 2017, a research team at Google published the famous paper Attention Is All You Need, which proposed the brand-new Transformer architecture: it abandons recurrence entirely and relies completely on the attention mechanism to process token sequences. The Generative Pre-trained Transformer (GPT), born from this architecture, opened the era of large language models.


From this part on, we will build a real GPT model step by step:

  • Input representation: token embedding and position embedding, which turn text into vectors that carry information;

  • Self-attention: causal, weighted, and multi-head, which let tokens attend to each other and understand context;

  • Pre-training: residual connections, normalization, and dropout, which make the model deeper, bigger, and well trained;

  • Inference: sampling strategies, stopping criteria, the KV cache, and batch inference, which control generation and make it more efficient;

  • Fine-tuning: supervised fine-tuning and preference optimization, which teach the model to move from the pre-trained “continue the text” mode to a “conversation” mode.

In this chapter, we take the first step: building the most basic framework and connecting the dataset through token embedding.

💡 Tip: By importing src.core, we can directly use the model training framework built in the previous chapters.

Dataset

Character-encoding dataset

The GPT dataset is exactly the same as the RNN dataset, and needs no modification:

  • vocab (vocabulary): tokenized by character;

  • tokens (token table): the whole text converted into a sequence of index encodings;

  • xx (feature): a token sequence cut from the text, tokens[i: i + context_size];

  • yy (label): the feature token sequence shifted as a whole by one position, tokens[i + 1: i + context_size + 1].

That is, each sample contains context_size prediction tasks: predict the 2nd token from the 1st, the 3rd token from the first 2, and so on, up to predicting token context_size + 1 from the first context_size tokens.

This way of training, predicting the next token from what is already there, is called autoregressive training, and it is the core training paradigm of GPT. Unlike an RNN, which must compute token by token in order, GPT can process all the tokens of a sample in parallel in one go.

Activation functions

Gaussian error linear unit (GELU)

So far, we have used ReLU as the hidden layer activation function. GPT uses an upgraded version: the Gaussian error linear unit (GELU).

The curve of GELU is very similar to that of ReLU: negative numbers are mostly filtered to 0, and positive numbers are kept as they are. The difference is that GELU bends smoothly around the origin, without the sharp kink of ReLU. The smooth curve makes the gradient change more steadily, which helps the training of deep models such as GPT.


Forward propagation: the exact definition of GELU needs the cumulative distribution function of the Gaussian distribution, which is expensive to compute. In practice, an approximation is usually used:

GELU(x)≈0.5 x(1+tanh⁡(2π(x+0.044715 x3)))\text{GELU}(x) \approx 0.5 \, x \left( 1 + \tanh\left( \sqrt{\frac{2}{\pi}} \left( x + 0.044715 \, x^3 \right) \right) \right)

Gradient computation: the gradient function gradient_fn of backpropagation is also the derivative of this approximation.

Let us look at the effect of the GELU activation function:

<Figure size 500x300 with 1 Axes>

Loss function

GPT cross-entropy loss function

An RNN model computes token by token, so we also computed the cross-entropy loss token by token and then added the losses up.

A GPT model can compute all the tokens of a sample at once and outputs many predictions, with the shape (batch size, context size, vocabulary size). In practice, we can flatten both the predictions and the labels into one big 2-dimensional array with the shape (batch size * context size, vocabulary size), and use the vectorized operations of NumPy to compute the whole cross-entropy loss at once.

GPTLoss is the upgraded version of the cross-entropy loss function, computing all the positions of a batch of samples at once.

Model

A complete GPT model consists of three modules:

  • Embedding (embedding layer): converts the index encodings of the input text into word vectors;

  • Transformer (Transformer block): called many times in a loop, refining features from the word vectors layer by layer;

  • Output (output layer): maps the word vectors to probabilities over the vocabulary.

Basic modules of GPT: the embedding layer, the Transformer block, and the output layer
Figure: Basic modules of GPT

GPT embedding layer

The GPT embedding layer is the first layer of the GPT model. It converts the index encodings of the whole text into dense word vectors.

Unlike the RNN model, it no longer uses a mean pooling layer to merge all the word vectors of the text into one bag-of-words vector, which would lose the word order. The GPT model keeps the word vector of every token, so the word order information runs through the whole model.

GPT feed-forward network layer

The GPT feed-forward network layer (FFN) is a standard two-layer fully connected network: a linear hidden layer + a GELU activation function + a linear output layer. It digs out the inner logic of the data.

💡 Tip: The hidden layer of the feed-forward network layer expands the data size by a factor of 4, and the output layer then compresses it back to the original size, so that the data can connect smoothly from layer to layer. This is also the standard configuration of GPT models.

GPT Transformer block

The GPT Transformer block is the core component of the GPT model. For now it contains only a feed-forward network layer, and we will extend it with the attention mechanism later.

Although a GPT model can process all the tokens of a sample in parallel in one go, a single pass obviously cannot train it fully. So the Transformer block is called many times in a loop, gradually refining the inner logic of the data.

GPT output layer

The main body of the GPT output layer is a linear layer. It maps the word vector at each position to a vector of the vocabulary size, matching the label. The output values are logits. After conversion by the Softmax activation function included in the cross-entropy loss function, each value finally represents the probability of the corresponding token.

GPT model

Finally, we assemble the three parts into the complete GPT model, which includes several Transformer blocks to refine the features of the data many times.

As data moves through the parts of the model, its shape changes too:

(batch,context)→embedding(batch,context,embedding)→Transformer block×n(batch,context,embedding)→output(batch,context,vocabulary)(\text{batch}, \text{context}) \xrightarrow{\text{embedding}} (\text{batch}, \text{context}, \text{embedding}) \xrightarrow{\text{Transformer block} \times n} (\text{batch}, \text{context}, \text{embedding}) \xrightarrow{\text{output}} (\text{batch}, \text{context}, \text{vocabulary})

We can see that the sequence dimensions (batch size, context size) stay unchanged from beginning to end. Every position completes its own prediction independently, which is exactly the key to why GPT can be trained in parallel.

GPT trainer

The GPT trainer is much the same as the RNN trainer, with three notable differences:

  • Loss computation: there is no more looping over time steps; a single call to the loss function computes all the positions;

  • Disabling gradients: during evaluation and text generation, there is no need to build the computational graph or backpropagate. We use the function Tensor.no_grad provided by the framework to switch off gradient computation temporarily, saving memory and compute;

  • Text generation: the generation method generate implements the autoregressive generation of GPT:

    • encode the prompt prompt into a token sequence;

    • each time, take the last context_size tokens as the input and run the model;

    • take only the logits of the last position of the prediction, convert them into a probability distribution, and sample the next token at random;

    • append the new token to the end of the token sequence, and repeat the process.

💡 Tip: Generating text by random sampling instead of always taking the most probable token lets each generation be worded differently and keeps the model from falling into repetition.

Hyperparameters

Learning rate

Batch size

Number of epochs

Context size

Embedding size

Number of Transformer blocks

This is a new hyperparameter. It defines how many Transformer blocks the GPT model contains.

Modeling

We build the model with the GPT model, the GPT loss function, and the GPT trainer.

Training

Evaluation

prediction:	1742 steps, each (4, 32, 65)
loss:	2.4602363050736735

Inference

ROMEO:
ABIO:
Prt gee wl d lore wesed.
Tr'
IO, ftids theshisin and yono avero s.
DUnd mer wn gack nome sthal nksel aichosd a d ast t, aif we bllyoobatis, thee, higherel llote he
Whiosofispenccche hee weldealvigis y winosouless prio, o whagsd lld sentte did st Lom

In this chapter, we built the basic skeleton of the GPT model:

  • the embedding layer turns text into vectors;

  • the Transformer blocks refine features;

  • the output layer produces probabilities over the vocabulary.

Finally, autoregressive generation lets the model speak.

However, the current model has two obvious problems, so its output is not noticeably better than that of the RNN model:

  • No position information: the word vector of each token contains only “what it is”, not “where it is”;

  • No communication across the context: the feed-forward network is a two-layer fully connected neural network. Every position is computed independently, tokens do not affect each other, and the prediction at each position depends only on itself.

In the following chapters, we will keep extending the model to solve these two problems.

Exercises

  1. A GPT model chains multiple Transformer blocks to refine features layer by layer. Try changing the number of Transformer blocks BLOCKS, and observe how the training speed and generation quality change.