Jump straight from a clean sample x0 to any noise level t in a single operation, without simulating the intermediate steps.
Applying the forward kernel t 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; αˉtx0, (1−αˉt)I)
Via the reparameterization trick this becomes an explicit, differentiable formula:
xt=αˉtx0+1−αˉtε,ε∼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 and 1−αˉt, and that they satisfy (αˉt)2+(1−αˉt)2=1: the forward process is variance preserving.
Implement:
def q_sample(x0, t, alpha_bars, noise):
Return the noisy sample xt as a NumPy array with the same shape as x0.
A NumPy array with the same shape as x0.
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 both coefficients equal 0.5≈0.7071, so the output is 0.7071 * x0 + 0.7071 * noise.
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())
[0.8485, -0.4243, -0.0707]
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.
0 <= t < len(alpha_bars).noise is supplied.