Hoffman 2021 - ChEES Criterion and Algorithm 1

Summary

The ChEES criterion is : an ESJD of the centred, squared norm. It is shift/rotation invariant, dominated by high-variance directions and focused on second moments. Algorithm 1 ascends its gradient with Adam on using one jittered length per iteration shared by all chains, weights chains by acceptance probability, and tunes step size by dual averaging on the harmonic-mean acceptance probability (target 0.651).

Overview

Section 2.1 argued for minimising first-order autocorrelation of with the highest-variance direction. We cannot know , so ChEES is a heuristic satisfying three desiderata: (i) invariance to shifts and rotations, (ii) insensitivity to low-variance directions, (iii) focus on second-moment estimation.

Main Content

ChEES (eq. 7)

With , at equilibrium and :

Centring gives shift invariance; dependence only on squared norms gives rotation invariance.

ChEES decomposition (eqs 8-9)

Take , for , and . Then

The first term is constant in . The second equals where is the first-order autocorrelation of . The cross terms are small if dimensions are approximately independent after rotation. The weights (the variance of ) are generally proportional to , so the criterion aggressively weights high-variance directions, as desired.

Gradient with respect to (eq. 10)

Sketch. Differentiate along Hamilton’s equations: . The integral over is the Monte Carlo average over the uniform jitter .

Algorithm 1 (ChEES-HMC) in words

Inputs: unnormalised target, initial states for chains , initial step size , samples, , Halton sequence . Initialise and moving averages .

For :

  1. Draw momenta and pick the jittered length .
  2. Propose .
  3. Accept with .
  4. If : compute the harmonic-mean acceptance and update by dual averaging toward ; estimate means , ; compute per-chain gradient estimates combine , update with Adam, and set , .
  5. At freeze , .

Design choices and their rationale

  • Adam on because the scale of is problem dependent: step size (not sensitive), (no momentum), .
  • One shared for all chains so every chain does the same work per iteration (simpler, faster code on SIMD).
  • Weight by acceptance probability so obviously invalid states do not drive .
  • Estimate from the initial and final integrator states across chains.
  • Harmonic-mean acceptance prevents a “straggler” chain stuck in a region requiring small steps from being ignored by an arithmetic average; if any chain has tiny the harmonic mean pulls down for all.
  • Round up to an integer multiple of ; adapt only during warmup to avoid bias from hyperparameters depending on recent states.
  • Halton sequence (Owen 2017) instead of i.i.d. uniform jitter for more evenly spread lengths. It is determined a priori so the stationary distribution is unaffected.

Examples

Numpy sketch of ChEES-HMC on a 3-D Gaussian (tested)

Target , 64 chains, 1500 iterations, 1000 warmup. In three seeds the adapted ended at about 6.0, 6.2 and 6.5, close to the rule from Hoffman 2021 - Gaussian Autocorrelation Analysis and Trajectory Jitter (the match is approximate, not guaranteed; this is an illustration, not the paper’s code).

import numpy as np
def halton(i, b=2):
    f, r = 1.0, 0.0
    while i > 0: f /= b; r += f*(i % b); i //= b
    return r
# per iteration n, with theta (M,D), eps, T, adam state:
#   t = halton(n)*T ; L = ceil(t/eps) ; r ~ N(0,I)
#   th2, r2 = leapfrog(theta, r, eps, L, gradL)
#   a = min(1, exp(logp(th2)-logp(theta) - .5|r2|^2 + .5|r|^2))
#   g_m = t*(|th2-mean(th2)|^2 - |theta-mean(theta)|^2) * sum((th2-mean(th2))*r2, -1)
#   g = sum(a*g_m)/sum(a);  Adam step on log T with lr .025, b1=0, b2=.95
#   eps via dual averaging on harmonic mean of a (target .651)
#   accept per chain with prob a;  freeze eps,T at warmup end (use EMAs)

Examples (PyMC-style)

Motivating example E86 (examples page): ChEES-HMC is available in blackjax. Untested sketch:

import blackjax, jax, jax.numpy as jnp
# logdensity_fn: a JAX log-density over a flat position vector (e.g. from pymc.sampling.jax or hand-written)
warmup = blackjax.chees_adaptation(logdensity_fn, num_chains=128)
key = jax.random.key(0)
(last_states, parameters), _ = warmup.run(key, initial_positions, step_size=0.1, optim=None, num_steps=500)
kernel = blackjax.dynamic_hmc(logdensity_fn, **parameters).step   # then jax.vmap over chains

API names and arguments may differ across blackjax versions; check the installed docs before use.

Connections

Follows from Hoffman 2021 - Gaussian Autocorrelation Analysis and Trajectory Jitter. Results: Hoffman 2021 - Experiments - ESS per Gradient and GPU Throughput. MEADS, the next step, replaces trajectory-length tuning by tuning damping in generalised HMC: Hoffman 2022 - MEADS Heuristics - Step Size, Damping, Drift and Eigenvalue Estimation.

See Also

Hoffman 2021 - ChEES-HMC - Overview, Efficient MCMC