Sparse autoencoders
Learn a large dictionary of sparse features from a model's activations, so that each activation is explained by a few readable pieces.
In 60 seconds
Sparse autoencoders
Learn a large dictionary of sparse features from a model's activations, so that each activation is explained by a few readable pieces.
How it works
- 1
Collect activations
Run lots of text through the model and save, for example, the residual stream at one layer. - 2
Encode
Multiply by an encoder matrix and apply ReLU. This gives many feature values, most of them zero. - 3
Decode
Add up decoder directions, weighted by the feature values, to rebuild the activation. - 4
Train
Minimise reconstruction error plus a sparsity penalty (often an L1 penalty on the feature values). - 5
Interpret
For each feature, look at the inputs that make it fire most strongly.
The central trade-off
| If the sparsity penalty is... | Reconstruction | Features | Risk |
|---|---|---|---|
| Too weak | Very good | Many active at once, each mixed | Back to polysemantic mush |
| Balanced | Good | Few active, often readable | The sweet spot you search for |
| Too strong | Poor | Very few active | The SAE ignores real information |
A tiny SAE, trained by hand
import numpy as np
def sae_forward(xb, W_enc, b_enc, W_dec, b_dec, l1):
pre = (xb - b_dec) @ W_enc + b_enc
f = np.maximum(0, pre) # sparse feature values
x_hat = f @ W_dec + b_dec # rebuilt activation
recon = np.mean(np.sum((x_hat - xb) ** 2, axis=1))
sparsity = np.mean(np.sum(f, axis=1)) # L1 penalty
return f, x_hat, recon + l1 * sparsityInterpreting features
- Look at the top activating examples. A feature might fire on Devanagari script, on phone numbers, or on code comments.
- Check what the feature does: add its decoder direction to the activations and see how the model's output changes.
- Researchers often use a language model to write a first label from the top examples, then test the label on new text. Labels can be wrong, so testing matters.
Limits to keep in mind
- Dead features: some dictionary entries never fire on any input. They waste capacity. Training tricks exist to revive them.
- Not all features are found: the SAE never rebuilds activations perfectly. The leftover error may contain important features the dictionary missed.
- Features depend on choices: a bigger dictionary may split one feature ("sport") into several ("cricket", "football"). There is no single true list.
- Labels are guesses: a feature that seems to mean "Mumbai" may also fire on other things. Top examples can mislead.
- Cost: training SAEs on large models takes a lot of compute and data.
Watch and read more
Lab
A sparse autoencoder trained from scratch in numpy that recovers hidden features from synthetic activations.
The problem
Run the starter (needs numpy, runs in seconds). Then:
- Record how many true features were recovered, how many dictionary features are dead, and the variance explained.
- Change
l1to0.03and to1.0. For each, record active features per example, variance explained and features recovered. Describe the trade-off in two sentences. - Change
mto 16 (the same as the layer size). Does it still recover all 32 true features? Why not? - The SAE uses about 3 features per example, but the data has fewer than 2 true features on per example. Look at pairs of decoder rows with high cosine and explain what is happening.
Practice lab
Edit the code and run it. Python runs in your browser — nothing is sent to our server.
No output. Add print(...) to see values.
You are done when
Hard questions
Try to answer before you reveal. If you can answer these, you understood the lesson.
Q1On the toy data you can check recovered features against the truth. On a real model you cannot. What would you use instead to judge an SAE?Reveal
Several indirect checks: how much of the activation it reconstructs, and how much the model's loss gets worse when you replace the real activations with the SAE's reconstruction; how sparse the codes are; how many features are dead; whether features are interpretable when people or models label them and the labels predict firing on new text; and whether changing a feature changes the model's behaviour as expected. None is perfect alone.
Q2Why might a bigger dictionary split "cricket" into "batting", "bowling" and "IPL" features, and what does this say about the idea of a true list of features?Reveal
With more entries, the SAE can lower its loss by giving finer patterns their own direction, because each finer feature is still sparse and rebuilds some inputs more cheaply. So the features you get depend on the dictionary size and penalty. This suggests features may be organised at many levels of detail, and there may be no single correct list. The dictionary is a useful lens, not the model's own ground truth.
Questions people ask
Is a sparse autoencoder the same as the autoencoders used for compression?
No, almost the opposite. A compression autoencoder squeezes data into fewer numbers. A sparse autoencoder expands it into many more numbers, but forces most of them to be zero. The goal is readability, not compression.
Why normalise the decoder directions?
Without it, the SAE can cheat the L1 penalty: make feature values tiny and decoder directions huge, which gives the same reconstruction with a smaller penalty. Keeping each decoder direction at length 1 blocks this trick.
How do I know an SAE feature is real and not an artefact?
You cannot be fully sure. Good signs: it fires on a clear, consistent set of inputs; a label written from some examples predicts firing on new examples; and changing the feature changes the model's output in the expected way. Features that pass all three are more trustworthy.
Can I train an SAE on my tiny GPT?
Yes, and it is a good exercise. Save the residual stream at one layer over your training text, then train the lab code on it. The tiny GPT may have fewer clean features, but you will learn the workflow.
Lesson test
5 questions. Get 3 right (60%) to pass and complete this lesson.