GenAI Course · Module 5 · Session 17

Motivation & Self-Attention

⏱ 12 min read🎯 Beginner friendly🖼 4 diagrams🧪 2 live demos🐍 Python code

Every modern LLM, from BERT to GPT to Claude, is built on one simple idea: let every word look at every other word. This idea is called self-attention. In this session, let us see why we needed it, and exactly what it computes.

In this session

  • Why RNNs found long sentences difficult, and why they were slow to train
  • The big idea: direct connections between all words
  • Query, Key and Value, explained with a YouTube search
  • What attention actually computes, step by step with real numbers
  • Self-attention from scratch in 10 lines of NumPy

01The problem with RNNs

Before transformers, language models were mostly RNNs (Recurrent Neural Networks) and their improved versions, LSTMs and GRUs. An RNN reads a sentence one word at a time, and carries a small “memory” vector from one word to the next.

RNN: one word at a time, memory passed along the chain The animal didn't cross · · · it h1h2h3h4h20 “animal”has faded Step 1 → Step 2 → Step 3 … each step must wait for the previous one.
By the time the RNN reaches “it”, the information about “animal” has passed through many steps and become weak.
📢

Like passing a message down a long line at a wedding. The first person says it clearly, but by the 20th person the message is half forgotten. RNNs had the same problem with long sentences.

RNNs had three big problems:

02The big idea: every word looks at every word

In 2017, the famous paper “Attention Is All You Need” removed recurrence completely. Instead of passing a memory along a chain, each word directly looks at all the other words and decides which ones matter for it.

Self-attention: direct links, all computed at the same time
“it” can reach “animal” in one step, and all words are processed in parallel.
RNN / LSTMSelf-attention
Reads wordsOne by oneAll at once (parallel)
Path from word 1 to word 2019 steps1 step
Training speed on GPUsSlowFast
Cost for long textGrows linearlyGrows with length² (we cover this in Session 19)

03Query, Key and Value

How does a word decide which other words matter? Self-attention gives every word three roles. The easiest way to understand them is a YouTube search.

Query“masala chai recipe” what you are looking for Masala Chai in 5 min Cold Coffee at Home Cricket Highlights Keys: the titles you compare with match 0.85match 0.14match 0.01 Values: the actual videos you get, mixed by match score
Query = what I want · Key = what each item offers · Value = the content I take away.

In self-attention, every word is all three at once. Each word creates its own query, key and value by multiplying its embedding with three learned weight matrices:

“it”embedding x × W_Q × W_K × W_V q: “who am I referring to?” k: “I am a pronoun” v: the information I carry
W_Q, W_K and W_V are learned during training. The labels in quotes are only intuition; the real vectors are just numbers.

04What attention actually computes

For one word, attention does three simple things:

  1. Score: compare its query with every word’s key using a dot product. High score = good match.
  2. Softmax: turn the scores into weights between 0 and 1 that add up to 1.
  3. Mix: take a weighted sum of all the value vectors. This is the word’s new, context-aware vector.

Let us do it with real numbers. Our sentence has three words, I love chai, and we compute the new vector for “chai”. Press Next to go step by step:

Demo · Attention by hand
Notice: “chai” gave most weight (0.665) to itself, but it also mixed in information from “love” and “I”. That mixing is how a word picks up context.

Now see it on a real sentence. Pick a word and watch where its attention goes:

Demo · Where does each word look?

05Self-attention from scratch in NumPy

Here is the whole idea in about 10 lines. Run it in Colab or Jupyter:

self_attention.py
import numpy as np
np.random.seed(42)

X = np.random.randn(4, 8)                     # 4 tokens, each an 8-number embedding
Wq, Wk, Wv = [np.random.randn(8, 4) for _ in range(3)]

Q, K, V = X @ Wq, X @ Wk, X @ Wv              # queries, keys, values
scores = Q @ K.T                              # how well each query matches each key
weights = np.exp(scores - scores.max(axis=1, keepdims=True))
weights /= weights.sum(axis=1, keepdims=True) # softmax, row by row
output = weights @ V                          # weighted mix of values

print(output.shape)
print(weights.round(2))
(4, 4) [[0.03 0. 0.52 0.45] [0. 0.75 0. 0.25] [0. 0.03 0.97 0. ] [1. 0. 0. 0. ]]

Each row of weights adds up to 1: it shows how much one token looks at each of the four tokens. Notice how extreme some rows are (0.97, 1.00). With bigger vectors, this gets worse. In Session 18 we fix it by scaling the scores.

06Summary

07Quick quiz

1. Why were RNNs slow to train on GPUs?

2. The attention score between two words is computed from…

3. After softmax, the attention weights for one word…

4. How many steps does “it” need to reach “animal” in self-attention?

5. What is the final output of attention for a word?

08References

Created by Ajeetkumar