Seyed Masoud Hosseini · Overview · Study log · Ideas · Transcript · RSS feed

Neural Networks: Zero to Hero · Lecture 7 of 10 · 1:56:20

Lecture 7: Let's Build GPT From Scratch

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

Study guide

What this lecture covers

This lecture answers a concrete question: what neural network is actually running inside ChatGPT, and how do you build one yourself? Starting from an empty file, Andrej Karpathy writes a character-level GPT step by step, training it on a small text file (Tiny Shakespeare) until it generates plausible-looking Shakespeare.

This is lecture 7 of 10 in the Neural Networks: Zero to Hero series, and it assumes the tensor and language-modeling groundwork built in the earlier "makemore" videos. After watching, you'll be able to explain tokenization, self-attention, multi-head attention, residual connections, and layer normalization well enough to read the nanoGPT codebase and understand what each part of a Transformer block does.

Key ideas

  • Tokenization: converting raw text into integers using a vocabulary; this lecture uses a simple character-level tokenizer instead of a subword scheme like GPT-2's byte pair encoding.
  • Block size and batches: training samples fixed-length chunks (the context length) and stacks many of them into a batch so the GPU can process examples in parallel.
  • Self-attention: each token produces a query (what it's looking for), a key (what it contains), and a value (what it shares); dot products between queries and keys become weights for aggregating values.
  • Scaled attention: dividing the attention scores by sqrt(head_size) keeps their variance controlled so softmax doesn't collapse into near one-hot outputs at initialization.
  • Multi-head attention: running several smaller self-attention heads in parallel and concatenating their outputs, so different heads can specialize in different relationships between tokens.
  • Residual connections and layer norm: skip connections let gradients flow directly to early layers, and layer normalization stabilizes activations, both of which make deep Transformers trainable.
  • Decoder-only vs. encoder-decoder: this lecture builds a decoder-only Transformer (like GPT) that masks future tokens; the original "Attention Is All You Need" paper also has an encoder and cross-attention for machine translation, which this build skips.

Walkthrough

Setup and the language-modeling task (0:00)

Karpathy introduces ChatGPT as a probabilistic language model and traces it back to the 2017 "Attention Is All You Need" paper, which introduced the Transformer. He explains that this lecture will build a much smaller character-level Transformer trained on the Tiny Shakespeare dataset, rather than reproducing ChatGPT itself, and previews the reference codebase, nanoGPT.

Reading data and tokenizing (7:52)

The Tiny Shakespeare file is loaded and its unique characters form a 65-character vocabulary. A simple encoder/decoder maps characters to integers and back. Karpathy contrasts this with subword tokenizers such as OpenAI's tiktoken, noting the trade-off between vocabulary size and sequence length.

Batching chunks of data (14:27)

Training never feeds the whole text at once. Instead, random fixed-length chunks (block_size) are sampled, and each chunk of length n contains n training examples, since the model must learn to predict the next character from every possible amount of preceding context. Multiple chunks are stacked into a batch dimension for parallel processing on the GPU.

The bigram baseline (22:11)

A minimal model looks up each token's embedding directly as logits for the next character, with no communication between tokens. Karpathy implements the forward pass, the cross-entropy loss, and a generate function, then trains this baseline with the Adam optimizer, watching the loss drop from around 4.7 toward 2.5.

The self-attention trick (42:13)

Before writing self-attention, Karpathy shows how to average a token's own features with the features of every earlier token, first with an explicit loop, then far more efficiently using matrix multiplication against a lower-triangular matrix. He then generalizes this from a simple average to a masked softmax over the raw dot-product scores.

Building self-attention (1:02:00)

This is the core of the lecture: each token produces a query, a key, and a value through linear layers. Attention weights come from query-key dot products, masked so future tokens can't be seen, then softmaxed and used to weight the values being aggregated. Karpathy explains attention as a data-dependent communication mechanism over a directed graph of nodes, distinguishes self-attention from cross-attention, and shows why scaling by sqrt(head_size) matters.

From one head to a full Transformer block (1:21:59)

Multiple attention heads run in parallel and concatenate their outputs. A feedforward layer is added so tokens can process what they gathered from attention. Residual connections and layer normalization are then introduced to keep the network optimizable as it gets deeper, and these pieces are grouped into a repeatable block, following the structure in the paper.

Scaling up and comparing to real GPTs (1:39:15)

With dropout added for regularization and hyperparameters scaled up (larger batch size, longer context, more layers and heads), the validation loss drops to about 1.48, producing noticeably more Shakespeare-like text. Karpathy closes by comparing this roughly 10-million-parameter model to GPT-3's 175 billion parameters, walking through nanoGPT's model.py, and outlining how pretraining differs from the supervised fine-tuning and RLHF stages used to turn a document completer into an assistant like ChatGPT.

Before you watch

  • Watch the earlier "makemore" videos in this series first; this lecture assumes comfort with PyTorch tensors, nn.Module, and the autoregressive language-modeling framework.
  • Basic calculus and statistics help with following the loss function and gradient discussion.
  • Access to a GPU (the instructor uses an A100) is useful for reproducing the later, larger training runs, though the earlier examples run fine on a CPU.

Check your understanding

  1. Why does sampling training chunks of a fixed block size produce multiple training examples from a single chunk?
  2. What roles do the query, key, and value vectors play in self-attention, and how do they combine to produce an output?
  3. Why is scaling the attention scores by 1/sqrt(head_size) important at initialization?
  4. What problem do residual connections and layer normalization solve as Transformers get deeper?
  5. What distinguishes the decoder-only Transformer built in this lecture from the encoder-decoder Transformer in the original paper?

Chapters

From the YouTube description

We build a Generatively Pretrained Transformer (GPT), following the paper "Attention is All You Need" and OpenAI's GPT-2 / GPT-3. We talk about connections to ChatGPT, which has taken the world by storm. We watch GitHub Copilot, itself a GPT, help us write a GPT (meta :D!) . I recommend people watch the earlier makemore videos to get comfortable with the autoregressive language modeling framework and basics of tensors and PyTorch nn, which we take for granted in this video.

Links:
- Google colab for the video: https://colab.research.google.com/drive/1JMLa53HDuA-i7ZBmqV7ZnA3c_fvtXnx-?usp=sharing
- GitHub repo for the video: https://github.com/karpathy/ng-video-lecture
- Playlist of the whole Zero to Hero series so far: https://www.youtube.com/watch?v=VMj-3S1tku0&list=PLAqhIrjkxbuWI23v9cThsA9GvCAUhRvKZ
- nanoGPT repo: https://github.com/karpathy/nanoGPT
- my website: https://karpathy.ai
- my twitter: https://twitter.com/karpathy
- our Discord channel: https://discord.gg/3zy8kqD9Cp

Supplementary links:
- Attention is All You Need paper: https://arxiv.org/abs/1706.03762
- OpenAI GPT-3 paper: https://arxiv.org/abs/2005.14165
- OpenAI ChatGPT blog post: https://openai.com/blog/chatgpt/
- The GPU I'm training the model on is from Lambda GPU Cloud, I think the best and easiest way to spin up an on-demand GPU instance in the cloud that you can ssh to: https://lambdalabs.com . If you prefer to work in notebooks, I think the easiest path today is Google Colab.

Suggested exercises:
- EX1: The n-dimensional tensor mastery challenge: Combine the `Head` and `MultiHeadAttention` into one class that processes all the heads in parallel, treating the heads as another batch dimension (answer is in nanoGPT).
- EX2: Train the GPT on your own dataset of choice! What other data could be fun to blabber on about? (A fun advanced suggestion if you like: train a GPT to do addition of two numbers, i.e. a+b=c. You may find it helpful to predict the digits of c in reverse order, as the typical addition algorithm (that you're hoping it learns) would proceed right to left too. You may want to modify the data loader to simply serve random problems and skip the generation of train.bin, val.bin. You may want to mask out the loss at the input positions of a+b that just specify the problem using y=-1 in the targets (see CrossEntropyLoss ignore_index). Does your Transformer learn to add? Once you have this, swole doge project: build a calculator clone in GPT, for all of +-*/. Not an easy problem. You may need Chain of Thought traces.)
- EX3: Find a dataset that is very large, so large that you can't see a gap between train and val loss. Pretrain the transformer on this data, then initialize with that model and finetune it on tiny shakespeare with a smaller number of steps and lower learning rate. Can you obtain a lower validation loss by the use of pretraining?
- EX4: Read some transformer papers and implement one additional feature or change that people seem to use. Does it improve the performance of your GPT?

Chapters:
00:00:00 intro: ChatGPT, Transformers, nanoGPT, Shakespeare
baseline language modeling, code setup
00:07:52 reading and exploring the data
00:09:28 tokenization, train/val split
00:14:27 data loader: batches of chunks of data
00:22:11 simplest baseline: bigram language model, loss, generation
00:34:53 training the bigram model
00:38:00 port our code to a script
Building the "self-attention"
00:42:13 version 1: averaging past context with for loops, the weakest form of aggregation
00:47:11 the trick in self-attention: matrix multiply as weighted aggregation
00:51:54 version 2: using matrix multiply
00:54:42 version 3: adding softmax
00:58:26 minor code cleanup
01:00:18 positional encoding
01:02:00 THE CRUX OF THE VIDEO: version 4: self-attention
01:11:38 note 1: attention as communication
01:12:46 note 2: attention has no notion of space, operates over sets
01:13:40 note 3: there is no communication across batch dimension
01:14:14 note 4: encoder blocks vs. decoder blocks
01:15:39 note 5: attention vs. self-attention vs. cross-attention
01:16:56 note 6: "scaled" self-attention. why divide by sqrt(head_size)
Building the Transformer
01:19:11 inserting a single self-attention block to our network
01:21:59 multi-headed self-attention
01:24:25 feedforward layers of transformer block
01:26:48 residual connections
01:32:51 layernorm (and its relationship to our previous batchnorm)
01:37:49 scaling up the model! creating a few variables. adding dropout
Notes on Transformer
01:42:39 encoder vs. decoder vs. both (?) Transformers
01:46:22 super quick walkthrough of nanoGPT, batched multi-headed self-attention
01:48:53 back to ChatGPT, GPT-3, pretraining vs. finetuning, RLHF
01:54:32 conclusions

Corrections:
00:57:00 Oops "tokens from the _future_ cannot communicate", not "past". Sorry! :)
01:20:05 Oops I should be using the head_size for the normalization, not C

← Lecture 6: Building a WaveNet · Lecture 8: State of GPT →