Skip to content

Allow user to define a schedule for adaptation during burn-in #79

Closed

Description

@LkHardcastle

We would like to allow for the user to specify a schedule that allows for different adaptation strategies to be used at different points during warm-up.

For example:

Stage 1: For the first 50 iterations, adapt the scale and use the identity matrix as a fixed proposal covariance.
Stage 2: For the next 50 iterations adapt the scale, and adaptively learn a diagonal proposal covariance.
Stage 3: For the remaining warm-up iterations adapt the scale and adaptively learn a dense proposal covariance.

At each stage adaptation parameters would be initialised at the values at the end of the previous stage.

This could be specified as an argument in the sample_chain function as

results <- sample_chain(
  # Other arguments
  adapters = list(
   list(scale_adapter(), fixed_shape(), 50), # Stage 1 (scale adapter, shape adapter, number of iterations)
   list(scale_adapter(), variance_shape_adapter(), 50), # Stage 2 (scale adapter, shape adapter, number of iterations)
  # Stage 3 (scale adapter, shape adapter) 
  # Number of iterations taken as remaining warm-up iterations
   list(scale_adapter(), covariance_shape_adapter()) 
)
)

In addition to the above, is it possible for the user to fix either the scale or shape of the proposal but learn the other adaptively?

Activity

  1. matt-graham commented on Jul 17, 2025

    @matt-graham
    Collaborator

    Hi @LkHardcastle, thanks for raising this!

    Extending the adaptation interface to support this sort of scheduling / staging is definitely a good idea, and I like your proposed interface of just having the adapters argument to sample_chain accept a list of per-stage adapters and number of iterations.

    In addition to the above, is it possible for the user to fix either the scale or shape of the proposal but learn the other adaptively?

    Yes, rmcmc already allows either just the proposal shape or scale to be adapted, by just passing in a single adapter in the list passed to sample_chains, for example adapters = list(scale_adapter()) would just adapt the scale (in which case the shape is implicitly assumed to be an identity matrix). I think because of this we can probably get away without needing to have an explicit fixed_shape dummy adapter object so in your example above could just have list(scale_adapter(), 50) as the first stage specification.

    In Mici, something similar is implemented by the mici.stagers module, which creates a object which returns a sequence of 'chain stages', each defining the adapters to be used and number of iterations in the stage. These objects automatically alllocate the number of iterations per stage based on the number of warm-up iterations. I like the simpler interface of your proposal, but I think we could also support something similar for common schedule configurations by allowing also passing a function to the adapters argument that will be called with n_warm_up_iteration as the argument, to allow quickly setting up standard schedules that will work whatever the number of warm-up iterations the user specifies. For example if we had something like this with

    progressive_adaptation_schedule <- function(
        n_fixed_shape_iteration = 50,
        n_diagonal_shape_iteration = 50,
        scale_adapter_ = scale_adapter(),
        diagonal_shape_adapter = shape_adapter("variance"),
        dense_shape_adapter = shape_adapter("covariance"),
    ) {
        function(n_iteration) {
            if (n_fixed_shape_iteration + n_diagonal_shape_iteration) > n_iteration) {
                n_fixed_shape_iteration <- n_iteration %/% 2
                n_diagonal_shape_iteration <- n_iteration - n_fixed_shape_iteration
            }
            n_dense_shape_iteration <- max(n_iteration - n_fixed_shape_iteration - n_diagonal_shape_iteration, 0)
            list(
                list(scale_adapter_, n_fixed_shape_iteration),
                list(scale_adapter_, diagonal_shape_adapter , n_diagonal_shape_iteration),
                list(scale_adapter_, dense_shape_adapter, n_dense_shape_iteration)
            )
        }
    }

    then your example above could be

    results <- sample_chain(..., adapters = progressive_adaptation_schedule())

    while still allowing the user the flexibility to fully customise the scheduling by directly passing in a list (or doing variants of the above scheme by altering the default arguments to progressive_adaptation_schedule).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions