]> git.sesse.net Git - stockfish/commitdiff
Do not use lazy evaluation inside NNUE
authorStéphane Nicolet <cassio@free.fr>
Wed, 26 May 2021 23:10:00 +0000 (01:10 +0200)
committerStéphane Nicolet <cassio@free.fr>
Wed, 26 May 2021 23:21:56 +0000 (01:21 +0200)
This simplification patch implements two changes:

1. it simplifies away the so-called "lazy" path in the NNUE evaluation internals,
   where we trusted the psqt head alone to avoid the costly "positional" head in
   some cases;
2. it raises a little bit the NNUEThreshold1 in evaluate.cpp (from 682 to 800),
   which increases the limit where we switched from NNUE eval to Classical eval.

Both effects increase the number of positional evaluations done by our new net
architecture, but the results of our tests below seem to indicate that the loss
of speed will be compensated by the gain of eval quality.

STC:
LLR: 2.95 (-2.94,2.94) <-2.50,0.50>
Total: 26280 W: 2244 L: 2137 D: 21899
Ptnml(0-2): 72, 1755, 9405, 1810, 98
https://tests.stockfishchess.org/tests/view/60ae73f112066fd299795a51

LTC:
LLR: 2.95 (-2.94,2.94) <-2.50,0.50>
Total: 20592 W: 750 L: 677 D: 19165
Ptnml(0-2): 9, 614, 8980, 681, 12
https://tests.stockfishchess.org/tests/view/60ae88e812066fd299795a82

closes https://github.com/official-stockfish/Stockfish/pull/3503

Bench: 3817907

src/evaluate.cpp
src/evaluate.h
src/nnue/evaluate_nnue.cpp
src/nnue/nnue_feature_transformer.h

index 04d41d5f6b0880d569aca2e14fe11811d66e2c54..40c41a8667add483ed8f4facd16dfb1e6e755e6b 100644 (file)
@@ -216,9 +216,8 @@ namespace {
   // Threshold for lazy and space evaluation
   constexpr Value LazyThreshold1    =  Value(1565);
   constexpr Value LazyThreshold2    =  Value(1102);
-  constexpr Value LazyThresholdNNUE =  Value(1400);
   constexpr Value SpaceThreshold    = Value(11551);
-  constexpr Value NNUEThreshold1    =   Value(682);
+  constexpr Value NNUEThreshold1    =   Value(800);
   constexpr Value NNUEThreshold2    =   Value(176);
 
   // KingAttackWeights[PieceType] contains king attack weights by piece type
@@ -1120,7 +1119,7 @@ Value Eval::evaluate(const Position& pos) {
 
          int scale = 903 + 28 * pos.count<PAWN>() + 28 * pos.non_pawn_material() / 1024;
 
-         Value nnue = NNUE::evaluate(pos, true, LazyThresholdNNUE) * scale / 1024;
+         Value nnue = NNUE::evaluate(pos, true) * scale / 1024;
 
          if (pos.is_chess960())
              nnue += fix_FRC(pos);
@@ -1133,15 +1132,14 @@ Value Eval::evaluate(const Position& pos) {
       Value psq = Value(abs(eg_value(pos.psq_score())));
       int   r50 = 16 + pos.rule50_count();
       bool  largePsq = psq * 16 > (NNUEThreshold1 + pos.non_pawn_material() / 64) * r50;
-      bool  classical = largePsq;
 
       // Use classical evaluation for really low piece endgames.
       // One critical case is the draw for bishop + A/H file pawn vs naked king.
       bool lowPieceEndgame =   pos.non_pawn_material() == BishopValueMg
                             || (pos.non_pawn_material() < 2 * RookValueMg && pos.count<PAWN>() < 2);
 
-      v = classical || lowPieceEndgame ? Evaluation<NO_TRACE>(pos).value()
-                                       : adjusted_NNUE();
+      v = largePsq || lowPieceEndgame ? Evaluation<NO_TRACE>(pos).value()  // classical
+                                      : adjusted_NNUE();                   // NNUE
 
       // If the classical eval is small and imbalance large, use NNUE nevertheless.
       // For the case of opposite colored bishops, switch to NNUE eval with small
index 6bc1f0b387b4c02ddde1a9a37ef61ebc7e2fc534..41aace67fcb7ff00cf52cf7ae552c45a17c389a3 100644 (file)
@@ -43,7 +43,7 @@ namespace Eval {
 
   namespace NNUE {
 
-    Value evaluate(const Position& pos, bool adjusted = false, Value lazyThreshold = VALUE_INFINITE);
+    Value evaluate(const Position& pos, bool adjusted = false);
     bool load_eval(std::string name, std::istream& stream);
     bool save_eval(std::ostream& stream);
     void init();
index 99711cd564673c1432b4e3ddc599fb85654d86ac..4a3c206b8087fcb065ad0b9c4e595c68495701a8 100644 (file)
@@ -134,7 +134,7 @@ namespace Stockfish::Eval::NNUE {
   }
 
   // Evaluation function. Perform differential calculation.
-  Value evaluate(const Position& pos, bool adjusted, Value lazyThreshold) {
+  Value evaluate(const Position& pos, bool adjusted) {
 
     // We manually align the arrays on the stack because with gcc < 9.3
     // overaligning stack variables with alignas() doesn't work correctly.
@@ -158,27 +158,21 @@ namespace Stockfish::Eval::NNUE {
     ASSERT_ALIGNED(buffer, alignment);
 
     const std::size_t bucket = (pos.count<ALL_PIECES>() - 1) / 4;
-    const auto [psqt, lazy] = featureTransformer->transform(pos, transformedFeatures, bucket, lazyThreshold);
+    const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket);
+    const auto output = network[bucket]->propagate(transformedFeatures, buffer);
 
-    if (lazy)
-      return static_cast<Value>(psqt / OutputScale);
-    else
-    {
-      const auto output = network[bucket]->propagate(transformedFeatures, buffer);
+    int materialist = psqt;
+    int positional  = output[0];
 
-      int materialist = psqt;
-      int positional  = output[0];
+    int delta_npm = abs(pos.non_pawn_material(WHITE) - pos.non_pawn_material(BLACK));
+    int entertainment = (adjusted && delta_npm <= BishopValueMg - KnightValueMg ? 7 : 0);
 
-      int delta_npm = abs(pos.non_pawn_material(WHITE) - pos.non_pawn_material(BLACK));
-      int entertainment = (adjusted && delta_npm <= BishopValueMg - KnightValueMg ? 7 : 0);
+    int A = 128 - entertainment;
+    int B = 128 + entertainment;
 
-      int A = 128 - entertainment;
-      int B = 128 + entertainment;
+    int sum = (A * materialist + B * positional) / 128;
 
-      int sum = (A * materialist + B * positional) / 128;
-
-      return static_cast<Value>( sum / OutputScale );
-    }
+    return static_cast<Value>( sum / OutputScale );
   }
 
   // Load eval, from a file stream or a memory stream
index e81f54fa3e0dea266d2ce4e431b062423422237e..741d97cf1190c539bdcf2766ae6852bdefc52a12 100644 (file)
@@ -169,7 +169,7 @@ namespace Stockfish::Eval::NNUE {
     }
 
     // Convert input features
-    std::pair<std::int32_t, bool> transform(const Position& pos, OutputType* output, int bucket, Value lazyThreshold) const {
+    std::int32_t transform(const Position& pos, OutputType* output, int bucket) const {
       update_accumulator(pos, WHITE);
       update_accumulator(pos, BLACK);
 
@@ -182,9 +182,6 @@ namespace Stockfish::Eval::NNUE {
           - psqtAccumulation[static_cast<int>(perspectives[1])][bucket]
         ) / 2;
 
-      if (abs(psqt) > (int)lazyThreshold * OutputScale)
-        return { psqt, true };
-
   #if defined(USE_AVX512)
       constexpr IndexType NumChunks = HalfDimensions / (SimdWidth * 2);
       static_assert(HalfDimensions % (SimdWidth * 2) == 0);
@@ -291,7 +288,7 @@ namespace Stockfish::Eval::NNUE {
       _mm_empty();
   #endif
 
-      return { psqt, false };
+      return psqt;
     }
 
    private: