Method
the distillation loss, MCTS at inference, Elo bisection
The Loss
Stockfish plays self-games at fixed search-depth D = 15. At each
position, before the chosen move is played, the teacher reports its
multipv = 8 candidate moves with their centipawn scores. Those
scores are passed through a softmax at temperature T = 1 pawn to
produce a target distribution over the 8 candidates:
π(move_k) = softmax( cp_k / (100·T) )
The student is trained to match π (cross-entropy) and the eventual
game outcome z (MSE on [-1, +1]).
policy_loss = -(target_dist * F.log_softmax(logits, dim=-1)).sum(dim=-1).mean()
value_loss = F.mse_loss(value_pred, z)
total = policy_loss + 1.0 * value_loss
target_dist is the dense reconstruction of the sparse multipv
distribution. Padding for late-game positions with fewer than 8 legal
moves: multipv_indices[i, j] = -1 and multipv_logprobs[i, j] = -inf,
masked out by exp(-inf) = 0.
The choice of soft multipv targets vs hard one-hot targets is its own ablation — see Experiments → Soft vs Hard Targets.
Why The Student Can’t Exceed The Teacher
Stockfish at depth 15 is ~2,500 Elo, but its strength comes from calculating ~10 plies deep over millions of positions. The student is asked to predict the output of that search in a single forward pass. There’s no calculation, only a learned prior.
Empirically, supervised distillation lands ~600–800 Elo below the teacher. That’s the alpha-beta search contribution that can’t be transferred to a small ResNet. To close the gap requires either deeper search at inference time (a free +277 Elo, see Experiments → Search) or self-play RL on top (the Lc0 path, running now).
How We Measure Elo
The default for milestone checkpoints is Elo bisection — a binary
search over Stockfish’s UCI_Elo setting that converges to the score
near 0.5, where the Elo conversion is most accurate. The legacy
“fixed-anchor” approach (a single 100-game match against UCI=1,350)
is kept as a fast sanity check during training but isn’t authoritative.
The Formula
Each probe plays N games against a Stockfish opponent at fixed
UCI_Elo = O and computes the agent’s score s ∈ [0, 1] (W + ½·D out
of N). The agent’s Elo relative to the opponent is the inverse of the
logistic CDF:
ΔElo = -400 · log10(1/s - 1)
Elo = O + ΔElo
So a score of s = 0.5 puts the agent at the opponent’s Elo. A score
of s = 0.933 (the d15 baseline vs UCI=1,350) implies
-400 · log10(0.067/0.933) = +457, giving an absolute Elo of
1,350 + 457 = 1,807.
Worked example from a real result file:
=== eval vs Stockfish UCI=1350 ===
W/D/L: 93 / 8 / 3
score: 0.933 95% CI: [0.885, 0.981]
Elo gap to opponent: +457
Agent absolute Elo (anchor 1350): 1807 [1704, 2034]
The Elo CI is wide because at N=100 games the score CI is ±10 percentage points, which translates to a wide implied Elo range when the opponent is far from the agent’s strength. That’s the problem the bisection solves.
The Bisection
- Bracket:
lo = 1,350,hi = 2,800(covers all checkpoints to date). - Probe at the midpoint with N=104 games.
- If
score ≥ 0.5: agent is stronger thanmid→ raiselo. - If
score < 0.5: agent is weaker thanmid→ lowerhi. - Stop when bracket ≤ 100 Elo, or when a probe lands in
[0.45, 0.55](where the Elo conversion is sharpest).
Three to four probes converge to ±50 Elo precision in roughly 30–40
minutes on a g6.4xlarge. Implementation at
experiments/distill-soft/scripts/elo_bisect.py,
covered by 13 unit tests for the Elo math, bracket halving, stop
conditions, and end-to-end convergence on synthetic agents at 1,400 /
1,800 / 2,400 Elo.
Legacy: Fixed-Anchor Evals
Before bisection we used a simpler protocol: play 100 games at each of
two fixed UCI_Elo anchors (1,350 and 1,800) and report both
absolute Elos. This is what the auto-eval
daemon
still runs on every new checkpoint — fast, comparable across the
whole training run, but the Elo CI can be wide when the score is far
from 0.5. The bisection is the authoritative number for milestones.
Why Not Just Track Training Loss
Training loss and top-1 accuracy plateau by epoch 10, but Elo keeps climbing through epoch 20. The training objective and the play-strength objective aren’t perfectly aligned. Top-K accuracy of 87% sounds excellent; the actual Elo says the model is 1,807, not 2,500 (the teacher’s strength). The bridge between supervised metrics and game-playing Elo is uncertain, sometimes inverted, and worth measuring directly with games.