Implement staged warm-up adaptation schedule#127
Open
jennajiali wants to merge 8 commits into
Open
Conversation
… indentation to improve readability
…sts, with minor changes of indentation to improve readability.
…itial_shape parameter Previously all adapter initialize() functions ignored the current proposal parameters on re-initialisation, causing the scale and shape estimates accumulated during one staged warm-up stage to be discarded at the start of the next. This contradicted the requirement in issue UCL#79 that adaptation parameters be initialised at the values at the end of the previous stage. Changes in R/adaptation.R: - stochastic_approximation_scale_adapter: when initial_scale is not user-specified, initialize() now reads proposal$parameters()$scale and uses it as the starting log-scale if available, falling back to proposal$default_initial_scale() only when no current scale exists. - dual_averaging_scale_adapter: same fix. Note that mu, smoothed_log_scale and accept_prob_error already persisted across stages via closure scope and required no change. - variance_shape_adapter: initialize() now follows a three-priority order: (1) explicit initial_shape constructor argument if supplied, (2) current proposal shape if it is a vector of matching length, (3) unit variances as before. The length check prevents accidentally carrying over a matrix-valued shape from a covariance adapter stage. Adds initial_shape parameter (numeric vector of per-dimension scales) to the function signature and roxygen documentation, addressing the request to allow users to supply domain-knowledge-based starting values. - covariance_shape_adapter: same three-priority fix. Carries over the current proposal Cholesky factor if it is a matrix of matching dimensions, falls back to the identity otherwise. The is.matrix() guard prevents carrying over a vector-valued shape from a variance adapter stage. Adds initial_shape parameter (lower-triangular Cholesky factor matrix) to the function signature and roxygen documentation. Changes in tests/testthat/test-adaptation.R: - Four tests for scale adapter carry-over: both stochastic_approximation and dual_averaging variants are checked for (a) reading the current proposal scale on re-initialisation and (b) explicit initial_scale still taking priority over the proposal's current value. - Four tests for variance_shape_adapter: carry-over from a vector proposal shape; explicit initial_shape override; NULL proposal falls back to unit variances; matrix-valued proposal shape (incompatible type) falls back to unit variances. - Four tests for covariance_shape_adapter: carry-over from a matrix proposal shape; explicit initial_shape override; NULL proposal falls back to identity; vector-valued proposal shape (incompatible type) falls back to identity. - One end-to-end integration test via sample_chain with trace_warm_up=TRUE: verifies that the log_scale in warm_up_statistics does not jump back to the default value at the stage boundary between two consecutive scale-adapter-only stages.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #127 +/- ##
===========================================
- Coverage 100.00% 99.85% -0.15%
===========================================
Files 11 11
Lines 595 696 +101
===========================================
+ Hits 595 695 +100
- Misses 0 1 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
This PR implements the staged warm-up adaptation interface proposed in issue #79, allowing users to specify different adapter configurations at different points during warm-up. It builds on the partial implementation started on the mmg/adapter-staging branch and ensures adapter states correctly carry over across stage boundaries.
Background
Previously,
sample_chain()ran all adapters from iteration 1 of warm-up with no way to vary which adapters were active over time. This is suboptimal in practice: the shape adapter (which estimates the proposal covariance) should not start until the scale adapter has had enough iterations to stabilise, because early covariance estimates based on poorly-mixed samples can make the sampler worse rather than better.Furthermore, previously all adapter
initialize()functions ignored the current proposal parameters on re-initialisation, causing the scale and shape estimates accumulated during one staged warm-up stage to be discarded at the start of the next. This contradicted the requirement in issue #79 that adaptation parameters be initialised at the values at the end of the previous stage.Changes
R/chains.R
check_and_process_adapters()— new internal function that normalises theadaptersargument into a canonical list of stage specifications, each with$adapters(a list of adapter objects) and$n_iteration(an integer). Accepts three input forms:n_warm_up_iterationand returning a staged list (used byprogressive_adaptation_schedule())sample_chain()— warm-up loop now iterates over stages produced bycheck_and_process_adapters(), passing each stage's adapter list and iteration count tochain_loop()separately. Several bugs in the initial partial implementation are fixed:warm_up_resultsinitialised with key$final_state(not$state) to be consistent withchain_loop()'s return valuestage$n_iterationrather than always using the fulln_warm_up_iterationstage$adapters(clean list of adapter objects) rather than the whole named stage listWarm-up (stage 1/3))combine_warm_up_results()— rewritten to userbindinstead ofmapply(c, ...). This correctly handles the bootstrap case (rbind(NULL, matrix)returns the matrix unchanged) and uses the correct$final_statekey throughoutcombine_stage_results()— fixed$state→$final_stateto matchchain_loop()'s return value@param adaptersdocumentation — updated to describe all three input formsR/adaptation.R
progressive_adaptation_schedule()— new exported convenience function that returns a schedule constructor. When called withn_warm_up_iteration, it produces a three-stage adaptation schedule following common practice:n_fixed_shape_iterationiterations (default 50)shape_adapter("variance")), forn_diagonal_shape_iterationiterations (default 50)shape_adapter("covariance")), for remaining iterationsn_warm_up_iteration, both are reduced proportionally and stage 3 is skipped. All adapter objects and iteration counts are customisable via arguments. Includes full roxygen documentation and a working example.stochastic_approximation_scale_adapteranddual_averaging_scale_adapter: wheninitial_scaleis not user-specified,initialize()now readsproposal$parameters()$scaleand uses it as the starting log-scale if available, falling back toproposal$default_initial_scale()only when no current scale exists. Note that fordual_averaging_scale_adapter,mu,smoothed_log_scaleandaccept_prob_erroralready persisted across stages via closure scope and required no change.variance_shape_adapterandcovariance_shape_adapter:initialize()now follows a three-priority order:initial_shapeconstructor argument if supplied.variance_shape_adapterrequires a vector of matching length to prevent accidentally carrying over a matrix-valued shape.covariance_shape_adapterrequires a matrix of matching dimensions (Cholesky factor) to prevent carrying over a vector-valued shape.initial_shapeparameter (numeric vector of per-dimension scales for variance; lower-triangular Cholesky factor matrix for covariance) to the respective function signatures and roxygen documentation, addressing the request to allow users to supply domain-knowledge-based starting values.tests/testthat/test-chains.R
New tests appended after existing tests:
check_and_process_adapters()covering all three input forms, the last-stage remainder logic, and all error cases (non-last stage missing count, counts not summing ton_warm_up_iteration, invalid input types)sample_chain()with staged adapters: correct warm-up row counts across two and three stages, correct behaviour with differing adapter sets across stages whentrace_warm_up = FALSE, function-form adapters argument, correctfinal_statetype, and invalid adapters error propagationtests/testthat/test-adaptation.R
New tests appended after existing tests covering
progressive_adaptation_schedule():n_warm_up>n_fixed+n_diagonal), the exact-boundary case (no dense stage), and the fallback case (n_warm_up<n_fixed+n_diagonal)n_warm_up_iteration = 1n_fixed_shape_iterationandn_diagonal_shape_iterationare respectedcheck_and_process_adapters()across a range ofn_warm_up_iterationvaluessample_chain()integration testNew tests covering state carry-over across stages:
stochastic_approximationanddual_averagingvariants are checked for (a) reading the current proposal scale on re-initialisation and (b) explicitinitial_scalestill taking priority over the proposal's current value.variance_shape_adapter: carry-over from a vector proposal shape; explicitinitial_shapeoverride;NULLproposal falls back to unit variances; matrix-valued proposal shape (incompatible type) falls back to unit variances.covariance_shape_adapter: carry-over from a matrix proposal shape; explicitinitial_shapeoverride;NULLproposal falls back to identity; vector-valued proposal shape (incompatible type) falls back to identity.sample_chainwithtrace_warm_up=TRUE: verifies that thelog_scaleinwarm_up_statisticsdoes not jump back to the default value at the stage boundary between two consecutive scale-adapter-only stages.Usage examples
Fully custom staged schedule:
Using the convenience constructor with defaults:
Existing flat-list usage is unchanged:
Known limitation
When trace_warm_up = TRUE and stages use different adapter sets (e.g. scale-only in stage 1, scale + shape in stage 2), the warm-up statistics matrices from each stage have different column counts and cannot be rbind-ed. This causes an error. A future PR could address this by filling NA for missing columns. For now, trace_warm_up = TRUE with staged adapters is only safe when all stages use the same adapter set. This limitation is documented in the new tests.