Background
Sections
IntroductionModule 01 β€” Tensors 🧊01 Β· Creating Tensors 🧊02 Β· Indexing & Reshaping πŸ”ͺ03 Β· Tensor Math βž—04 Β· Device Placement πŸ–₯️⚑Module 02 β€” Autograd βš™οΈ01 Β· The Computational Graph πŸ•ΈοΈ02 Β· Backward Pass & Gradients ⬅️03 Β· Turning Autograd Off πŸ›‘04 Β· Gradient Gotchas πŸͺ€Module 03 β€” Neural Networks01 Β· The `nn.Module` Basics 🧱02 Β· Common Layers 🧩03 Β· Building a Network πŸ—οΈ04 Β· Inspecting Models πŸ”Module 04 β€” Data Handling πŸ—‚οΈ01 Β· Dataset Basics πŸ“‡02 Β· The DataLoader 🚚03 Β· Transforms 🎨04 Β· Splits & Built-in Datasets βœ‚οΈModule 05 β€” The Training Loop πŸ”01 Β· Loss Functions 🎯02 Β· Optimizers βš™οΈ03 Β· The Training Loop πŸ”04 Β· Evaluation & Metrics πŸ“ŠModule 06 β€” Saving & Loading πŸ’Ύ01 Β· `state_dict` Basics πŸ’Ύ02 Β· Checkpoints & Resuming ⏸️03 Β· Loading for Inference πŸš€04 Β· Best Model & Early Stopping πŸ…Module 07 β€” Computer Vision πŸ‘οΈ01 Β· Convolutions πŸ”²02 Β· CNN Architecture πŸ›οΈ03 Β· Transfer Learning πŸ”04 Β· Image Classification Project πŸ§ͺModule 08 β€” NLP & Transformers πŸ’¬01 Β· Text Data & Tokenization πŸ”€02 Β· Embeddings 🧭03 Β· Recurrent Layers & LSTMs πŸ”„04 Β· Intro to Transformers ⚑Module 09 β€” Ecosystem: PyTorch Lightning ⚑01 Β· Why Lightning? πŸ€”02 Β· The LightningModule 🧩03 Β· The Trainer πŸŽ›οΈ04 Β· DataModules & Callbacks 🧰Module 10 β€” Deployment & Optimization πŸš€01 Β· Exporting Models πŸ“¦02 Β· `torch.compile` ⚑03 Β· Inference Optimization πŸͺΆ04 Β· Serving & Next Steps πŸŽ“

04 · Intro to Transformers ⚑

5 min read

The architecture that dethroned the LSTM and powers every large language model you've heard of. Its secret is a deceptively simple idea: let every token look directly at every other token.


1. The 'Why'

LSTMs (sub-module 03) carry memory through a sequence, but they have two stubborn limitations. First, they're sequential by nature β€” token t can't be processed until token t-1 is done β€” which makes them slow to train and unable to fully exploit the parallel hardware you learned to love in Module 01. Second, even with gating, information from far-back tokens has to survive a long chain of updates to influence the present, so very long-range dependencies remain hard. For years these were accepted costs of doing sequence modeling. Then, in 2017, the paper "Attention Is All You Need" proposed throwing out recurrence entirely, and the field changed overnight.

The Transformer's core innovation is self-attention: instead of passing memory step by step, every token directly computes how much it should pay attention to every other token in the sequence, and builds its new representation as a weighted blend of them all. A pronoun can attend straight to the noun it refers to, however far away, in a single step β€” and because every position is computed independently, the whole sequence processes in parallel. This combination of long-range reach and parallelism is why Transformers scale to enormous models and datasets in ways RNNs never could, and it's the foundation of GPT, BERT, and modern LLMs. This sub-module gives you the intuition and shows you PyTorch's built-in nn.Transformer building blocks β€” a first look, not a deep dive, but enough to demystify what's under the hood of today's AI.


2. Core Concepts

Self-attention (Query, Key, Value). Each token produces a query, a key, and a value vector. A token's output is a weighted sum of all tokens' values, where the weights come from matching its query against every key. In plain terms: each token asks "who here is relevant to me?" and blends in the answers.

Multi-head attention. Attention is run several times in parallel ("heads"), each learning to focus on different kinds of relationships (syntax, coreference, etc.), then combined. nn.MultiheadAttention implements this.

Positional encoding. Because attention has no inherent sense of order (it sees a set of tokens), Transformers add position information to the embeddings so the model knows token order β€” recovering what recurrence gave for free.

Encoder vs. decoder. The encoder builds rich representations of an input (great for classification/understanding β€” BERT-style). The decoder generates a sequence one token at a time using masked self-attention (GPT-style). nn.Transformer provides both; nn.TransformerEncoderLayer is the common starting block.

It still starts with embeddings. Everything from sub-modules 01–02 still applies: tokenize, embed, (add positions), then attention. Transformers replace the recurrent middle, not the text plumbing.


3. Code in Action

Self-attention with nn.MultiheadAttention

import torch
import torch.nn as nn

attn = nn.MultiheadAttention(embed_dim=16, num_heads=4, batch_first=True)

x = torch.randn(2, 5, 16)          # (batch=2, seq_len=5, embed_dim=16)
# Self-attention: query, key, value are all the same sequence
out, weights = attn(x, x, x)
print(out.shape)                   # torch.Size([2, 5, 16]) -> attended representations
print(weights.shape)               # torch.Size([2, 5, 5]) -> who attends to whom

A Transformer encoder block/stack

import torch
import torch.nn as nn

# One encoder layer = self-attention + feed-forward, with norms and residuals built in
layer = nn.TransformerEncoderLayer(
    d_model=16,          # embedding/model dimension
    nhead=4,             # number of attention heads
    dim_feedforward=64,  # size of the internal MLP
    batch_first=True,
)
encoder = nn.TransformerEncoder(layer, num_layers=2)   # stack 2 such layers

x = torch.randn(2, 5, 16)
encoded = encoder(x)
print(encoded.shape)     # torch.Size([2, 5, 16]) -> contextualized token vectors

Adding positional information (the missing order)

import torch
import torch.nn as nn

seq_len, d_model = 5, 16
token_embed = nn.Embedding(20, d_model, padding_idx=0)
pos_embed   = nn.Embedding(seq_len, d_model)            # a learnable position table

ids = torch.tensor([[3, 4, 6, 7, 0]])                   # (batch, seq_len)
positions = torch.arange(seq_len).unsqueeze(0)          # [[0,1,2,3,4]]
x = token_embed(ids) + pos_embed(positions)             # combine meaning + order
# `x` is now ready to feed into the TransformerEncoder above.
print(x.shape)                                          # torch.Size([1, 5, 16])

4. Common Pitfalls

Pitfall 1 β€” Forgetting positional encoding. Self-attention is order-agnostic: without position information, "dog bites man" and "man bites dog" look identical to the model. You must add positional encodings/embeddings to the token embeddings before the Transformer layers.

Pitfall 2 β€” Omitting the padding mask. Attention will happily attend to <pad> tokens, contaminating every position's output. Pass a key_padding_mask (or src_key_padding_mask) marking pad positions so they're ignored β€” the mask from sub-module 01 comes back here.

Pitfall 3 β€” Confusing encoder and decoder / their masks. An encoder sees the whole sequence; a decoder must use a causal mask so each position can't peek at future tokens (essential for generation). Using the wrong one β€” or no causal mask in a generative model β€” leaks the answer and breaks training. Match the block and mask to your task.


5. Further Reading & Watch List


⬅️ Prev: 03 Β· Recurrent Layers & LSTMs Β· 🏁 Module complete! Back to the module index or on to Module 09 β€” Ecosystem: Lightning.