summaryrefslogtreecommitdiff
path: root/src/nnueaccum.c
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-10-20 09:26:44 -0700
committerScott Gasch <[email protected]>2026-10-20 09:26:44 -0700
commitc8c6bbc2c1a103e5b07b079a0f8bdf66c7724d80 (patch)
treeb6c2137c9ac577fa83b1e948fa0311d53dfe445d /src/nnueaccum.c
parent3b5d3677bb14ae14728a1c4b221176bb83667d92 (diff)
Wire NNUE eval into search, build the training pipeline, and add a fast
move/eval-agreement benchmark against Stockfish (tests/lop) Implements the architecture decisions in src/docs/NNUE.md: HalfKAv2_hm feature set, int16/int8 quantization, per-ply accumulator backup for king moves, and a lazy-eval-ready integration into search.c/eval.c. Adds the full annotate_pgns/ training pipeline (extraction, K-fit/ labeling, quiet filtering, tensor building, training, export) plus an end-to-end orchestrator (run_nnue_pipeline.py) and validation tooling (sanity_check_net.py, compare_vs_stockfish_net.py). Adds tests/lop: a 10k-position list-of-positions benchmark comparing engine eval rank and move choice against pre-computed Stockfish/lc0 references, much cheaper than a full self-play match for day-to-day progress checks. First sd10-matched self-play result against classic HCE: LLR +2.28 (H1=+2.94), -72=119+169 over 360 games, confirming the net is "smarter per node" at matched depth. A real-time (--st 4) match is currently weaker (candidate loses ~3 plies of depth to a ~3.3-3.7x nps gap against an unrecalibrated search), consistent with NNUE.md's adoption-criterion section -- pruning/reduction constants still need retuning for the new eval's score scale before a fair real-time comparison is possible. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'src/nnueaccum.c')
-rw-r--r--src/nnueaccum.c30
1 files changed, 13 insertions, 17 deletions
diff --git a/src/nnueaccum.c b/src/nnueaccum.c
index 8f01692..7a3010f 100644
--- a/src/nnueaccum.c
+++ b/src/nnueaccum.c
@@ -34,16 +34,12 @@ Author:
#include "chess.h"
-// Placeholder embedding table -- see chess.h's extern declaration and
-// its own comment. Zero-initialized (C's static/global default), so
-// every accumulator is currently all-zero regardless of position;
-// real weight loading (reading annotate_pgns/nnue_train.py's trained
-// checkpoint) is separate, not-yet-built follow-up work. This is
-// sufficient to prove incremental-vs-recompute-from-scratch
-// correctness, which only depends on both paths reading the SAME
-// table consistently, not on its values being meaningful yet.
-float g_rgfNnueWeight[NNUE_DIMENSIONS][NNUE_ACCUMULATOR_SIZE];
-float g_rgfNnueBias[NNUE_ACCUMULATOR_SIZE];
+// Quantized embedding table -- see chess.h's extern declaration and
+// its own comment. Zero-initialized (C's static/global default) until
+// NnueLoadWeights reads a real exported checkpoint.
+SHORT g_rgfNnueWeight[NNUE_DIMENSIONS][NNUE_ACCUMULATOR_SIZE];
+SHORT g_rgfNnueBias[NNUE_ACCUMULATOR_SIZE];
+float g_fNnueFtScale = 1.0f;
void
NnueAccumAddFeature(NNUE_ACCUMULATOR *pAccum, ULONG uPerspective,
@@ -57,12 +53,12 @@ Routine description:
**/
{
int idx = NnueFeatureIndex(uPerspective, cKingOwn, cPieceSquare, pPiece);
- const float *pRow = g_rgfNnueWeight[idx];
+ const SHORT *pRow = g_rgfNnueWeight[idx];
ULONG i;
for (i = 0; i < NNUE_ACCUMULATOR_SIZE; i++)
{
- pAccum->rgfValue[i] += pRow[i];
+ pAccum->rgiValue[i] += pRow[i];
}
}
@@ -76,18 +72,18 @@ Routine description:
Subtracts one feature's weight row from *pAccum (in place). Hot
path -- the exact inverse of NnueAccumAddFeature, so that applying
- Add then Remove (or Remove then Add) for the same arguments is a
- no-op up to float rounding.
+ Add then Remove (or Remove then Add) for the same arguments is an
+ exact no-op (integer arithmetic, no float rounding to worry about).
**/
{
int idx = NnueFeatureIndex(uPerspective, cKingOwn, cPieceSquare, pPiece);
- const float *pRow = g_rgfNnueWeight[idx];
+ const SHORT *pRow = g_rgfNnueWeight[idx];
ULONG i;
for (i = 0; i < NNUE_ACCUMULATOR_SIZE; i++)
{
- pAccum->rgfValue[i] -= pRow[i];
+ pAccum->rgiValue[i] -= pRow[i];
}
}
@@ -125,7 +121,7 @@ Parameters:
for (i = 0; i < NNUE_ACCUMULATOR_SIZE; i++)
{
- pAccum->rgfValue[i] = g_rgfNnueBias[i];
+ pAccum->rgiValue[i] = g_rgfNnueBias[i];
}
// 0x88 COORs aren't a simple monotonic range (A1=0x70 > H8=0x07),