Implement the cosine noise schedule from Improved Denoising Diffusion Probabilistic Models (Nichol & Dhariwal, 2021), which is defined on αˉ directly and only afterwards converted back into betas.
The linear schedule destroys information too fast: by the middle of the trajectory the image is already almost pure noise, so the later steps contribute little. The cosine schedule instead defines
f(t)=cos2(1+st/T+s⋅2π),αˉt=f(0)f(t)
for t=0,1,…,T, where the small offset s=0.008 keeps β1 from becoming vanishingly small. By construction αˉ0=1 (no noise) and αˉT≈0 (pure noise).
The betas are then recovered from the ratio of consecutive cumulative products:
βt=1−αˉt−1αˉt
Near t=T this ratio goes to zero and βt approaches 1, which makes the sampler unstable, so the paper clips every beta to at most 0.999.
Implement:
def cosine_schedule(T, s=0.008):
Return (alpha_bars, betas), both 1-D NumPy arrays of length T covering t=1,…,T (0-based index i is t=i+1). alpha_bars must be the unclipped αˉt values; betas must be clipped to the range [0, 0.999].
A tuple (alpha_bars, betas) of NumPy arrays of length T.
ab, b = cosine_schedule(4)
print(np.round(ab, 4).tolist())
print(np.round(b, 4).tolist())
With T = 4 the cosine curve drops from just below 1 down to essentially 0, and the betas grow monotonically, with the final one hitting the 0.999 clip.
ab, b = cosine_schedule(4) print(np.round(ab, 4).tolist()) print(np.round(b, 4).tolist())
[0.847, 0.4938, 0.1443, 0.0] [0.153, 0.417, 0.7079, 0.999]
With T = 4 and s = 0.008 the offset grid is t/T = 0, 0.25, 0.5, 0.75, 1. Each maps through cos^2(((t/T + s)/(1+s)) * pi/2), and dividing by the t = 0 value normalises alpha_bar_0 to 1. Dropping that first entry leaves the four returned alpha-bars, which decay smoothly to ~0. Each beta is one minus the ratio of consecutive alpha-bars; the last ratio is essentially 0, so the raw beta would be ~1 and the 0.999 clip takes effect.
T entries for t≥1.[0, 0.999]. Do not clip alpha_bars.