jcandane commited on
Commit
27af39b
·
verified ·
1 Parent(s): 348c968

Delete ddpmx.py

Browse files
Files changed (1) hide show
  1. ddpmx.py +0 -597
ddpmx.py DELETED
@@ -1,597 +0,0 @@
1
- # how to use
2
- # ddpm = DDPM(Z_train, T=100, n_iter=20_000, key=random.PRNGKey(0))
3
- #
4
- # Fast unconditional samples (try 15–30 first)
5
- # z = ddpm.sample_dpmpp(N=4096, num_steps=20)
6
- #
7
- # Fast “refine latents” starting from an intermediate noise level
8
- #z_ref = ddpm.refine_latents_dpmpp(z0, t_start=30, num_steps=20, add_noise=True)
9
-
10
-
11
-
12
- # src/dima/ddpmx.py
13
- from __future__ import annotations
14
-
15
- from typing import Any, Optional
16
-
17
- import jax
18
- import jax.numpy as jnp
19
- from jax import random
20
-
21
- from flax import linen as nn
22
- from flax.training import train_state
23
- from flax import struct
24
- import optax
25
-
26
-
27
- # --- Add near the top of ddpm.py ---
28
- import numpy as np
29
-
30
- def _sigma_to_alpha_sigma_t(sigma: jnp.ndarray) -> tuple[jnp.ndarray, jnp.ndarray]:
31
- """
32
- EDM-style sigma parameterization used by many DPM-Solver++ implementations:
33
- alpha_t = 1 / sqrt(1 + sigma^2)
34
- sigma_t = sigma * alpha_t
35
- so that x = alpha_t * x0 + sigma_t * eps
36
- """
37
- alpha_t = 1.0 / jnp.sqrt(1.0 + sigma**2)
38
- sigma_t = sigma * alpha_t
39
- return alpha_t, sigma_t
40
-
41
-
42
- def _make_lu_sigma_schedule(
43
- sigma_start: float,
44
- sigma_end: float,
45
- num_steps: int,
46
- ) -> np.ndarray:
47
- """
48
- "Lu" schedule in lambda-space (uniform in lambda = -log(sigma)),
49
- which is a common default for DPM-Solver samplers.
50
- """
51
- sigma_start = float(max(sigma_start, 1e-12))
52
- sigma_end = float(max(sigma_end, 1e-12))
53
- lam_start = -np.log(sigma_start)
54
- lam_end = -np.log(sigma_end)
55
- lambdas = np.linspace(lam_start, lam_end, num_steps, dtype=np.float32)
56
- sigmas = np.exp(-lambdas).astype(np.float32)
57
- return sigmas
58
-
59
-
60
- # ------------------------------
61
- # Schedules & embeddings
62
- # ------------------------------
63
- def cosine_schedule(T: int, s: float = 0.008):
64
- """
65
- Nichol & Dhariwal cosine schedule.
66
-
67
- Returns:
68
- alpha: (T,)
69
- beta: (T,)
70
- alpha_bar: (T,)
71
- """
72
- steps = jnp.arange(T + 1, dtype=jnp.float32)
73
- f = jnp.cos(((steps / T + s) / (1.0 + s)) * jnp.pi / 2.0) ** 2
74
- alpha_bar_all = f / f[0]
75
- alpha_bar = alpha_bar_all[1:] # (T,)
76
- alpha = alpha_bar / jnp.concatenate([jnp.array([1.0], dtype=jnp.float32), alpha_bar[:-1]])
77
- beta = 1.0 - alpha
78
- return alpha, beta, alpha_bar
79
-
80
-
81
- def sinusoidal_embedding(t_idx: jnp.ndarray, dim: int) -> jnp.ndarray:
82
- """
83
- t_idx: (B,1) int32
84
- returns: (B,dim)
85
- """
86
- if t_idx.ndim != 2 or t_idx.shape[1] != 1:
87
- raise ValueError("t_idx must have shape (B,1)")
88
- t = t_idx.astype(jnp.float32)
89
- half = dim // 2
90
- denom = float(max(half - 1, 1))
91
- freqs = jnp.exp(-jnp.log(10_000.0) * jnp.arange(half, dtype=jnp.float32) / denom)
92
- args = t * freqs
93
- emb = jnp.concatenate([jnp.sin(args), jnp.cos(args)], axis=-1)
94
- if dim % 2 == 1:
95
- emb = jnp.pad(emb, ((0, 0), (0, 1)))
96
- return emb
97
-
98
-
99
- # ------------------------------
100
- # Model: epsilon predictor
101
- # ------------------------------
102
- class EpsMLP(nn.Module):
103
- """Simple MLP epsilon-predictor for DDPM in R^D."""
104
- hidden: int
105
- t_dim: int
106
- data_dim: int
107
-
108
- @nn.compact
109
- def __call__(self, x: jnp.ndarray, t_idx: jnp.ndarray) -> jnp.ndarray:
110
- # x: (B,D), t_idx: (B,1)
111
- t_emb = sinusoidal_embedding(t_idx, self.t_dim)
112
- t_h = nn.Dense(self.hidden)(t_emb)
113
- t_h = nn.gelu(t_h)
114
-
115
- h = nn.Dense(self.hidden)(x)
116
- h = nn.gelu(h + t_h)
117
-
118
- t_h2 = nn.Dense(self.hidden)(t_h)
119
- h = nn.Dense(self.hidden)(h)
120
- h = nn.gelu(h + t_h2)
121
-
122
- out = nn.Dense(self.data_dim)(h)
123
- return out
124
-
125
-
126
- # ------------------------------
127
- # TrainState with EMA
128
- # ------------------------------
129
- @struct.dataclass
130
- class TrainStateEMA(train_state.TrainState):
131
- """Flax TrainState extended with EMA params."""
132
- ema_params: Any = struct.field(pytree_node=True)
133
-
134
- def apply_gradients(self, *, grads, ema_decay: float):
135
- updates, new_opt_state = self.tx.update(grads, self.opt_state, self.params)
136
- new_params = optax.apply_updates(self.params, updates)
137
- new_ema = optax.incremental_update(new_params, self.ema_params, step_size=1.0 - ema_decay)
138
- return self.replace(
139
- step=self.step + 1,
140
- params=new_params,
141
- opt_state=new_opt_state,
142
- ema_params=new_ema,
143
- )
144
-
145
-
146
- # ------------------------------
147
- # DDPM
148
- # ------------------------------
149
- class DDPM:
150
- """
151
- DDPM for D-dimensional latents.
152
-
153
- API expected by your DIMA wrapper:
154
- - DDPM(Z_train, ...): trains in __init__ (n_iter can be 0 to skip)
155
- - refine_latents(z0, t_start, key, add_noise) -> z_refined
156
- - __call__(...) delegates to refine_latents
157
- - sample(N) -> latent samples
158
- - attributes: state.params, state.ema_params, T, D, model.hidden, model.t_dim, beta_max, eps
159
- """
160
-
161
- def __init__(
162
- self,
163
- Z_iX: jnp.ndarray,
164
- *,
165
- T: int = 100,
166
- hidden_dim: int = 128,
167
- t_embed_dim: int = 64,
168
- learning_rate: float = 1e-3,
169
- n_iter: int = 20_000,
170
- ema_decay: float = 0.999,
171
- beta_max: float = 0.02,
172
- batch_size: Optional[int] = None,
173
- key: jax.Array = random.PRNGKey(0),
174
- verbose_every: int = 0,
175
- eps: float = 1e-5,
176
- ):
177
- Z_iX = jnp.asarray(Z_iX, dtype=jnp.float32)
178
- if Z_iX.ndim != 2:
179
- raise ValueError("Z_iX must be 2D (N,D).")
180
-
181
- self.D = int(Z_iX.shape[1])
182
- self.T = int(T)
183
- self.key = key
184
- self.ema_decay = float(ema_decay)
185
- self.batch_size = batch_size
186
- self.verbose_every = int(verbose_every)
187
- self.eps = float(eps)
188
- self.beta_max = float(beta_max)
189
-
190
- # schedule (cosine, clipped by beta_max)
191
- alpha, beta, alpha_bar = cosine_schedule(self.T)
192
- beta = jnp.minimum(beta, self.beta_max)
193
- alpha = 1.0 - beta
194
- alpha_bar = jnp.cumprod(alpha)
195
-
196
- self.alpha_s = alpha.astype(jnp.float32)
197
- self.beta_s = beta.astype(jnp.float32)
198
- self.alpha_bar_s = alpha_bar.astype(jnp.float32)
199
-
200
- # model + optimizer + EMA
201
- self.model = EpsMLP(hidden=int(hidden_dim), t_dim=int(t_embed_dim), data_dim=self.D)
202
-
203
- params = self.model.init(
204
- self.key,
205
- jnp.zeros((1, self.D), dtype=jnp.float32),
206
- jnp.zeros((1, 1), dtype=jnp.int32),
207
- )["params"]
208
-
209
- tx = optax.adam(float(learning_rate))
210
- self.state = TrainStateEMA.create(apply_fn=self.model.apply, params=params, tx=tx, ema_params=params)
211
-
212
- # train
213
- if int(n_iter) > 0:
214
- self._train(Z_iX, int(n_iter))
215
-
216
- # ---------- training ----------
217
- @staticmethod
218
- def _loss(params, apply_fn, x_t, t_idx, eps_true):
219
- eps_pred = apply_fn({"params": params}, x_t, t_idx)
220
- return jnp.mean((eps_pred - eps_true) ** 2)
221
-
222
- @staticmethod
223
- @jax.jit
224
- def _train_step(
225
- state: TrainStateEMA,
226
- x0_batch: jnp.ndarray,
227
- key: jax.Array,
228
- alpha_bar_s: jnp.ndarray,
229
- ema_decay: float,
230
- eps: float,
231
- ):
232
- B = x0_batch.shape[0]
233
- key, k_eps, k_t = random.split(key, 3)
234
-
235
- eps_noise = random.normal(k_eps, shape=x0_batch.shape) # (B,D)
236
- t_idx = random.randint(k_t, shape=(B, 1), minval=0, maxval=alpha_bar_s.shape[0])
237
-
238
- a_bar_t = jnp.take(alpha_bar_s, t_idx.squeeze(-1))[:, None]
239
- a_bar_t = jnp.clip(a_bar_t, eps, 1.0)
240
-
241
- x_t = jnp.sqrt(a_bar_t) * x0_batch + jnp.sqrt(1.0 - a_bar_t) * eps_noise
242
-
243
- def loss_fn(p):
244
- return DDPM._loss(p, state.apply_fn, x_t, t_idx, eps_noise)
245
-
246
- loss, grads = jax.value_and_grad(loss_fn)(state.params)
247
- new_state = state.apply_gradients(grads=grads, ema_decay=ema_decay)
248
- return new_state, loss, key
249
-
250
- def _train(self, Z_iX: jnp.ndarray, n_iter: int):
251
- N = int(Z_iX.shape[0])
252
- bs = N if (self.batch_size is None) else min(int(self.batch_size), N)
253
-
254
- for it in range(n_iter):
255
- if bs >= N:
256
- batch = Z_iX
257
- else:
258
- self.key, k_perm = random.split(self.key)
259
- idx = random.permutation(k_perm, N)[:bs]
260
- batch = Z_iX[idx]
261
-
262
- self.state, loss, self.key = self._train_step(
263
- self.state,
264
- batch,
265
- self.key,
266
- self.alpha_bar_s,
267
- self.ema_decay,
268
- self.eps,
269
- )
270
-
271
- if self.verbose_every and (it % self.verbose_every == 0 or it == n_iter - 1):
272
- print(f"iter {it:6d} loss {float(loss):.6f}", end="\r")
273
-
274
- if self.verbose_every:
275
- print("\ntraining complete.")
276
-
277
- # ---------- diffusion utilities ----------
278
- @staticmethod
279
- def _posterior_variance(alpha_s, beta_s, alpha_bar_s, t):
280
- a_bar_t = alpha_bar_s[t]
281
- a_bar_prev = jnp.where(t > 0, alpha_bar_s[t - 1], jnp.array(1.0, dtype=alpha_bar_s.dtype))
282
- return ((1.0 - a_bar_prev) / (1.0 - a_bar_t)) * beta_s[t]
283
-
284
- @staticmethod
285
- def _make_sampler_step(params_ema, apply_fn, alpha_s, beta_s, alpha_bar_s, eps: float):
286
- @jax.jit
287
- def step(carry, _):
288
- key, t, x = carry # x: (B,D)
289
- key, k = random.split(key)
290
-
291
- alpha_t = jnp.clip(alpha_s[t], eps, 1.0)
292
- a_bar_t = jnp.clip(alpha_bar_s[t], eps, 1.0)
293
-
294
- sqrt_alpha = jnp.sqrt(alpha_t)
295
- sqrt_one_minus_a_bar = jnp.sqrt(jnp.clip(1.0 - a_bar_t, eps, 1.0))
296
-
297
- B = x.shape[0]
298
- t_batch = jnp.full((B, 1), t, dtype=jnp.int32)
299
- eps_pred = apply_fn({"params": params_ema}, x, t_batch) # (B,D)
300
-
301
- # predict x0
302
- x0_hat = (x - sqrt_one_minus_a_bar * eps_pred) / jnp.sqrt(a_bar_t)
303
-
304
- a_bar_prev = jnp.where(t > 0, alpha_bar_s[t - 1], jnp.array(1.0, dtype=alpha_bar_s.dtype))
305
- denom = jnp.clip(1.0 - a_bar_t, eps, 1.0)
306
-
307
- coef1 = jnp.sqrt(jnp.clip(a_bar_prev, eps, 1.0)) * beta_s[t] / denom
308
- coef2 = sqrt_alpha * (1.0 - a_bar_prev) / denom
309
-
310
- mean = coef1 * x0_hat + coef2 * x
311
-
312
- beta_tilde = DDPM._posterior_variance(alpha_s, beta_s, alpha_bar_s, t)
313
- sigma = jnp.sqrt(jnp.clip(beta_tilde, 0.0, 1.0))
314
-
315
- z = random.normal(k, x.shape)
316
- z = jnp.where(t == 0, 0.0, z)
317
- x_prev = mean + sigma * z
318
-
319
- return (key, t - 1, x_prev), x_prev
320
-
321
- return step
322
-
323
- # ---------- API ----------
324
- def refine_latents(
325
- self,
326
- z0: jnp.ndarray,
327
- t_start: int = 10,
328
- key: Optional[jax.Array] = None,
329
- add_noise: bool = True,
330
- ) -> jnp.ndarray:
331
- """
332
- Refine latents by:
333
- (optional) forward-noise z0 to step t_start
334
- reverse-diffuse from t_start -> 0 using EMA params.
335
- """
336
- z0 = jnp.asarray(z0, dtype=jnp.float32)
337
- if z0.ndim != 2 or z0.shape[1] != self.D:
338
- raise ValueError(f"z0 must have shape (B,{self.D}).")
339
- if not (0 <= int(t_start) < self.T):
340
- raise ValueError(f"t_start must be in [0, {self.T-1}]")
341
-
342
- t_start = int(t_start)
343
-
344
- if key is None:
345
- self.key, key = random.split(self.key)
346
- else:
347
- # advance internal RNG too
348
- self.key, _ = random.split(key)
349
-
350
- # forward diffuse to t_start
351
- key, k_eps = random.split(key)
352
- eps_noise = random.normal(k_eps, z0.shape)
353
-
354
- a_bar_t = jnp.clip(self.alpha_bar_s[t_start], self.eps, 1.0)
355
- if add_noise:
356
- z_t = jnp.sqrt(a_bar_t) * z0 + jnp.sqrt(1.0 - a_bar_t) * eps_noise
357
- else:
358
- z_t = z0
359
-
360
- step = self._make_sampler_step(
361
- self.state.ema_params,
362
- self.state.apply_fn,
363
- self.alpha_s,
364
- self.beta_s,
365
- self.alpha_bar_s,
366
- self.eps,
367
- )
368
-
369
- (final_key, _, _), trace = jax.lax.scan(
370
- step,
371
- (key, t_start, z_t),
372
- xs=None,
373
- length=t_start + 1,
374
- )
375
- self.key = final_key
376
- return trace[-1]
377
-
378
- def __call__(
379
- self,
380
- z0: jnp.ndarray,
381
- t_start: int = 10,
382
- key: Optional[jax.Array] = None,
383
- add_noise: bool = True,
384
- ) -> jnp.ndarray:
385
- return self.refine_latents(z0, t_start=t_start, key=key, add_noise=add_noise)
386
-
387
- def reverse_from_T(self, x_T: jnp.ndarray) -> jnp.ndarray:
388
- x_T = jnp.asarray(x_T, dtype=jnp.float32)
389
- if x_T.ndim != 2 or x_T.shape[1] != self.D:
390
- raise ValueError(f"x_T must have shape (B,{self.D}).")
391
-
392
- step = self._make_sampler_step(
393
- self.state.ema_params,
394
- self.state.apply_fn,
395
- self.alpha_s,
396
- self.beta_s,
397
- self.alpha_bar_s,
398
- self.eps,
399
- )
400
- self.key, k0 = random.split(self.key)
401
- (_, _, _), trace = jax.lax.scan(
402
- step,
403
- (k0, self.T - 1, x_T),
404
- xs=None,
405
- length=self.T,
406
- )
407
- return trace[-1]
408
-
409
- def sample(self, N: int = 10_000) -> jnp.ndarray:
410
- self.key, k = random.split(self.key)
411
- noise = random.normal(k, (int(N), self.D))
412
- return self.reverse_from_T(noise)
413
-
414
- # --- In __init__ AFTER you compute self.alpha_bar_s ---
415
- # sigma_in is the "EDM-style" sigma = sigma_t / alpha_t = sqrt((1-a_bar)/a_bar)
416
- self.sigma_in_train = jnp.sqrt(
417
- jnp.clip((1.0 - self.alpha_bar_s) / jnp.clip(self.alpha_bar_s, self.eps, 1.0), self.eps, 1e12)
418
- ).astype(jnp.float32)
419
-
420
- def _make_dpmpp_schedule(self, *, num_steps: int, t_start: int) -> tuple[jnp.ndarray, jnp.ndarray]:
421
- """
422
- Returns:
423
- sigmas_in: (K+1,) float32, decreasing, last one is 0
424
- t_cont: (K,) float32, "continuous" time indices to feed the model
425
- """
426
- t_start = int(t_start)
427
- if not (0 <= t_start < self.T):
428
- raise ValueError(f"t_start must be in [0, {self.T-1}]")
429
- if int(num_steps) < 1:
430
- raise ValueError("num_steps must be >= 1")
431
-
432
- # Start/end sigmas from your trained VP schedule
433
- sigma_start = float(self.sigma_in_train[t_start])
434
- sigma_end = float(self.sigma_in_train[0])
435
-
436
- # Build sigma schedule (length K) and append final sigma=0
437
- sigmas_k = _make_lu_sigma_schedule(sigma_start, sigma_end, int(num_steps))
438
- sigmas = np.concatenate([sigmas_k, np.array([0.0], np.float32)], axis=0)
439
-
440
- # Map sigma -> continuous t by interpolating in log(sigma) over the training sigmas
441
- sigma_train = np.array(self.sigma_in_train).astype(np.float32) # (T,)
442
- log_sig_train = np.log(np.maximum(sigma_train, 1e-12)) # increasing with t
443
- t_train = np.arange(self.T, dtype=np.float32)
444
-
445
- # For model calls, we only need times for the K "current" sigmas (exclude final 0)
446
- log_sig = np.log(np.maximum(sigmas[:-1], 1e-12))
447
- t_cont = np.interp(log_sig, log_sig_train, t_train).astype(np.float32) # (K,)
448
-
449
- return jnp.array(sigmas, dtype=jnp.float32), jnp.array(t_cont, dtype=jnp.float32)
450
-
451
- @staticmethod
452
- @jax.jit
453
- def _dpmpp_2m_midpoint_sample(
454
- params_ema: Any,
455
- apply_fn: Any,
456
- x_start: jnp.ndarray, # (B,D)
457
- sigmas_in: jnp.ndarray, # (K+1,)
458
- t_cont: jnp.ndarray, # (K,)
459
- eps: float,
460
- ) -> jnp.ndarray:
461
- """
462
- DPM-Solver++ (2M, midpoint) sampler.
463
-
464
- Uses:
465
- - first-order update on step 0
466
- - second-order midpoint update on steps 1..K-2
467
- - first-order update on final step K-1 (important when next sigma is 0)
468
- """
469
- # Current/next sigma for each step
470
- sigma_s = sigmas_in[:-1] # (K,)
471
- sigma_t = sigmas_in[1:] # (K,)
472
-
473
- alpha_s, sigma_s_t = _sigma_to_alpha_sigma_t(sigma_s) # both (K,)
474
- alpha_t, sigma_t_t = _sigma_to_alpha_sigma_t(sigma_t) # both (K,)
475
-
476
- # lambda = log(alpha) - log(sigma_t); for this parameterization it's ~ -log(sigma_in)
477
- # Avoid log(0) warnings: allow inf; we will not use 2nd-order formula on final step.
478
- lambda_s = jnp.log(alpha_s) - jnp.log(sigma_s_t)
479
- lambda_t = jnp.log(alpha_t) - jnp.log(sigma_t_t)
480
-
481
- K = t_cont.shape[0]
482
- is_first = jnp.arange(K) == 0
483
- is_last = jnp.arange(K) == (K - 1)
484
-
485
- def step(carry, inp):
486
- x, m_prev, lam_prev = carry
487
- (a_s, s_s, a_t, s_t, lam_s, lam_t, t_i, first_i, last_i) = inp
488
-
489
- B = x.shape[0]
490
- t_batch = jnp.full((B, 1), t_i, dtype=jnp.float32)
491
-
492
- # model predicts epsilon
493
- eps_pred = apply_fn({"params": params_ema}, x, t_batch) # (B,D)
494
-
495
- # convert epsilon -> x0 (data prediction)
496
- a_s_b = jnp.clip(a_s, eps, 1.0)
497
- x0 = (x - s_s * eps_pred) / a_s_b # (B,D)
498
-
499
- h = lam_t - lam_s
500
- exp_neg_h = jnp.exp(-h)
501
-
502
- # 1st-order (DDIM-like in dpmsolver++ form)
503
- x_first = (s_t / s_s) * x - (a_t * (exp_neg_h - 1.0)) * x0
504
-
505
- def do_second(_):
506
- # 2nd-order multistep midpoint
507
- h0 = lam_s - lam_prev
508
- # r0 = h0/h; clip to avoid division by 0 if something degenerate happens
509
- r0 = h0 / jnp.clip(h, 1e-12)
510
- D1 = (x0 - m_prev) / jnp.clip(r0, 1e-12)
511
- x_second = (s_t / s_s) * x - (a_t * (exp_neg_h - 1.0)) * (x0 + 0.5 * D1)
512
- return x_second
513
-
514
- x_next = jax.lax.cond(first_i | last_i, lambda _: x_first, do_second, operand=None)
515
- return (x_next, x0, lam_s), x_next
516
-
517
- # Pack per-step scalars
518
- xs = (
519
- alpha_s, sigma_s_t,
520
- alpha_t, sigma_t_t,
521
- lambda_s, lambda_t,
522
- t_cont, is_first, is_last
523
- )
524
-
525
- # init prev buffers (unused on first step)
526
- x0_init = jnp.zeros_like(x_start)
527
- lam_init = jnp.array(0.0, dtype=jnp.float32)
528
-
529
- (x_final, _, _), _trace = jax.lax.scan(step, (x_start, x0_init, lam_init), xs)
530
- return x_final
531
-
532
- # --- Public API: fast refine/sample methods ---
533
- def refine_latents_dpmpp(
534
- self,
535
- z0: jnp.ndarray,
536
- *,
537
- t_start: int = 10,
538
- num_steps: int = 20,
539
- key: Optional[jax.Array] = None,
540
- add_noise: bool = True,
541
- ) -> jnp.ndarray:
542
- z0 = jnp.asarray(z0, dtype=jnp.float32)
543
- if z0.ndim != 2 or z0.shape[1] != self.D:
544
- raise ValueError(f"z0 must have shape (B,{self.D}).")
545
- if not (0 <= int(t_start) < self.T):
546
- raise ValueError(f"t_start must be in [0, {self.T-1}]")
547
-
548
- if key is None:
549
- self.key, key = random.split(self.key)
550
- else:
551
- self.key, _ = random.split(key)
552
-
553
- # Forward-noise to t_start (same as your original code)
554
- key, k_eps = random.split(key)
555
- eps_noise = random.normal(k_eps, z0.shape)
556
-
557
- a_bar = jnp.clip(self.alpha_bar_s[int(t_start)], self.eps, 1.0)
558
- if add_noise:
559
- x_start = jnp.sqrt(a_bar) * z0 + jnp.sqrt(1.0 - a_bar) * eps_noise
560
- else:
561
- x_start = z0
562
-
563
- sigmas_in, t_cont = self._make_dpmpp_schedule(num_steps=int(num_steps), t_start=int(t_start))
564
-
565
- x_final = self._dpmpp_2m_midpoint_sample(
566
- self.state.ema_params,
567
- self.state.apply_fn,
568
- x_start,
569
- sigmas_in,
570
- t_cont,
571
- self.eps,
572
- )
573
- return x_final
574
-
575
- def reverse_from_T_dpmpp(self, x_T: jnp.ndarray, *, num_steps: int = 20) -> jnp.ndarray:
576
- x_T = jnp.asarray(x_T, dtype=jnp.float32)
577
- if x_T.ndim != 2 or x_T.shape[1] != self.D:
578
- raise ValueError(f"x_T must have shape (B,{self.D}).")
579
-
580
- sigmas_in, t_cont = self._make_dpmpp_schedule(num_steps=int(num_steps), t_start=self.T - 1)
581
-
582
- return self._dpmpp_2m_midpoint_sample(
583
- self.state.ema_params,
584
- self.state.apply_fn,
585
- x_T,
586
- sigmas_in,
587
- t_cont,
588
- self.eps,
589
- )
590
-
591
- def sample_dpmpp(self, N: int = 10_000, *, num_steps: int = 20) -> jnp.ndarray:
592
- self.key, k = random.split(self.key)
593
- x_T = random.normal(k, (int(N), self.D)).astype(jnp.float32)
594
- return self.reverse_from_T_dpmpp(x_T, num_steps=int(num_steps))
595
-
596
-
597
- __all__ = ["DDPM", "EpsMLP", "cosine_schedule", "sinusoidal_embedding"]