Circuits: tracing a behaviour
Find which parts of a model cause a behaviour by swapping activations between runs. Induction heads are the classic worked example.
In 60 seconds
Circuits: tracing a behaviour
Find which parts of a model cause a behaviour by swapping activations between runs. Induction heads are the classic worked example.
Activation patching
- 1
Clean run
Run a prompt where the model does the behaviour, for example completes "The Taj Mahal is in the city of" with "Agra". Save all activations. - 2
Corrupted run
Run a similar prompt that breaks it, for example with a different monument. The answer changes. - 3
Patch
Run the corrupted prompt again, but replace one component's activation with its value from the clean run. - 4
Measure
How much of the gap between clean and corrupted output does that patch restore? - 5
Repeat
Do this for every component. The ones that restore a lot are candidates for the circuit.
Patching a toy network
import numpy as np
rng = np.random.default_rng(1)
W1 = rng.normal(size=(8, 6)) # input (6) -> hidden (8)
w2 = rng.normal(size=8) # hidden (8) -> one output score
def run(x, patch=None):
h = np.maximum(0, W1 @ x) # hidden activations
if patch is not None: # patch = (unit index, value to force)
i, v = patch
h = h.copy()
h[i] = v
return w2 @ h, h
clean = rng.normal(size=6) # e.g. a prompt where the model answers well
corrupt = clean.copy()
corrupt[2] += 3.0 # change one "token" of the input
y_clean, h_clean = run(clean)
y_corrupt, _ = run(corrupt)
print(f"clean output {y_clean:.2f}, corrupted output {y_corrupt:.2f}")
# Patch one hidden unit at a time from the clean run into the corrupted run.
for i in range(8):
y_patched, _ = run(corrupt, patch=(i, h_clean[i]))
recovered = round((y_patched - y_corrupt) / (y_clean - y_corrupt), 3) + 0.0
print(f"unit {i}: recovers {recovered:6.1%} of the gap")A classic example: induction heads
- They are usually described as a two-part circuit. An earlier previous-token head writes "the token before me was A" into each position. A later induction head then searches for positions whose previous token matches the current one, and copies what is there.
- Researchers have found heads like this in many transformer models, from tiny ones to large ones.
- In studies of training, they tend to appear fairly suddenly, around the same time the model gets better at using earlier context in the prompt. This links them to in-context learning, though they are not thought to be the whole story.
Watch and read more
Lab
Patching results on a toy network, and a test of what happens when two units back each other up.
The problem
Use the code block from this lesson as your starter (needs numpy).
- Run it and list the units that recover most of the gap. Do the recovered shares add up to about 100%? Why might they, in this toy?
- Change the corruption to
corrupt[4] += 3.0. Do different units matter now? - Add redundancy: after creating
W1, copy the row of the most important unit into another row (W1[j] = W1[i]) and setw2[j] = w2[i]. Patch each unit alone, then patch both together. What do you see? - Write three sentences on what this means for finding circuits in large models.
You are done when
Hard questions
Try to answer before you reveal. If you can answer these, you understood the lesson.
Q1Your patching experiment shows head 5.3 restores most of the behaviour. A teammate concludes "head 5.3 is the circuit." What else should you check?Reveal
Whether the result holds on many prompt pairs, not one; whether other components matter when patched together (interactions and backups); what head 5.3 reads from and writes to, so you know its inputs and which later parts use its output; whether ablating it hurts the behaviour on new prompts; and whether the effect depends on your choice of corrupted prompt. A circuit is a path, not a single part.
Q2Why does the choice of corrupted prompt matter so much in patching?Reveal
Patching measures the effect of the difference between the two runs. If the corrupted prompt changes only the name of the monument, you find components that carry that fact. If it also changes grammar or length, you also find components for those, and mix up the story. Different corruptions answer different questions, so you must choose them to match the claim you want to test.
Questions people ask
What is the difference between patching and ablation?
Ablation removes a component's signal (sets it to zero or to its mean) and sees what breaks. Patching swaps in the activation from a different, carefully chosen run. Patching is more targeted, because the only difference between the runs is the thing you changed in the prompt.
Why do the clean and corrupted prompts need to be so similar?
So that the difference in output comes from one controlled change. If the prompts differ in length or in many words, many components will change for unrelated reasons, and the results become hard to read.
Isn't patching every component very slow?
It can be, since each patch needs a forward pass. Researchers use faster approximations based on gradients to shortlist components, then confirm the important ones with real patching. Approximations can be wrong, so confirmation matters.
Can I find induction heads in my tiny GPT?
Often, yes, if it has at least two layers and is trained on text with repetition. Feed it a random sequence of tokens repeated twice, and look for heads that, in the second copy, attend to the token right after the earlier match. Then ablate them and see if predicting the repeated half gets worse.
Lesson test
5 questions. Get 3 right (60%) to pass and complete this lesson.