dagloop5 commited on
Commit
517e01d
·
verified ·
1 Parent(s): cb865f6

Update pk_workflow.py

Browse files
Files changed (1) hide show
  1. pk_workflow.py +200 -0
pk_workflow.py CHANGED
@@ -294,6 +294,191 @@ def _er_sde_step(scheduler, generator, model_output, timestep, sample, s_noise:
294
  scheduler._step_index += 1
295
  return prev_sample
296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  class use_schedule:
298
  """Set each scheduler's shift for one request, and — for anything but `native` — force its sigma grid onto
299
  one of `SCHEDULE_SIGMA_FUNCS`'s named schedules.
@@ -357,6 +542,21 @@ class use_schedule:
357
  def stepped(model_output, timestep, sample, return_dict=True, _s=scheduler, _g=generator, **_kwargs):
358
  return (_er_sde_step(_s, _g, model_output, timestep, sample),)
359
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360
  scheduler.step = stepped
361
  return self
362
 
 
294
  scheduler._step_index += 1
295
  return prev_sample
296
 
297
+ class _BatchedBrownianTree:
298
+ """Minimal port of k-diffusion's `BatchedBrownianTree` (single-seed case only — MiniMax-H3 requests run at
299
+ batch size 1). Wraps `torchsde.BrownianTree` so consecutive noise draws at adjacent sigma pairs are
300
+ correlated through a shared stochastic path, as `dpmpp_2m_sde`/`dpmpp_3m_sde` require — independent
301
+ per-step Gaussian noise (as used for `euler_ancestral`/`er_sde` above) is a materially different sampler.
302
+ """
303
+
304
+ def __init__(self, x, t0, t1, seed, cpu=False):
305
+ import torchsde
306
+
307
+ self.cpu_tree = cpu
308
+ if t0 > t1:
309
+ t0, t1, self.sign = t1, t0, -1
310
+ else:
311
+ self.sign = 1
312
+ w0 = torch.zeros_like(x)
313
+ if self.cpu_tree:
314
+ t0, w0, t1 = t0.detach().cpu(), w0.detach().cpu(), t1.detach().cpu()
315
+ self.tree = torchsde.BrownianTree(t0, w0, t1, entropy=seed)
316
+
317
+ def __call__(self, t0, t1):
318
+ if t0 > t1:
319
+ t0, t1, sign = t1, t0, -1
320
+ else:
321
+ sign = 1
322
+ device, dtype = t0.device, t0.dtype
323
+ if self.cpu_tree:
324
+ t0, t1 = t0.detach().cpu().float(), t1.detach().cpu().float()
325
+ return self.tree(t0, t1).to(device=device, dtype=dtype) * (self.sign * sign)
326
+
327
+
328
+ class _BrownianTreeNoiseSampler:
329
+ """Port of k-diffusion's `BrownianTreeNoiseSampler`. `cpu=False` matches the `*_gpu` sampler names — noise
330
+ is generated directly on the accelerator rather than the CPU-tree variant the non-`_gpu` names use."""
331
+
332
+ def __init__(self, x, sigma_min, sigma_max, seed, cpu=False):
333
+ self.tree = _BatchedBrownianTree(x, torch.as_tensor(sigma_min), torch.as_tensor(sigma_max), seed, cpu=cpu)
334
+
335
+ def __call__(self, sigma, sigma_next):
336
+ t0, t1 = torch.as_tensor(sigma), torch.as_tensor(sigma_next)
337
+ return self.tree(t0, t1) / (t1 - t0).abs().sqrt()
338
+
339
+ def _dpmpp_2m_sde_step(scheduler, model_output, timestep, sample, eta: float = 1.0, s_noise: float = 1.0):
340
+ """Ports k-diffusion's `sample_dpmpp_2m_sde` (`solver_type='midpoint'`, matching ComfyUI's `dpmpp_2m_sde_gpu`
341
+ — the `_heun` variant is a different `solver_type` and is not ported here) onto one `MiniMaxH3Scheduler.step()`
342
+ call. Single model evaluation per step; second-order accuracy comes from the previous step's denoised
343
+ estimate. History and the Brownian-tree noise sampler live on the scheduler instance, reset each request.
344
+ """
345
+ if scheduler._step_index is None:
346
+ scheduler._step_index = scheduler.index_for_timestep(timestep) if scheduler._begin_index is None else scheduler._begin_index
347
+ i = scheduler._step_index
348
+
349
+ if not isinstance(timestep, torch.Tensor):
350
+ timestep = torch.tensor(timestep, dtype=sample.dtype)
351
+ sigma_from_timestep = 1 - timestep.to(device=sample.device, dtype=sample.dtype)
352
+ while sigma_from_timestep.ndim < sample.ndim:
353
+ sigma_from_timestep = sigma_from_timestep.unsqueeze(-1)
354
+ denoised = sample + sigma_from_timestep * model_output
355
+
356
+ compute_dtype = torch.float32 if sample.dtype in (torch.float16, torch.bfloat16) else sample.dtype
357
+ sigmas = scheduler.sigmas.to(device=sample.device, dtype=compute_dtype)
358
+ sigma, sigma_next = sigmas[i], sigmas[i + 1]
359
+ x = sample.to(dtype=compute_dtype)
360
+ denoised = denoised.to(dtype=compute_dtype)
361
+
362
+ if i == 0 and float(sigma) >= 1.0:
363
+ base = torch.tensor(1.0 - 1e-4, dtype=compute_dtype, device=sample.device)
364
+ shift = float(scheduler.shift)
365
+ sigma = shift * base / (1 + (shift - 1) * base)
366
+
367
+ if scheduler._dpmpp_sde_noise_sampler is None:
368
+ scheduler._dpmpp_sde_noise_sampler = _BrownianTreeNoiseSampler(
369
+ x, sigmas[sigmas > 0].min(), sigmas.max(), seed=scheduler._dpmpp_sde_seed, cpu=False
370
+ )
371
+
372
+ def half_log_snr(s):
373
+ return torch.log((1 - s) / s)
374
+
375
+ if sigma_next == 0:
376
+ prev_sample = denoised
377
+ else:
378
+ lambda_s, lambda_t = half_log_snr(sigma), half_log_snr(sigma_next)
379
+ h = lambda_t - lambda_s
380
+ h_eta = h * (eta + 1)
381
+ alpha_next = 1 - sigma_next
382
+
383
+ prev_sample = (sigma_next / sigma) * (-h * eta).exp() * x + alpha_next * (-h_eta).expm1().neg() * denoised
384
+
385
+ old_denoised = scheduler._dpmpp_sde_old_denoised
386
+ h_last = scheduler._dpmpp_sde_h_last
387
+ if old_denoised is not None:
388
+ r = h_last / h
389
+ prev_sample = prev_sample + 0.5 * alpha_next * (-h_eta).expm1().neg() * (1 / r) * (denoised - old_denoised)
390
+
391
+ if eta > 0 and s_noise > 0:
392
+ noise = scheduler._dpmpp_sde_noise_sampler(sigma, sigma_next).to(device=x.device, dtype=compute_dtype)
393
+ prev_sample = prev_sample + noise * sigma_next * (-2 * h * eta).expm1().neg().sqrt() * s_noise
394
+
395
+ scheduler._dpmpp_sde_h_last = h
396
+
397
+ scheduler._dpmpp_sde_old_denoised = denoised
398
+ prev_sample = prev_sample.to(dtype=sample.dtype)
399
+ scheduler._step_index += 1
400
+ return prev_sample
401
+
402
+
403
+ def _dpmpp_3m_sde_step(scheduler, model_output, timestep, sample, eta: float = 1.0, s_noise: float = 1.0):
404
+ """Ports k-diffusion's `sample_dpmpp_3m_sde` (matching ComfyUI's `dpmpp_3m_sde_gpu`) onto one
405
+ `MiniMaxH3Scheduler.step()` call. Single model evaluation per step; third-order accuracy (once two prior
406
+ steps exist) comes from history carried on the scheduler instance, plus the same Brownian-tree noise as
407
+ `_dpmpp_2m_sde_step`.
408
+ """
409
+ if scheduler._step_index is None:
410
+ scheduler._step_index = scheduler.index_for_timestep(timestep) if scheduler._begin_index is None else scheduler._begin_index
411
+ i = scheduler._step_index
412
+
413
+ if not isinstance(timestep, torch.Tensor):
414
+ timestep = torch.tensor(timestep, dtype=sample.dtype)
415
+ sigma_from_timestep = 1 - timestep.to(device=sample.device, dtype=sample.dtype)
416
+ while sigma_from_timestep.ndim < sample.ndim:
417
+ sigma_from_timestep = sigma_from_timestep.unsqueeze(-1)
418
+ denoised = sample + sigma_from_timestep * model_output
419
+
420
+ compute_dtype = torch.float32 if sample.dtype in (torch.float16, torch.bfloat16) else sample.dtype
421
+ sigmas = scheduler.sigmas.to(device=sample.device, dtype=compute_dtype)
422
+ sigma, sigma_next = sigmas[i], sigmas[i + 1]
423
+ x = sample.to(dtype=compute_dtype)
424
+ denoised = denoised.to(dtype=compute_dtype)
425
+
426
+ if i == 0 and float(sigma) >= 1.0:
427
+ base = torch.tensor(1.0 - 1e-4, dtype=compute_dtype, device=sample.device)
428
+ shift = float(scheduler.shift)
429
+ sigma = shift * base / (1 + (shift - 1) * base)
430
+
431
+ if scheduler._dpmpp_sde_noise_sampler is None:
432
+ scheduler._dpmpp_sde_noise_sampler = _BrownianTreeNoiseSampler(
433
+ x, sigmas[sigmas > 0].min(), sigmas.max(), seed=scheduler._dpmpp_sde_seed, cpu=False
434
+ )
435
+
436
+ def half_log_snr(s):
437
+ return torch.log((1 - s) / s)
438
+
439
+ if sigma_next == 0:
440
+ prev_sample = denoised
441
+ else:
442
+ lambda_s, lambda_t = half_log_snr(sigma), half_log_snr(sigma_next)
443
+ h = lambda_t - lambda_s
444
+ h_eta = h * (eta + 1)
445
+ alpha_next = 1 - sigma_next
446
+
447
+ prev_sample = (sigma_next / sigma) * (-h * eta).exp() * x + alpha_next * (-h_eta).expm1().neg() * denoised
448
+
449
+ denoised_1 = scheduler._dpmpp_sde_old_denoised
450
+ denoised_2 = scheduler._dpmpp_sde_old_denoised_2
451
+ h_1 = scheduler._dpmpp_sde_h_last
452
+ h_2 = scheduler._dpmpp_sde_h_last_2
453
+
454
+ if h_2 is not None:
455
+ r0, r1 = h_1 / h, h_2 / h
456
+ d1_0 = (denoised - denoised_1) / r0
457
+ d1_1 = (denoised_1 - denoised_2) / r1
458
+ d1 = d1_0 + (d1_0 - d1_1) * r0 / (r0 + r1)
459
+ d2 = (d1_0 - d1_1) / (r0 + r1)
460
+ phi_2 = h_eta.neg().expm1() / h_eta + 1
461
+ phi_3 = phi_2 / h_eta - 0.5
462
+ prev_sample = prev_sample + (alpha_next * phi_2) * d1 - (alpha_next * phi_3) * d2
463
+ elif h_1 is not None:
464
+ r = h_1 / h
465
+ d = (denoised - denoised_1) / r
466
+ phi_2 = h_eta.neg().expm1() / h_eta + 1
467
+ prev_sample = prev_sample + (alpha_next * phi_2) * d
468
+
469
+ if eta > 0 and s_noise > 0:
470
+ noise = scheduler._dpmpp_sde_noise_sampler(sigma, sigma_next).to(device=x.device, dtype=compute_dtype)
471
+ prev_sample = prev_sample + noise * sigma_next * (-2 * h * eta).expm1().neg().sqrt() * s_noise
472
+
473
+ scheduler._dpmpp_sde_h_last_2 = h_1
474
+ scheduler._dpmpp_sde_h_last = h
475
+
476
+ scheduler._dpmpp_sde_old_denoised_2 = scheduler._dpmpp_sde_old_denoised
477
+ scheduler._dpmpp_sde_old_denoised = denoised
478
+ prev_sample = prev_sample.to(dtype=sample.dtype)
479
+ scheduler._step_index += 1
480
+ return prev_sample
481
+
482
  class use_schedule:
483
  """Set each scheduler's shift for one request, and — for anything but `native` — force its sigma grid onto
484
  one of `SCHEDULE_SIGMA_FUNCS`'s named schedules.
 
542
  def stepped(model_output, timestep, sample, return_dict=True, _s=scheduler, _g=generator, **_kwargs):
543
  return (_er_sde_step(_s, _g, model_output, timestep, sample),)
544
 
545
+ scheduler.step = stepped
546
+ elif self.sampler_name in ("dpmpp_2m_sde_gpu", "dpmpp_3m_sde_gpu"):
547
+ step_fn = _dpmpp_2m_sde_step if self.sampler_name == "dpmpp_2m_sde_gpu" else _dpmpp_3m_sde_step
548
+ for offset, attr_name in enumerate(self.attr_names):
549
+ scheduler = getattr(self.pipe, attr_name)
550
+ scheduler._dpmpp_sde_old_denoised = None
551
+ scheduler._dpmpp_sde_old_denoised_2 = None
552
+ scheduler._dpmpp_sde_h_last = None
553
+ scheduler._dpmpp_sde_h_last_2 = None
554
+ scheduler._dpmpp_sde_noise_sampler = None
555
+ scheduler._dpmpp_sde_seed = self.seed + offset
556
+
557
+ def stepped(model_output, timestep, sample, return_dict=True, _s=scheduler, _f=step_fn, **_kwargs):
558
+ return (_f(_s, model_output, timestep, sample),)
559
+
560
  scheduler.step = stepped
561
  return self
562