Skip to content

Add Human-SL even-game ELO rank ladder configs (gtp_human<rank>.cfg, 8d→25k) - #1209

Open
ChinChangYang wants to merge 1 commit into
lightvector:masterfrom
ChinChangYang:gtp-human-rank-configs
Open

Add Human-SL even-game ELO rank ladder configs (gtp_human<rank>.cfg, 8d→25k)#1209
ChinChangYang wants to merge 1 commit into
lightvector:masterfrom
ChinChangYang:gtp-human-rank-configs

Conversation

@ChinChangYang

@ChinChangYang ChinChangYang commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR now ships a direct even-game ELO ladder — 33 GTP configs (gtp_human<rank>.cfg, 8d → 25k) that make KataGo + the Human-SL net play at a chosen amateur strength — and is slimmed to configs + documentation + one 13-line rank-parsing extension.

@lightvector — you were right that the komi-0.5 pairing is only half a stone. Rather than re-derive a rank spacing, this revision abandons rank-spacing entirely: each rung is tuned/measured against its stronger neighbour in a normal even game (komi 6.5, colours alternated), so the ladder no longer depends on any KGS handicap convention.

What changed since the previous revision

  • Calibration target: komi-0.5 handicap @ 50% winrate → even game @ +100 ELO per rung, each adjacent gap held to a 95% CI ⊂ [70, 130].
  • Configs: maxVisits 400 → 40, winLossUtilityFactor 1.0 → 0 (the old wLU=1 made the AI excessively strong even for DDK profiles), main net kata1-b28c512nbt-s8326494464-d4628051565 — every header names this exact net, and the calibrated rungs additionally warn that a different main net invalidates the calibration.
  • Scope: the tunehuman subcommand, tests, and tuning scripts are removed from this PR — the engine should focus on playing and analysis, not offline tuning. The calibration harness lives in my fork (tunehuman-mlx). What remains: 33 configs + docs/HumanSL_Rank_Ladder.md + a 13-line extension of SGFMetadata::getProfile (rank strings 21k–30k; upstream parsing stops at 20k, so preaz_21kpreaz_25k would otherwise throw at startup — the rank input encoding itself already saturates at inverse-rank 34 = 25k).
  • 9d dropped: the old gtp_human9d.cfg was a 400-visit, wLU=1 legacy reference measured roughly +655 ELO above 8d — not a rung of this ladder.

Method (brief)

Chained calibration anchored at a hand-set 8d top rung (λ=0.06): each rung is tuned via humanSLChosenMovePiklLambda so its already-locked stronger neighbour beats it by 100 ELO in even games (Japanese rules, komi 6.5, alternating colours, 40 visits). The lock criterion is the Wilson 95% CI of the gap, measured on games concentrated at the single shipped λ (binomial, φ=1). Full method, findings, and reproduction: docs/HumanSL_Rank_Ladder.md.

Results

7d → 14k — the 100-ELO staircase

Config Profile Baseline (stronger) Even-game gap (95% CI) Games piklLambda
gtp_human8d.cfg preaz_8d — (hand-set anchor) anchor, not calibrated 0.06
gtp_human7d.cfg preaz_7d gtp_human8d.cfg +100 [72, 128] ✅ 644 0.07760
gtp_human6d.cfg preaz_6d gtp_human7d.cfg +100 [71, 130] ✅ 576 0.09940
gtp_human5d.cfg preaz_5d gtp_human6d.cfg +91 [70, 111] ✅ 1208 0.13240
gtp_human4d.cfg preaz_4d gtp_human5d.cfg +76 [57, 96] ⚠ below +100 1256 0.15750
gtp_human3d.cfg preaz_3d gtp_human4d.cfg +112 [89, 134] ⚠ above +100 1039 0.18960
gtp_human2d.cfg preaz_2d gtp_human3d.cfg +101 [74, 127] ✅ 719 0.21300
gtp_human1d.cfg preaz_1d gtp_human2d.cfg +106 [85, 128] ✅ 1087 0.19170
gtp_human1k.cfg preaz_1k gtp_human1d.cfg +105 [82, 129] ✅ 896 0.20150
gtp_human2k.cfg preaz_2k gtp_human1k.cfg +96 [71, 121] ✅ 800 0.19950
gtp_human3k.cfg preaz_3k gtp_human2k.cfg +100 [72, 127] ✅ 664 0.20760
gtp_human4k.cfg preaz_4k gtp_human3k.cfg +93 [71, 114] ✅ 1088 0.21180
gtp_human5k.cfg preaz_5k gtp_human4k.cfg +108 [86, 129] ✅ 1104 0.21600
gtp_human6k.cfg preaz_6k gtp_human5k.cfg +93 [71, 115] ✅ 1000 0.22480
gtp_human7k.cfg preaz_7k gtp_human6k.cfg +100 [71, 129] ✅ 608 0.24590
gtp_human8k.cfg preaz_8k gtp_human7k.cfg +102 [75, 129] ✅ 688 0.25840
gtp_human9k.cfg preaz_9k gtp_human8k.cfg +107 [85, 129] ✅ 1032 0.30620
gtp_human10k.cfg preaz_10k gtp_human9k.cfg +101 [74, 128] ✅ 688 0.37250
gtp_human11k.cfg preaz_11k gtp_human10k.cfg +103 [76, 129] ✅ 704 0.40810
gtp_human12k.cfg preaz_12k gtp_human11k.cfg +100 [71, 129] ✅ 608 0.46300
gtp_human13k.cfg preaz_13k gtp_human12k.cfg +104 [79, 129] ✅ 800 0.83000
gtp_human14k.cfg preaz_14k gtp_human13k.cfg +100 [71, 129] ✅ 592 3.40040

All rungs run at maxVisits = 40; strength is set by λ only.

Honest exceptions, stated up front: 4d (+76) and 3d (+112) were re-measured at their exact shipped λ after an optimistic pooled estimator was found and removed (it had averaged a λ-gradient into a biased, too-tight CI on the steep dan rungs). Their honest gaps fall just outside [70, 130]; they are documented as measured, not re-tuned. All other dan/low-kyu rungs certify in-band.

15k → 25k — pure-human tail (λ = 1e8)

At this depth adjacent Human-SL ranks are near-tied: the even-game gap is non-monotonic in λ and peaks below +100 ELO, so a 100-ELO step is not reachable by the λ lever alone. These rungs ship at pure-human imitation and their natural gap vs the rung above is measured, not forced:

Config Profile Baseline (stronger) Even-game gap (95% CI) Games piklLambda
gtp_human15k.cfg preaz_15k gtp_human14k.cfg +29 [-1, 59] 528 1e8
gtp_human16k.cfg preaz_16k gtp_human15k.cfg +24 [-6, 55] 512 1e8
gtp_human17k.cfg preaz_17k gtp_human16k.cfg +44 [14, 75] 504 1e8
gtp_human18k.cfg preaz_18k gtp_human17k.cfg +70 [40, 101] 520 1e8
gtp_human19k.cfg preaz_19k gtp_human18k.cfg +32 [2, 62] 520 1e8
gtp_human20k.cfg preaz_20k gtp_human19k.cfg +8 [-22, 39] 504 1e8
gtp_human21k.cfg preaz_21k gtp_human20k.cfg +23 [-7, 54] 504 1e8
gtp_human22k.cfg preaz_22k gtp_human21k.cfg +29 [-1, 59] 504 1e8
gtp_human23k.cfg preaz_23k gtp_human22k.cfg −1 [-32, 29] 496 1e8
gtp_human24k.cfg preaz_24k gtp_human23k.cfg +55 [25, 85] 536 1e8
gtp_human25k.cfg preaz_25k gtp_human24k.cfg +86 [55, 116] 528 1e8

The small deep-kyu gaps are an honest property of the Human-SL net (adjacent deep-kyu rank inputs encode nearly the same strength), consistent with the earlier evaluation of the old rank-spaced ladder, which found several deep-kyu pairs tied or inverted. A full 100-ELO deep-kyu staircase would need a different weakening lever (fewer visits, temperature, or a weaker human-model rank) — possible future work.

Notes

  • The rank calibration is realized at move selection (GTP genmove). The analysis engine can load the human model and return humanPolicy under these settings via overrideSettings, but it does not itself perform the calibrated move choice.
  • Configs use humanSLProfile = preaz_<rank> (pre-AlphaZero KGS-rank profiles) with b18c384nbt-humanv0 as the human model.

🤖 Generated with Claude Code

https://claude.ai/code/session_014DKwH3TAhhGUSWqsMMoQcH

ChinChangYang added a commit to ChinChangYang/KataGo that referenced this pull request Jun 26, 2026
…<year>)

Consolidate rank_*/preaz_* into unified <rank> keys driven by the
empirically-tuned KGS-rank ladder from lightvector/KataGo PR lightvector#1209
(preaz_<rank> + tuned humanSLChosenMovePiklLambda), and rename
proyear_<year> to "Pro <year>" derived from the 9d config with lambda 0.06.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoQvc49FJf5btyZsHLawb3
ChinChangYang added a commit to ChinChangYang/KataGo that referenced this pull request Jun 26, 2026
TDD plan: rewrite HumanSLModel around clean menu keys (lightvector#1209 preaz_<rank>
ladder + Pro <year>), legacy input normalization, picker wiring, and a
3-platform verification pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoQvc49FJf5btyZsHLawb3
ChinChangYang added a commit to ChinChangYang/KataGo that referenced this pull request Jun 26, 2026
Consolidate rank_*/preaz_* into single <rank> keys driven by PR lightvector#1209's
tuned KGS-rank ladder (preaz_<rank> + per-rank humanSLChosenMovePiklLambda),
rename proyear_<year> to 'Pro <year>' (9d-derived, lambda 0.06), and add
legacy input normalization. AI profile behavior preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoQvc49FJf5btyZsHLawb3
ChinChangYang added a commit to ChinChangYang/KataGo that referenced this pull request Jun 26, 2026
Human-profile engine moves search a fixed 400 visits (lightvector#1209 calibration
point) instead of the time budget, so a rank plays at its calibrated
strength; "Time per move" applies only to the AI profile (human profiles
get an Engine/Human toggle). Continuous analysis stays unbounded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoQvc49FJf5btyZsHLawb3
ChinChangYang added a commit to ChinChangYang/KataGo that referenced this pull request Jun 26, 2026
Add GtpCommandBuilder.searchBudgetCommands: AI profile stays time-bounded
with unbounded visits; human rank/pro profiles use a fixed 400 visits
(lightvector#1209 calibration point) + a safety time cap, ignoring Time per move.
genMoveAnalyzeCommands now takes the effective profile.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoQvc49FJf5btyZsHLawb3
ChinChangYang added a commit to ChinChangYang/KataGo that referenced this pull request Jun 28, 2026
The redesigned human-SL parameters played too strong and slow. Revert the
engine parameters in HumanSLModel to the pre-redesign (4be0ad7~1) level-based
formulas while keeping the new clean-key UI/structure (allProfiles,
canonicalProfile, legacy normalization, preaz_/proyear_ mapping):

- winLossUtilityFactor for human profiles 1.0 -> 0.0 (imitate, not try-to-win)
- humanSLRootExploreProbWeightless 0.8 -> 0.5
- restore level-based temperatures + quadratic lambda 0.06+(level-9)^2*0.03;
  delete the lightvector#1209 rankLambda/proLambda ladder
- reintroduce `level`, derived from the clean keys (AI/pro->9, Nd->N-1, Nk->-N)
- AI profile unchanged

Make the human play-move visit budget rank-dependent so weaker ranks play fast:
9d and all Pro -> 400 visits; ranks 8d..20k -> 40 (humanSLPlayVisitBudget(for:)
in GtpCommandBuilder). Continuous-analysis reset-to-unbounded sites unchanged.

Tests updated to the old expected values via a tolerance-based value helper.
Full iOS suite 439/439; iOS/visionOS/macOS build green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WoQvc49FJf5btyZsHLawb3
@lightvector

Copy link
Copy Markdown
Owner

29 configs, gtp_human{9d…1d,1k…20k}.cfg. The Human-SL net is conditioned on KGS rank, so a
1-rank gap is well-defined: per KGS, 1 rank = 1 stone, realized as an even game where the
stronger side (White) gets no komi compensation (komi 0.5). Each rung is tuned so the weaker
rank (Black, komi 0.5) is an even game (50%) vs the rung above, with the 95% CI ⊂
[40%, 60%], under Japanese rules.

Isn't that only half a stone?

KGS's match system by default matches players 1 rank apart with no-komi games, but that's to conform to convention. I'm pretty sure the ranking system understands this too.

@lightvector

Copy link
Copy Markdown
Owner

i.e. I'm pretty sure the ranking system understands and is calibrated for the fact that for players exactly 1 rank apart (in internal full-precision ratings) who play a no-komi game, white is expected to win more often than 50%. The true 1-rank difference would be a reverse-komi game.

@ChinChangYang

ChinChangYang commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

I’m retuning Lambda with winLossUtilityFactor=0, 28b main network + maxVisits=40, and an ELO gap set to +100. The estimated time to completion is around 20 days. I’ll update this PR once it’s ready.

The retuning aims to address the following issues:

  • The winLossUtilityFactor=1 makes the AI excessively strong, even for DDK profiles.
  • The 6b network is weaker compared to the 18b human SL network for high-dan profiles.
  • Tuning by 0.5 or 1 stone gaps results in unstable ELO gaps between ranks. Some ranks have ELO gaps exceeding 100, while others have nearly 0 ELO gaps.

@glittering-snow

Copy link
Copy Markdown

Thanks for working on this.
The rank-as-strength calibration is exactly the missing piece for my educational use case. When the retuning is complete, would the resulting per-rank settings also be intended for the analysis engine via overrideSettings, or only for GTP configs? I’d also be happy to test a few ranks in real user-facing play once candidate configs are available.

33 GTP configs that make KataGo + the Human-SL net play at a chosen amateur
strength. Each adjacent gap is directly measured in normal even games (komi
6.5, alternating colours, Japanese rules, b28c512 main net, 40 visits,
winLossUtilityFactor=0):

- 8d: hand-set top anchor (lambda 0.06).
- 7d->14k: a fixed 100-ELO staircase - each rung tuned via
  humanSLChosenMovePiklLambda so the rung above beats it by +100 ELO,
  certified to a 95% CI within [70,130]. Honest exceptions documented as
  measured, not re-tuned: 4d +76 [57,96], 3d +112 [89,134].
- 15k->25k: pure-human tail (lambda 1e8). Adjacent deep-kyu Human-SL ranks
  are near-tied (the even-game gap is non-monotonic in lambda and peaks
  below +100), so each rung ships pure-human with its natural measured gap
  (-1..+86) documented.
- cpp/neuralnet/sgfmetadata.cpp: 13-line extension of SGFMetadata::getProfile
  rank parsing from 20k down to 30k, so the preaz_21k..preaz_25k profiles used
  by the deep-kyu configs parse (the rank input encoding saturates at
  inverse-rank 34 = 25k, so 26k..30k encode identically to 25k). Without it
  those five configs fail at startup.

docs/HumanSL_Rank_Ladder.md documents the method (chained even-game
calibration anchored at 8d, single-lambda Wilson-CI lock), the full
per-rung results (lambda / gap / 95% CI / games), and findings. The
calibration harness (the tunehuman subcommand and drivers) lives in the
author's fork and is intentionally not part of this PR: the engine should
focus on playing and analysis, not offline tuning.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014DKwH3TAhhGUSWqsMMoQcH
@ChinChangYang
ChinChangYang force-pushed the gtp-human-rank-configs branch from 26c7a0c to bc99f75 Compare August 6, 2026 23:39
@ChinChangYang ChinChangYang changed the title Add Human-SL KGS-rank ladder (gtp_human<rank>.cfg, 9d→20k) + tunehuman subcommand Add Human-SL even-game ELO rank ladder configs (gtp_human<rank>.cfg, 8d→25k) Aug 6, 2026
@ChinChangYang
ChinChangYang marked this pull request as ready for review August 6, 2026 23:40
@ChinChangYang

Copy link
Copy Markdown
Contributor Author

The ladder is now calibrated for normal even games (komi 6.5, alternating colors), with each rung tuned against its stronger neighbor to achieve a +100 ELO gain per rung. Additionally, every adjacent gap is directly measured to a 95% confidence interval (per-rung λ / gap / CI / games), as described in the updated description and docs/HumanSL_Rank_Ladder.md.

I also reduced the PR to configurations, documentation, and a 13-line SGFMetadata::getProfile extension for parsing preaz_21k and preaz_25k. The tunehuman calibration harness remains in my fork because the engine should focus on playing and analysis. Two honest caveats are documented rather than overlooked: 4d (+76 [57,96]) and 3d (+112 [89,134]) measurements are just outside the [70,130] range at their shipped λ, and the deep-kyu tail (15k→25k) is shipped as a pure-human imitation. (λ=1e8) because the ranks of adjacent deep-kyu Human-SL are nearly tied.

ChinChangYang added a commit to ChinChangYang/KataGo that referenced this pull request Aug 8, 2026
Replace HumanSLModel's quadratic lambda formula with the certified
per-rank humanSLChosenMovePiklLambda table from KataGo PR lightvector#1209
(gtp-human-rank-configs): the 7d-14k ~100-ELO staircase, the 15k-25k
pure-human tail (1e8), and the hand-set 8d anchor. Rank profiles share
the ladder's constant human params (root-explore 0.8, temps
0.70/0.25/30/1.0, imitation winLoss 0, score utils 0.5/0.5); pros reuse
the 8d-anchor lambda 0.06; 9d becomes the docs' legacy-strong reference
(lambda 0.045, try-to-win, 400 visits). The level-formula machinery is
deleted.

Human profiles also adopt the calibration's search-heuristic settings
(useLcbForSelection/useUncertainty/useNoisePruning off,
subtreeValueBiasFactor 0), mirrored by explicit restores in the AI
profile so the sticky kata-set-param state never leaks into
full-strength play or analysis.

The menu extends to 25k (34 ranks, 259 profiles); preaz_21k..25k
parsing comes from the PR's sgfmetadata.cpp extension (21k-30k inverse
ranks), applied verbatim. Visit budgets are unchanged: 9d/pros 400,
ladder rungs 40.

Verified: iOS suite 1476/1476, all five schemes build, and a headless
katago-engine session accepts preaz_25k/preaz_21k plus all four
heuristics via kata-set-param and gen-moves at the 40-visit cap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01An63LYQDTk7aX8jjtmxVrF
ChinChangYang added a commit to ChinChangYang/KataGo that referenced this pull request Aug 8, 2026
…adoption

The f076a37 re-adoption extended the rank menu to 25k and re-based the
calibration story (~100-ELO rungs certified at 40 visits; 400 is now the
legacy-strong 9d/pro budget), leaving four stale surfaces:

- README: the per-side profile picker offers 9d through 25k, not 20k.
- GtpCommandBuilder comments: the 400/40 budget constants and the
  budget helper described the old 8d..20k band and the obsolete
  '1 KGS stone at 400 visits' calibration point.
- The two 2026-06-26 specs now carry amend-in-place sections recording
  what shipped: the retuned lambda ladder, imitation-mode rungs with the
  legacy-strong 9d exception, the mirrored search heuristics, the
  per-rank visit budgets, and the b28c512/8-thread calibration caveat.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01An63LYQDTk7aX8jjtmxVrF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants