PIXELBANKv9.1.0
Menu

Linear Beta Schedule and Alpha-Bar

Problem Statement

Build the linear noise schedule used by the original DDPM paper and derive the two quantities every later formula depends on: the per-step signal retention alpha_t and the cumulative signal retention alpha_bar_t.

Background

The forward diffusion process corrupts data one small step at a time:

q(xt∣xt−1)=N ⁣(xt; 1−βt xt−1, βtI)q(x_t \mid x_{t-1}) = \mathcal{N}\!\left(x_t;\ \sqrt{1-\beta_t}\,x_{t-1},\ \beta_t I\right)

The variances β1,…,βT\beta_1, \dots, \beta_T are the noise schedule. DDPM uses a linear schedule: TT values spaced evenly (endpoints included) from beta_start to beta_end, with the defaults β1=10−4\beta_1 = 10^{-4} and βT=0.02\beta_T = 0.02 for T=1000T = 1000.

From the betas we define

αt=1−βt,αˉt=∏s=1tαs\alpha_t = 1 - \beta_t, \qquad \bar{\alpha}_t = \prod_{s=1}^{t} \alpha_s

αˉt\bar{\alpha}_t is the running product, not a running sum. It is what makes the forward process collapse into a single closed-form Gaussian, so getting it right is the foundation of everything else in diffusion.

Your Task

Implement:

def linear_schedule(T, beta_start=1e-4, beta_end=0.02):

Return a tuple (betas, alphas, alpha_bars) of three 1-D NumPy arrays, each of length T, using 0-based indexing (element i corresponds to timestep t=i+1t = i+1 in the maths above).

Input Format

  • T (int): number of diffusion steps, T >= 1.
  • beta_start, beta_end (float): first and last beta. Both endpoints must appear in the array.

Output Format

A tuple of three NumPy arrays (betas, alphas, alpha_bars).

Sample

b, a, ab = linear_schedule(5, 0.1, 0.5)
print(np.round(b, 4).tolist())
print(np.round(a, 4).tolist())
print(np.round(ab, 4).tolist())
[0.1, 0.2, 0.3, 0.4, 0.5]
[0.9, 0.8, 0.7, 0.6, 0.5]
[0.9, 0.72, 0.504, 0.3024, 0.1512]

Betas are evenly spaced from 0.1 to 0.5, alphas are 1 - beta, and alpha_bars is their cumulative product, so it decays quickly toward zero.

Example:

Input:
b, a, ab = linear_schedule(5, 0.1, 0.5)
print(np.round(b, 4).tolist())
print(np.round(a, 4).tolist())
print(np.round(ab, 4).tolist())
Output:
[0.1, 0.2, 0.3, 0.4, 0.5]
[0.9, 0.8, 0.7, 0.6, 0.5]
[0.9, 0.72, 0.504, 0.3024, 0.1512]
Reasoning:

np.linspace(0.1, 0.5, 5) gives betas [0.1, 0.2, 0.3, 0.4, 0.5], so alphas are [0.9, 0.8, 0.7, 0.6, 0.5]. The cumulative product runs 0.9, 0.9*0.8 = 0.72, 0.72*0.7 = 0.504, 0.504*0.6 = 0.3024, 0.3024*0.5 = 0.1512 -- the signal that survives to each step. Using a cumulative sum instead would give values above 1, which is impossible for a variance-preserving process.

Constraints:

  • T >= 1; when T == 1 the array holds beta_start only.
  • betas must include both endpoints (np.linspace, not np.arange).
  • alpha_bars is a cumulative product, not a cumulative sum.
  • Use float (float64) arrays; do not round inside the function.
solution.py

Test Results

0/0
Run code to see test results.