kefirski.me
COLMPaper 1420259 min read

Teach Old SAEs New Domain Tricks with Boosting

A small second autoencoder learns only what a pretrained sparse autoencoder misses on a new domain, so interpretability extends without retraining and general performance does not move.

The dictionary only knows its corpus

A sparse autoencoder turns one dense activation vector into a handful of named ingredients. It reconstructs an activation xx as x^=Wdecσ(Wencx+benc)+bdec\hat{x}=W_{\mathrm{dec}}\,\sigma(W_{\mathrm{enc}}x+b_{\mathrm{enc}})+b_{\mathrm{dec}}, where the columns of WdecW_{\mathrm{dec}} are feature directions and σ\sigma keeps only a few of them active. Read the active features and you can see what the model is representing, one concept at a time.

The catch is that the dictionary is learned from a corpus. Concepts that rarely dominate the training data never earn a direction, so an SAE trained on general web text goes partially blind on chemical nomenclature, diplomatic language, or another writing system, even when the underlying model handles them fine. On Russian text our general-web SAE explains only 0.455 of activation variance. The model is not confused there; our microscope is.

The obvious fixes are expensive or destructive. Scaling the dictionary until rare concepts reliably appear takes features on the order of billions, as Templeton and colleagues observed. Retraining on domain text risks catastrophic forgetting, and fine-tuning a handful of freshly initialized features gives no guarantee that they land on what is actually missing. We wanted the missing features, exactly those, and nothing else touched.

Train on the error, not the domain

Whatever the pretrained SAE misses is sitting in plain sight: it is the reconstruction error e=xx^e=x-\hat{x}. So we freeze the general SAE and train a second, much smaller one to predict that error on domain text. The booster reads the same activation xx and outputs e^=Wdecresσ(Wencresx+bencres)\hat{e}=W^{\mathrm{res}}_{\mathrm{dec}}\,\sigma(W^{\mathrm{res}}_{\mathrm{enc}}x+b^{\mathrm{res}}_{\mathrm{enc}}), trained with the standard objective ee^22+λLreg\|e-\hat{e}\|_2^2+\lambda\,\mathcal{L}_{\mathrm{reg}}. Gradient boosting, applied to interpretability.

One activation, two dictionaries

The mechanism
The general SAE never changes; the booster is trained only against its error on domain text. Summing the training-time pieces is exactly the inference-time model, so nothing learned ever competes with an existing feature.

Two design choices keep the booster polite. It has no decoder bias, so when none of its features fire it adds exactly nothing. And it is tiny: 1,024 features with k=5k=5 active per token, next to k=50k=50 in the frozen base. At inference we simply add the outputs, xx^+e^x\approx\hat{x}+\hat{e}, and because each booster only ever modeled error, boosters for different domains stack: xx^+ie^(i)x\approx\hat{x}+\sum_i\hat{e}^{(i)}.

Adaptation as a plug-in

Modularity
Each booster is trained independently against the same frozen base, so any subset can be attached at inference. Running all three at once costs UN-debates quality 0.004 of explained variance relative to the single-domain booster.

Three domains, two backbones, one recipe

Explained variance on domain text

explained variance
pretrained SAE+ SAE Boost
Explained variance on domain text Qwen-2.5-7B activations, layer 24. The booster recovers variance the frozen SAE cannot express: +25.4 percent on chemistry, +59.3 percent on Russian, +11.4 percent on UN debates. chemistry: pretrained SAE 0.571; + SAE Boost 0.716 Russian: pretrained SAE 0.455; + SAE Boost 0.725 UN debates: pretrained SAE 0.693; + SAE Boost 0.774 00.20.40.60.8 0.571pretrained SAE: chemistry, 0.5710.716+ SAE Boost: chemistry, 0.716chemistry0.455pretrained SAE: Russian, 0.4550.725+ SAE Boost: Russian, 0.725Russian0.693pretrained SAE: UN debates, 0.6930.774+ SAE Boost: UN debates, 0.774UN debates explained variance
Qwen-2.5-7B activations, layer 24. The booster recovers variance the frozen SAE cannot express: +25.4 percent on chemistry, +59.3 percent on Russian, +11.4 percent on UN debates.

The language model agrees with the reconstructions too. Patching boosted reconstructions back into Qwen drops cross-entropy from 0.935 to 0.767 on chemistry, from 4.716 to 2.060 on Russian, and from 2.464 to 2.279 on UN debates. The same recipe applied to a public Llama Scope SAE moves chemistry from 0.551 to 0.702 explained variance, so the effect is not an artifact of our own base model.

The general domain barely notices. With a booster attached, explained variance on Fineweb-edu changes by at most 0.28 percent across all three domains and both backbones, and cross-entropy by at most 0.21 percent. The residual construction is doing what it promises: the new features live where the old model was silent.

Seven languages, one general-web SAE

explained variance
pretrained SAE+ SAE Boost
0.455 0.725
Russian
0.348 0.695
Japanese
0.532 0.735
Portuguese
0.543 0.742
Italian
0.568 0.744
Dutch
0.510 0.748
Polish
0.559 0.733
German
Every language improves, and the biggest jump belongs to Japanese, the language farthest from the English-heavy training corpus: from 0.348 to 0.695 explained variance.

Languages make the pattern vivid. The gain tracks distance from the training distribution, and the learned features respect linguistic structure: embedded and projected, booster features cluster with their language family, Slavic beside Slavic and Romance beside Romance, with Japanese in its own island. The boosters are not memorizing text; they are naming structure the base dictionary had no words for.

Against the obvious alternatives

General quality against domain quality

UN-debates explained variance
SAE Boost (ours)extended dictionarySAE stitchingfull fine-tuning
General quality against domain quality Upper right is better. Full fine-tuning wins the domain and forgets the general web, 0.719 to 0.515. Stitching keeps the general domain and barely adapts. Matching everyone at 1,024 added features and one billion tokens, the booster sits at the corner. SAE Boost (ours): SAE Boost, general 0.719, domain 0.774 extended dictionary: most-active init, general 0.714, domain 0.770; random init, general 0.716, domain 0.774 SAE stitching: stitching, general 0.719, domain 0.703 full fine-tuning: full fine-tuning, general 0.515, domain 0.850 0.650.710.770.820.880.480.550.620.690.76 most-active initextended dictionary: most-active init, general 0.714, domain 0.770random initextended dictionary: random init, general 0.716, domain 0.774stitchingSAE stitching: stitching, general 0.719, domain 0.703full fine-tuningfull fine-tuning: full fine-tuning, general 0.515, domain 0.850SAE BoostSAE Boost (ours): SAE Boost, general 0.719, domain 0.774 general-domain explained variance UN-debates explained variance
Upper right is better. Full fine-tuning wins the domain and forgets the general web, 0.719 to 0.515. Stitching keeps the general domain and barely adapts. Matching everyone at 1,024 added features and one billion tokens, the booster sits at the corner.

Full fine-tuning reaches the best domain score, 0.850, and pays with catastrophic forgetting: general explained variance collapses from 0.719 to 0.515. SAE stitching, which grafts the most-changed features of a fine-tuned copy back into the base, preserves the general domain but barely adapts, 0.703 against a no-adaptation baseline of 0.695. Extending the dictionary with 1,024 trainable features comes close to us but needs more active features per token, 64 against our 61, to get there.

Stacking is where the residual construction pulls away. With chemistry, Russian, and UN-debates boosters all attached, UN-debates quality holds at 0.770 and the general domain at 0.715. Stitching under the same triple load degrades to 0.670 on the domain and 0.674 in general, worse than doing nothing for the domain it was adapted to. Modularity is a property of the objective, not a deployment trick.

Are the new features real

Interpretability metrics say the boosted features are not reconstruction filler. Scored with automated detection and fuzzing evaluations over all 1,024 chemistry features, residual features average 0.75 detection against 0.67 for a matched sample of base features, and 0.68 against 0.64 on fuzzing. Reading them directly makes the point better than the scores do.

What the base dictionary offers instead

SAE Boost featureNearest base-SAE features by cosine similarity
Oxygen in chemical contextsnumerical thresholds; names of people; risk-related phrases
Chemical and thermal stabilitydurability references; legal protections; safety responsibilities
Supramolecular structure formationprotein databases; scientific measurements; mineralogy terms
Chemistry energy valueschemical reaction terms; calibration concepts; physics discussions
Hydrogen chemistrypersonal relationships; compound applications; synthetic processes
For five chemistry booster features, the three most similar directions in the general dictionary. The base model does not hold a worse version of these concepts; it holds nothing adjacent at all.

That table is the feature-blindness argument in miniature. The nearest base neighbors of oxygen in chemical contexts are numerical thresholds, names of people, and risk-related phrases: not a coarser oxygen feature, just unrelated directions. The residual signal is learnable precisely because the base dictionary spans none of it.

One practical warning from our training runs: an undertrained booster is worse than none. Below roughly 100 million tokens, half-formed features can cost the general domain up to 31 percent of explained variance; past 200 million tokens the interference drops under 1 percent. Boosters must converge before they are attached. And raising kk buys little: moving from 5 to 50 active features lifts domain quality only from 0.774 to 0.798 while the active-feature count nearly doubles, so we keep k=5k=5.

A frozen dictionary plus a small residual one covers a new domain for exactly the cost of the features it was missing, and nothing else moves.