key = jax.random.PRNGKey(0)
mix = d2l.GaussianMixture(means=[[-2.5, -1.5], [2.5, -1.5], [0.0, 2.5]],
weights=[0.5, 0.3, 0.2], std=0.5)
key, k1, k2 = jax.random.split(key, 3)
data, test = mix.sample(k1, 2000), mix.sample(k2, 2000)
T = 200
beta = jnp.linspace(1e-4, 0.1, T)
alpha = 1 - beta
alpha_bar = jnp.cumprod(alpha)
print(f'alpha_bar_T = {alpha_bar[-1]:.1e}: after T steps the data are scaled '
f'by {jnp.sqrt(alpha_bar[-1]):.3f}')
x = data
for t in range(T): # the chain, step by step
key, subkey = jax.random.split(key)
x = jnp.sqrt(alpha[t]) * x + jnp.sqrt(beta[t]) * jax.random.normal(subkey, x.shape)
if t + 1 in (10, 50, 200):
key, subkey = jax.random.split(key)
one_shot = (jnp.sqrt(alpha_bar[t]) * data
+ jnp.sqrt(1 - alpha_bar[t]) * jax.random.normal(subkey, data.shape))
print(f'step {t + 1:3d}: chain: mean {[round(float(m), 3) for m in x.mean(0)]}, '
f'var {x.var(0).mean():.3f} | one shot: mean '
f'{[round(float(m), 3) for m in one_shot.mean(0)]}, '
f'var {one_shot.var(0).mean():.3f}')