Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
d1b738e
Add QRS-Tune PUCT hyperparameter tuning and match statistics
claude Mar 31, 2026
80c8ff7
Add build/ to .gitignore
claude Mar 31, 2026
ef10813
Fix missing NeuralNet::globalCleanup() and minor cleanup in tuneparams
ChinChangYang Mar 31, 2026
d22c0f2
Fix naming conventions and comment style to match KataGo codebase
claude Mar 31, 2026
efb3338
Fix tuneparams signal handling, pruning bias, and header inline consi…
ChinChangYang Mar 31, 2026
b52825b
Add Bradley-Terry convergence warning and fix header inline linkage
ChinChangYang Mar 31, 2026
7528c87
Add tune-params and QRS-Tune documentation to README files
ChinChangYang Apr 1, 2026
b6cb552
Add example config for tune-params subcommand
ChinChangYang Apr 1, 2026
57d4403
Revert .gitignore change that removed build/ entry
ChinChangYang Apr 1, 2026
0746c0a
Split QRSOptimizer from header-only into header + source file
ChinChangYang Apr 1, 2026
460b71e
Add build/ to .gitignore for root-level build directory
claude Apr 1, 2026
3fa5749
Revert adding build/ to .gitignore
claude Apr 1, 2026
4a88e32
Move match statistics functions to core namespaces
claude Apr 1, 2026
6d7ac6e
Simplify: fix review findings and update cpp/README.md
claude Apr 1, 2026
e622289
Improve QRSOptimizer readability and add unit tests
claude Apr 1, 2026
cee03a9
Add 10% progress reporting with ETA to tune-params
ChinChangYang Apr 1, 2026
4cdf5bc
Add 95% CIs via delta method, remove misleading ASCII charts
ChinChangYang Apr 1, 2026
a940abb
Use short param names in tune-params progress CIs for consistency
ChinChangYang Apr 1, 2026
51a0030
Merge progress and CI lines into single-line output in tune-params
ChinChangYang Apr 1, 2026
66da59b
Comment out unused numGameThreads in tune_params_example.cfg
ChinChangYang Apr 1, 2026
33aaaf7
Remove unused ys parameter from computeOptimumSE
ChinChangYang Apr 1, 2026
2202b1d
Print suggested match command after tune-params results
ChinChangYang Apr 1, 2026
75d82c7
Add shifted-optimum convergence test for QRSTuner
ChinChangYang Apr 2, 2026
eff8ecf
Fix pruning bias that drives optimizer to boundary values
ChinChangYang Apr 2, 2026
0dfde0c
Restore ASCII-art regression curves in tune-params output
ChinChangYang Apr 2, 2026
cf2457e
Fix convex-dim handling and add verbose diagnostic logging
ChinChangYang Apr 2, 2026
7a9f39b
Remove cpuctExploration from tune-params tuned dimensions
ChinChangYang Apr 3, 2026
c349aa6
Add intercept divergence regression test and enable GTP-equivalent de…
ChinChangYang Apr 3, 2026
29dba7a
Remove cpuctUtilityStdevPrior from tune-params tuned dimensions
ChinChangYang Apr 3, 2026
5381fbd
Append game outcome to QRS sample log line in tune-params verbose mode
ChinChangYang Apr 3, 2026
406048b
Switch tune-params example config to Tromp-Taylor rules with komi 7
ChinChangYang Apr 3, 2026
0fadb78
Add cpuctUtilityStdevPrior and cpuctUtilityStdevPriorWeight to tune-p…
ChinChangYang Apr 3, 2026
41139ee
Rename verbose log label from convex=Y/N to concave=Y/N
ChinChangYang Apr 4, 2026
eb8ca5e
Remove cpuctUtilityStdevPriorWeight from tune-params and soften pruning
ChinChangYang Apr 4, 2026
0bc3dfe
Append experiment bot color to QRS sample verbose log
ChinChangYang Apr 5, 2026
16748a3
Remove cpuctUtilityStdevPrior from tune-params tuned dimensions
ChinChangYang Apr 6, 2026
af20477
Add convergence scaling tests for QRSOptimizer with 100, 1000, and 10…
ChinChangYang Apr 6, 2026
f0659aa
Use uniform sampling in QRS optimizer when model has convex dimensions
ChinChangYang Apr 6, 2026
2f07ba0
Fix review findings: Bradley-Terry stderr, null game handling, test p…
claude Apr 10, 2026
cbe0d4c
Merge pull request #21 from ChinChangYang/claude/review-katago-pr-117…
ChinChangYang Apr 10, 2026
e7b63a5
Simplify convergence tests to 1D and add flat landscape test case
ChinChangYang Apr 12, 2026
54833cb
Switch tune-params dimension from cpuctExplorationLog to cpuctExplora…
ChinChangYang Apr 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ Run a high-performance match engine that will play a pool of bots against each o

* `./katago match -config <MATCH_CONFIG>.cfg -log-file match.log -sgf-output-dir <DIR TO WRITE THE SGFS>`

Tune PUCT search hyperparameters via QRS-Tune sequential optimization:

* `./katago tune-params -config <TUNE_CONFIG>.cfg`

Force OpenCL tuner to re-tune:

* `./katago tuner -config <GTP_CONFIG>.cfg`
Expand Down
2 changes: 2 additions & 0 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ add_executable(katago
tests/tinymodel.cpp
tests/tinymodeldata.cpp
distributed/client.cpp
qrstune/QRSOptimizer.cpp
command/commandline.cpp
command/analysis.cpp
command/benchmark.cpp
Expand All @@ -318,6 +319,7 @@ add_executable(katago
command/gputest.cpp
command/gtp.cpp
command/match.cpp
command/tuneparams.cpp
command/misc.cpp
command/runtests.cpp
command/sandbox.cpp
Expand Down
2 changes: 2 additions & 0 deletions cpp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Summary of source folders, in approximate dependency order, from lowest level to
* `distributed` - Code for talking to https webserver for volunteers to contribute distributed self-play games for training.
* `tests` - A variety of tests.
* `models` - A directory with a small number of small-sized (and not very strong) models for running tests.
* `qrstune` - QRS-Tune (Quadratic Response Surface) optimizer for hyperparameter tuning.
* `command` - Top-level subcommands callable by users. GTP, analysis commands, benchmarking, selfplay data generation, etc.
* `commandline.{cpp,h}` - Common command line logic shared by all subcommands.
* `gtp.cpp` - Main GTP engine.
Expand All @@ -44,6 +45,7 @@ Summary of source folders, in approximate dependency order, from lowest level to
* `selfplay.cpp` - Selfplay data generation engine.
* `gatekeeper.cpp` - Gating engine to filter neural nets for selfplay data generation.
* `match.cpp` - Match engine for testing different parameters that can use huge batch sizes to efficiently play games in parallel.
* `tuneparams.cpp` - Tune PUCT search hyperparameters via QRS-Tune sequential optimization.

Other folders:

Expand Down
74 changes: 73 additions & 1 deletion cpp/command/match.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "../core/global.h"
#include "../core/elo.h"
#include "../core/fancymath.h"
#include "../core/fileutils.h"
#include "../core/makedir.h"
#include "../core/config_parser.h"
Expand All @@ -11,6 +13,7 @@
#include "../command/commandline.h"
#include "../main.h"

#include <array>
#include <csignal>

using namespace std;
Expand Down Expand Up @@ -250,10 +253,13 @@ int MainCmds::match(const vector<string>& args) {
int64_t gameCount = 0;
std::map<string,double> timeUsedByBotMap;
std::map<string,double> movesByBotMap;
map<pair<string,string>, array<int64_t,3>> pairStats;
//key: {nameA, nameB} with nameA < nameB lexicographically
//value: {winsA, winsB, draws}

auto runMatchLoop = [
&gameRunner,&matchPairer,&sgfOutputDir,&logger,&gameSeedBase,&patternBonusTables,
&statsMutex, &gameCount, &timeUsedByBotMap, &movesByBotMap
&statsMutex, &gameCount, &timeUsedByBotMap, &movesByBotMap, &pairStats
](
uint64_t threadHash
) {
Expand Down Expand Up @@ -303,6 +309,20 @@ int MainCmds::match(const vector<string>& args) {
movesByBotMap[gameData->bName] += (double)gameData->bMoveCount;
movesByBotMap[gameData->wName] += (double)gameData->wMoveCount;

//Update pairwise W/L/D stats
{
const string& bName = gameData->bName;
const string& wName = gameData->wName;
Player winner = gameData->endHist.winner;
bool aIsBlack = (bName < wName);
const string& nameA = aIsBlack ? bName : wName;
const string& nameB = aIsBlack ? wName : bName;
auto& ps = pairStats[{nameA, nameB}];
if(winner == P_BLACK) { if(aIsBlack) ps[0]++; else ps[1]++; }
else if(winner == P_WHITE) { if(aIsBlack) ps[1]++; else ps[0]++; }
else { ps[2]++; }
}

int64_t x = gameCount;
while(x % 2 == 0 && x > 1) x /= 2;
if(x == 1 || x == 3 || x == 5) {
Expand Down Expand Up @@ -344,6 +364,58 @@ int MainCmds::match(const vector<string>& args) {
for(int i = 0; i<threads.size(); i++)
threads[i].join();

//Final match statistics
if(!pairStats.empty()) {
vector<string> activeBots;
{
set<string> seen;
for(auto& kv : pairStats) {
seen.insert(kv.first.first);
seen.insert(kv.first.second);
}
activeBots.assign(seen.begin(), seen.end());
}

vector<double> elo, eloStderr;
bool eloConverged = ComputeElos::computeBradleyTerryElo(activeBots, pairStats, elo, eloStderr);

logger.write("");
if(!eloConverged)
logger.write("Warning: Bradley-Terry Elo estimation did not fully converge");
logger.write("=== match Results ===");
logger.write("Global Elo (Bradley-Terry MLE, reference=" + activeBots[0] + "):");
for(int i = 0; i < (int)activeBots.size(); i++) {
string sign = (elo[i] >= 0) ? "+" : "";
string line = " " + activeBots[i] + " : " +
sign + Global::strprintf("%.1f", elo[i]) + " +/- " + Global::strprintf("%.1f", eloStderr[i]);
if(i == 0) line += " (reference)";
logger.write(line);
}
logger.write("");
logger.write("Pairwise summary:");
for(auto& kv : pairStats) {
int64_t wA = kv.second[0], wB = kv.second[1], d = kv.second[2];
int64_t total = wA + wB + d;
if(total == 0) continue;
double wins = wA + 0.5 * d;
double lo, hi;
FancyMath::wilsonCI95(wins, (double)total, lo, hi);
double pval = FancyMath::oneTailedPValue(wins, (double)total);
string sig = (pval < 0.05) ? " *" : "";
logger.write(
" " + kv.first.first + " vs " + kv.first.second +
" : Games=" + Global::int64ToString(total) +
" W=" + Global::int64ToString(wA) +
" L=" + Global::int64ToString(wB) +
" D=" + Global::int64ToString(d) +
" | " + kv.first.first + " winrate=" + Global::strprintf("%.3f", wins/total) +
" [95% CI: " + Global::strprintf("%.3f", lo) + ", " + Global::strprintf("%.3f", hi) + "]" +
" | p=" + Global::strprintf("%.4f", pval) + sig
);
}
logger.write("");
}

delete matchPairer;
delete gameRunner;

Expand Down
2 changes: 2 additions & 0 deletions cpp/command/runtests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "../core/rand.h"
#include "../core/elo.h"
#include "../core/fancymath.h"
#include "../qrstune/QRSOptimizer.h"
#include "../core/config_parser.h"
#include "../core/datetime.h"
#include "../core/fileutils.h"
Expand Down Expand Up @@ -35,6 +36,7 @@ int MainCmds::runtests(const vector<string>& args) {
DateTime::runTests();
FancyMath::runTests();
ComputeElos::runTests();
QRSTune::runTests();
Base64::runTests();
ThreadTest::runTests();

Expand Down
Loading
Loading