Kiru Lab / Mechanistic Interpretability / Features and Representation
Features, Directions, and Superposition
A feature is a direction in activation space. Models pack more features than dimensions, and that is why neurons look confusing.
Concept · about 40 minutes
The working hypothesis of the field is that models represent features as directions in activation space, and that a feature is present when the activation vector has a large component along its direction. Note the immediate consequence: a feature need not align with any single neuron, because a neuron is just one basis vector of an arbitrary coordinate system.
Superposition
A layer with 4096 dimensions can represent far more than 4096 features, provided most features are rare and rarely co-occur. Near-orthogonal directions in high-dimensional space are plentiful, and the interference between them is tolerable when activations are sparse. Models exploit this aggressively, and the result is polysemanticity: individual neurons fire for several unrelated things, because they are participating in several superposed features at once.
- A neuron that activates on Python code, on legal citations, and on chess notation is not confused. It is one coordinate of three different feature directions.
- Reading individual neurons therefore gives a systematically misleading picture of what a layer represents.
- Sparse autoencoders attempt to recover the feature basis by learning an overcomplete dictionary in which activations become sparse — trading a compact confusing basis for a large legible one.
import numpy as np
rng = np.random.default_rng(0)
d, n_features = 64, 2000
directions = rng.normal(size=(n_features, d))
directions /= np.linalg.norm(directions, axis=1, keepdims=True)
gram = directions @ directions.T
np.fill_diagonal(gram, 0.0)
print(f"max |cosine| between any pair: {np.abs(gram).max():.3f}")
# 2000 directions in 64 dimensions, and no pair is more than weakly aligned.
# That headroom is the resource superposition spends.The activation basis is not privileged. Neurons are an artifact of how the computation was written down, not of what it means. Any interpretability method that treats the neuron basis as meaningful is reading a coordinate system rather than a mechanism.
Hold on to
- Features are directions; neurons are arbitrary basis vectors
- Superposition packs many features into fewer dimensions
- Polysemantic neurons are the expected consequence, not an anomaly
Work through
Try each one before opening the solution. Getting it wrong first is most of where the learning happens.
-
Run the near-orthogonality experiment across dimensions 16, 64, 256 and plot maximum pairwise alignment against dimension.
Hint
Generate random unit vectors, take the Gram matrix, and read off the largest off-diagonal magnitude.
Solution
Maximum pairwise alignment falls sharply as dimension grows: cramped and highly interfering at 16 dimensions, comfortable at 64, and near-orthogonal at 256 even with thousands of directions. That headroom is the resource superposition spends — a model can store many more features than it has dimensions provided they are sparse enough that interference rarely matters. It also means the number of features is not bounded by the number of neurons, which is why counting neurons tells you nothing about capacity.
import numpy as np rng = np.random.default_rng(0) for d in (16, 64, 256): dirs = rng.normal(size=(2000, d)) dirs /= np.linalg.norm(dirs, axis=1, keepdims=True) gram = dirs @ dirs.T np.fill_diagonal(gram, 0.0) print(f"d={d:4d} max|cos|={np.abs(gram).max():.3f} " f"mean|cos|={np.abs(gram).mean():.4f}")Check your work
Paste this after your own code. If it runs without raising, you have it.
import numpy as np rng = np.random.default_rng(0) def max_align(d, n=2000): v = rng.normal(size=(n, d)); v /= np.linalg.norm(v, axis=1, keepdims=True) g = v @ v.T; np.fill_diagonal(g, 0.0) return np.abs(g).max() assert max_align(256) < max_align(16) print("ok") -
Find a polysemantic neuron in a small open model by collecting its top-activating inputs. Name at least two unrelated triggers.
Hint
Run a corpus through the model, record one neuron's activation per token, and take the top 50.
Solution
You will typically find a neuron whose top activations span genuinely unrelated contexts — a programming construct, a phrase in another language, and a formatting pattern, say. The temptation is to invent a story that unifies them; resist it. The straightforward reading is that this neuron is one coordinate shared by several superposed feature directions, and no single label describes it because no single feature owns it.
import torch activations = [] handle = model.blocks[LAYER].mlp.register_forward_hook( lambda m, i, o: activations.append(o[0, :, NEURON].detach())) with torch.no_grad(): for batch in corpus_batches: model(batch) handle.remove() flat = torch.cat(activations) top = flat.topk(50).indices # Map those positions back to their tokens and read the contexts.
Sign in to track your progress through the lab.