Repository navigation
Add a gainExponent for auto-tuning; default 0.6 for BactrianSubtreeSlide - #218
Merged
Merged
Conversation
Auto-tuning moves an operator's tuned value (on its tuning scale) by (acceptance - target) / n after n proposals. With that 1/n gain the total distance it can travel grows only as about 0.7 ln n, so a start that is wrong by more than a few thousand-fold never tunes. The subtree slide's size is in the tree's own units, so its right value ranges from about 0.01 to 10^5 between ordinary analyses (#200): a start at 1.0 is stuck too large on substitution-scale trees, and a start at 0.01 (#201) is stuck too small on trees a few thousand units tall. Add gainExponent e, so that the gain is 1/n^e with 0 < e <= 1: - OperatorSchedule gets a gainExponent input, for operators that don't set their own. 1 is the classic 1/n and 0.5 is transform="sqrt"; it can't be combined with a transform other than none. - Operator gets a gainExponent input and getGainExponent() / getDefaultGainExponent(), on the pattern of targetAcceptanceProbability. The default is NaN, meaning the schedule decides, so no operator changes unless it overrides it. - BactrianSubtreeSlide defaults to 0.6, the usual choice for diminishing adaptation (Andrieu and Thoms 2008); it can travel as n^0.4 instead. The state file already stores the counts the gain is computed from, so resumed runs continue with the same gain.
Member
|
To check:
Smaller points:
|
…s at load From the review of #218: - Precedence is now: the operator's gainExponent input, then the schedule's gainExponent or transform, then the operator's built-in default, then 1/n. A schedule transform="sqrt" or gainExponent="1" is no longer ignored for the subtree slide. - An operator's gainExponent is checked when it is added to a schedule, so a bad value fails at load time, also with autoOptimize="false", and calcDelta no longer builds a message string on every call. - Warn, don't reject, at gainExponent <= 0.5: the tuned value may not settle (Robbins-Monro needs 0.5 < e <= 1); transform="sqrt" is 0.5. - The classic SubtreeSlide also defaults to 0.6 (same issue, #200). - Tests: schedule settings override the slide default, bad operator exponents fail when added, operator boundary values, classic slide.
Member
Author
|
Thanks, Walter. Fixed in 0ccfdc8, point by point:
The full |
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a
gainExponentfor operator auto-tuning, and makesBactrianSubtreeSlidedefault to 0.6, so that the subtree slide tunes from any start size. Addresses #200; an alternative or complement to #201 (start at 0.01) and #214 (BactrianSubtreeScale). Found during release testing (#183).Problem
Auto-tuning moves an operator's tuned value, on its tuning scale, by (acceptance − target) / n after n proposals. With this 1/n gain the total distance it can travel grows only as about 0.7 ln n. In our runs the slide's size moved by at most about 8,000-fold in 3M steps, so a start that is wrong by more than that never tunes.
The subtree slide's size is in the tree's own units, so its right value ranges over many orders of magnitude between ordinary analyses. Measured on the BEAUti test analyses (beast3-test, BEAST 3 v2.8.0-rc2, 3M steps, seeds 1 and 2):
Trees this tall are not unusual: on PhyloData, 29 of 110 experiments have a mean root age ≥ 100 and 3 have one ≥ 1000, the tallest 2.3 million (a Yule tree with the clock fixed per year). The posterior is correct in every case; a stuck slide costs about 20–35 % of the ESS of the likelihood and tree height.
Change
The gain becomes 1/n^e, with 0 < e ≤ 1:
OperatorSchedulegets againExponentinput, for operators that don't set their own. 1 is the classic 1/n and 0.5 is the same astransform="sqrt". It can't be combined with atransformother thannone.Operatorgets againExponentinput andgetGainExponent()/getDefaultGainExponent(), on the pattern oftargetAcceptanceProbability. The default is NaN, meaning the schedule decides, so no other operator's tuning changes.BactrianSubtreeSlideand the classicSubtreeSlideoverride the default with 0.6, the usual choice for diminishing adaptation (Andrieu & Thoms 2008). Their log size can then travel as n^0.4 instead of ln n.gainExponent="1"on the operator (or on the schedule) restores the old behaviour.Precedence: the operator's input, then the schedule's
gainExponentortransform, then the operator's default, then 1/n. Exponents are checked at load time; 0 < e ≤ 1 is allowed, with a warning at e ≤ 0.5, where the tuned value may not settle. The state file already stores the counts the gain is computed from, so resumed runs of the same build continue with the same gain.Because 1/n can also get stuck on other operators, the schedule-wide
gainExponentlets an analysis use 0.6 for every operator. Whether that should become the schedule default needs a broader test and is left for later.Results
With this branch and unchanged XML, all four stuck cases tune to 30 % acceptance and match the posterior of the reference runs (seeds 1 and 2, ESS per million steps, two replicates summed):
BactrianSubtreeScale: 3309)BactrianSubtreeScale: 5639)BactrianSubtreeScale: 3121)BactrianSubtreeScale: 5681)BactrianSubtreeScale: 3121)BactrianSubtreeScale: 5681)Reference runs: the default-tuned slide on the 0.19 tree (rc2), and
BactrianSubtreeScalefrom #214 on the tall trees. The tuned size from both starts is the same.Where 1/n already tuned
Same build, unchanged XML, seeds 1 and 2, the slide starting at 1.0. The slide reaches the same size, every posterior matches, and the ESS of every logged column is unchanged on median:
* compared with the
BactrianSubtreeScalerun, whose build also has theSampleOffValuesfix (#203); its columns include 129 binary indicators.Across all tuned runs, from either start and with either gain, the slide settles at 0.25–0.45 × H / √(2n − 1).
Tests
OperatorGainExponentTest: the default gain is still exactly 1/n; schedulegainExponent1 and 0.5 reproduce the default andtransform="sqrt"; an operator's exponent overrides the schedule's; both slides default to 0.6, the schedule's settings override that, and the slide's own input overrides the schedule; invalid values are rejected at load time, also with auto-tuning off; operator boundary values (1, 0.5, 1e-6) are accepted.beast-basesuite passes: 580 tests, 3 skipped (JDK 26, macOS).Not done
BactrianSubtreeSlide. See Where 1/n already tuned above: no systematic change in mixing.gainExponent="1".BactrianSubtreeScaleand resume tests pass on the result. With both merged,BactrianSubtreeSlidedefaults to 0.6 andBactrianSubtreeScalekeeps the schedule's gain; it doesn't need a slower one, since it ends at the same size (about 0.19) on every tree height.🤖 Generated with Claude Code