Skip to content

Commit ad2aa8c

Browse files
committed
Normalize evaluation
Normalizes the internal value as reported by evaluate or search to the UCI centipawn result used in output. This value is derived from the win_rate_model() such that Stockfish outputs an advantage of "100 centipawns" for a position if the engine has a 50% probability to win from this position in selfplay at fishtest LTC time control. The reason to introduce this normalization is that our evaluation is, since NNUE, no longer related to the classical parameter PawnValueEg (=208). This leads to the current evaluation changing quite a bit from release to release, for example, the eval needed to have 50% win probability at fishtest LTC (in cp and internal Value): June 2020 : 113cp (237) June 2021 : 115cp (240) April 2022 : 134cp (279) July 2022 : 167cp (348) With this patch, a 100cp advantage will have a fixed interpretation, i.e. a 50% win chance. To keep this value steady, it will be needed to update the win_rate_model() from time to time, based on fishtest data. This analysis can be performed with a set of scripts currently available at https://github.com/vondele/WLD_model fixes #4155 closes #4216 No functional change
1 parent 61a2cb8 commit ad2aa8c

File tree

3 files changed

+17
-6
lines changed

3 files changed

+17
-6
lines changed

src/nnue/evaluate_nnue.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ namespace Stockfish::Eval::NNUE {
220220

221221
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
222222

223-
int cp = std::abs(100 * v / PawnValueEg);
223+
int cp = std::abs(100 * v / UCI::NormalizeToPawnValue);
224224
if (cp >= 10000)
225225
{
226226
buffer[1] = '0' + cp / 10000; cp %= 10000;
@@ -251,7 +251,7 @@ namespace Stockfish::Eval::NNUE {
251251

252252
buffer[0] = (v < 0 ? '-' : v > 0 ? '+' : ' ');
253253

254-
double cp = 1.0 * std::abs(int(v)) / PawnValueEg;
254+
double cp = 1.0 * std::abs(int(v)) / UCI::NormalizeToPawnValue;
255255
sprintf(&buffer[1], "%6.2f", cp);
256256
}
257257

src/uci.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,13 +207,17 @@ namespace {
207207
// The coefficients of a third-order polynomial fit is based on the fishtest data
208208
// for two parameters that need to transform eval to the argument of a logistic
209209
// function.
210-
double as[] = { 0.50379905, -4.12755858, 18.95487051, 152.00733652};
211-
double bs[] = {-1.71790378, 10.71543602, -17.05515898, 41.15680404};
210+
constexpr double as[] = { 1.04790516, -8.58534089, 39.42615625, 316.17524816};
211+
constexpr double bs[] = { -3.57324784, 22.28816201, -35.47480551, 85.60617701 };
212+
213+
// Enforce that NormalizeToPawnValue corresponds to a 50% win rate at ply 64
214+
static_assert(UCI::NormalizeToPawnValue == int(as[0] + as[1] + as[2] + as[3]));
215+
212216
double a = (((as[0] * m + as[1]) * m + as[2]) * m) + as[3];
213217
double b = (((bs[0] * m + bs[1]) * m + bs[2]) * m) + bs[3];
214218

215219
// Transform the eval to centipawns with limited range
216-
double x = std::clamp(double(100 * v) / PawnValueEg, -2000.0, 2000.0);
220+
double x = std::clamp(double(v), -4000.0, 4000.0);
217221

218222
// Return the win rate in per mille units rounded to the nearest value
219223
return int(0.5 + 1000 / (1 + std::exp((a - x) / b)));
@@ -312,7 +316,7 @@ string UCI::value(Value v) {
312316
stringstream ss;
313317

314318
if (abs(v) < VALUE_MATE_IN_MAX_PLY)
315-
ss << "cp " << v * 100 / PawnValueEg;
319+
ss << "cp " << v * 100 / NormalizeToPawnValue;
316320
else
317321
ss << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
318322

src/uci.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ class Position;
3030

3131
namespace UCI {
3232

33+
// Normalizes the internal value as reported by evaluate or search
34+
// to the UCI centipawn result used in output. This value is derived from
35+
// the win_rate_model() such that Stockfish outputs an advantage of
36+
// "100 centipawns" for a position if the engine has a 50% probability to win
37+
// from this position in selfplay at fishtest LTC time control.
38+
const int NormalizeToPawnValue = 348;
39+
3340
class Option;
3441

3542
/// Define a custom comparator, because the UCI options should be case-insensitive

0 commit comments

Comments
 (0)