Skip to content
AI360Xpert
Beta

Normalizing Constants and Annealed Importance Sampling

Model comparison needs the constant Bayes rule divides by, and annealing from an easy distribution to the hard one estimates it without bias.

A chain of heated intermediate distributions bridges the easy base to the hard target, and the product of stepwise ratios estimates the normalizing constant
A chain of heated intermediate distributions bridges the easy base to the hard target, and the product of stepwise ratios estimates the normalizing constant

Why Does This Exist?

Bayes rule divides by the marginal likelihood Z=∫p(data∣θ)p(θ)dθZ = \int p(\text{data} \mid \theta) p(\theta) d\theta, and energy models divide by a partition function of the same shape. These constants are the price of model comparison: the ratio of two ZZ values is the Bayes factor. Yet plain Monte Carlo cannot touch them, because the integrand concentrates where the prior rarely lands.

Annealed importance sampling (Neal, 2001) builds a bridge. Start from an easy distribution with known Z0Z_0, heat it through intermediates toward the target, move samples along with MCMC at each temperature, and multiply the stepwise ratios. The product estimates ZZ unbiasedly. This page covers the constant and the annealing estimator; one-step importance sampling is the single-bridge special case, and posterior sampling itself is under Bayesian inference.

The one idea you need first

Importance sampling estimates Ep[f]\mathbb{E}_p[f] from draws qq by weighting each draw with p/qp/q. When qq misses where pp concentrates, a few draws carry all the weight and the estimate collapses. Annealing fixes the mismatch gradually instead of in one jump.

Think of It Like This

Crossing a river on chained boats

You must cross a wide river but cannot jump it. Nobody can throw a rope across either. Instead a chain of boats anchors between the banks, each close enough to toss a rope to the next. You cross boat by boat, and the product of each small crossing's odds gives the odds of the whole trip.

The near bank is the easy base distribution, the far bank the target. Each boat is an intermediate temperature; adjacent boats overlap enough that one-step importance weights stay tame. A single leap (plain importance sampling) drowns when the banks are far apart.

How It Actually Works

Define intermediates pk(x)∝p0(x)1−βkpT(x)βkp_k(x) \propto p_0(x)^{1 - \beta_k} p_T(x)^{\beta_k} with 0=β0<β1<⋯<βK=10 = \beta_0 < \beta_1 < \cdots < \beta_K = 1. Here p0p_0 is the easy base (known Z0Z_0) and pTp_T the target. One AIS run: draw x0x_0 from p0p_0, then for each kk apply a transition TkT_k leaving pkp_k invariant, and accumulate

w=∏k=1Kp~k(xk−1)p~k−1(xk−1)w = \prod_{k=1}^{K} \frac{\tilde{p}_k(x_{k-1})}{\tilde{p}_{k-1}(x_{k-1})}

with unnormalized densities p~\tilde{p}. Average ww over runs times Z0Z_0 estimates ZTZ_T unbiasedly. In log space the product becomes a sum, which is how it is implemented.

Worked example

Estimate ZZ for p~T(x)=exp⁡(−x2/2)×(1+x2/10)\tilde{p}_T(x) = \exp(-x^2/2) \times (1 + x^2/10) against base p0=N(0,1)p_0 = N(0,1) with Z0=1Z_0 = 1. True Z=1+1/10=1.1Z = 1 + 1/10 = 1.1 (since EN(0,1)[x2]=1\mathbb{E}_{N(0,1)}[x^2] = 1). Use K=4K = 4 temperatures β=(0,0.25,0.5,0.75,1)\beta = (0, 0.25, 0.5, 0.75, 1). A typical run through x=(0.5,0.7,0.4,0.9)x = (0.5, 0.7, 0.4, 0.9) gives stepwise ratios about (1.006,1.012,1.02,1.05)(1.006, 1.012, 1.02, 1.05), product ≈1.09\approx 1.09. Average over 200200 runs lands near 1.10±0.031.10 \pm 0.03: the bridge recovers the constant one leap would have missed, since direct importance weights here have variance several times larger.

Schedule and diagnostics

Geometric or sigmoid β\beta schedules with KK in the hundreds to thousands are standard for real models. Diagnose with the effective sample size of the ww values: below a few percent of runs, add temperatures near where the stepwise variance spikes.

Code

def ais_estimate(n_runs: int = 200) -> float:    import random    import math    betas = [0.0, 0.25, 0.5, 0.75, 1.0]    total = 0.0    for _ in range(n_runs):        x = random.gauss(0, 1)  # draw from the base        w = 1.0        for b_prev, b in zip(betas, betas[1:]):            # Unnormalized intermediate densities at the current x.            def tilde(bb: float) -> float:                return math.exp(-0.5 * x * x) * (1 + bb * x * x / 10)            w *= tilde(b) / tilde(b_prev)  # stepwise ratio            x = random.gauss(x * 0.9, 0.4)  # short MCMC move toward p_b        total += w    return round(total / n_runs, 3)

print(ais_estimate())  # -> about 1.1 (typical draws give 1.07 to 1.13)

The mean over runs targets Z=1.1Z = 1.1; the comment records the typical band rather than a fixed digit, since sampling varies run to run.

Watch Out For

Averaging weights in raw space

AIS weights span orders of magnitude, so a naive mean overflows or underflows past a few dozen temperatures. Always accumulate log⁡w\log w and combine runs with log-sum-exp. If your estimate changes by factors of two when you reorder runs, you averaged in the wrong space.

Too few temperatures with a distant target

With KK tiny and a far target, one stepwise ratio carries everything and AIS degrades to plain importance sampling with all its variance. Symptoms: effective sample size under 1%1\%. Double KK (halving gaps) before adding runs; temperatures are cheaper than wasted samples.

The Quick Version

  • The normalizing constant ZZ prices model comparison but resists plain Monte Carlo.
  • AIS bridges an easy base to the target through heated intermediates with MCMC moves.
  • The product of stepwise unnormalized ratios estimates ZZ unbiasedly.
  • The worked bridge recovers Z=1.1Z = 1.1 within about 0.030.03 over 200200 runs.
  • Implement in log space with log-sum-exp; raw-space averaging overflows.
  • Diagnose with effective sample size and add temperatures where stepwise variance spikes.