Evaluate the per-sample denoising terms Lt−1 of the diffusion variational lower bound, using the SNR form that makes the bound's structure obvious.
The VLB of a diffusion model decomposes into one KL per timestep. For the denoising terms the KL is between two Gaussians that differ only in their means, and after substituting the DDPM posterior mean and variance it collapses to a remarkably clean statement (Kingma et al., Variational Diffusion Models):
Lt−1=21(SNR(t−1)−SNR(t))∥x0−x^0(xt,t)∥22
where SNR(t)=αˉt/(1−αˉt) and x^0 is the model's reconstruction of the clean sample.
Two things to read off this formula:
The squared norm is a sum over all the data dimensions of one sample, not a mean.
Implement:
def vlb_terms(x0, x0_pred, timesteps, alpha_bars):
Return a 1-D NumPy array of length N holding Lt−1 for each sample in the batch.
Every timestep must satisfy t >= 1 (the t=0 term is the separate reconstruction term L0, which this function does not handle). If any entry is < 1, raise ValueError.
A 1-D NumPy array of N floats.
ab = np.array([0.9, 0.5, 0.1])
x0 = np.array([[1.0, 0.0]])
x0_pred = np.array([[0.5, 0.0]])
print(np.round(vlb_terms(x0, x0_pred, np.array([1]), ab), 4).tolist())
SNR(0) = 9.0, SNR(1) = 1.0, the squared error is 0.25, so the term is 0.5 * (9.0 - 1.0) * 0.25 = 1.0.
ab = np.array([0.9, 0.5, 0.1]) x0 = np.array([[1.0, 0.0]]) x0_pred = np.array([[0.5, 0.0]]) print(np.round(vlb_terms(x0, x0_pred, np.array([1]), ab), 4).tolist())
[1.0]
alpha_bars[0] = 0.9 gives SNR(0) = 9.0 and alpha_bars[1] = 0.5 gives SNR(1) = 1.0. The squared error summed over the two dimensions is (1.0-0.5)^2 + 0^2 = 0.25. So the term is 0.5 * (9.0 - 1.0) * 0.25 = 1.0. Using a mean instead of a sum over dimensions would halve it.
x0 and x0_pred both have shape (N, D); the output has shape (N,).D axis, not a mean.< 1 must raise ValueError.alpha_bars).