Stockfish interpretation
Actively under development: methods, results and the atlas are still changing.
Actively under development. Known errors in some records are not yet corrected, and the criteria may change.
What is being interpreted
Stockfish 17.1 evaluates positions with NNUE (efficiently updatable neural network) nets. This writeup and the atlas cover the smaller of its two nets. King-relative piece-square inputs feed 128 accumulator neurons per side. Pair j (0 to 63) multiplies accumulator neurons Aj (neuron j) and Bj (neuron j + 64) after clipping each to the range 0 to 127. The pair values feed one of 8 layer stacks, chosen by piece count, each with fully connected layers fc0 and fc1 and a skip channel. That gives 576 units: 64 pairs, 128 factors (the A and B neurons), 120 fc0, 8 skip and 256 fc1. Of these, 19 fc1 units are dead (firing rate below 0.01%) and have no hypothesis, leaving 557 live.
The question is whether such a network can be read unit by unit. The work rests on an integer PyTorch replica that matches the engine exactly, at every intermediate value, on 10,000 test positions.
How the data was sourced
My first database took 62% of its positions from the Lichess analysis (evaluation) database. That source mixes real game positions with board-editor setups and records no provenance. Those positions dominated many units' extreme examples, so I rebuilt the database. It now has 3,215,779 positions, of which 2,897,376 are natural:
| Natural source | Positions | Share |
|---|---|---|
| Rated human Lichess games, September 2026 | 1,655,447 | 57.1% |
| Official Lichess puzzles | 598,967 | 20.7% |
| Stockfish 17.1 self-play, 2,000 nodes per move | 363,993 | 12.6% |
| Stockfish 17.1 self-play, 50,000 nodes, from Lichess game openings | 230,102 | 7.9% |
| Lichess games against engine (BOT) accounts | 48,867 | 1.7% |
The remainder is almost all synthetic (random moves added, pieces removed, positions just after random self-play openings) and is kept out of examples and tests, apart from a separately reported robustness check. The train/held-out split is drawn by game and leaves 291,874 natural held-out positions. The Lichess game and puzzle exports are released under the CC0 license, according to the Lichess open database page.
Concept probes: a baseline without language models
The baseline is a hand-coded library of 292 chess concepts (material, king safety, pawn structure, threats) plus 87 terms from Stockfish 15.1's classical evaluation. Each unit gets rank correlations and a sparse linear (Lasso) probe over these 379 features. These give any description something to beat.
How the agents form hypotheses
The method follows Nick Cammarata's "Neural networks are already clean" (Goodfire, October 2026).
One model, gpt-6-luna, wrote every hypothesis in the atlas. Its first prompt for a unit draws only on training positions and shows:
- examples spread across activation ranks, at both poles for units with signed values, each as an image, a FEN string (standard chess position notation), a text board and a piece list;
- the positions where zeroing the unit (for a factor, its pair) changes the evaluation most, and a table of how concepts differ between poles;
- the results of single-piece edits run through the network;
- the hypotheses already written for a pair's factors or for a stack unit's strongest inputs;
- for factors and pairs, a digest of the unit's largest weights.
It returns a sentence saying what the unit distinguishes, plus a Python function f(board, perspective, c) whose output should rise with the unit's activation. Here board is the position, perspective the side the unit belongs to, and c the concept values. The code runs in a restricted sandbox.
How the hypotheses are tested
All tests use held-out natural positions:
- Fidelity: the mean AUC (area under the receiver operating characteristic curve) with which f separates the unit's top 1% of samples, and its bottom 1% if the unit is signed, from random samples.
- Edit test: the Spearman correlation ρ between the change in f and the change in true activation, over single-piece edits of extreme positions.
- Specificity: where the unit ranks within its layer group by how closely f tracks it.
A unit is solved if fidelity is at least 0.85, ρ is at least 0.3 and specificity is in the top 3. It is partial if fidelity is at least 0.70. A hypothesis that is not solved gets up to 3 revisions, each shown its scores and held-out boards and edits where it disagrees with the unit. The best round is then re-scored on a separate confirmation set that excludes the selection positions and the games of every board the explainer saw. The full run cost $7.00 over 2,618 model calls.
Results
146 of 557 live units (26%) are solved and 378 are partial. Factors do best (55 of 128) and pairs worst (9 of 64). Audits and controls lower that figure:
- Audits: a re-validation of 60 sampled records, using no language model, rebuilt their evaluation sets and reproduced the recorded numbers, then re-tested each unit on fresh positions and checked each description against the data and the code. Most sampled solved factors hold up (5 of 6), but only 5 of the 9 solved pairs survive strictly, and only 4 of 18 sampled solved stack units are confirmed as better than a library concept. Material balance alone meets the fidelity and edit conditions for 105 of 365 live stack units. My rough extrapolation is that about 70 of 557 units (7–17%) have a description that is correct and more than a library concept.
- No-digest rerun: without the weight digest, solved factors fall from 55 to 34 while solved pairs stay at 9. Most factor descriptions come from activation data; the digest lifts borderline ones over the thresholds. Counting only no-digest factors would cut their part of the estimate above from about 46 to about 28.
- Chess-blind control: on 50 units, an explainer given abstract tokens and no chess vocabulary solved 9, against 24 for the normal explainer.
Activation fit is not behavioral fidelity
The clearest limitation appears when pairs are replaced by calibrated scorers and the rest of the network is run exactly. Variance retained is an R²-style measure on the positional output, over 20,000 held-out positions. Elo comes from matches at a search depth of 2 plies (one move by each side) against the original net over 100 opening pairs.
| All 64 pairs replaced by | Positional variance retained | Elo (95% interval) |
|---|---|---|
| Concept probes | 0.257 | −104 (−149, −58) |
| LLM hypotheses | 0.161 | −207 (−266, −160) |
| A constant per pair | −0.043 | −200 (−260, −149) |
In these matches the hypotheses do no better than constants. They win on sparse, square-specific pairs (pair 37 reaches activation R² 0.64 against 0.04 for its probe). They lose on the material pairs that carry most of the variance. Fidelity correlates with activation R² (Spearman 0.47) but not with the advantage over the probe (−0.08), so a high atlas score does not predict good replacement. Two-ply Elo is coarse (a linear concept fit ties the net), so it is a sanity check, not a measure of strength.
Ablation by category is also inconclusive: zeroing the 286 units labeled "material" removes 91% of positional variance, but no more than random groups of the same make-up.
Other limitations
- Stockfish 17.1 only uses this net when its simple material evaluation is lopsided (above 962 in absolute value). I estimate that covers about 19% of natural positions, and that regime has not been analyzed separately.
- Tail AUC measures separation of the extremes, not tracking of the whole activation, and statuses near a threshold flip between evaluation sets.
- One explainer and one concept vocabulary produced every description, so "undescribed" may reflect their limits.
What is unfinished
- Correcting known bad records. The atlas still shows pair 41 and pair 49 as solved, though the audits found pair 41's description wrong and pair 49 only partial; a few others have scorer bugs.
- Tightening "solved" (stack units should beat the best single concept), adding a replacement criterion, and measuring run-to-run model noise.
- Re-analysing the existing records on the positions where the engine actually uses this net.