ChatGPT Stockfish 19: Training der Engine:
Was sich beim NNUE-Training geändert hat
Stockfish 19 verwendet SFNNv16. Dabei wurde die Architektur nicht einfach größer gemacht, sondern gezielt verschlankt und gleichzeitig stärker:
Redundante Threat-Features wurden entfernt.
Dafür kamen neue Pawn-Pair-Features hinzu.
Das bisherige sekundäre NNUE-Netz, das seit Stockfish 16.1 verwendet wurde, ist wieder weggefallen.
Besonders interessant: Das Training verwendet jetzt Quantization-Aware Training (QAT).
Die neuen Trainingsmethoden wurden auf hunderten Milliarden Positionen angewendet.
Diese Positionen wurden durchgehend mit einem starken Leela-Chess-Zero-Netz neu bewertet („rescored“).
Stockfish
Der letzte Punkt ist meines Erachtens besonders spannend. Stockfish bewegt sich beim Training immer stärker weg von dem klassischen Schema
Stockfish spielt → Positionen sammeln → Stockfish-Evaluation als Trainingsziel
und hin zu einem heterogenen Trainingsdatensatz, bei dem Lc0 zusätzliche Bewertungsinformationen liefert. Schon bei Stockfish 18 wurde der Trainingsprozess automatisiert und reproduzierbar gemacht und es wurden mehr als 100 Milliarden Lc0-bewertete Positionen eingesetzt.
Stockfish
Was bedeutet „effektiver trainieren“ konkret?
Das ist wahrscheinlich genau das, worauf du hinauswillst.
Es geht nicht nur darum, mehr Positionen zu trainieren. Viel wichtiger ist das Verhältnis:
Rechenzeit → Trainingspositionen → Informationsgehalt → Spielstärke
QAT ist beispielsweise interessant, weil NNUE-Netze später mit stark quantisierten Gewichten sehr schnell auf der CPU laufen müssen. Anstatt ein Netz zunächst in hoher Präzision zu trainieren und anschließend zu quantisieren, wird die Quantisierung bereits während des Trainings berücksichtigt. Das kann dazu führen, dass das Netz seine Kapazität besser dafür nutzt, was in der späteren Integer-Auswertung tatsächlich relevant ist.
Und Stockfish 19 ist dabei laut Entwicklerteam nicht nur kleiner geworden: Gegen SF18 wurden in Tests bis zu 44 Elo Gewinn gemessen.
Stockfish
Noch interessanter: Die Trainingspipeline selbst
Wenn du dich für das „Wie trainiert man heutzutage ein Stockfish-NNUE?“ interessierst, würde ich sogar noch eine Ebene tiefer gehen.
Das Stockfish-Team hat bereits mit SF18 die Trainingspipeline grundlegend umgebaut. Das Training ist inzwischen automatisiert und reproduzierbar, sodass komplexe Trainingsstufen über standardisierte „Recipes“ miteinander verkettet werden können.
Und im aktuellen nnue-pytorch-Projekt sieht man, dass daran weiter intensiv gearbeitet wird – beispielsweise an höherem Training Throughput und neuen Scheduling-/Trainer-Implementierungen.
Das bedeutet: Die eigentliche Innovation liegt mittlerweile mindestens genauso in der Datenpipeline und dem Trainingsverfahren wie in der NNUE-Architektur selbst.
Wenn du möchtest, kann ich dir als Nächstes genau erklären, wie das Stockfish-19-NNUE trainiert wird – von der Erzeugung der Positionen über Lc0-Rescoring, Target-Werte, Loss, QAT bis zum fertigen .nnue-Netz. Das ist ziemlich faszinierend und man kann dabei auch gut verstehen, warum ein kleineres Netz stärker sein kann als ein größeres:
Ja. Ich würde das sogar etwas genauer formulieren als in meiner ersten Antwort: Der interessante Fortschritt bei Stockfish 19 ist nicht einfach „ein neues Netz“, sondern die ganze Trainingspipeline wird effizienter.
Ich gehe es einmal von unten nach oben durch.
1. Was bekommt das NNUE überhaupt als Eingabe?
Das NNUE sieht nicht einfach ein Schachbrettbild wie ein CNN.
Vereinfacht wird aus der Stellung eine große Menge diskreter Features erzeugt, insbesondere mit Informationen darüber,
wo die Könige stehen,
welche Figuren auf welchen Feldern stehen,
welche Figur relativ zu welchem König steht.
Das klassische Stockfish-NNUE benutzt dafür das HalfKP/King-Piece-Prinzip. Der große Vorteil: Nach einem Zug ändern sich nur relativ wenige Features. Deshalb kann Stockfish den sogenannten Accumulator inkrementell aktualisieren, anstatt das komplette neuronale Netz neu auszurechnen.
Das ist ein entscheidender Punkt:
Das NN muss nicht nur „gut“, sondern auch extrem billig auszuwerten sein.
2. Woher kommen die Trainingsstellungen?
Hier wird es richtig interessant.
Man erzeugt zunächst riesige Mengen von Schachstellungen. Aber eine Stellung allein ist noch kein gutes Trainingsbeispiel.
Das Netz braucht ein Target:
„Wie gut ist diese Stellung?“
Früher konnte man dafür relativ direkt die Stockfish-Suche verwenden. Das Problem ist aber offensichtlich: Dann trainiert Stockfish gewissermaßen darauf, Stockfish nachzuahmen.
Die moderne Pipeline versucht deshalb, bessere bzw. unterschiedlichartige Informationen in die Daten zu bekommen.
Die Stockfish-NNUE-Entwicklung arbeitet mittlerweile mit sehr großen Datensätzen und einer automatisierten Trainingspipeline. Im aktuellen nnue-pytorch-Projekt sieht man beispielsweise eigene Data-Loader, Validierungsdaten, verteiltes Training und automatisierte Tests.
3. Der wirklich interessante Teil: Lc0 als „zweite Meinung“
Hier kommt Leela Chess Zero ins Spiel.
Stockfish und Lc0 beurteilen eine Stellung auf grundsätzlich unterschiedliche Weise:
Stockfish:
Alpha-Beta-Suche + NNUE-Evaluation
Lc0:
neuronales Netz + MCTS
Wenn man nun sehr viele Stellungen von Lc0 bewerten lässt, bekommt man eine Art zweite Perspektive auf die Schachstellung.
Das ist enorm wertvoll.
Denn wenn man ausschließlich Stockfish-Daten verwendet, besteht die Gefahr, dass das neue NN nur immer besser darin wird, die Eigenheiten des bisherigen Stockfish-Evaluators zu reproduzieren.
Mit Lc0-Rescoring erhält man zusätzliche Information darüber, wie ein anderes starkes Such-/Netzsystem die Stellung einschätzt.
4. Warum nicht einfach Lc0 als Lehrer nehmen?
Weil das ebenfalls nicht optimal wäre.
Man möchte nicht:
„Stockfish NNUE soll Lc0 kopieren.“
Das Ziel ist vielmehr, aus den unterschiedlichen Informationsquellen ein besseres Trainingssignal zu erzeugen.
Man kann sich das ungefähr so vorstellen:
Schachstellungen
│
┌─────────┴─────────┐
│ │
Stockfish Lc0
Analyse Analyse
│ │
└─────────┬─────────┘
│
Trainingsdaten
│
▼
NNUE Training
│
▼
neues NN
│
▼
Spieltests / SPRT
│
stärker?
/ \
ja nein
│ │
behalten verwerfen
Das Entscheidende ist also die Datenqualität, nicht bloß die Zahl der Trainingspositionen.
5. Und jetzt kommt QAT
Das ist wahrscheinlich der technisch spannendste Punkt.
NNUE muss extrem schnell laufen.
Die Gewichte werden deshalb stark quantisiert – also beispielsweise von Fließkommazahlen auf Integer-Darstellungen reduziert.
Normalerweise könnte man folgendes machen:
FP32-Netz trainieren
↓
fertiges Netz
↓
quantisieren
↓
schnelles Integer-Netz
Das hat aber einen Nachteil.
Während des Trainings weiß das Netz nicht, dass seine Gewichte später quantisiert werden.
Es optimiert also für:
„Wie bekomme ich die beste FP32-Evaluation?“
und nicht unbedingt für:
„Wie bekomme ich die beste Evaluation unter den Einschränkungen meiner späteren Integer-Darstellung?“
6. Quantization-Aware Training
Bei QAT wird die spätere Quantisierung bereits während des Trainings simuliert.
Sehr vereinfacht:
Gewicht
│
▼
FP-Wert
│
▼
Quantisierung simulieren
│
▼
Integer-artiger Wert
│
▼
Netzberechnung
│
▼
Loss
│
▼
Backpropagation
Damit lernt das Netz:
„Mit diesen wenigen verfügbaren Quantisierungsstufen muss ich trotzdem möglichst viel Schachinformation erhalten.“
Das ist besonders interessant bei NNUE, weil hier Rechengeschwindigkeit und Speicherzugriffe extrem wichtig sind.
7. Warum kann ein kleineres Netz stärker sein?
Das klingt zunächst paradox.
Man könnte denken:
Mehr Neuronen = mehr Wissen = stärker.
Das stimmt bei diesen Netzen aber nicht zwangsläufig.
Ein zu großes Netz kann seine Kapazität auch dafür verwenden, Rauschen oder Besonderheiten des Trainingsdatensatzes zu lernen.
Ein kleineres Netz kann dagegen gezwungen sein, die wirklich wichtigen Zusammenhänge zu komprimieren.
Stell dir zwei Schüler vor:
Schüler A
merkt sich 10 Millionen konkrete Stellungen.
Schüler B
versteht Bauernstrukturen, Königssicherheit, Figurenkoordination, Raum, Initiative usw.
Für unbekannte Positionen kann B besser sein.
Genau deshalb sind Änderungen an den Features so wichtig.
Bei SFNNv16 wurden beispielsweise die bisherigen Threat-Features verändert bzw. entfernt und neue Pawn-Pair-Features eingeführt. Das ist kein „größer = besser“, sondern ein Versuch, die begrenzte Netzkapazität auf besonders informative Schachmerkmale zu konzentrieren.
8. Und hier wird die Sache für mich besonders spannend
Wenn man die Entwicklung betrachtet, verschiebt sich die eigentliche Forschungsfrage immer mehr von
„Wie groß muss das NN sein?“
„Welche Information geben wir dem NN überhaupt zum Lernen?“
Das ist ein gewaltiger Unterschied.
Man kann ein Netz mit
besseren Features,
besseren Targets,
besserer Datenverteilung,
besserer Quantisierung,
besserem Sampling,
besserem Training
deutlich stärker machen, ohne es einfach immer größer zu machen.
Dass im aktuellen Stockfish-NNUE-Projekt parallel sogar am Training-Data-Loader, verteiltem Training und höherem Durchsatz gearbeitet wird, zeigt ziemlich gut, dass inzwischen die gesamte Pipeline optimiert wird.
9. Der vielleicht wichtigste Punkt: Daten sind heute der Engpass
Wenn du beispielsweise
100 Milliarden schlechte Positionen
hast, heißt das nicht automatisch, dass du ein gutes NN bekommst.
Interessanter wären vielleicht:
10 Milliarden sehr gut ausgewählte Positionen.
Deshalb sind Fragen wie
Welche Stellungen kommen überhaupt in den Datensatz?
Wie häufig kommen taktische Positionen vor?
Wie häufig Endspiele?
Wie werden triviale Stellungen herausgefiltert?
Wie werden ähnliche Positionen behandelt?
Welche Such-Tiefe wurde verwendet?
Wie werden Lc0 und Stockfish kombiniert?
Welche Targets verwendet man?
Wie stark gewichtet man verschiedene Positionen?
mindestens so wichtig wie die reine Anzahl der Positionen.
Und hier könnten wir noch eine Ebene tiefer gehen
Wenn dich Computerschach technisch interessiert, kann ich dir als Nächstes den eigentlichen Trainingsvorgang anhand eines konkreten Beispiels zeigen:
eine einzelne Schachstellung → Stockfish/Lc0 erzeugen Target → NNUE berechnet Output → Loss → Backpropagation → Gewichtsänderung → Quantisierung → fertiges .nnue
Und dabei kann ich auch erklären, was ein NNUE-Feature wie HalfKP/Pawn-Pair tatsächlich mathematisch bedeutet und warum der Accumulator Stockfish so schnell macht.
Das wäre meiner Meinung nach der spannendste nächste Schritt.