V-Prediction Conversions
Problem Statement
Implement the v-parameterization: the velocity target used by progressive distillation, Imagen Video and Stable Diffusion 2.x, plus its inverse back to x0 and ε.
Background
Write αˉt=cosϕ and 1−αˉt=sinϕ, so that xt=cosϕx0+sinϕε traces a circular arc between the clean sample and pure noise. The velocity is the derivative of that arc:
v=αˉtε−1−αˉtx0
v and xt are orthogonal unit-scaled directions, which makes the inverse a rotation by the same angle:
x^0=αˉtxt−1−αˉtv,ε^=1−αˉtxt+αˉtv
Note there is no division by αˉt anywhere. That is the whole point: ε-prediction degenerates at αˉt→0 (the target becomes trivially xt itself, and recovering x0 divides by something tiny), while x0-prediction degenerates at αˉt→1. The v target is well-conditioned at both ends, which is what makes few-step distillation and zero-terminal-SNR schedules work.
Your Task
Implement two functions:
def compute_v(x0, eps, alpha_bar):
def v_to_x0_eps(x_t, v, alpha_bar):
compute_v returns the velocity target; v_to_x0_eps returns the tuple (x0, eps).
Input Format
- x0, eps, x_t, v: NumPy arrays of matching shape.
- alpha_bar (float): the scalar αˉt in (0, 1].
Output Format
compute_v returns one array; v_to_x0_eps returns a tuple of two arrays.
Sample
x0 = np.array([1.0, -1.0])
eps = np.array([0.5, 0.25])
ab = 0.36
v = compute_v(x0, eps, ab)
print(np.round(v, 4).tolist())
x_t = np.sqrt(ab) * x0 + np.sqrt(1 - ab) * eps
r0, re = v_to_x0_eps(x_t, v, ab)
print(np.round(r0, 4).tolist())
print(np.round(re, 4).tolist())
With sqrt(0.36) = 0.6 and sqrt(0.64) = 0.8, v = 0.6eps - 0.8x0, and the inverse rotation returns exactly the original x0 and eps.
Example:
x0 = np.array([1.0, -1.0]) eps = np.array([0.5, 0.25]) ab = 0.36 v = compute_v(x0, eps, ab) print(np.round(v, 4).tolist()) x_t = np.sqrt(ab) * x0 + np.sqrt(1 - ab) * eps r0, re = v_to_x0_eps(x_t, v, ab) print(np.round(r0, 4).tolist()) print(np.round(re, 4).tolist())
[-0.5, 0.95] [1.0, -1.0] [0.5, 0.25]
sqrt(0.36) = 0.6 and sqrt(0.64) = 0.8. So v = 0.6*[0.5, 0.25] - 0.8*[1.0, -1.0] = [-0.5, 0.95]. The noisy sample is x_t = 0.6*x0 + 0.8*eps = [1.0, -0.4]. Rotating back, x0_hat = 0.6*x_t - 0.8*v and eps_hat = 0.8*x_t + 0.6*v return the originals exactly, since the two maps are transposed rotations.
Constraints:
0 < alpha_bar <= 1.- Both functions use the same two coefficients αˉt and 1−αˉt -- no divisions.
- Mind the signs:
compute_vsubtracts the x0 term, and the x0 recovery subtracts the v term while the ε recovery adds it. - The two maps must round-trip: with
x_t = sqrt(ab)*x0 + sqrt(1-ab)*eps, callingv_to_x0_eps(x_t, compute_v(x0, eps, ab), ab)returns(x0, eps). - Do not round inside either function.
1. Background Knowledge
Diffusion models are generative models that learn to reverse a gradual noising process. In the standard formulation, a clean data point x0 is corrupted by Gaussian noise ε over T steps. The state at any intermediate step t is defined as xt=αˉtx0+1−αˉtε. Here, αˉt represents the cumulative product of noise schedule parameters, effectively controlling how much of the original signal remains versus how much noise has been added.
Traditionally, models predict either the noise ε or the clean data x0. However, these parameterizations suffer from numerical instability at the extremes of the diffusion process. Predicting ε becomes ill-conditioned when αˉt→0 (high noise), while predicting x0 becomes ill-conditioned when αˉt→1 (low noise). The v-parameterization addresses this by predicting the "velocity" vector v, which is tangent to the circular arc connecting x0 and ε. This approach ensures stable gradients and accurate predictions throughout the entire diffusion trajectory, making it ideal for advanced techniques like progressive distillation.
The mathematical foundation relies on a rotation interpretation. If we define cosϕ=αˉt and sinϕ=1−αˉt, the forward process is a rotation of the vector (x0,ε). The velocity v is defined as v=αˉtε−1−αˉtx0. Crucially, recovering x0 and ε from xt and v involves a simple inverse rotation, requiring no division by small numbers. This geometric symmetry is what provides the numerical stability.
2. Algorithm Approach
The core algorithmic task is to implement two linear transformations based on the provided trigonometric identities. Since the operations are element-wise and involve only basic arithmetic (multiplication, addition, subtraction) and square roots, the approach is straightforward vectorization.
For compute_v, you must calculate the weighted difference between the noise and the clean data. The weights are determined by the square root of the noise schedule parameter αˉt and its complement 1−αˉt.
For v_to_x0_eps, you must perform the inverse transformation. This is essentially a rotation matrix multiplication. Given the noisy sample xt and the predicted velocity v, you combine them using the same weights but with different signs to isolate x0 and ε. The key insight is that this is a linear system that can be solved directly without iterative methods or matrix inversions.
3. Step-by-Step Strategy
Continue the full explanation
You're reading the free preview. Unlock the complete walkthrough, the code editor, test runner and reference solution with Premium.
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.