v9.1.1
Menu

Recover x0 from a Predicted Noise

easyFREEParameterizations and the Reverse PosteriorDiffusion ModelsDiffusion Models 1

Problem Statement

Invert the forward process: given a noisy sample and the network's predicted noise, reconstruct the model's estimate of the clean data.

Background

A DDPM ε\varepsilon-predictor never outputs an image. What it outputs is the noise it believes was added. Because the forward process is a closed-form affine map,

\quad\Longrightarrow\quad \hat{x}_0 = \frac{x_t - \sqrt{1-\bar{\alpha}_t}\,\hat{\varepsilon}_\theta(x_t, t)}{\sqrt{\bar{\alpha}_t}}$$ This conversion is everywhere: the DDPM posterior mean, the DDIM update and every guidance trick are all written in terms of $\hat{x}_0$. It is also numerically delicate. At high noise $\bar{\alpha}_t$ is tiny, so the division blows up any error in $\hat{\varepsilon}$ and $\hat{x}_0$ can land far outside the valid data range. Real samplers therefore **clip** the reconstruction to the data range (typically $[-1, 1]$ for images) before feeding it onward -- the **clip_denoised** flag in the reference implementation. ## Your Task Implement: ```python def predict_x0_from_eps(x_t, t, eps, alpha_bars, clip=True): ``` Return the estimated $x_0$ as an array shaped like **x_t**, clipped element-wise to **[-1.0, 1.0]** when **clip** is true. ## Input Format - **x_t**: NumPy array of any shape. - **t** (int): 0-based index into **alpha_bars**. - **eps**: array shaped like **x_t**, the predicted noise. - **alpha_bars**: 1-D array of cumulative alphas. - **clip** (bool): whether to clamp the result to **[-1, 1]**. ## Output Format A NumPy array shaped like **x_t**. ## Sample ```python ab = np.array([0.9, 0.5, 0.04]) x_t = np.array([0.6, -0.4]) eps = np.array([0.1, 0.2]) print(np.round(predict_x0_from_eps(x_t, 1, eps, ab, clip=False), 4).tolist()) ``` Both coefficients are $\sqrt{0.5}$, so the result is **(x_t - 0.7071 * eps) / 0.7071**.

Example

Input
ab = np.array([0.9, 0.5, 0.04])
x_t = np.array([0.6, -0.4])
eps = np.array([0.1, 0.2])
print(np.round(predict_x0_from_eps(x_t, 1, eps, ab, clip=False), 4).tolist())
Output
[0.7485, -0.7657]
Reasoning
  • Inputs: x_t = [0.6, -0.4] is the noisy sample, eps = [0.1, 0.2] is the noise the network predicts was mixed in, and t = 1 picks the second entry of alpha_bars, so αˉ1=0.5\bar{\alpha}_1 = 0.5.
  • Coefficients: the signal weight is αˉ1=0.5≈0.7071\sqrt{\bar{\alpha}_1} = \sqrt{0.5} \approx 0.7071 and the noise weight is 1−0.5=0.5≈0.7071\sqrt{1 - 0.5} = \sqrt{0.5} \approx 0.7071 too, an equal mix of data and noise.
  • First element: remove the scaled noise, 0.6−0.7071×0.1=0.52930.6 - 0.7071 \times 0.1 = 0.5293, then undo the signal scaling, 0.5293/0.7071≈0.74850.5293 / 0.7071 \approx 0.7485.
  • Second element: −0.4−0.7071×0.2=−0.5414-0.4 - 0.7071 \times 0.2 = -0.5414, and −0.5414/0.7071≈−0.7657-0.5414 / 0.7071 \approx -0.7657.
  • Output: [0.7485, -0.7657], same shape as x_t. With clip false nothing is clamped.
  • Notice: because the two weights are equal here, x^0=xt/0.7071−ε^\hat{x}_0 = x_t / 0.7071 - \hat{\varepsilon}, e.g. 0.8485−0.1=0.74850.8485 - 0.1 = 0.7485. At t=2t = 2 (αˉ=0.04\bar{\alpha} = 0.04) the divisor is only 0.20.2, which is why results there land far outside [−1,1][-1, 1].

Constraints

  • 0 <= t < len(alpha_bars).
  • Subtract the scaled noise before dividing; the division is by αˉt\sqrt{\bar{\alpha}_t}, not by αˉt\bar{\alpha}_t.
  • Clipping happens last, and only when clip is true.
  • Do not round inside the function.

Learn this in

More from Diffusion Models 1

solution.py

Test results

Sign in to run your code against the test cases.