-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add dirty and possibly short lived tuner based on bench
- Loading branch information
Showing
6 changed files
with
209 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
quiet-labeled.v7.epd.gz |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.venv | ||
__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
{ | ||
"depth": 6, | ||
"uci_options": { | ||
"Hash": "128", | ||
"SyzygyPath": "../../syzygy", | ||
"max_history_stats_impact": "20" | ||
}, | ||
"cases": [ | ||
"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", | ||
"r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq - 0 10", | ||
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 0 11", | ||
"4rrk1/pp1n3p/3q2pQ/2p1pb2/2PP4/2P3N1/P2B2PP/4RRK1 b - - 7 19", | ||
"rq3rk1/ppp2ppp/1bnpb3/3N2B1/3NP3/7P/PPPQ1PP1/2KR3R w - - 7 14 moves d4e6", | ||
"r1bq1r1k/1pp1n1pp/1p1p4/4p2Q/4Pp2/1BNP4/PPP2PPP/3R1RK1 w - - 2 14 moves g2g4", | ||
"r3r1k1/2p2ppp/p1p1bn2/8/1q2P3/2NPQN2/PPP3PP/R4RK1 b - - 2 15", | ||
"r1bbk1nr/pp3p1p/2n5/1N4p1/2Np1B2/8/PPP2PPP/2KR1B1R w kq - 0 13", | ||
"r1bq1rk1/ppp1nppp/4n3/3p3Q/3P4/1BP1B3/PP1N2PP/R4RK1 w - - 1 16", | ||
"4r1k1/r1q2ppp/ppp2n2/4P3/5Rb1/1N1BQ3/PPP3PP/R5K1 w - - 1 17", | ||
"2rqkb1r/ppp2p2/2npb1p1/1N1Nn2p/2P1PP2/8/PP2B1PP/R1BQK2R b KQ - 0 11", | ||
"r1bq1r1k/b1p1npp1/p2p3p/1p6/3PP3/1B2NN2/PP3PPP/R2Q1RK1 w - - 1 16", | ||
"3r1rk1/p5pp/bpp1pp2/8/q1PP1P2/b3P3/P2NQRPP/1R2B1K1 b - - 6 22", | ||
"r1q2rk1/2p1bppp/2Pp4/p6b/Q1PNp3/4B3/PP1R1PPP/2K4R w - - 2 18", | ||
"4k2r/1pb2ppp/1p2p3/1R1p4/3P4/2r1PN2/P4PPP/1R4K1 b - - 3 22", | ||
"3q2k1/pb3p1p/4pbp1/2r5/PpN2N2/1P2P2P/5PP1/Q2R2K1 b - - 4 26", | ||
"6k1/6p1/6Pp/ppp5/3pn2P/1P3K2/1PP2P2/3N4 b - - 0 1", | ||
"3b4/5kp1/1p1p1p1p/pP1PpP1P/P1P1P3/3KN3/8/8 w - - 0 1", | ||
"2K5/p7/7P/5pR1/8/5k2/r7/8 w - - 0 1 moves g5g6 f3e3 g6g5 e3f3", | ||
"8/6pk/1p6/8/PP3p1p/5P2/4KP1q/3Q4 w - - 0 1", | ||
"7k/3p2pp/4q3/8/4Q3/5Kp1/P6b/8 w - - 0 1", | ||
"8/2p5/8/2kPKp1p/2p4P/2P5/3P4/8 w - - 0 1", | ||
"8/1p3pp1/7p/5P1P/2k3P1/8/2K2P2/8 w - - 0 1", | ||
"8/pp2r1k1/2p1p3/3pP2p/1P1P1P1P/P5KR/8/8 w - - 0 1", | ||
"8/3p4/p1bk3p/Pp6/1Kp1PpPp/2P2P1P/2P5/5B2 b - - 0 1", | ||
"5k2/7R/4P2p/5K2/p1r2P1p/8/8/8 b - - 0 1", | ||
"6k1/6p1/P6p/r1N5/5p2/7P/1b3PP1/4R1K1 w - - 0 1", | ||
"1r3k2/4q3/2Pp3b/3Bp3/2Q2p2/1p1P2P1/1P2KP2/3N4 w - - 0 1", | ||
"6k1/4pp1p/3p2p1/P1pPb3/R7/1r2P1PP/3B1P2/6K1 w - - 0 1", | ||
"8/3p3B/5p2/5P2/p7/PP5b/k7/6K1 w - - 0 1", | ||
"8/8/8/8/5kp1/P7/8/1K1N4 w - - 0 1", | ||
"8/8/8/5N2/8/p7/8/2NK3k w - - 0 1", | ||
"8/3k4/8/8/8/4B3/4KB2/2B5 w - - 0 1", | ||
"8/8/1P6/5pr1/8/4R3/7k/2K5 w - - 0 1", | ||
"8/2p4P/8/kr6/6R1/8/8/1K6 w - - 0 1", | ||
"8/8/3P3k/8/1p6/8/1P6/1K3n2 b - - 0 1", | ||
"8/R7/2q5/8/6k1/8/1P5p/K6R w - - 0 124", | ||
"6k1/3b3r/1p1p4/p1n2p2/1PPNpP1q/P3Q1p1/1R1RB1P1/5K2 b - - 0 1", | ||
"r2r1n2/pp2bk2/2p1p2p/3q4/3PN1QP/2P3R1/P4PP1/5RK1 w - - 0 1" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import argparse | ||
import subprocess | ||
from pathlib import Path | ||
|
||
from pydantic import BaseModel | ||
from tqdm import tqdm | ||
|
||
|
||
class BenchSuite(BaseModel): | ||
depth: int | ||
uci_options: dict[str, str] | ||
cases: list[str] | ||
|
||
|
||
class Case(BaseModel): | ||
depth: int | ||
uci_options: dict[str, str] | ||
fen: str | ||
|
||
|
||
def run_bench(engine: Path, case: Case) -> int: | ||
proc = subprocess.Popen([engine], stdout=subprocess.PIPE, stdin=subprocess.PIPE) | ||
assert proc.stdout is not None | ||
assert proc.stdin is not None | ||
|
||
indata = "\n".join( | ||
["uci"] | ||
+ [f"setoption name {k} value {v}" for k, v in case.uci_options.items()] | ||
+ [f"position fen {case.fen}", f"go depth {case.depth}\n"] | ||
).encode() | ||
proc.stdin.write(indata) | ||
proc.stdin.flush() | ||
|
||
nodes = None | ||
for line in map(bytes.decode, iter(proc.stdout.readline, b"")): | ||
if line.startswith("bestmove"): | ||
break | ||
if line.startswith("info"): | ||
words = line.split() | ||
for label, value in zip(words[1:], words[2:]): | ||
if label == "nodes": | ||
nodes = int(value) | ||
|
||
proc.stdin.write(b"quit\n") | ||
proc.stdin.flush() | ||
proc.wait() | ||
assert nodes is not None, f"no nodes counted for {case.fen}" | ||
return nodes | ||
|
||
|
||
def run_suite(engine: Path, suite: BenchSuite, progress: bool = True) -> int: | ||
return sum( | ||
run_bench( | ||
engine, Case(depth=suite.depth, uci_options=suite.uci_options, fen=fen) | ||
) | ||
for fen in (suite.cases if not progress else tqdm(suite.cases)) | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument("engine", type=Path) | ||
parser.add_argument("benchfile", type=Path) | ||
parser.add_argument("--no-progress", action="store_true") | ||
args = parser.parse_args() | ||
|
||
assert args.engine.exists() and args.engine.is_file() | ||
assert args.benchfile.exists() and args.benchfile.is_file() | ||
|
||
with open(args.benchfile) as f: | ||
suite = BenchSuite.model_validate_json(f.read()) | ||
|
||
print(f"{run_suite(args.engine, suite, progress=not args.no_progress):_} nodes") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"options": [ | ||
{ | ||
"name": "max_history_stats_impact", | ||
"bounds": [ | ||
7, | ||
13 | ||
] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import argparse | ||
from functools import cache | ||
from pathlib import Path | ||
|
||
import numpy as np | ||
from pydantic import BaseModel | ||
from scipy.optimize import brute | ||
from tqdm import tqdm | ||
|
||
from bench import BenchSuite, run_suite | ||
|
||
|
||
class OptionConfig(BaseModel): | ||
name: str | ||
bounds: tuple[int, int] | ||
|
||
|
||
class TuneConfig(BaseModel): | ||
options: list[OptionConfig] | ||
|
||
|
||
def tune( | ||
engine: Path, config: TuneConfig, suite: BenchSuite | ||
) -> tuple[int, dict[str, int]]: | ||
|
||
@cache | ||
def inner(args: tuple[str]) -> int: | ||
print("Running with args:", args) | ||
for i, opt in enumerate(config.options): | ||
suite.uci_options[opt.name] = args[i] | ||
return run_suite(engine, suite, progress=True) | ||
|
||
def objective(x: np.ndarray) -> int: | ||
x = np.round(x).astype(int) | ||
args = tuple(str(xi) for xi in x) | ||
return inner(args) | ||
|
||
def callback(x: np.ndarray, f: float, context: int): | ||
print(f"\n\nnodes: {f} params: {x}, context: {context}\n") | ||
|
||
bounds = [slice(*opt.bounds) for opt in config.options] | ||
|
||
result = brute(objective, bounds, Ns=1, disp=True, full_output=True) | ||
|
||
with open("/tmp/tune_result.pickl", "wb") as f: | ||
import pickle | ||
|
||
pickle.dump(result, f) | ||
|
||
print( | ||
"Global minimum:", | ||
", ".join(f"{opt.name}: {x} " for x, opt in zip(result[0], config.options)), | ||
) | ||
print("Nodes:", result[1]) | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument("engine", type=Path) | ||
parser.add_argument("benchfile", type=Path) | ||
parser.add_argument("configfile", type=Path) | ||
args = parser.parse_args() | ||
|
||
assert args.engine.exists() and args.engine.is_file() | ||
assert args.benchfile.exists() and args.benchfile.is_file() | ||
assert args.configfile.exists() and args.configfile.is_file() | ||
|
||
with open(args.benchfile) as f: | ||
suite = BenchSuite.model_validate_json(f.read()) | ||
with open(args.configfile) as f: | ||
config = TuneConfig.model_validate_json(f.read()) | ||
|
||
tune(args.engine, config, suite) |