Adam scale adapter implementation#132
Open
jennajiali wants to merge 3 commits into
Open
Conversation
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.
Summary
Adds a third scale-adaptation algorithm to
rmcmc, alongside the existing Robbins–Monro (stochastic_approximation) and Nesterov dual-averaging (dual_averaging) schemes. The new adapter applies the Adam optimizer of Kingma & Ba (2014) to the log of the proposal scale, using the acceptance-rate residualtarget_accept_prob accept_probas the (stochastic) gradient — the same gradient signal already used by the two existing scale adapters, plugged into the Adam update rule instead of a power-law schedule.The design follows the C++ implementation in the
walnutslibrary, including itslearning_rate / t^learn_rate_decayschedule needed to match the stability of dual averaging (per Bob Carpenter's note on NUTS improvements).Public API
Two-level exposure as requested in #130:
High-level wrapper —
scale_adapter(algorithm = "adam", ...)accepts the commoninitial_scale/target_accept_probarguments plus the single Adam tuning knob users actually reach for:Low-level function —
adam_scale_adapter()exposes all Adam hyperparameters for advanced users:Defaults and rationale
learning_rate0.051e-3is too slow to hit the shared 2000-iteration /tol = 1e-2convergence test used by all scale adapters.0.05gives fast, stable coercion in typical MCMC warm-up lengths. The docstring notes that1e-3matches the original paper.beta_10.9beta_20.999epsilon1e-8learn_rate_decay0.50) oscillates.Algorithm
On each
update, witht = sample_index:β₁ᵗandβ₂ᵗare maintained incrementally asbeta_1_pow,beta_2_powrather than recomputed each step, matching walnuts and avoiding.Machine$double.xminunderflow for long chains.Sign convention
grad = target − observedcombined withlog_scale −= η · m̂ / (√v̂ + ε)reproduces the "accept_prob > target ⇒ scale increases" behaviour of the other two scale adapters. This is verified by both the directional and convergence tests in the sweep below. An inline comment inadam_scale_adapterflags the sign for future maintainers.Changes
R/adaptation.Rscale_adapter()roxygen:"adam"bullet under@param algorithm.@param ...to document the two-level exposure design.[adam_scale_adapter()]to@seealso.@references.adam = adam_scale_adapterto theswitch()inscale_adapter().adam_scale_adapter()function (roxygen block + implementation) placed immediately afterdual_averaging_scale_adapter.state():log_scale,m,v(bothbeta_*_powkept internal — they're implementation detail and would only add noise towarm_up_statisticswhentrace_warm_up = TRUE).initialize()resets all Adam state so the same adapter object can be re-initialised mid-run (used in the tests).finalize = NULL, matching walnuts and the SA adapter — no smoothed-scale tail.tests/testthat/test-adaptation.Rcheck_adam_scale_adapter_state()helper (mirrors the SA / dual averaging state checkers).target_accept_prob ∈ {0.2, 0.4, 0.6}×initial_scale ∈ {0.5, 1, 2}×learning_rate ∈ {0.05, 0.1}— 18 test cases — each of which:t = 1for bothaccept_prob > targetand
accept_prob < target,check_scale_adapter_coerces_to_target_accept_prob()helper (2000 iterations,
tol = 1e-2).{1L, 2L, 5L}) using the sharedcheck_scale_adapter_with_default_args_works()helper to verify the default-construction path.All unit tests passed when I ran
devtools::test()