Spaces:
Running on Zero
Running on Zero
Update pk_workflow.py
Browse files- 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 |
|