Learning Objectives

  • Understand attention as a learned weighting mechanism
  • Implement scaled dot-product attention
  • Understand multi-head attention
  • Bridge the gap to Transformers (Module 6)

5.1 The Problem Attention Solves

In RNNs, all information must flow through a single hidden state vector. When translating a long sentence, the encoder must compress the entire input into one vector. Attention lets each output position directly access relevant parts of the input.

Example: translating "The quick brown fox jumps over the lazy dog" — each output word can attend (focus on) whichever input words are relevant, rather than pulling everything from a single summary vector.

5.2 Scaled Dot-Product Attention

The Formula

Attention(Q, K, V) = softmax(Q K^T / √d_k) · V Q — Queries: from decoder, "what am I looking for?" K — Keys: from encoder, "what information do I have?" V — Values: from encoder, "what is the content?" d_k — dimension of keys (scaling prevents softmax saturation)

Intuition

  • Compute similarity between each query and all keys (Q KT)
  • Scale by 1/√d_k to prevent softmax saturation at large dimensions
  • Softmax to get attention weights (probability distribution over positions)
  • Weight values by attention weights to produce output
Haskell — scaled dot-product attention
-- Scaled dot-product attention
attention
  :: Matrix Double      -- Q: queries  (seq_len_query, d_k)
  -> Matrix Double      -- K: keys     (seq_len_key, d_k)
  -> Matrix Double      -- V: values   (seq_len_value, d_v)
  -> Matrix Double      -- Output      (seq_len_query, d_v)
attention queries keys values =
  let d_k          = fromIntegral (cols keys)
      scores       = matmul queries (transpose keys)  -- (seq_q, seq_k)
      scaledScores = map (/ sqrt d_k) scores
      weights      = softmaxRows scaledScores         -- rows sum to 1
  in matmul weights values

-- Softmax per row for numerical stability
softmaxVector :: Vector Double -> Vector Double
softmaxVector vec =
  let maxVal  = maximum vec
      shifted = map (\x -> x - maxVal) vec  -- stability: subtract max first
      exps    = map exp shifted
      sumExps = sum exps
  in map (/ sumExps) exps

5.3 Multi-Head Attention

A single attention head can only attend to one type of relationship at a time. With h heads, the model can simultaneously attend to different aspects of the input (e.g., syntactic vs. semantic relationships).

MultiHead(Q, K, V) = Concat(head_1, ..., head_h) · W^O head_i = Attention(Q W_i^Q, K W_i^K, V W_i^V)
Haskell — multi-head attention
data MultiHeadAttention = MultiHeadAttention
  { numHeads          :: Int
  , d_model           :: Int
  , queryProjections  :: [Matrix Double]
  , keyProjections    :: [Matrix Double]
  , valueProjections  :: [Matrix Double]
  , outputProjection  :: Matrix Double
  }

multiHeadAttention
  :: MultiHeadAttention
  -> Matrix Double   -- Query
  -> Matrix Double   -- Key
  -> Matrix Double   -- Value
  -> Matrix Double
multiHeadAttention mha queries keys values =
  let queryHeads    = [matmul queries (queryProjections mha !! i) | i <- [0..numHeads mha - 1]]
      keyHeads      = [matmul keys   (keyProjections   mha !! i) | i <- [0..numHeads mha - 1]]
      valueHeads    = [matmul values (valueProjections mha !! i) | i <- [0..numHeads mha - 1]]
      headOutputs   = zipWith3 attention queryHeads keyHeads valueHeads
      concatenated  = horizontalConcat headOutputs
  in matmul concatenated (outputProjection mha)

5.4 Masked Attention

During generation, a model must not attend to future tokens (they don't exist yet). We apply a causal mask before the softmax — future positions are set to a large negative number so they receive near-zero attention weight.

Haskell — masked attention sketch
-- Mask future positions before softmax
maskedAttention
  :: Matrix Double   -- queries
  -> Matrix Double   -- keys
  -> Matrix Double   -- values
  -> Matrix Double   -- causal mask (1 = attend, 0 = block)
  -> Matrix Double
maskedAttention queries keys values mask =
  let d_k          = fromIntegral (cols keys)
      scores       = matmul queries (transpose keys)
      scaledScores = map (/ sqrt d_k) scores
      -- Set future positions to -1e9 before softmax
      maskedScores = elementwiseAdd
                       (elementwiseMultiply scaledScores mask)
                       (scalarMultiply (-1.0e9) (oneMinus mask))
      weights      = softmaxRows maskedScores
  in matmul weights values

Reading & Viewing

Essential paper

Attention Is All You Need (2017) Vaswani, Shazeer, Parmar, Uszkoreit, Jones, Gomez, Kaiser, Polosukhin The Transformer paper. Read this thoroughly — it is foundational. arxiv.org/abs/1706.03762
Neural Machine Translation by Jointly Learning to Align and Translate (2014) Bahdanau, Cho, Bengio The original attention mechanism (before Transformers). arxiv.org/abs/1409.0473

Video

Attention Is All You Need — Paper Explained Yannic Kilcher Step-by-step breakdown of the attention mechanism. YouTube

Blog

Attention? Attention! Lilian Weng (Lil'Log) Excellent visual walkthrough of attention variants. lilianweng.github.io
Attention and Augmented Recurrent Neural Networks Olah & Carter — Distill.pub distill.pub/2016/augmented-rnns/