Speaker Notes

Let's build GPT: from scratch, in code, spelled out.

Building a GPT language model from scratch in PyTorch reveals the inner mechanics of tokenization, cross-entropy loss, attention scaling, and transformer optimizations.

Andrej Karpathy · 1:56:20 · YouTube ↗

Tutorial · solo speaker  Beginner · code and concepts

Highlights

8 clips · 21 min of 116 min
    • Character-level tokenization uses tiny vocabularies but creates very long sequences.
    • Subword tokenizers like Tiktoken use larger vocabularies to shorten sequence lengths.
    • Production systems trade codebook size against computational constraints.
    • Transformers train on random chunks of data defined by a block size.
    • A single chunk packs multiple training examples where target text is offset by one.
    • Training across all context lengths from 1 to block size prepares the model for inference generation.
    • PyTorch cross-entropy expects specific tensor dimensions for multi-dimensional inputs.
    • Logits of shape batch by time by channel must be flattened to two dimensions.
    • Targets must also be flattened to match the expected batch-times-time shape.
    • Triangular matrices zero out future token interactions.
    • Normalizing rows to sum to one turns dot products into weighted averages.
    • Batched matrix multiplication processes all sequence elements in parallel.
    • Unscaled dot products grow in variance with the head size.
    • High variance causes softmax to prematurely collapse into one-hot outputs.
    • Dividing by the square root of head size preserves unit variance at initialization.
    • Dividing by the square root of the head size scales variance back to 1 at initialization.
    • Without scaling, dot product outputs grow with head size, driving softmax values into extreme peaky distributions.
    • Peak softmax outputs cause gradients to vanish by turning probability distributions into one-hot vectors.
    • Residual connections use skip connections with addition to bypass intermediate blocks.
    • Addition distributes gradients equally during backpropagation, creating a super highway straight to the input.
    • Blocks are initialized to contribute nearly nothing, allowing them to come online gradually during training.
    • Layer norm normalizes rows (features per token) rather than columns across the batch dimension.
    • Modern architectures prefer pre-norm (applying layer norm before transformations) over post-norm for stability.
    • Batch and time dimensions act combined as batch dimensions during normalization.
    • Dropout randomly zeros a subset of neurons on every forward and backward pass.
    • This acts like training an exponential ensemble of sub-networks.
    • At test time, all neurons are fully enabled, merging the sub-networks into a single ensemble.

Questions this video answers

14 · every answer cites the moment it was said
01 Why is chat GPT considered a probabilistic system? 2 sources · 0:49

Chat GPT generates responses sequentially from left to right, and for any given prompt, it can produce multiple different answers. This means its outputs are not deterministic and vary across different runs.

02 How does a character-level tokenizer convert text into integers? 2 sources · 8:56

It sorts all unique characters occurring in the dataset to create a vocabulary and assigns each an integer. To encode a string, it maps every individual character to its corresponding integer, and reverses the process to decode.

03 Why do we train on chunks of data instead of the entire text at once? 2 sources · 14:36

Feeding the entire text into a transformer at once would be computationally very expensive and prohibitive. Instead, we sample random little chunks and train on them using a specified block size.

04 What is the purpose of the block size and batch dimensions in data loading? 2 sources · 19:12

The block size defines the maximum context length used for predictions during training and inference. The batch dimension allows processing multiple independent text chunks simultaneously to keep GPUs busy via parallel processing.

05 How does the bigram language model generate text predictions? 2 sources · 23:25

It uses an embedding table where each token ID plucks out a corresponding row of scores called logits for the next character. During generation, it applies softmax to these logits and uses multinomial sampling to pick the next integer.

06 Why use torch.no_grad() during model evaluation? 2 sources · 41:11

Wrapping evaluation code in torch.no_grad() tells PyTorch that backpropagation will not be called, saving memory. It allows the framework to avoid storing intermediate variables needed for backward passes.

07 How can we efficiently compute running averages of past tokens without for loops? 3 sources · 47:10

You can vectorize the operation using batched matrix multiplication with a lower triangular matrix. Using torch.tril combined with row normalization allows computing variable-length averages across batches in parallel.

08 What is the purpose of adding positional encodings to token embeddings? 3 sources · 1:00:30

Token embeddings alone are translation invariant and lack spatial awareness, meaning the model cannot distinguish token order. Adding a positional embedding table allows the model to know where each token is positioned in the sequence.

09 How do keys, queries, and values interact in a single self-attention head? 3 sources · 1:04:12

Every token emits a query vector representing what it is looking for and a key vector representing what it contains. Their dot product computes token affinities, which are then masked, normalized via softmax, and used to aggregate value vectors.

10 Why do we scale attention weights by the square root of the head size? 2 sources · 1:17:37

Scaling by the square root of the head size controls the variance of the dot product at initialization. Without it, the weights grow too large, causing the softmax function to become overly peaky and assign all weight to a single node.

11 How does multi-head attention work in PyTorch? 2 sources · 1:22:25

Multi-head attention runs multiple smaller self-attention heads in parallel and concatenates their outputs over the channel dimension. This provides independent communication channels so tokens can gather different types of data simultaneously.

12 Why are residual connections necessary when building deeper networks? 2 sources · 1:28:09

Deep neural networks suffer from optimization issues, and residual connections provide a gradient superhighway for backpropagation. By adding skip connections, gradients flow directly from supervision to the input unimpeded, helping the network remain optimizable.

13 How does layer normalization differ from batch normalization in transformers? 2 sources · 1:34:28

Layer normalization normalizes the feature rows for every individual token independently rather than normalizing across the batch dimension. In modern pre-norm transformers, these layer norms are applied directly to the input before each sub-layer transformation.

14 What is the difference between pre-training and fine-tuning a language model? 2 sources · 1:49:07

Pre-training trains a decoder-only transformer on a massive chunk of internet text to act as a document completer. The subsequent fine-tuning stage aligns the model to act as a helpful assistant using supervised data, reward modeling, and reinforcement learning.

Section-by-section summary

24 parts

Language models perform probabilistic sequence completion

Systems like ChatGPT model sequences of tokens and predict the next element based on context. They are probabilistic, meaning the same prompt can yield slightly different outputs.

Transformers provide the core architecture for modern AI

Introduced in the 2017 attention is all you need paper, the Transformer architecture handles sequence modeling and has become foundational across artificial intelligence.

Building a character-level model on Tiny Shakespeare

Instead of massive internet datasets, we train a simplified character-level language model on a one-megabyte file of Shakespeare works to understand under-the-hood mechanics.

Tokenization maps text strings to integer sequences

Character-level tokenization translates individual characters into integers using a small vocabulary, contrasting with subword tokenizers used in production systems like GPT-2.

Training chunks use block size and batch dimensions

Transformers train on small random chunks of text rather than the full sequence. Using a block size defines the maximum context length, while batching allows parallel GPU processing.

Bigram models predict tokens using embedding tables

The simplest language model uses an embedding table to map single token indices to logits. PyTorch cross-entropy loss requires flattening multi-dimensional tensors into two dimensions.

Autoregressive generation samples from predicted probabilities

The generation loop iteratively predicts the next token by applying softmax to output logits and sampling from a multinomial distribution. The new token is appended to the context for subsequent steps.

Training updates model parameters via AdamW

An AdamW optimizer updates the network weights using gradients computed from sampled batches. Running the training loop iteratively decreases the loss and improves generated text quality.

Packaging code into a standalone script

The notebook code is consolidated into a script supporting GPU acceleration and less noisy loss estimation. Utilizing torch.no_grad() and evaluation modes ensures memory efficiency during evaluation phases.

Averaging past tokens for communication

To enable tokens to share information without looking into the future, we can compute a running average of past representations. A nested loop approach correctly builds this history summary but is computationally inefficient.

Vectorizing aggregations with matrix multiplication

Using lower triangular matrices combined with batched matrix multiplication replaces slow loops with parallelized tensor operations. Normalizing rows to sum to one turns the operation into an efficient weighted average.

Masking future tokens with negative infinity

Setting future positions to negative infinity before applying softmax creates a clean lower-triangular weight matrix. This setup prepares the model for data-dependent affinities where tokens dynamically determine their interaction weights.

Introducing embedding and positional encodings

Moving beyond direct vocabulary mapping, the architecture now uses embedding dimensions and a language modeling head. Adding positional embeddings allows the model to track token locations, which is necessary for attention blocks.

Building a single self-attention head

Tokens independently emit query and key vectors whose dot products compute data-dependent affinities. Masking out future tokens and multiplying by value vectors yields a powerful, context-aware information aggregation mechanism.

Understanding attention as a communication graph

Attention functions as a directed graph where nodes aggregate information via weighted sums regardless of spatial layout. Distinctions like encoder versus decoder blocks determine whether full or masked connectivity is permitted.

Scaling attention weights to control variance

Dividing the dot product by the square root of the head size preserves unit variance before softmax. This scaling prevents softmax from collapsing into one-hot vectors at initialization, ensuring proper gradient flow.

Multi-head attention runs independent communication channels

Multi-head attention splits the embedding dimension into multiple parallel communication channels with smaller head sizes. This allows tokens to gather different types of relational data simultaneously, analogous to group convolutions.

Interspersing communication with per-token computation

While self-attention handles token-to-token communication, a position-wise feed-forward MLP processes each token independently to think over the gathered data. Stacking these operations improves loss, paving the way for full transformer blocks.

Residual connections enable training deep neural networks

Skip connections with addition create a gradient super highway that allows error signals to flow unimpeded straight to the input. Initializing these blocks close to zero lets them gradually contribute to the residual stream during optimization.

Layer normalization stabilizes row features for deep models

Unlike batch norm which normalizes columns across the batch, layer norm normalizes across the features of each individual token. Applying layer norm before transformations (pre-norm) further improves network optimizability and depth scaling.

Scaling up hyperparameters yields coherent text structures

Increasing context length, embedding dimensions, layers, and adding dropout allows the model to achieve a lower validation loss of 1.48 on Shakespeare. Although the generated text remains semantically nonsensical at the character level, it successfully adopts stylistic patterns.

Decoder-only versus encoder-decoder architectures

The original transformer used an encoder-decoder setup for machine translation tasks like converting French to English via cross-attention. Language models like GPT use a decoder-only architecture because they perform unconditional generation and text completion.

Scaling laws separate pre-training from massive infrastructure

Pre-training builds a document completer using a fraction of internet-scale data for small models or hundreds of billions of tokens for massive 175-billion parameter models. While architectural designs remain identical, scaling up requires thousands of GPUs cooperating in distributed clusters.

Fine-tuning aligns base models into helpful assistants

Raw pre-trained models only complete documents rather than answering questions directly. Transforming them into chat assistants requires supervised fine-tuning on dialogue data, reward modeling, and reinforcement learning via policy gradients.

0:00 / 1:56:20
k play/pause · f fullscreen · m mute
n next · p previous clip · t highlights/full
< > slower/faster · / search what was said
  • Transformer35× · first 2:25

    A neural network architecture that does the heavy lifting for modern language models like GPT.

  • Tiny Shakespeare5× · first 3:53

    A toy dataset containing a concatenation of all works of Shakespeare in a single file.

  • Bigram model3× · first 22:23

    The simplest possible neural network language model that predicts the next token based on a single current token.

  • AdamW1× · first 35:00

    An advanced optimizer in PyTorch used to update model parameters via gradients.

  • Positional embedding2× · first 1:00:38

    An embedding table providing positional information to tokens so the model knows their sequence order.

  • Self-attention25× · first 42:15

    A communication mechanism where tokens compute data-dependent affinities using keys, queries, and values.

  • Scaled attention2× · first 1:17:21

    Attention mechanism that divides the dot product by the square root of the head size to stabilize variance.

  • Residual connections2× · first 1:28:38

    Skip connections that add input features directly to the output of a sub-layer to ease gradient flow.

  • Layer normalization9× · first 1:33:00

    Normalization technique that scales features across the hidden dimensions for each individual token.