mirror of
https://github.com/sockspls/badfish
synced 2025-07-11 19:49:14 +00:00
Do not use lazy evaluation inside NNUE
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
This commit is contained in:
parent
1b325bf86d
commit
f193778446
4 changed files with 18 additions and 29 deletions
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,12 +158,7 @@ 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);
|
||||
|
||||
if (lazy)
|
||||
return static_cast<Value>(psqt / OutputScale);
|
||||
else
|
||||
{
|
||||
const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket);
|
||||
const auto output = network[bucket]->propagate(transformedFeatures, buffer);
|
||||
|
||||
int materialist = psqt;
|
||||
|
@ -179,7 +174,6 @@ namespace Stockfish::Eval::NNUE {
|
|||
|
||||
return static_cast<Value>( sum / OutputScale );
|
||||
}
|
||||
}
|
||||
|
||||
// Load eval, from a file stream or a memory stream
|
||||
bool load_eval(std::string name, std::istream& stream) {
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Reference in a new issue