Skip to content

Commit

Permalink
SPSA Tune (#516)
Browse files Browse the repository at this point in the history
Bench: 3055980

SPSA tune a large majority of the parameters in Berserk. This patch seems to scale incredibly.

Elo | -14.12 +- 6.72 (95%)
SPRT | 10.0+0.10s Threads=1 Hash=8MB
LLR | -2.25 (-2.25, 2.89) [0.00, 2.00]
Games | N: 4950 W: 1095 L: 1296 D: 2559
Penta | [30, 692, 1222, 511, 20]
http://chess.grantnet.us/test/34092/

Elo | 8.74 +- 4.43 (95%)
SPRT | 60.0+0.60s Threads=1 Hash=64MB
LLR | 2.89 (-2.25, 2.89) [0.00, 2.00]
Games | N: 10380 W: 2418 L: 2157 D: 5805
Penta | [10, 1072, 2768, 1327, 13]
http://chess.grantnet.us/test/34094/
  • Loading branch information
jhonnold authored Oct 21, 2023
1 parent 005ff4d commit e4a2148
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 41 deletions.
2 changes: 1 addition & 1 deletion src/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
EXE = berserk
SRC = *.c nn/*.c pyrrhic/tbprobe.c
CC = gcc
VERSION = 20231020b
VERSION = 20231021
MAIN_NETWORK = networks/berserk-01c3a52e404a.nn
EVALFILE = $(MAIN_NETWORK)
DEFS = -DVERSION=\"$(VERSION)\" -DEVALFILE=\"$(EVALFILE)\" -DNDEBUG
Expand Down
56 changes: 28 additions & 28 deletions src/search.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,19 @@ int STATIC_PRUNE[2][MAX_SEARCH_PLY];
void InitPruningAndReductionTables() {
for (int depth = 1; depth < MAX_SEARCH_PLY; depth++)
for (int moves = 1; moves < 64; moves++)
LMR[depth][moves] = log(depth) * log(moves) / 2.25 + 0.25;
LMR[depth][moves] = log(depth) * log(moves) / 2.1872 + 0.2487;

LMR[0][0] = LMR[0][1] = LMR[1][0] = 0;

for (int depth = 0; depth < MAX_SEARCH_PLY; depth++) {
// LMP has both a improving (more strict) and non-improving evalution
// parameter for lmp. If the evaluation is getting better we want to check
// more
LMP[0][depth] = (3 + depth * depth) / 2;
LMP[1][depth] = 3 + depth * depth;
LMP[0][depth] = 1.2973 + 0.3772 * depth * depth;
LMP[1][depth] = 2.7002 + 0.9448 * depth * depth;

STATIC_PRUNE[0][depth] = -SEE_PRUNE_CUTOFF * depth * depth; // quiet move cutoff
STATIC_PRUNE[1][depth] = -SEE_PRUNE_CAPTURE_CUTOFF * depth; // capture cutoff
STATIC_PRUNE[0][depth] = -14.9419 * depth * depth; // quiet move cutoff
STATIC_PRUNE[1][depth] = -103.9379 * depth; // capture cutoff
}
}

Expand Down Expand Up @@ -200,9 +200,9 @@ void Search(ThreadData* thread) {

// One at depth 5 or later, start search at a reduced window
if (thread->depth >= 5) {
alpha = Max(score - WINDOW, -CHECKMATE);
beta = Min(score + WINDOW, CHECKMATE);
delta = WINDOW;
delta = 9;
alpha = Max(score - delta, -CHECKMATE);
beta = Min(score + delta, CHECKMATE);
}

while (1) {
Expand Down Expand Up @@ -270,7 +270,7 @@ void Search(ThreadData* thread) {
else if (Limits.timeset && thread->depth >= 5 && !Threads.stopOnPonderHit) {
int sameBestMove = bestMove == previousBestMove; // same move?
searchStability = sameBestMove ? Min(10, searchStability + 1) : 0; // increase how stable our best move is
double stabilityFactor = 1.25 - 0.05 * searchStability;
double stabilityFactor = 1.3658 - 0.0482 * searchStability;

Score searchScoreDiff = scores[thread->depth - 3] - bestScore;
Score prevScoreDiff = thread->previousScore - bestScore;
Expand All @@ -279,14 +279,14 @@ void Search(ThreadData* thread) {
if (thread->previousScore == UNKNOWN)
searchScoreDiff *= 2, prevScoreDiff = 0;

double scoreChangeFactor = 0.1 + //
0.0275 * searchScoreDiff * (searchScoreDiff > 0) + //
0.0275 * prevScoreDiff * (prevScoreDiff > 0);
scoreChangeFactor = Max(0.5, Min(1.5, scoreChangeFactor));
double scoreChangeFactor = 0.0995 + //
0.0286 * searchScoreDiff * (searchScoreDiff > 0) + //
0.0261 * prevScoreDiff * (prevScoreDiff > 0);
scoreChangeFactor = Max(0.4843, Min(1.4498, scoreChangeFactor));

uint64_t bestMoveNodes = thread->rootMoves[0].nodes;
double pctNodesNotBest = 1.0 - (double) bestMoveNodes / thread->nodes;
double nodeCountFactor = Max(0.5, pctNodesNotBest * 2 + 0.4);
double nodeCountFactor = Max(0.5464, pctNodesNotBest * 2.1394 + 0.4393);
if (bestScore >= TB_WIN_BOUND)
nodeCountFactor = 0.5;

Expand Down Expand Up @@ -454,12 +454,12 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV*
// Reverse Futility Pruning
// i.e. the static eval is so far above beta we prune
if (depth <= 8 && !ss->skip && eval < TB_WIN_BOUND && eval >= beta &&
eval - 69 * depth + 112 * (improving && !board->easyCapture) >= beta &&
(!hashMove || GetHistory(ss, thread, hashMove) > 12288))
eval - 67 * depth + 112 * (improving && !board->easyCapture) >= beta &&
(!hashMove || GetHistory(ss, thread, hashMove) > 12525))
return eval;

// Razoring
if (depth <= 6 && eval + 250 * depth <= alpha) {
if (depth <= 6 && eval + 252 * depth <= alpha) {
score = Quiesce(alpha, beta, 0, thread, ss);
if (score <= alpha)
return score;
Expand All @@ -469,10 +469,10 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV*
// i.e. Our position is so good we can give our opponnent a free move and
// they still can't catch up (this is usually countered by captures or mate
// threats)
if (depth >= 3 && (ss - 1)->move != NULL_MOVE && !ss->skip && eval >= beta &&
if (depth >= 4 && (ss - 1)->move != NULL_MOVE && !ss->skip && eval >= beta &&
// weiss conditional
HasNonPawn(board) > (depth > 12)) {
int R = 4 + 188 * depth / 1024 + Min(5 * (eval - beta) / 1024, 3) + !board->easyCapture;
int R = 5 + 221 * depth / 1024 + Min(5 * (eval - beta) / 1024, 4) + !board->easyCapture;
R = Min(depth, R); // don't go too low

TTPrefetch(KeyAfter(board, NULL_MOVE));
Expand All @@ -491,7 +491,7 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV*
// Prob cut
// If a relatively deep search from our TT doesn't say this node is
// less than beta + margin, then we run a shallow search to look
int probBeta = beta + 200;
int probBeta = beta + 197;
if (depth >= 5 && !ss->skip && abs(beta) < TB_WIN_BOUND && !(ttHit && ttDepth >= depth - 3 && ttScore < probBeta)) {
InitPCMovePicker(&mp, thread, probBeta > eval);
while ((move = NextMove(&mp, board, 1))) {
Expand Down Expand Up @@ -547,12 +547,12 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV*
if (!IsCap(move) && PromoPT(move) != QUEEN) {
int lmrDepth = Max(1, depth - LMR[Min(depth, 63)][Min(legalMoves, 63)]);

if (!killerOrCounter && lmrDepth < 6 && history < -2500 * (depth - 1)) {
if (!killerOrCounter && lmrDepth < 7 && history < -2658 * (depth - 1)) {
skipQuiets = 1;
continue;
}

if (!inCheck && lmrDepth < 10 && eval + 88 + 47 * lmrDepth + 13 * history / 2048 <= alpha)
if (!inCheck && lmrDepth < 10 && eval + 87 + 46 * lmrDepth + 15 * history / 2048 <= alpha)
skipQuiets = 1;

if (!SEE(board, move, STATIC_PRUNE[0][lmrDepth]))
Expand Down Expand Up @@ -595,7 +595,7 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV*

// no score failed above sBeta, so this is singular
if (score < sBeta) {
if (!isPV && score < sBeta - 18 && ss->de <= 6) {
if (!isPV && score < sBeta - 17 && ss->de <= 6) {
extension = 2;
ss->de = (ss - 1)->de + 1;
} else {
Expand Down Expand Up @@ -650,15 +650,15 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV*
R += 1 + !IsCap(move);

// adjust reduction based on historical score
R -= 9 * history / 65536;
R -= 8 * history / 65536;

// prevent dropping into QS, extending, or reducing all extensions
R = Min(depth - 1, Max(R, 1));

score = -Negamax(-alpha - 1, -alpha, newDepth - R, 1, thread, &childPv, ss + 1);

if (score > alpha && R > 1) {
newDepth += (score > bestScore + 75);
newDepth += (score > bestScore + 76);

score = -Negamax(-alpha - 1, -alpha, newDepth - 1, !cutnode, thread, &childPv, ss + 1);
}
Expand Down Expand Up @@ -707,12 +707,12 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV*
alpha = score;

if (alpha < beta && score > -TB_WIN_BOUND)
depth -= (depth >= 2 && depth <= 10);
depth -= (depth >= 2 && depth <= 11);
}

// we're failing high
if (alpha >= beta) {
UpdateHistories(ss, thread, move, depth + (bestScore > beta + 86), quiets, numQuiets, captures, numCaptures);
UpdateHistories(ss, thread, move, depth + (bestScore > beta + 78), quiets, numQuiets, captures, numCaptures);
break;
}
}
Expand Down Expand Up @@ -807,7 +807,7 @@ int Quiesce(int alpha, int beta, int depth, ThreadData* thread, SearchStack* ss)

bestScore = eval;

futility = bestScore + DELTA_CUTOFF;
futility = bestScore + 60;
}

if (!inCheck)
Expand Down
10 changes: 0 additions & 10 deletions src/search.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,6 @@
#define TB_WIN_SCORE MATE_BOUND
#define TB_WIN_BOUND (TB_WIN_SCORE - MAX_SEARCH_PLY)

// static evaluation pruning
#define SEE_PRUNE_CAPTURE_CUTOFF 104
#define SEE_PRUNE_CUTOFF 17

// delta pruning in QS
#define DELTA_CUTOFF 55

// base window value
#define WINDOW 10

void InitPruningAndReductionTables();

void StartSearch(Board* board, uint8_t ponder);
Expand Down
4 changes: 2 additions & 2 deletions src/uci.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ void ParseGo(char* in, Board* board) {
if (movesToGo == -1) {
int total = Max(1, time + 50 * inc - MOVE_OVERHEAD);

Limits.alloc = Min(time * 0.33, total / 20.0);
Limits.max = Min((time - MOVE_OVERHEAD) * 0.8, Limits.alloc * 5.5);
Limits.alloc = Min(time * 0.3784, total * 0.0570);
Limits.max = Min((time - MOVE_OVERHEAD) * 0.7776, Limits.alloc * 5.8320);
} else {
int total = Max(1, time + movesToGo * inc - MOVE_OVERHEAD);

Expand Down

0 comments on commit e4a2148

Please sign in to comment.