v9.1.1
Menu

Closed-Form Forward Sample q(x_t | x_0)

easyPROForward Process and Noise SchedulesDiffusion ModelsDiffusion Models 1

Problem Statement

Jump straight from a clean sample x0x_0 to any noise level tt in a single operation, without simulating the intermediate steps.

Background

Applying the forward kernel tt times and repeatedly using the fact that the sum of two independent Gaussians is Gaussian collapses the whole chain into one closed form:

q(xt∣x0)=N ⁣(xt; αˉt x0, (1−αˉt)I)q(x_t \mid x_0) = \mathcal{N}\!\left(x_t;\ \sqrt{\bar{\alpha}_t}\,x_0,\ (1-\bar{\alpha}_t) I\right)

Via the reparameterization trick this becomes an explicit, differentiable formula:

xt=αˉt x0+1−αˉt ε,ε∼N(0,I)x_t = \sqrt{\bar{\alpha}_t}\,x_0 + \sqrt{1-\bar{\alpha}_t}\,\varepsilon, \qquad \varepsilon \sim \mathcal{N}(0, I)

This is the single most-used line of code in diffusion training: it lets you sample a random timestep for every element of a batch and produce its noisy version in O(1), instead of running a t-step loop.

Note the coefficients are square roots of αˉt\bar{\alpha}_t and 1−αˉt1-\bar{\alpha}_t, and that they satisfy (αˉt)2+(1−αˉt)2=1(\sqrt{\bar{\alpha}_t})^2 + (\sqrt{1-\bar{\alpha}_t})^2 = 1: the forward process is variance preserving.

Your Task

Implement:

def q_sample(x0, t, alpha_bars, noise):

Return the noisy sample xtx_t as a NumPy array with the same shape as x0.

Input Format

  • x0: NumPy array of any shape, the clean data.
  • t (int): 0-based index into alpha_bars.
  • alpha_bars: 1-D NumPy array of cumulative alphas.
  • noise: NumPy array with the same shape as x0, the standard-normal sample ε\varepsilon.

Output Format

A NumPy array with the same shape as x0.

Sample

x0 = np.array([1.0, -1.0, 0.5])
noise = np.array([0.2, 0.4, -0.6])
ab = np.array([0.9, 0.5, 0.1])
print(np.round(q_sample(x0, 1, ab, noise), 4).tolist())

With αˉ1=0.5\bar{\alpha}_1 = 0.5 both coefficients equal 0.5≈0.7071\sqrt{0.5} \approx 0.7071, so the output is 0.7071 * x0 + 0.7071 * noise.

Example

Input
x0 = np.array([1.0, -1.0, 0.5])
noise = np.array([0.2, 0.4, -0.6])
ab = np.array([0.9, 0.5, 0.1])
print(np.round(q_sample(x0, 1, ab, noise), 4).tolist())
Output
[0.8485, -0.4243, -0.0707]
Reasoning

At t = 1 the schedule gives alpha_bar = 0.5, so sqrt(0.5) = 0.7071 multiplies both terms. Element-wise: 0.7071*1.0 + 0.7071*0.2 = 0.8485, 0.7071*(-1.0) + 0.7071*0.4 = -0.4243, 0.7071*0.5 + 0.7071*(-0.6) = -0.0707. Scaling by alpha_bar instead of its square root would break the variance-preserving property.

Constraints

  • 0 <= t < len(alpha_bars).
  • Use the square roots of αˉt\bar{\alpha}_t and 1−αˉt1-\bar{\alpha}_t, not the raw values.
  • Do not draw any randomness: noise is supplied.
  • Do not round inside the function.

Learn this in

More from Diffusion Models 1

PRO

Editor locked

The code editor is locked for Pro problems. It is only available for free problems. Please upgrade to gain access to the code editor for all problems.

solution.py

Test results

Sign in to run your code against the test cases.