AnyLearn
All lessons
AIintermediate

Attention and Transformers

From the limits of RNNs to the self-attention mechanism that replaced them. Learn how queries, keys, and values implement scaled dot-product attention, why multi-head attention captures richer structure, how positional encodings inject order, and how all of this assembles into a transformer block.

Not signed in β€” your progress and quiz score won't be saved.
Lesson progress1 / 9

What RNNs get wrong

Recurrent neural networks process sequences one token at a time, passing a hidden state ht=f(htβˆ’1,xt)h_t = f(h_{t-1}, x_t) forward. Two fundamental problems:

  • Sequential bottleneck: each step depends on the previous one β€” you cannot parallelize across time. Training on long sequences is painfully slow on modern GPUs built for parallelism.
  • Long-range forgetting: information from step 1 must survive through hundreds of hidden-state updates to influence step 500. Even LSTMs with their gating mechanisms lose distant context in practice β€” the hidden state is a fixed-size vector being rewritten at every step.

The 2017 paper Attention Is All You Need (Vaswani et al.) replaced recurrence entirely. Instead of forcing all context through a sequential bottleneck, attention lets every token directly attend to every other token in one parallel operation. Training became orders of magnitude faster; long-range dependencies became trivial.

Full lesson text

All 9 steps on one page β€” for reading, reference, and search.

Show

1. What RNNs get wrong

Recurrent neural networks process sequences one token at a time, passing a hidden state ht=f(htβˆ’1,xt)h_t = f(h_{t-1}, x_t) forward. Two fundamental problems:

  • Sequential bottleneck: each step depends on the previous one β€” you cannot parallelize across time. Training on long sequences is painfully slow on modern GPUs built for parallelism.
  • Long-range forgetting: information from step 1 must survive through hundreds of hidden-state updates to influence step 500. Even LSTMs with their gating mechanisms lose distant context in practice β€” the hidden state is a fixed-size vector being rewritten at every step.

The 2017 paper Attention Is All You Need (Vaswani et al.) replaced recurrence entirely. Instead of forcing all context through a sequential bottleneck, attention lets every token directly attend to every other token in one parallel operation. Training became orders of magnitude faster; long-range dependencies became trivial.

2. The attention mechanism: intuition

Attention is a soft, differentiable lookup. Imagine you're translating the word "bank" and need to decide whether it means a financial institution or a riverbank. You want to look up other words in the sentence and weight their influence by relevance.

Formally, given a query qq (what you're looking for), a set of keys KK (what each candidate offers), and values VV (what each candidate contributes), attention computes:

  1. Match query against every key: score si=qβ‹…kis_i = q \cdot k_i
  2. Normalize scores to weights: Ξ±i=softmax(s/dk)i\alpha_i = \text{softmax}(s / \sqrt{d_k})_i
  3. Weighted sum of values: output=βˆ‘iΞ±ivi\text{output} = \sum_i \alpha_i v_i

The scores tell you how relevant each position is. Softmax turns them into a probability distribution. The output is a context-weighted blend of values.

The dk\sqrt{d_k} scaling prevents dot products from growing large with dimension, which would push softmax into saturation.

3. Scaled dot-product self-attention

In self-attention, queries, keys, and values all come from the same sequence. For an input sequence X∈RTΓ—dmodelX \in \mathbb{R}^{T \times d_{\text{model}}}, three learned linear projections produce:

Q=XWQ,K=XWK,V=XWVQ = XW^Q, \quad K = XW^K, \quad V = XW^V

where WQ,WK,WV∈RdmodelΓ—dkW^Q, W^K, W^V \in \mathbb{R}^{d_{\text{model}} \times d_k}. The full attention computation:

Attention(Q,K,V)=softmax ⁣(QK⊀dk)V\text{Attention}(Q, K, V) = \text{softmax}\!\left(\frac{QK^\top}{\sqrt{d_k}}\right) V

The matrix product QK⊀∈RTΓ—TQK^\top \in \mathbb{R}^{T \times T} produces one score per pair of positions β€” every token attends to every other token simultaneously. This is O(T2dk)O(T^2 d_k) in time and space, the famous quadratic complexity in sequence length that motivates efficient attention research (Linformer, Flash Attention, etc.).

import torch, torch.nn.functional as F

def attention(Q, K, V):
    d_k = Q.shape[-1]
    scores = Q @ K.transpose(-2, -1) / d_k**0.5  # (B, T, T)
    weights = F.softmax(scores, dim=-1)
    return weights @ V  # (B, T, d_k)

4. Multi-head attention

A single attention head learns one type of relationship (e.g., subject–verb agreement). Multi-head attention runs hh attention heads in parallel with different projections, then concatenates and projects:

MultiHead(Q,K,V)=Concat(head1,…,headh) WO\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h)\, W^O headi=Attention(QWiQ,KWiK,VWiV)\text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V)

Each head attends to different parts of the representation space simultaneously. In BERT's analysis, different heads specialize: some track syntactic dependencies, others track coreference, others attend to the previous/next tokens.

# PyTorch built-in multi-head attention
attn = torch.nn.MultiheadAttention(
    embed_dim=512, num_heads=8, batch_first=True
)
x = torch.randn(2, 64, 512)  # (batch, seq_len, d_model)
out, weights = attn(x, x, x)  # self-attention: Q=K=V=x
# out shape: (2, 64, 512)

With dmodel=512d_{\text{model}} = 512 and h=8h = 8 heads, each head uses dk=dv=64d_k = d_v = 64. Total parameter count stays the same as a single head with dk=512d_k = 512 β€” the expressiveness gain is free.

5. Positional encodings

Attention is permutation-equivariant: shuffle the input tokens and you get the same output, shuffled. For language, word order is everything β€” "dog bites man" β‰  "man bites dog". We must inject position information.

The original transformer adds fixed sinusoidal encodings to the input embeddings:

PE(pos,2i)=sin⁑ ⁣(pos100002i/dmodel),PE(pos,2i+1)=cos⁑ ⁣(pos100002i/dmodel)PE_{(pos, 2i)} = \sin\!\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right), \quad PE_{(pos, 2i+1)} = \cos\!\left(\frac{pos}{10000^{2i/d_{\text{model}}}}\right)

Properties: different frequencies encode different position ranges; the model can extrapolate to longer sequences than seen in training; relative position pos1βˆ’pos2pos_1 - pos_2 can be expressed as a linear function of PEpos1PE_{pos_1} and PEpos2PE_{pos_2}.

Modern models use learned positional embeddings (BERT, GPT) or rotary position embeddings β€” RoPE (LLaMA, GPT-NeoX), which encode position in the attention scores rather than the embeddings themselves, giving better length generalization.

6. The transformer block

A transformer block combines multi-head self-attention with a position-wise feedforward network, both wrapped in residual connections and layer normalization:

x' = LayerNorm(x + MultiHeadAttention(x, x, x))  # attention sublayer
x'' = LayerNorm(x' + FFN(x'))                     # feedforward sublayer

The FFN is just two linear layers with a nonlinearity: FFN(x)=W2β‹…ReLU(W1x+b1)+b2\text{FFN}(x) = W_2 \cdot \text{ReLU}(W_1 x + b_1) + b_2, with dff=4Γ—dmodeld_{\text{ff}} = 4 \times d_{\text{model}}. Surprisingly, this FF component stores most of the factual knowledge in GPT-style models.

The two sublayer pattern obeys Pre-LN (norm before attention) in modern practice rather than the original Post-LN: x' = x + MultiHeadAttention(LayerNorm(x)). Pre-LN trains more stably and doesn't require the careful learning-rate warmup that Post-LN demands.

7. Inside a transformer block

One transformer block (Pre-LN variant). Both sublayers use residual connections.

flowchart TD
  IN["Input x"]
  LN1["LayerNorm"]
  ATTN["Multi-Head Self-Attention"]
  ADD1["Add residual: x + Attention(LN(x))"]
  LN2["LayerNorm"]
  FFN["Feed-Forward Network: W2 ReLU(W1 x + b1) + b2"]
  ADD2["Add residual: x + FFN(LN(x))"]
  OUT["Output x''"]
  IN --> LN1 --> ATTN --> ADD1
  IN --> ADD1
  ADD1 --> LN2 --> FFN --> ADD2
  ADD1 --> ADD2
  ADD2 --> OUT

8. Encoder, decoder, and encoder-decoder architectures

Three transformer variants serve different tasks:

ArchitectureAttention typeModelsBest for
Encoder-onlyBidirectional self-attentionBERT, RoBERTaClassification, embeddings, NER
Decoder-onlyCausal (masked) self-attentionGPT-2/3/4, LLaMAText generation, language modeling
Encoder-decoderBidirectional + cross-attentionT5, BART, WhisperTranslation, summarization, ASR

Causal masking in decoders sets attention scores for future positions to βˆ’βˆž-\infty before softmax, ensuring position tt can only attend to positions ≀t\leq t. This preserves the autoregressive property needed for generation: predict one token at a time, left to right.

Cross-attention in encoder-decoder models lets decoder queries attend to encoder keys and values β€” this is how the decoder "reads" the source sequence while generating the target.

9. Scaling laws and why transformers dominate

Transformers are the dominant architecture today not because they are cleverly designed for language β€” they are general-purpose. They scale predictably with compute.

Chinchilla scaling laws (Hoffmann et al., 2022): for a given compute budget CC (in FLOPs), optimal model size NN and training tokens DD satisfy N∝C0.5N \propto C^{0.5} and D∝C0.5D \propto C^{0.5}. Bigger model + more data beats just a bigger model.

Why transformers beat CNNs and RNNs at scale:

  • Parallelism: self-attention on all tokens at once β€” GPU utilization is high.
  • Capacity: FC layers in the FFN store information densely.
  • Expressiveness: attention weights are input-dependent (unlike convolution weights, which are fixed after training).

The cost: O(T2)O(T^2) memory in attention limits context. Flash Attention (2022) reorders computation to use O(T)O(T) memory via hardware-aware tiling β€” enabling 100k-token contexts on modern hardware.

Check your understanding

The lesson ends with a 5-question quiz. Take it in the player above to see your score.

  1. In scaled dot-product attention, why is the dot product divided by $\sqrt{d_k}$?
    • To normalize the output values to the range [0, 1] like a probability.
    • To prevent the dot products from growing large with dimension, which would push softmax into saturation and create near-zero gradients.
    • To ensure the attention weights sum to $d_k$ rather than 1.
    • To reduce the computational cost of the matrix multiply from $O(T^2 d_k)$ to $O(T^2)$.
  2. What is the time and space complexity of standard self-attention with respect to sequence length $T$?
    • $O(T \log T)$ β€” the attention matrix is computed using FFT.
    • $O(T)$ β€” each token attends only to its neighbors.
    • $O(T^2)$ β€” every token attends to every other token, producing a $T \times T$ matrix.
    • $O(T \cdot d_{\text{model}})$ β€” linear in sequence length.
  3. Why do transformer decoders use causal (masked) self-attention during training?
    • To reduce memory usage by computing only half the attention matrix.
    • To prevent position $t$ from attending to future positions $> t$, preserving the autoregressive left-to-right generation property.
    • Because causal masking improves translation quality by forcing the model to focus on the source sentence.
    • To implement the positional encoding by masking positions based on their sinusoidal values.
  4. Multi-head attention with 8 heads and $d_{\text{model}} = 512$ uses $d_k = 64$ per head. Compared to single-head attention with $d_k = 512$, which statement is true?
    • Multi-head attention has 8x more parameters because it runs 8 separate heads.
    • Multi-head attention captures diverse relationship types in parallel while keeping total parameter count comparable.
    • Single-head attention is more expressive because it uses larger $d_k$.
    • Multi-head attention is always faster because each head processes a smaller dimension.
  5. Sinusoidal positional encodings are added to input embeddings. What property motivates this specific choice over simply appending a position integer?
    • Sinusoids are bounded between -1 and 1, preventing gradient explosion from large position values.
    • Sinusoids enable relative position $pos_1 - pos_2$ to be expressed as a linear combination of the encodings, and allow generalization to longer sequences than seen during training.
    • Sinusoids are differentiable, whereas learned embeddings are not.
    • Sinusoidal encodings can be computed once and cached, saving computation compared to learned embeddings.

Related lessons