summaryrefslogtreecommitdiff
path: root/src/chess.h
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-10-20 18:37:20 -0700
committerScott Gasch <[email protected]>2026-10-20 18:37:20 -0700
commit9cf14e14e6999420f234cda951894337e034f57c (patch)
treed4845d0cf127ef4226a5cd2e60472ee750213614 /src/chess.h
parentc8c6bbc2c1a103e5b07b079a0f8bdf66c7724d80 (diff)
NNUE: re-fit raw-to-score calibration, NNU4 weight format, super-lazy default-on, lazy probe measured net-negative
Fits an affine (a + b*raw) correction into every exported .nnue file (export_nnue_weights.py's CalibrateScoreMapping) so the engine's consumed centipawn output tracks Stockfish's real score scale rather than the net's nominal raw WDL-sigmoid output -- training variance alone shifts this mapping across retrains even with an identical recipe, so it's re-fit and baked in per export rather than assumed constant. Weight format bumped to "NNU4" to carry the two new floats; older NNU1/2/3 files are no longer readable. Super-lazy (material-only) pre-filter promoted to default-on (g_fUseNnueSuperLazy = TRUE) with a recalibrated per-material-bucket margin table (measured against the recalibrated net, 16-shard cross_sectional_200k.ep_ sample) -- real, measured nps win across all three curated suites. The separate lazy-probe gate (accumulator-based early exit) is measured net-negative on real search traffic at this net's probe-vs-forward latency ratio and stays off by default (g_fUseNnueLazyProbe = FALSE); code kept live since margin tuning could still flip this, per docs/NNUE.md. Also: direct per-call latency instrumentation for NnueProbeScore/ NnueForward (root.c, EVAL_TIME build) to make the lazy-probe breakeven math measurable directly instead of inferred; QSearch futility margins given real-data-derived NNUE_FULL/NNUE_LAZY starting points. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'src/chess.h')
-rwxr-xr-xsrc/chess.h25
1 files changed, 25 insertions, 0 deletions
diff --git a/src/chess.h b/src/chess.h
index 3e65e7f..34099b2 100755
--- a/src/chess.h
+++ b/src/chess.h
@@ -1431,6 +1431,25 @@ typedef struct _COUNTERS
UINT64 u64CyclesSuperLazyExit;
UINT64 u64CyclesLazyExit;
UINT64 u64CyclesFullEvalExit;
+
+ // 2026-10-20: direct per-call latency of the two NNUE eval
+ // primitives (nnueeval.c), as opposed to the HCE-oriented
+ // whole-path-cost counters above (which NNUE's Eval() branch
+ // doesn't feed -- it's gated on g_fUseNnueEval at runtime, not
+ // #ifdef LAZY_EVAL). u64CyclesNnueProbeCall/u64CyclesNnueForwardCall
+ // time just the TIMED_EVAL_CALL-wrapped NnueProbeScore()/
+ // NnueForward() calls themselves (eval.c's production NNUE
+ // branch); u64NnueProbeAttempts counts every probe call made
+ // (hit or miss) -- unlike u64LazyEvals, which only counts
+ // hits -- needed as the denominator for a true avg-cost-per-
+ // attempt (the question that actually matters for judging
+ // whether the gate pays for itself: cost is paid on every
+ // attempt, the saving only on a hit). u64FullEvals already
+ // counts NnueForward calls 1:1 on this path, so no separate
+ // attempt counter is needed for it.
+ UINT64 u64CyclesNnueProbeCall;
+ UINT64 u64CyclesNnueForwardCall;
+ UINT64 u64NnueProbeAttempts;
}
tree;
@@ -2378,6 +2397,12 @@ extern CHAR g_rgfNnueFc3Weight[NNUE_L3];
extern float g_rgfNnueFc3Bias;
extern float g_rgfNnueActScale[3];
extern float g_rgfNnueWeightScale[3];
+// Affine raw-to-real-score correction (a + b*raw), re-fit and baked
+// into every export by CalibrateScoreMapping -- see nnueeval.c's
+// declaration comment and the 2026-10-20 "keeping this stable across
+// retrains" conversation. Defaults (0,1) are the identity transform.
+extern float g_fNnueCalibA;
+extern float g_fNnueCalibB;
extern FLAG g_fNnueWeightsLoaded;
extern FLAG g_fUseNnueEval;