Skip to content

Commit 579ca76

Browse files
committed
Optimize virtual loss parameters
Perform match games to tune the following KataGo parameters: - suppressVirtualLossExploreFactor - suppressVirtualLossHindsight - suppressVirtualLossLeakCatchUp - numSearchThreads - useNoisePruning Relates to: lightvector/KataGo#864
1 parent 0349501 commit 579ca76

File tree

1 file changed

+104
-58
lines changed

1 file changed

+104
-58
lines changed

match.py

Lines changed: 104 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from sgfmill import sgf
77
from scipy.stats import bernoulli
88

9+
910
def spawn_process(command: "list[str]"):
1011
"""Spawn a process with the command and wait until the process ends.
1112
@@ -18,59 +19,91 @@ def spawn_process(command: "list[str]"):
1819
except Exception as e:
1920
print(f"Error occurred: {str(e)}")
2021

22+
2123
def get_command(x) -> str:
22-
command = f'{x["exe"]} gtp -config {x["config"]} -model {x["model"]} -override-config maxVisits={x["maxVisits"]}'
24+
command = f'{x["exe"]} gtp -config {x["config"]} -model {x["model"]}'
25+
override_options = [
26+
"maxVisits",
27+
"suppressVirtualLossExploreFactor",
28+
"suppressVirtualLossHindsight",
29+
"suppressVirtualLossLeakCatchUp",
30+
"numSearchThreads",
31+
"useNoisePruning",
32+
]
33+
34+
for option in override_options:
35+
if option in x:
36+
command += f" -override-config {option}={x[option]}"
37+
2338
return command
2439

25-
def match(black_parameters, white_parameters, gogui_classpath, game_count, sgffile_prefix="match", verbose=True) -> int:
40+
41+
def match(
42+
black_parameters,
43+
white_parameters,
44+
gogui_classpath,
45+
game_count,
46+
sgffile_prefix="match",
47+
verbose=True,
48+
) -> int:
2649
black_command = get_command(black_parameters)
2750
white_command = get_command(white_parameters)
2851
board_size = 19
2952
komi = 7.5
30-
twogtp = ['java',
31-
'-cp',
32-
gogui_classpath,
33-
'net.sf.gogui.tools.twogtp.Main',
34-
'-black',
35-
black_command,
36-
'-white',
37-
white_command,
38-
'-size',
39-
f'{board_size}',
40-
'-komi',
41-
f'{komi}',
42-
'-auto',
43-
'-sgffile',
44-
f'{sgffile_prefix}-{game_count}']
53+
twogtp = [
54+
"java",
55+
"-cp",
56+
gogui_classpath,
57+
"net.sf.gogui.tools.twogtp.Main",
58+
"-black",
59+
black_command,
60+
"-white",
61+
white_command,
62+
"-size",
63+
f"{board_size}",
64+
"-komi",
65+
f"{komi}",
66+
"-auto",
67+
"-sgffile",
68+
f"{sgffile_prefix}-{game_count}",
69+
]
4570

4671
spawn_process(twogtp)
47-
sgffile = f'{sgffile_prefix}-{game_count}-0.sgf'
72+
sgffile = f"{sgffile_prefix}-{game_count}-0.sgf"
4873
is_won = 0
4974

5075
with open(sgffile, "rb") as f:
5176
sgf_string = f.read()
5277
game = sgf.Sgf_game.from_bytes(sgf_string)
5378
winner = game.get_winner()
5479

55-
if (winner == 'b'):
80+
if winner == "b":
5681
# Black won
5782
is_won = -1
5883
if verbose:
59-
print(f'Game {game_count}: Black won')
60-
elif (winner == 'w'):
84+
print(f"Game {game_count}: Black won")
85+
elif winner == "w":
6186
# White won
6287
is_won = 1
6388
if verbose:
64-
print(f'Game {game_count}: White won')
89+
print(f"Game {game_count}: White won")
6590
else:
6691
# Draw
6792
is_won = 0
6893
if verbose:
69-
print(f'Game {game_count}: Draw')
94+
print(f"Game {game_count}: Draw")
7095

7196
return is_won
7297

73-
def match_games(black_parameters, white_parameters, game_count_start, games, sgffile_prefix="match", verbose=True) -> (int, int, int):
98+
99+
def match_games(
100+
black_parameters,
101+
white_parameters,
102+
game_count_start,
103+
games,
104+
sgffile_prefix="match",
105+
verbose=True,
106+
) -> (int, int, int):
74107
results = []
75108
game_count_stop = game_count_start + games
76109

@@ -81,7 +114,8 @@ def match_games(black_parameters, white_parameters, game_count_start, games, sgf
81114
"/Users/chinchangyang/Code/gogui/bin",
82115
game_count,
83116
sgffile_prefix=sgffile_prefix,
84-
verbose=verbose)
117+
verbose=verbose,
118+
)
85119

86120
results.append(result)
87121

@@ -94,6 +128,7 @@ def match_games(black_parameters, white_parameters, game_count_start, games, sgf
94128

95129
return (black_win, white_win, draw)
96130

131+
97132
def elo(M: float, N: float) -> float:
98133
"""Calculate expected ELO
99134
@@ -105,12 +140,13 @@ def elo(M: float, N: float) -> float:
105140
float: expected ELO
106141
"""
107142
if N <= M:
108-
return float('inf')
143+
return float("inf")
109144
elif M <= 0:
110-
return float('-inf')
145+
return float("-inf")
111146
else:
112147
return -400 * math.log10(-1 + (N / M))
113148

149+
114150
def elo_range(M: int, N: int, a: float) -> float:
115151
"""Calculate ELO standard deviation
116152
@@ -122,9 +158,9 @@ def elo_range(M: int, N: int, a: float) -> float:
122158
float: ELO standard deviation
123159
"""
124160
if N == M:
125-
return (float('inf'), float('inf'))
161+
return (float("inf"), float("inf"))
126162
elif M == 0:
127-
return (float('-inf'), float('-inf'))
163+
return (float("-inf"), float("-inf"))
128164
else:
129165
p = M / N # mean
130166
var = bernoulli.var(p) / N # variance of sample mean
@@ -134,70 +170,80 @@ def elo_range(M: int, N: int, a: float) -> float:
134170
elo_negative_delta = elo(M - delta, N) # ELO with negative delta
135171
return (elo_negative_delta, elo_positive_delta)
136172

173+
137174
if __name__ == "__main__":
138175
t0 = time.time()
139-
bot_a_name = 'b18c384nbt'
176+
bot_a_name = "K1e10-Hoff-LCUoff-T8-NPon"
140177

141178
bot_a_parameters = {
142179
"exe": "/Users/chinchangyang/Code/KataGo/cpp/build/katago",
143180
"config": "/Users/chinchangyang/.katago/default_gtp.cfg",
144-
"model": "/Users/chinchangyang/Code/KataGo-Models/kata1-b18c384nbt-s7709731328-d3715293823.bin.gz",
145-
"maxVisits": "2"
181+
"model": "/Users/chinchangyang/.katago/default_model.bin.gz",
182+
"suppressVirtualLossExploreFactor": "1e10",
183+
"suppressVirtualLossHindsight": "false",
184+
"suppressVirtualLossLeakCatchUp": "false",
185+
"numSearchThreads": "8",
186+
"useNoisePruning": "true",
146187
}
147188

148-
bot_b_name = 'b28c512nbt'
189+
bot_b_name = "K8-Hoff-LCUoff-T4-NPoff"
149190

150191
bot_b_parameters = {
151-
"exe": "/Users/chinchangyang/Code/KataGo-CCY/cpp/build/katago",
152-
"config": "/Users/chinchangyang/Code/KataGo-CCY/cpp/configs/misc/coreml_example.cfg",
153-
"model": "/Users/chinchangyang/Code/KataGo-Models/b28c512nbt-s1436726784-d3907069532.bin.gz",
154-
"maxVisits": "2"
192+
"exe": "/Users/chinchangyang/Code/KataGo/cpp/build/katago",
193+
"config": "/Users/chinchangyang/.katago/default_gtp.cfg",
194+
"model": "/Users/chinchangyang/.katago/default_model.bin.gz",
195+
"suppressVirtualLossExploreFactor": "8", # {4, 64}
196+
"suppressVirtualLossHindsight": "false", # {false, true}
197+
"suppressVirtualLossLeakCatchUp": "false", # {false, true}
198+
"numSearchThreads": "4", # {8, 32}
199+
"useNoisePruning": "false", # {false, true}
155200
}
156201

157-
total_games = 1024
202+
total_games = 100
158203
half_games = int(total_games / 2)
159204

160205
black_win, white_win, draw = match_games(
161-
bot_a_parameters,
162-
bot_b_parameters,
163-
0,
164-
half_games)
206+
bot_a_parameters, bot_b_parameters, 0, half_games
207+
)
165208

166209
bot_a_win = black_win
167210
bot_b_win = white_win
168211
both_draw = draw
169212

170-
print(f'{bot_a_name} Won: {bot_a_win}')
171-
print(f'{bot_b_name} Won: {bot_b_win}')
172-
print(f'Draw: {both_draw}')
213+
print(f"{bot_a_name} Won: {bot_a_win}")
214+
print(f"{bot_b_name} Won: {bot_b_win}")
215+
print(f"Draw: {both_draw}")
173216

174217
black_win, white_win, draw = match_games(
175-
bot_b_parameters,
176-
bot_a_parameters,
177-
half_games,
178-
half_games)
218+
bot_b_parameters, bot_a_parameters, half_games, half_games
219+
)
179220

180221
bot_a_win = bot_a_win + white_win
181222
bot_b_win = bot_b_win + black_win
182223
both_draw = both_draw + draw
183224

184-
print(f'{bot_a_name} Won: {bot_a_win}')
185-
print(f'{bot_b_name} Won: {bot_b_win}')
186-
print(f'Draw: {both_draw}')
225+
print(f"{bot_a_name} Won: {bot_a_win}")
226+
print(f"{bot_b_name} Won: {bot_b_win}")
227+
print(f"Draw: {both_draw}")
187228

188229
bot_a_outcome = bot_a_win + (both_draw / 2)
189230
bot_b_outcome = bot_b_win + (both_draw / 2)
190231

191232
print(
192-
f'Expected ELO of {bot_a_name} parameters (from {total_games} games) = {elo(bot_a_outcome, total_games)}')
233+
f"Expected ELO of {bot_a_name} parameters (from {total_games} games) = {elo(bot_a_outcome, total_games)}"
234+
)
193235
print(
194-
f'Expected ELO of {bot_b_name} parameters (from {total_games} games) = {elo(bot_b_outcome, total_games)}')
236+
f"Expected ELO of {bot_b_name} parameters (from {total_games} games) = {elo(bot_b_outcome, total_games)}"
237+
)
195238
print(
196-
f'ELO range (+/- 1.0 standard deviation) of {bot_b_name} parameters = {elo_range(bot_b_outcome, total_games, 1.0)}')
239+
f"ELO range (+/- 1.0 standard deviation) of {bot_b_name} parameters = {elo_range(bot_b_outcome, total_games, 1.0)}"
240+
)
197241
print(
198-
f'ELO range (+/- 2.0 standard deviation) of {bot_b_name} parameters = {elo_range(bot_b_outcome, total_games, 2.0)}')
242+
f"ELO range (+/- 2.0 standard deviation) of {bot_b_name} parameters = {elo_range(bot_b_outcome, total_games, 2.0)}"
243+
)
199244
print(
200-
f'ELO range (+/- 3.0 standard deviation) of {bot_b_name} parameters = {elo_range(bot_b_outcome, total_games, 3.0)}')
245+
f"ELO range (+/- 3.0 standard deviation) of {bot_b_name} parameters = {elo_range(bot_b_outcome, total_games, 3.0)}"
246+
)
201247

202248
elapsed = time.time() - t0
203-
print(f'Elapsed: {str(datetime.timedelta(seconds=round(elapsed)))}')
249+
print(f"Elapsed: {str(datetime.timedelta(seconds=round(elapsed)))}")

0 commit comments

Comments
 (0)