Kiru Lab / Mechanistic Interpretability / Causal Methods
Probing: What a Classifier on Activations Can and Cannot Tell You
Training a probe shows information is present. It does not show the model uses it.
Concept · about 35 minutes
A probe is a small classifier — usually logistic regression, from track three — trained on a model's internal activations to predict some property. High probe accuracy shows that the property is linearly recoverable from that layer. That is a real and useful finding, and it is narrower than it is usually reported to be.
The core confound
Information being present is not the same as information being used. A probe can read a property out of a layer that no downstream component ever attends to. A sufficiently expressive probe can also extract structure that the model itself could not use — at which point you are measuring your probe, not the model.
- Keep probes linear unless you have a specific reason not to. A deep probe learns the task itself.
- Always include a control task: a probe trained on random labels establishes what accuracy your setup produces from nothing.
- Report selectivity — real-task accuracy minus control-task accuracy — rather than raw accuracy.
- Follow a probing result with a causal test. If the direction the probe found matters, intervening along it should change behavior.
from sklearn.linear_model import LogisticRegression
import numpy as np
probe = LogisticRegression(max_iter=2000).fit(activations, labels)
direction = probe.coef_[0] / np.linalg.norm(probe.coef_[0])
# The claim: this direction carries the property.
# The test: push activations along it and see whether the output moves.
def steer(activation, alpha):
return activation + alpha * direction
# If large alpha does not change the model's behavior on the property,
# the probe found something readable that the model does not read.This is the same warning as the logistic coefficient in track three and the attention weight in track five, now stated in its final form. Every convenient number that looks like an explanation must be converted into a prediction and tested by intervention before it counts. That conversion is the discipline this entire curriculum exists to teach.
Hold on to
- Probes establish availability of information, not use of it
- Control tasks and selectivity are mandatory, not optional
- A probing result becomes a claim only after a steering or patching test
Work through
Try each one before opening the solution. Getting it wrong first is most of where the learning happens.
-
Train probes for one property at every layer and plot accuracy against depth. Add the random-label control on the same axes.
Hint
Train the same probe at every layer, and a second probe on shuffled labels as the control.
Solution
Real-task accuracy typically rises through the early-to-middle layers and plateaus or falls near the output. The control probe sits near chance if your setup is sound — if it does not, your probe is memorizing and every number above it is inflated. Plot them together and report the gap, not the raw accuracy; that gap is selectivity and it is the only part of the result that means anything.
import numpy as np from sklearn.linear_model import LogisticRegression real, control = [], [] shuffled = np.random.default_rng(0).permutation(labels) for layer in range(n_layers): A = activations_at(layer) # (n_samples, d_model) real.append(LogisticRegression(max_iter=2000).fit(A, labels).score(A_test, labels_test)) control.append(LogisticRegression(max_iter=2000).fit(A, shuffled).score(A_test, shuffled_test)) import matplotlib.pyplot as plt plt.plot(real, label="task"); plt.plot(control, "--", label="random labels") plt.xlabel("layer"); plt.ylabel("probe accuracy"); plt.legend(); plt.show() -
Take your best probe direction and steer along it. Report whether behavior changed, and what you conclude either way.
Hint
Add alpha times the unit direction to the residual stream and sweep alpha.
Solution
Two outcomes and both are publishable. If behavior shifts systematically with alpha, the direction is used by downstream computation and the probe found something causal. If large alpha changes nothing while the probe still reads 95% accuracy, the information is present but unused — the probe found a readable correlate, not a mechanism. Report which one you got. The second result is the one most people quietly leave out, and it is the more informative of the two.
import torch def steer(model, ids, layer, direction, alpha): d = torch.as_tensor(direction, dtype=torch.float32) d = d / d.norm() handle = model.blocks[layer].register_forward_hook( lambda m, i, o: o + alpha * d) with torch.no_grad(): out = model(ids) handle.remove() return out for alpha in (-20, -5, 0, 5, 20): logits = steer(model, ids, LAYER, probe.coef_[0], alpha) print(alpha, measure_property(logits))
Sign in to track your progress through the lab.