summaryrefslogtreecommitdiff
path: root/src/testnnue.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/testnnue.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/testnnue.c')
-rw-r--r--src/testnnue.c31
1 files changed, 17 insertions, 14 deletions
diff --git a/src/testnnue.c b/src/testnnue.c
index fdfaf35..4ee516d 100644
--- a/src/testnnue.c
+++ b/src/testnnue.c
@@ -30,6 +30,12 @@ Abstract:
afterward so this test has no side effect on anything that runs
after it in the same process.
+ g_rgfNnueWeight/g_rgfNnueBias are SHORT (quantized) and
+ NNUE_ACCUMULATOR.rgiValue is INT -- all integer arithmetic, so
+ incremental-vs-recompute comparison is exact (no float-rounding
+ tolerance needed, unlike the original float-accumulator version
+ of this test).
+
Author:
Scott Gasch ([email protected]) 15 Oct 2026
@@ -59,12 +65,12 @@ Routine description:
for (j = 0; j < NNUE_ACCUMULATOR_SIZE; j++)
{
g_rgfNnueWeight[i][j] =
- ((float)(i % 97) * 0.1f) + ((float)(j % 13) * 0.01f) + 1.0f;
+ (SHORT)(((i % 97) * 10) + ((j % 13) * 1) + 100);
}
}
for (j = 0; j < NNUE_ACCUMULATOR_SIZE; j++)
{
- g_rgfNnueBias[j] = (float)(j % 7) * 0.5f;
+ g_rgfNnueBias[j] = (SHORT)((j % 7) * 50);
}
}
@@ -95,12 +101,10 @@ Routine description:
against ctx->sPosition and compares it element-by-element against
the incrementally-maintained ctx->sNnueAccum. Panics (via
UtilPanic, same convention as every other self-test) on any
- mismatch outside a small float-rounding tolerance -- real
- indexing/logic bugs produce large deltas (a whole missing or
- extra ~1-100-magnitude weight row), not rounding noise, so the
- tolerance only needs to be loose enough to absorb summation-order
- differences between the two paths, not loose enough to hide a
- real bug.
+ mismatch. Integer arithmetic throughout (SHORT table, INT
+ accumulator) means incremental and from-scratch recompute must
+ match EXACTLY -- no rounding tolerance needed or wanted; any
+ nonzero delta is a real indexing/logic bug.
Parameters:
@@ -114,7 +118,6 @@ Return value:
**/
{
- static const float EPSILON = 0.01f;
NNUE_ACCUMULATOR sFresh;
ULONG uColor;
ULONG i;
@@ -124,16 +127,16 @@ Return value:
NnueAccumRecompute(&sFresh, &ctx->sPosition, uColor);
for (i = 0; i < NNUE_ACCUMULATOR_SIZE; i++)
{
- float fDelta = sFresh.rgfValue[i] - ctx->sNnueAccum[uColor].rgfValue[i];
- if ((fDelta > EPSILON) || (fDelta < -EPSILON))
+ INT iDelta = sFresh.rgiValue[i] - ctx->sNnueAccum[uColor].rgiValue[i];
+ if (iDelta != 0)
{
Trace("TestNnueAccumulator: MISMATCH at %s, color=%lu, "
- "index=%lu: incremental=%f recompute=%f "
+ "index=%lu: incremental=%ld recompute=%ld "
"mv.uMove=0x%lx cFrom=0x%x cTo=0x%x pMoved=%u "
"pCaptured=%u pPromoted=%u bvFlags=0x%x FEN=%s\n",
szLabel, uColor, i,
- ctx->sNnueAccum[uColor].rgfValue[i],
- sFresh.rgfValue[i],
+ (long)ctx->sNnueAccum[uColor].rgiValue[i],
+ (long)sFresh.rgiValue[i],
mv.uMove, mv.cFrom, mv.cTo, mv.pMoved,
mv.pCaptured, mv.pPromoted, mv.bvFlags,
PositionToFen(&ctx->sPosition));