PIXELBANKv9.1.0
Menu

Closed-Form Forward Sample q(x_t | x_0)

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.
🔒

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

0/0
Run code to see test results.