diff --git a/README.md b/README.md
index 1345df6..7dc4c8f 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,24 @@
# ComfyUI-Wan-TimeToMove
-A native comfyui port of kijai's WanVideo-Wrapper TimeToMove
+A native comfyui port of Kijai's WanVideo-Wrapper TimeToMove
-
+
-https://github.com/user-attachments/assets/551eac0d-c5fe-49a8-b1a2-3884d0ece746
+https://github.com/user-attachments/assets/0b201e7a-d3c6-417f-8293-e20e8d2872fb
-**This node is still WIP.** For now only the [lcm sampler](https://github.com/GiusTex/ComfyUI-Wan-TimeToMove/blob/main/k_diffusion/sampling.py#L1020) supports TimeToMove, and the generated frames are a bit dark (this color difference is seen especially when a first frame is passed).
+### Updates:
+- Solved color issue.
+- Fixed other bugs.
-The second sampler can be found here: `https://github.com/GiusTex/ComfyUI-MoreEfficientSamplers` but you can change it, and the scheduler used is this: `https://github.com/BigStationW/flowmatch_scheduler-comfyui`, useful when you use lightx loras.
+### Nodes
+The custom node contains 4 new nodes:
+- `Encode WanVideo`: taken from wanvideo-wrapper, it encodes the reference video.
+- `TTM Latent Add`: taken from wanvideo-wrapper, it embeds in the latent the reference to the driving video.
+- `Timove To Move Guider`: this node adds the ttm latent to the latent noise before passing it to the sampling function. This node removes the necessity of a dedicated sampler.
+- `CFG Float List Scheduler`: taken from wanvideo-wrapper, it creates a list of cfg values, and submits them step by step, making possible using different cfg values at different steps.
+
+### Other custom nodes used:
+- The advanced sampler used in the [second workflow](https://github.com/GiusTex/ComfyUI-Wan-TimeToMove/blob/TTM-v2/wanvideo_2_2_I2V_A14B_TimeToMove_workflow2.json) can be found [here](https://github.com/GiusTex/ComfyUI-MoreEfficientSamplers). You can still use the native comfyui `sampler custom advanced` using [this](https://github.com/GiusTex/ComfyUI-Wan-TimeToMove/blob/TTM-v2/wanvideo_2_2_I2V_A14B_TimeToMove_workflow1.json) workflow.
+- The scheduler used is [this](https://github.com/BigStationW/flowmatch_scheduler-comfyui), useful for models using lightx loras. You can still use other samplers/schedulers.
### Download
To install ComfyUI-Wan-TimeToMove, follow these steps:
diff --git a/__init__.py b/__init__.py
index 5008448..e970d6c 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,20 +1,20 @@
-from .nodes import (WanVideoEncode,
- TTMKSamplerSelect,
- AddTTMLatent,
- WanVideoSamplerCustomUltraAdvancedEfficient)
+from .nodes import (EncodeWanVideo,
+ TTMLatentAdd,
+ TimeToMoveGuider,
+ CFGFloatListScheduler)
NODE_CLASS_MAPPINGS = {
- "WanVideoEncode": WanVideoEncode,
- "TTMKSamplerSelect": TTMKSamplerSelect,
- "AddTTMLatent": AddTTMLatent,
- "WanVideoSamplerCustomUltraAdvancedEfficient": WanVideoSamplerCustomUltraAdvancedEfficient,
+ "EncodeWanVideo": EncodeWanVideo,
+ "TTMLatentAdd": TTMLatentAdd,
+ "TimeToMoveGuider": TimeToMoveGuider,
+ "CFGFloatListScheduler": CFGFloatListScheduler,
}
NODE_DISPLAY_NAME_MAPPINGS = {
- "WanVideoEncode": "WanVideo Encode",
- "TTMKSamplerSelect": "TimeToMove KSampler Select",
- "AddTTMLatent": "Add TTM Latent",
- "WanVideoSamplerCustomUltraAdvancedEfficient": "WanVideoSampler Custom Ultra Advanced Efficient",
+ "EncodeWanVideo": "Encode WanVideo",
+ "TTMLatentAdd": "TTM Latent Add",
+ "TimeToMoveGuider": "TimeToMove Guider",
+ "CFGFloatListScheduler": "CFGFloatListScheduler",
}
-__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
\ No newline at end of file
+__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
diff --git a/k_diffusion/sampling.py b/k_diffusion/sampling.py
deleted file mode 100644
index 3019949..0000000
--- a/k_diffusion/sampling.py
+++ /dev/null
@@ -1,1811 +0,0 @@
-import math
-from functools import partial
-
-from scipy import integrate
-import torch
-from torch import nn
-import torchsde
-from tqdm.auto import trange, tqdm
-
-from comfy.k_diffusion import utils
-from comfy.k_diffusion import deis
-from comfy.k_diffusion import sa_solver
-import comfy.model_patcher
-import comfy.model_sampling
-
-def append_zero(x):
- return torch.cat([x, x.new_zeros([1])])
-
-
-def get_sigmas_karras(n, sigma_min, sigma_max, rho=7., device='cpu'):
- """Constructs the noise schedule of Karras et al. (2022)."""
- ramp = torch.linspace(0, 1, n, device=device)
- min_inv_rho = sigma_min ** (1 / rho)
- max_inv_rho = sigma_max ** (1 / rho)
- sigmas = (max_inv_rho + ramp * (min_inv_rho - max_inv_rho)) ** rho
- return append_zero(sigmas).to(device)
-
-
-def get_sigmas_exponential(n, sigma_min, sigma_max, device='cpu'):
- """Constructs an exponential noise schedule."""
- sigmas = torch.linspace(math.log(sigma_max), math.log(sigma_min), n, device=device).exp()
- return append_zero(sigmas)
-
-
-def get_sigmas_polyexponential(n, sigma_min, sigma_max, rho=1., device='cpu'):
- """Constructs an polynomial in log sigma noise schedule."""
- ramp = torch.linspace(1, 0, n, device=device) ** rho
- sigmas = torch.exp(ramp * (math.log(sigma_max) - math.log(sigma_min)) + math.log(sigma_min))
- return append_zero(sigmas)
-
-
-def get_sigmas_vp(n, beta_d=19.9, beta_min=0.1, eps_s=1e-3, device='cpu'):
- """Constructs a continuous VP noise schedule."""
- t = torch.linspace(1, eps_s, n, device=device)
- sigmas = torch.sqrt(torch.special.expm1(beta_d * t ** 2 / 2 + beta_min * t))
- return append_zero(sigmas)
-
-
-def get_sigmas_laplace(n, sigma_min, sigma_max, mu=0., beta=0.5, device='cpu'):
- """Constructs the noise schedule proposed by Tiankai et al. (2024). """
- epsilon = 1e-5 # avoid log(0)
- x = torch.linspace(0, 1, n, device=device)
- clamp = lambda x: torch.clamp(x, min=sigma_min, max=sigma_max)
- lmb = mu - beta * torch.sign(0.5-x) * torch.log(1 - 2 * torch.abs(0.5-x) + epsilon)
- sigmas = clamp(torch.exp(lmb))
- return sigmas
-
-
-
-def to_d(x, sigma, denoised):
- """Converts a denoiser output to a Karras ODE derivative."""
- return (x - denoised) / utils.append_dims(sigma, x.ndim)
-
-
-def get_ancestral_step(sigma_from, sigma_to, eta=1.):
- """Calculates the noise level (sigma_down) to step down to and the amount
- of noise to add (sigma_up) when doing an ancestral sampling step."""
- if not eta:
- return sigma_to, 0.
- sigma_up = min(sigma_to, eta * (sigma_to ** 2 * (sigma_from ** 2 - sigma_to ** 2) / sigma_from ** 2) ** 0.5)
- sigma_down = (sigma_to ** 2 - sigma_up ** 2) ** 0.5
- return sigma_down, sigma_up
-
-
-def default_noise_sampler(x, seed=None):
- if seed is not None:
- generator = torch.Generator(device=x.device)
- generator.manual_seed(seed)
- else:
- generator = None
-
- return lambda sigma, sigma_next: torch.randn(x.size(), dtype=x.dtype, layout=x.layout, device=x.device, generator=generator)
-
-
-class BatchedBrownianTree:
- """A wrapper around torchsde.BrownianTree that enables batches of entropy."""
-
- def __init__(self, x, t0, t1, seed=None, **kwargs):
- self.cpu_tree = kwargs.pop("cpu", True)
- t0, t1, self.sign = self.sort(t0, t1)
- w0 = kwargs.pop('w0', None)
- if w0 is None:
- w0 = torch.zeros_like(x)
- self.batched = False
- if seed is None:
- seed = (torch.randint(0, 2 ** 63 - 1, ()).item(),)
- elif isinstance(seed, (tuple, list)):
- if len(seed) != x.shape[0]:
- raise ValueError("Passing a list or tuple of seeds to BatchedBrownianTree requires a length matching the batch size.")
- self.batched = True
- w0 = w0[0]
- else:
- seed = (seed,)
- if self.cpu_tree:
- t0, w0, t1 = t0.detach().cpu(), w0.detach().cpu(), t1.detach().cpu()
- self.trees = tuple(torchsde.BrownianTree(t0, w0, t1, entropy=s, **kwargs) for s in seed)
-
- @staticmethod
- def sort(a, b):
- return (a, b, 1) if a < b else (b, a, -1)
-
- def __call__(self, t0, t1):
- t0, t1, sign = self.sort(t0, t1)
- device, dtype = t0.device, t0.dtype
- if self.cpu_tree:
- t0, t1 = t0.detach().cpu().float(), t1.detach().cpu().float()
- w = torch.stack([tree(t0, t1) for tree in self.trees]).to(device=device, dtype=dtype) * (self.sign * sign)
- return w if self.batched else w[0]
-
-
-class BrownianTreeNoiseSampler:
- """A noise sampler backed by a torchsde.BrownianTree.
-
- Args:
- x (Tensor): The tensor whose shape, device and dtype to use to generate
- random samples.
- sigma_min (float): The low end of the valid interval.
- sigma_max (float): The high end of the valid interval.
- seed (int or List[int]): The random seed. If a list of seeds is
- supplied instead of a single integer, then the noise sampler will
- use one BrownianTree per batch item, each with its own seed.
- transform (callable): A function that maps sigma to the sampler's
- internal timestep.
- """
-
- def __init__(self, x, sigma_min, sigma_max, seed=None, transform=lambda x: x, cpu=False):
- self.transform = transform
- t0, t1 = self.transform(torch.as_tensor(sigma_min)), self.transform(torch.as_tensor(sigma_max))
- self.tree = BatchedBrownianTree(x, t0, t1, seed, cpu=cpu)
-
- def __call__(self, sigma, sigma_next):
- t0, t1 = self.transform(torch.as_tensor(sigma)), self.transform(torch.as_tensor(sigma_next))
- return self.tree(t0, t1) / (t1 - t0).abs().sqrt()
-
-
-def sigma_to_half_log_snr(sigma, model_sampling):
- """Convert sigma to half-logSNR log(alpha_t / sigma_t)."""
- if isinstance(model_sampling, comfy.model_sampling.CONST):
- # log((1 - t) / t) = log((1 - sigma) / sigma)
- return sigma.logit().neg()
- return sigma.log().neg()
-
-
-def half_log_snr_to_sigma(half_log_snr, model_sampling):
- """Convert half-logSNR log(alpha_t / sigma_t) to sigma."""
- if isinstance(model_sampling, comfy.model_sampling.CONST):
- # 1 / (1 + exp(half_log_snr))
- return half_log_snr.neg().sigmoid()
- return half_log_snr.neg().exp()
-
-
-def offset_first_sigma_for_snr(sigmas, model_sampling, percent_offset=1e-4):
- """Adjust the first sigma to avoid invalid logSNR."""
- if len(sigmas) <= 1:
- return sigmas
- if isinstance(model_sampling, comfy.model_sampling.CONST):
- if sigmas[0] >= 1:
- sigmas = sigmas.clone()
- sigmas[0] = model_sampling.percent_to_sigma(percent_offset)
- return sigmas
-
-
-def ei_h_phi_1(h: torch.Tensor) -> torch.Tensor:
- """Compute the result of h*phi_1(h) in exponential integrator methods."""
- return torch.expm1(h)
-
-
-def ei_h_phi_2(h: torch.Tensor) -> torch.Tensor:
- """Compute the result of h*phi_2(h) in exponential integrator methods."""
- return (torch.expm1(h) - h) / h
-
-
-@torch.no_grad()
-def sample_euler(model, x, sigmas, extra_args=None, callback=None, disable=None, s_churn=0., s_tmin=0., s_tmax=float('inf'), s_noise=1.):
- """Implements Algorithm 2 (Euler steps) from Karras et al. (2022)."""
- extra_args = {} if extra_args is None else extra_args
- s_in = x.new_ones([x.shape[0]])
- for i in trange(len(sigmas) - 1, disable=disable):
- if s_churn > 0:
- gamma = min(s_churn / (len(sigmas) - 1), 2 ** 0.5 - 1) if s_tmin <= sigmas[i] <= s_tmax else 0.
- sigma_hat = sigmas[i] * (gamma + 1)
- else:
- gamma = 0
- sigma_hat = sigmas[i]
-
- if gamma > 0:
- eps = torch.randn_like(x) * s_noise
- x = x + eps * (sigma_hat ** 2 - sigmas[i] ** 2) ** 0.5
- denoised = model(x, sigma_hat * s_in, **extra_args)
- d = to_d(x, sigma_hat, denoised)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigma_hat, 'denoised': denoised})
- dt = sigmas[i + 1] - sigma_hat
- # Euler method
- x = x + d * dt
- return x
-
-
-@torch.no_grad()
-def sample_euler_ancestral(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
- if isinstance(model.inner_model.inner_model.model_sampling, comfy.model_sampling.CONST):
- return sample_euler_ancestral_RF(model, x, sigmas, extra_args, callback, disable, eta, s_noise, noise_sampler)
- """Ancestral sampling with Euler method steps."""
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- sigma_down, sigma_up = get_ancestral_step(sigmas[i], sigmas[i + 1], eta=eta)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
-
- if sigma_down == 0:
- x = denoised
- else:
- d = to_d(x, sigmas[i], denoised)
- # Euler method
- dt = sigma_down - sigmas[i]
- x = x + d * dt + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up
- return x
-
-@torch.no_grad()
-def sample_euler_ancestral_RF(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1.0, s_noise=1., noise_sampler=None):
- """Ancestral sampling with Euler method steps."""
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- # sigma_down, sigma_up = get_ancestral_step(sigmas[i], sigmas[i + 1], eta=eta)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
-
- if sigmas[i + 1] == 0:
- x = denoised
- else:
- downstep_ratio = 1 + (sigmas[i + 1] / sigmas[i] - 1) * eta
- sigma_down = sigmas[i + 1] * downstep_ratio
- alpha_ip1 = 1 - sigmas[i + 1]
- alpha_down = 1 - sigma_down
- renoise_coeff = (sigmas[i + 1]**2 - sigma_down**2 * alpha_ip1**2 / alpha_down**2)**0.5
- # Euler method
- sigma_down_i_ratio = sigma_down / sigmas[i]
- x = sigma_down_i_ratio * x + (1 - sigma_down_i_ratio) * denoised
- if eta > 0:
- x = (alpha_ip1 / alpha_down) * x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * renoise_coeff
- return x
-
-@torch.no_grad()
-def sample_heun(model, x, sigmas, extra_args=None, callback=None, disable=None, s_churn=0., s_tmin=0., s_tmax=float('inf'), s_noise=1.):
- """Implements Algorithm 2 (Heun steps) from Karras et al. (2022)."""
- extra_args = {} if extra_args is None else extra_args
- s_in = x.new_ones([x.shape[0]])
- for i in trange(len(sigmas) - 1, disable=disable):
- if s_churn > 0:
- gamma = min(s_churn / (len(sigmas) - 1), 2 ** 0.5 - 1) if s_tmin <= sigmas[i] <= s_tmax else 0.
- sigma_hat = sigmas[i] * (gamma + 1)
- else:
- gamma = 0
- sigma_hat = sigmas[i]
-
- sigma_hat = sigmas[i] * (gamma + 1)
- if gamma > 0:
- eps = torch.randn_like(x) * s_noise
- x = x + eps * (sigma_hat ** 2 - sigmas[i] ** 2) ** 0.5
- denoised = model(x, sigma_hat * s_in, **extra_args)
- d = to_d(x, sigma_hat, denoised)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigma_hat, 'denoised': denoised})
- dt = sigmas[i + 1] - sigma_hat
- if sigmas[i + 1] == 0:
- # Euler method
- x = x + d * dt
- else:
- # Heun's method
- x_2 = x + d * dt
- denoised_2 = model(x_2, sigmas[i + 1] * s_in, **extra_args)
- d_2 = to_d(x_2, sigmas[i + 1], denoised_2)
- d_prime = (d + d_2) / 2
- x = x + d_prime * dt
- return x
-
-
-@torch.no_grad()
-def sample_dpm_2(model, x, sigmas, extra_args=None, callback=None, disable=None, s_churn=0., s_tmin=0., s_tmax=float('inf'), s_noise=1.):
- """A sampler inspired by DPM-Solver-2 and Algorithm 2 from Karras et al. (2022)."""
- extra_args = {} if extra_args is None else extra_args
- s_in = x.new_ones([x.shape[0]])
- for i in trange(len(sigmas) - 1, disable=disable):
- if s_churn > 0:
- gamma = min(s_churn / (len(sigmas) - 1), 2 ** 0.5 - 1) if s_tmin <= sigmas[i] <= s_tmax else 0.
- sigma_hat = sigmas[i] * (gamma + 1)
- else:
- gamma = 0
- sigma_hat = sigmas[i]
-
- if gamma > 0:
- eps = torch.randn_like(x) * s_noise
- x = x + eps * (sigma_hat ** 2 - sigmas[i] ** 2) ** 0.5
- denoised = model(x, sigma_hat * s_in, **extra_args)
- d = to_d(x, sigma_hat, denoised)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigma_hat, 'denoised': denoised})
- if sigmas[i + 1] == 0:
- # Euler method
- dt = sigmas[i + 1] - sigma_hat
- x = x + d * dt
- else:
- # DPM-Solver-2
- sigma_mid = sigma_hat.log().lerp(sigmas[i + 1].log(), 0.5).exp()
- dt_1 = sigma_mid - sigma_hat
- dt_2 = sigmas[i + 1] - sigma_hat
- x_2 = x + d * dt_1
- denoised_2 = model(x_2, sigma_mid * s_in, **extra_args)
- d_2 = to_d(x_2, sigma_mid, denoised_2)
- x = x + d_2 * dt_2
- return x
-
-
-@torch.no_grad()
-def sample_dpm_2_ancestral(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
- if isinstance(model.inner_model.inner_model.model_sampling, comfy.model_sampling.CONST):
- return sample_dpm_2_ancestral_RF(model, x, sigmas, extra_args, callback, disable, eta, s_noise, noise_sampler)
-
- """Ancestral sampling with DPM-Solver second-order steps."""
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- sigma_down, sigma_up = get_ancestral_step(sigmas[i], sigmas[i + 1], eta=eta)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- d = to_d(x, sigmas[i], denoised)
- if sigma_down == 0:
- # Euler method
- dt = sigma_down - sigmas[i]
- x = x + d * dt
- else:
- # DPM-Solver-2
- sigma_mid = sigmas[i].log().lerp(sigma_down.log(), 0.5).exp()
- dt_1 = sigma_mid - sigmas[i]
- dt_2 = sigma_down - sigmas[i]
- x_2 = x + d * dt_1
- denoised_2 = model(x_2, sigma_mid * s_in, **extra_args)
- d_2 = to_d(x_2, sigma_mid, denoised_2)
- x = x + d_2 * dt_2
- x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up
- return x
-
-@torch.no_grad()
-def sample_dpm_2_ancestral_RF(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
- """Ancestral sampling with DPM-Solver second-order steps."""
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- downstep_ratio = 1 + (sigmas[i+1]/sigmas[i] - 1) * eta
- sigma_down = sigmas[i+1] * downstep_ratio
- alpha_ip1 = 1 - sigmas[i+1]
- alpha_down = 1 - sigma_down
- renoise_coeff = (sigmas[i+1]**2 - sigma_down**2*alpha_ip1**2/alpha_down**2)**0.5
-
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- d = to_d(x, sigmas[i], denoised)
- if sigma_down == 0:
- # Euler method
- dt = sigma_down - sigmas[i]
- x = x + d * dt
- else:
- # DPM-Solver-2
- sigma_mid = sigmas[i].log().lerp(sigma_down.log(), 0.5).exp()
- dt_1 = sigma_mid - sigmas[i]
- dt_2 = sigma_down - sigmas[i]
- x_2 = x + d * dt_1
- denoised_2 = model(x_2, sigma_mid * s_in, **extra_args)
- d_2 = to_d(x_2, sigma_mid, denoised_2)
- x = x + d_2 * dt_2
- x = (alpha_ip1/alpha_down) * x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * renoise_coeff
- return x
-
-def linear_multistep_coeff(order, t, i, j):
- if order - 1 > i:
- raise ValueError(f'Order {order} too high for step {i}')
- def fn(tau):
- prod = 1.
- for k in range(order):
- if j == k:
- continue
- prod *= (tau - t[i - k]) / (t[i - j] - t[i - k])
- return prod
- return integrate.quad(fn, t[i], t[i + 1], epsrel=1e-4)[0]
-
-
-@torch.no_grad()
-def sample_lms(model, x, sigmas, extra_args=None, callback=None, disable=None, order=4):
- extra_args = {} if extra_args is None else extra_args
- s_in = x.new_ones([x.shape[0]])
- sigmas_cpu = sigmas.detach().cpu().numpy()
- ds = []
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- d = to_d(x, sigmas[i], denoised)
- ds.append(d)
- if len(ds) > order:
- ds.pop(0)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- if sigmas[i + 1] == 0:
- # Denoising step
- x = denoised
- else:
- cur_order = min(i + 1, order)
- coeffs = [linear_multistep_coeff(cur_order, sigmas_cpu, i, j) for j in range(cur_order)]
- x = x + sum(coeff * d for coeff, d in zip(coeffs, reversed(ds)))
- return x
-
-
-class PIDStepSizeController:
- """A PID controller for ODE adaptive step size control."""
- def __init__(self, h, pcoeff, icoeff, dcoeff, order=1, accept_safety=0.81, eps=1e-8):
- self.h = h
- self.b1 = (pcoeff + icoeff + dcoeff) / order
- self.b2 = -(pcoeff + 2 * dcoeff) / order
- self.b3 = dcoeff / order
- self.accept_safety = accept_safety
- self.eps = eps
- self.errs = []
-
- def limiter(self, x):
- return 1 + math.atan(x - 1)
-
- def propose_step(self, error):
- inv_error = 1 / (float(error) + self.eps)
- if not self.errs:
- self.errs = [inv_error, inv_error, inv_error]
- self.errs[0] = inv_error
- factor = self.errs[0] ** self.b1 * self.errs[1] ** self.b2 * self.errs[2] ** self.b3
- factor = self.limiter(factor)
- accept = factor >= self.accept_safety
- if accept:
- self.errs[2] = self.errs[1]
- self.errs[1] = self.errs[0]
- self.h *= factor
- return accept
-
-
-class DPMSolver(nn.Module):
- """DPM-Solver. See https://arxiv.org/abs/2206.00927."""
-
- def __init__(self, model, extra_args=None, eps_callback=None, info_callback=None):
- super().__init__()
- self.model = model
- self.extra_args = {} if extra_args is None else extra_args
- self.eps_callback = eps_callback
- self.info_callback = info_callback
-
- def t(self, sigma):
- return -sigma.log()
-
- def sigma(self, t):
- return t.neg().exp()
-
- def eps(self, eps_cache, key, x, t, *args, **kwargs):
- if key in eps_cache:
- return eps_cache[key], eps_cache
- sigma = self.sigma(t) * x.new_ones([x.shape[0]])
- eps = (x - self.model(x, sigma, *args, **self.extra_args, **kwargs)) / self.sigma(t)
- if self.eps_callback is not None:
- self.eps_callback()
- return eps, {key: eps, **eps_cache}
-
- def dpm_solver_1_step(self, x, t, t_next, eps_cache=None):
- eps_cache = {} if eps_cache is None else eps_cache
- h = t_next - t
- eps, eps_cache = self.eps(eps_cache, 'eps', x, t)
- x_1 = x - self.sigma(t_next) * h.expm1() * eps
- return x_1, eps_cache
-
- def dpm_solver_2_step(self, x, t, t_next, r1=1 / 2, eps_cache=None):
- eps_cache = {} if eps_cache is None else eps_cache
- h = t_next - t
- eps, eps_cache = self.eps(eps_cache, 'eps', x, t)
- s1 = t + r1 * h
- u1 = x - self.sigma(s1) * (r1 * h).expm1() * eps
- eps_r1, eps_cache = self.eps(eps_cache, 'eps_r1', u1, s1)
- x_2 = x - self.sigma(t_next) * h.expm1() * eps - self.sigma(t_next) / (2 * r1) * h.expm1() * (eps_r1 - eps)
- return x_2, eps_cache
-
- def dpm_solver_3_step(self, x, t, t_next, r1=1 / 3, r2=2 / 3, eps_cache=None):
- eps_cache = {} if eps_cache is None else eps_cache
- h = t_next - t
- eps, eps_cache = self.eps(eps_cache, 'eps', x, t)
- s1 = t + r1 * h
- s2 = t + r2 * h
- u1 = x - self.sigma(s1) * (r1 * h).expm1() * eps
- eps_r1, eps_cache = self.eps(eps_cache, 'eps_r1', u1, s1)
- u2 = x - self.sigma(s2) * (r2 * h).expm1() * eps - self.sigma(s2) * (r2 / r1) * ((r2 * h).expm1() / (r2 * h) - 1) * (eps_r1 - eps)
- eps_r2, eps_cache = self.eps(eps_cache, 'eps_r2', u2, s2)
- x_3 = x - self.sigma(t_next) * h.expm1() * eps - self.sigma(t_next) / r2 * (h.expm1() / h - 1) * (eps_r2 - eps)
- return x_3, eps_cache
-
- def dpm_solver_fast(self, x, t_start, t_end, nfe, eta=0., s_noise=1., noise_sampler=None):
- noise_sampler = default_noise_sampler(x, seed=self.extra_args.get("seed", None)) if noise_sampler is None else noise_sampler
- if not t_end > t_start and eta:
- raise ValueError('eta must be 0 for reverse sampling')
-
- m = math.floor(nfe / 3) + 1
- ts = torch.linspace(t_start, t_end, m + 1, device=x.device)
-
- if nfe % 3 == 0:
- orders = [3] * (m - 2) + [2, 1]
- else:
- orders = [3] * (m - 1) + [nfe % 3]
-
- for i in range(len(orders)):
- eps_cache = {}
- t, t_next = ts[i], ts[i + 1]
- if eta:
- sd, su = get_ancestral_step(self.sigma(t), self.sigma(t_next), eta)
- t_next_ = torch.minimum(t_end, self.t(sd))
- su = (self.sigma(t_next) ** 2 - self.sigma(t_next_) ** 2) ** 0.5
- else:
- t_next_, su = t_next, 0.
-
- eps, eps_cache = self.eps(eps_cache, 'eps', x, t)
- denoised = x - self.sigma(t) * eps
- if self.info_callback is not None:
- self.info_callback({'x': x, 'i': i, 't': ts[i], 't_up': t, 'denoised': denoised})
-
- if orders[i] == 1:
- x, eps_cache = self.dpm_solver_1_step(x, t, t_next_, eps_cache=eps_cache)
- elif orders[i] == 2:
- x, eps_cache = self.dpm_solver_2_step(x, t, t_next_, eps_cache=eps_cache)
- else:
- x, eps_cache = self.dpm_solver_3_step(x, t, t_next_, eps_cache=eps_cache)
-
- x = x + su * s_noise * noise_sampler(self.sigma(t), self.sigma(t_next))
-
- return x
-
- def dpm_solver_adaptive(self, x, t_start, t_end, order=3, rtol=0.05, atol=0.0078, h_init=0.05, pcoeff=0., icoeff=1., dcoeff=0., accept_safety=0.81, eta=0., s_noise=1., noise_sampler=None):
- noise_sampler = default_noise_sampler(x, seed=self.extra_args.get("seed", None)) if noise_sampler is None else noise_sampler
- if order not in {2, 3}:
- raise ValueError('order should be 2 or 3')
- forward = t_end > t_start
- if not forward and eta:
- raise ValueError('eta must be 0 for reverse sampling')
- h_init = abs(h_init) * (1 if forward else -1)
- atol = torch.tensor(atol)
- rtol = torch.tensor(rtol)
- s = t_start
- x_prev = x
- accept = True
- pid = PIDStepSizeController(h_init, pcoeff, icoeff, dcoeff, 1.5 if eta else order, accept_safety)
- info = {'steps': 0, 'nfe': 0, 'n_accept': 0, 'n_reject': 0}
-
- while s < t_end - 1e-5 if forward else s > t_end + 1e-5:
- eps_cache = {}
- t = torch.minimum(t_end, s + pid.h) if forward else torch.maximum(t_end, s + pid.h)
- if eta:
- sd, su = get_ancestral_step(self.sigma(s), self.sigma(t), eta)
- t_ = torch.minimum(t_end, self.t(sd))
- su = (self.sigma(t) ** 2 - self.sigma(t_) ** 2) ** 0.5
- else:
- t_, su = t, 0.
-
- eps, eps_cache = self.eps(eps_cache, 'eps', x, s)
- denoised = x - self.sigma(s) * eps
-
- if order == 2:
- x_low, eps_cache = self.dpm_solver_1_step(x, s, t_, eps_cache=eps_cache)
- x_high, eps_cache = self.dpm_solver_2_step(x, s, t_, eps_cache=eps_cache)
- else:
- x_low, eps_cache = self.dpm_solver_2_step(x, s, t_, r1=1 / 3, eps_cache=eps_cache)
- x_high, eps_cache = self.dpm_solver_3_step(x, s, t_, eps_cache=eps_cache)
- delta = torch.maximum(atol, rtol * torch.maximum(x_low.abs(), x_prev.abs()))
- error = torch.linalg.norm((x_low - x_high) / delta) / x.numel() ** 0.5
- accept = pid.propose_step(error)
- if accept:
- x_prev = x_low
- x = x_high + su * s_noise * noise_sampler(self.sigma(s), self.sigma(t))
- s = t
- info['n_accept'] += 1
- else:
- info['n_reject'] += 1
- info['nfe'] += order
- info['steps'] += 1
-
- if self.info_callback is not None:
- self.info_callback({'x': x, 'i': info['steps'] - 1, 't': s, 't_up': s, 'denoised': denoised, 'error': error, 'h': pid.h, **info})
-
- return x, info
-
-
-@torch.no_grad()
-def sample_dpm_fast(model, x, sigma_min, sigma_max, n, extra_args=None, callback=None, disable=None, eta=0., s_noise=1., noise_sampler=None):
- """DPM-Solver-Fast (fixed step size). See https://arxiv.org/abs/2206.00927."""
- if sigma_min <= 0 or sigma_max <= 0:
- raise ValueError('sigma_min and sigma_max must not be 0')
- with tqdm(total=n, disable=disable) as pbar:
- dpm_solver = DPMSolver(model, extra_args, eps_callback=pbar.update)
- if callback is not None:
- dpm_solver.info_callback = lambda info: callback({'sigma': dpm_solver.sigma(info['t']), 'sigma_hat': dpm_solver.sigma(info['t_up']), **info})
- return dpm_solver.dpm_solver_fast(x, dpm_solver.t(torch.tensor(sigma_max)), dpm_solver.t(torch.tensor(sigma_min)), n, eta, s_noise, noise_sampler)
-
-
-@torch.no_grad()
-def sample_dpm_adaptive(model, x, sigma_min, sigma_max, extra_args=None, callback=None, disable=None, order=3, rtol=0.05, atol=0.0078, h_init=0.05, pcoeff=0., icoeff=1., dcoeff=0., accept_safety=0.81, eta=0., s_noise=1., noise_sampler=None, return_info=False):
- """DPM-Solver-12 and 23 (adaptive step size). See https://arxiv.org/abs/2206.00927."""
- if sigma_min <= 0 or sigma_max <= 0:
- raise ValueError('sigma_min and sigma_max must not be 0')
- with tqdm(disable=disable) as pbar:
- dpm_solver = DPMSolver(model, extra_args, eps_callback=pbar.update)
- if callback is not None:
- dpm_solver.info_callback = lambda info: callback({'sigma': dpm_solver.sigma(info['t']), 'sigma_hat': dpm_solver.sigma(info['t_up']), **info})
- x, info = dpm_solver.dpm_solver_adaptive(x, dpm_solver.t(torch.tensor(sigma_max)), dpm_solver.t(torch.tensor(sigma_min)), order, rtol, atol, h_init, pcoeff, icoeff, dcoeff, accept_safety, eta, s_noise, noise_sampler)
- if return_info:
- return x, info
- return x
-
-
-@torch.no_grad()
-def sample_dpmpp_2s_ancestral(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
- if isinstance(model.inner_model.inner_model.model_sampling, comfy.model_sampling.CONST):
- return sample_dpmpp_2s_ancestral_RF(model, x, sigmas, extra_args, callback, disable, eta, s_noise, noise_sampler)
-
- """Ancestral sampling with DPM-Solver++(2S) second-order steps."""
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
- sigma_fn = lambda t: t.neg().exp()
- t_fn = lambda sigma: sigma.log().neg()
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- sigma_down, sigma_up = get_ancestral_step(sigmas[i], sigmas[i + 1], eta=eta)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- if sigma_down == 0:
- # Euler method
- d = to_d(x, sigmas[i], denoised)
- dt = sigma_down - sigmas[i]
- x = x + d * dt
- else:
- # DPM-Solver++(2S)
- t, t_next = t_fn(sigmas[i]), t_fn(sigma_down)
- r = 1 / 2
- h = t_next - t
- s = t + r * h
- x_2 = (sigma_fn(s) / sigma_fn(t)) * x - (-h * r).expm1() * denoised
- denoised_2 = model(x_2, sigma_fn(s) * s_in, **extra_args)
- x = (sigma_fn(t_next) / sigma_fn(t)) * x - (-h).expm1() * denoised_2
- # Noise addition
- if sigmas[i + 1] > 0:
- x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up
- return x
-
-
-@torch.no_grad()
-def sample_dpmpp_2s_ancestral_RF(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
- """Ancestral sampling with DPM-Solver++(2S) second-order steps."""
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
- sigma_fn = lambda lbda: (lbda.exp() + 1) ** -1
- lambda_fn = lambda sigma: ((1-sigma)/sigma).log()
-
- # logged_x = x.unsqueeze(0)
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- downstep_ratio = 1 + (sigmas[i+1]/sigmas[i] - 1) * eta
- sigma_down = sigmas[i+1] * downstep_ratio
- alpha_ip1 = 1 - sigmas[i+1]
- alpha_down = 1 - sigma_down
- renoise_coeff = (sigmas[i+1]**2 - sigma_down**2*alpha_ip1**2/alpha_down**2)**0.5
- # sigma_down, sigma_up = get_ancestral_step(sigmas[i], sigmas[i + 1], eta=eta)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- if sigmas[i + 1] == 0:
- # Euler method
- d = to_d(x, sigmas[i], denoised)
- dt = sigma_down - sigmas[i]
- x = x + d * dt
- else:
- # DPM-Solver++(2S)
- if sigmas[i] == 1.0:
- sigma_s = 0.9999
- else:
- t_i, t_down = lambda_fn(sigmas[i]), lambda_fn(sigma_down)
- r = 1 / 2
- h = t_down - t_i
- s = t_i + r * h
- sigma_s = sigma_fn(s)
- # sigma_s = sigmas[i+1]
- sigma_s_i_ratio = sigma_s / sigmas[i]
- u = sigma_s_i_ratio * x + (1 - sigma_s_i_ratio) * denoised
- D_i = model(u, sigma_s * s_in, **extra_args)
- sigma_down_i_ratio = sigma_down / sigmas[i]
- x = sigma_down_i_ratio * x + (1 - sigma_down_i_ratio) * D_i
- # print("sigma_i", sigmas[i], "sigma_ip1", sigmas[i+1],"sigma_down", sigma_down, "sigma_down_i_ratio", sigma_down_i_ratio, "sigma_s_i_ratio", sigma_s_i_ratio, "renoise_coeff", renoise_coeff)
- # Noise addition
- if sigmas[i + 1] > 0 and eta > 0:
- x = (alpha_ip1/alpha_down) * x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * renoise_coeff
- # logged_x = torch.cat((logged_x, x.unsqueeze(0)), dim=0)
- return x
-
-
-@torch.no_grad()
-def sample_dpmpp_sde(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None, r=1 / 2):
- """DPM-Solver++ (stochastic)."""
- if len(sigmas) <= 1:
- return x
-
- extra_args = {} if extra_args is None else extra_args
- sigma_min, sigma_max = sigmas[sigmas > 0].min(), sigmas.max()
- seed = extra_args.get("seed", None)
- noise_sampler = BrownianTreeNoiseSampler(x, sigma_min, sigma_max, seed=seed, cpu=True) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
-
- model_sampling = model.inner_model.model_patcher.get_model_object('model_sampling')
- sigma_fn = partial(half_log_snr_to_sigma, model_sampling=model_sampling)
- lambda_fn = partial(sigma_to_half_log_snr, model_sampling=model_sampling)
- sigmas = offset_first_sigma_for_snr(sigmas, model_sampling)
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- if sigmas[i + 1] == 0:
- # Denoising step
- x = denoised
- else:
- # DPM-Solver++
- lambda_s, lambda_t = lambda_fn(sigmas[i]), lambda_fn(sigmas[i + 1])
- h = lambda_t - lambda_s
- lambda_s_1 = lambda_s + r * h
- fac = 1 / (2 * r)
-
- sigma_s_1 = sigma_fn(lambda_s_1)
-
- alpha_s = sigmas[i] * lambda_s.exp()
- alpha_s_1 = sigma_s_1 * lambda_s_1.exp()
- alpha_t = sigmas[i + 1] * lambda_t.exp()
-
- # Step 1
- sd, su = get_ancestral_step(lambda_s.neg().exp(), lambda_s_1.neg().exp(), eta)
- lambda_s_1_ = sd.log().neg()
- h_ = lambda_s_1_ - lambda_s
- x_2 = (alpha_s_1 / alpha_s) * (-h_).exp() * x - alpha_s_1 * (-h_).expm1() * denoised
- if eta > 0 and s_noise > 0:
- x_2 = x_2 + alpha_s_1 * noise_sampler(sigmas[i], sigma_s_1) * s_noise * su
- denoised_2 = model(x_2, sigma_s_1 * s_in, **extra_args)
-
- # Step 2
- sd, su = get_ancestral_step(lambda_s.neg().exp(), lambda_t.neg().exp(), eta)
- lambda_t_ = sd.log().neg()
- h_ = lambda_t_ - lambda_s
- denoised_d = (1 - fac) * denoised + fac * denoised_2
- x = (alpha_t / alpha_s) * (-h_).exp() * x - alpha_t * (-h_).expm1() * denoised_d
- if eta > 0 and s_noise > 0:
- x = x + alpha_t * noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * su
- return x
-
-
-@torch.no_grad()
-def sample_dpmpp_2m(model, x, sigmas, extra_args=None, callback=None, disable=None):
- """DPM-Solver++(2M)."""
- extra_args = {} if extra_args is None else extra_args
- s_in = x.new_ones([x.shape[0]])
- sigma_fn = lambda t: t.neg().exp()
- t_fn = lambda sigma: sigma.log().neg()
- old_denoised = None
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- t, t_next = t_fn(sigmas[i]), t_fn(sigmas[i + 1])
- h = t_next - t
- if old_denoised is None or sigmas[i + 1] == 0:
- x = (sigma_fn(t_next) / sigma_fn(t)) * x - (-h).expm1() * denoised
- else:
- h_last = t - t_fn(sigmas[i - 1])
- r = h_last / h
- denoised_d = (1 + 1 / (2 * r)) * denoised - (1 / (2 * r)) * old_denoised
- x = (sigma_fn(t_next) / sigma_fn(t)) * x - (-h).expm1() * denoised_d
- old_denoised = denoised
- return x
-
-
-@torch.no_grad()
-def sample_dpmpp_2m_sde(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None, solver_type='midpoint'):
- """DPM-Solver++(2M) SDE."""
- if len(sigmas) <= 1:
- return x
-
- if solver_type not in {'heun', 'midpoint'}:
- raise ValueError('solver_type must be \'heun\' or \'midpoint\'')
-
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- sigma_min, sigma_max = sigmas[sigmas > 0].min(), sigmas.max()
- noise_sampler = BrownianTreeNoiseSampler(x, sigma_min, sigma_max, seed=seed, cpu=True) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
-
- model_sampling = model.inner_model.model_patcher.get_model_object('model_sampling')
- lambda_fn = partial(sigma_to_half_log_snr, model_sampling=model_sampling)
- sigmas = offset_first_sigma_for_snr(sigmas, model_sampling)
-
- old_denoised = None
- h, h_last = None, None
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- if sigmas[i + 1] == 0:
- # Denoising step
- x = denoised
- else:
- # DPM-Solver++(2M) SDE
- lambda_s, lambda_t = lambda_fn(sigmas[i]), lambda_fn(sigmas[i + 1])
- h = lambda_t - lambda_s
- h_eta = h * (eta + 1)
-
- alpha_t = sigmas[i + 1] * lambda_t.exp()
-
- x = sigmas[i + 1] / sigmas[i] * (-h * eta).exp() * x + alpha_t * (-h_eta).expm1().neg() * denoised
-
- if old_denoised is not None:
- r = h_last / h
- if solver_type == 'heun':
- x = x + alpha_t * ((-h_eta).expm1().neg() / (-h_eta) + 1) * (1 / r) * (denoised - old_denoised)
- elif solver_type == 'midpoint':
- x = x + 0.5 * alpha_t * (-h_eta).expm1().neg() * (1 / r) * (denoised - old_denoised)
-
- if eta > 0 and s_noise > 0:
- x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * sigmas[i + 1] * (-2 * h * eta).expm1().neg().sqrt() * s_noise
-
- old_denoised = denoised
- h_last = h
- return x
-
-
-@torch.no_grad()
-def sample_dpmpp_2m_sde_heun(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None, solver_type='heun'):
- return sample_dpmpp_2m_sde(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, eta=eta, s_noise=s_noise, noise_sampler=noise_sampler, solver_type=solver_type)
-
-
-@torch.no_grad()
-def sample_dpmpp_3m_sde(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
- """DPM-Solver++(3M) SDE."""
-
- if len(sigmas) <= 1:
- return x
-
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- sigma_min, sigma_max = sigmas[sigmas > 0].min(), sigmas.max()
- noise_sampler = BrownianTreeNoiseSampler(x, sigma_min, sigma_max, seed=seed, cpu=True) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
-
- model_sampling = model.inner_model.model_patcher.get_model_object('model_sampling')
- lambda_fn = partial(sigma_to_half_log_snr, model_sampling=model_sampling)
- sigmas = offset_first_sigma_for_snr(sigmas, model_sampling)
-
- denoised_1, denoised_2 = None, None
- h, h_1, h_2 = None, None, None
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- if sigmas[i + 1] == 0:
- # Denoising step
- x = denoised
- else:
- lambda_s, lambda_t = lambda_fn(sigmas[i]), lambda_fn(sigmas[i + 1])
- h = lambda_t - lambda_s
- h_eta = h * (eta + 1)
-
- alpha_t = sigmas[i + 1] * lambda_t.exp()
-
- x = sigmas[i + 1] / sigmas[i] * (-h * eta).exp() * x + alpha_t * (-h_eta).expm1().neg() * denoised
-
- if h_2 is not None:
- # DPM-Solver++(3M) SDE
- r0 = h_1 / h
- r1 = h_2 / h
- d1_0 = (denoised - denoised_1) / r0
- d1_1 = (denoised_1 - denoised_2) / r1
- d1 = d1_0 + (d1_0 - d1_1) * r0 / (r0 + r1)
- d2 = (d1_0 - d1_1) / (r0 + r1)
- phi_2 = h_eta.neg().expm1() / h_eta + 1
- phi_3 = phi_2 / h_eta - 0.5
- x = x + (alpha_t * phi_2) * d1 - (alpha_t * phi_3) * d2
- elif h_1 is not None:
- # DPM-Solver++(2M) SDE
- r = h_1 / h
- d = (denoised - denoised_1) / r
- phi_2 = h_eta.neg().expm1() / h_eta + 1
- x = x + (alpha_t * phi_2) * d
-
- if eta > 0 and s_noise > 0:
- x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * sigmas[i + 1] * (-2 * h * eta).expm1().neg().sqrt() * s_noise
-
- denoised_1, denoised_2 = denoised, denoised_1
- h_1, h_2 = h, h_1
- return x
-
-
-@torch.no_grad()
-def sample_dpmpp_3m_sde_gpu(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
- if len(sigmas) <= 1:
- return x
- extra_args = {} if extra_args is None else extra_args
- sigma_min, sigma_max = sigmas[sigmas > 0].min(), sigmas.max()
- noise_sampler = BrownianTreeNoiseSampler(x, sigma_min, sigma_max, seed=extra_args.get("seed", None), cpu=False) if noise_sampler is None else noise_sampler
- return sample_dpmpp_3m_sde(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, eta=eta, s_noise=s_noise, noise_sampler=noise_sampler)
-
-
-@torch.no_grad()
-def sample_dpmpp_2m_sde_heun_gpu(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None, solver_type='heun'):
- if len(sigmas) <= 1:
- return x
- extra_args = {} if extra_args is None else extra_args
- sigma_min, sigma_max = sigmas[sigmas > 0].min(), sigmas.max()
- noise_sampler = BrownianTreeNoiseSampler(x, sigma_min, sigma_max, seed=extra_args.get("seed", None), cpu=False) if noise_sampler is None else noise_sampler
- return sample_dpmpp_2m_sde_heun(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, eta=eta, s_noise=s_noise, noise_sampler=noise_sampler, solver_type=solver_type)
-
-
-@torch.no_grad()
-def sample_dpmpp_2m_sde_gpu(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None, solver_type='midpoint'):
- if len(sigmas) <= 1:
- return x
- extra_args = {} if extra_args is None else extra_args
- sigma_min, sigma_max = sigmas[sigmas > 0].min(), sigmas.max()
- noise_sampler = BrownianTreeNoiseSampler(x, sigma_min, sigma_max, seed=extra_args.get("seed", None), cpu=False) if noise_sampler is None else noise_sampler
- return sample_dpmpp_2m_sde(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, eta=eta, s_noise=s_noise, noise_sampler=noise_sampler, solver_type=solver_type)
-
-
-@torch.no_grad()
-def sample_dpmpp_sde_gpu(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None, r=1 / 2):
- if len(sigmas) <= 1:
- return x
- extra_args = {} if extra_args is None else extra_args
- sigma_min, sigma_max = sigmas[sigmas > 0].min(), sigmas.max()
- noise_sampler = BrownianTreeNoiseSampler(x, sigma_min, sigma_max, seed=extra_args.get("seed", None), cpu=False) if noise_sampler is None else noise_sampler
- return sample_dpmpp_sde(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, eta=eta, s_noise=s_noise, noise_sampler=noise_sampler, r=r)
-
-
-def DDPMSampler_step(x, sigma, sigma_prev, noise, noise_sampler):
- alpha_cumprod = 1 / ((sigma * sigma) + 1)
- alpha_cumprod_prev = 1 / ((sigma_prev * sigma_prev) + 1)
- alpha = (alpha_cumprod / alpha_cumprod_prev)
-
- mu = (1.0 / alpha).sqrt() * (x - (1 - alpha) * noise / (1 - alpha_cumprod).sqrt())
- if sigma_prev > 0:
- mu += ((1 - alpha) * (1. - alpha_cumprod_prev) / (1. - alpha_cumprod)).sqrt() * noise_sampler(sigma, sigma_prev)
- return mu
-
-def generic_step_sampler(model, x, sigmas, extra_args=None, callback=None, disable=None, noise_sampler=None, step_function=None):
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- x = step_function(x / torch.sqrt(1.0 + sigmas[i] ** 2.0), sigmas[i], sigmas[i + 1], (x - denoised) / sigmas[i], noise_sampler)
- if sigmas[i + 1] != 0:
- x *= torch.sqrt(1.0 + sigmas[i + 1] ** 2.0)
- return x
-
-
-@torch.no_grad()
-def sample_ddpm(model, x, sigmas, extra_args=None, callback=None, disable=None, noise_sampler=None):
- return generic_step_sampler(model, x, sigmas, extra_args, callback, disable, noise_sampler, DDPMSampler_step)
-
-
-from ..utils import add_noise_at_step
-
-@torch.no_grad()
-def sample_lcm(model, x, sigmas, extra_args=None, callback=None, disable=None, noise_sampler=None):
- extra_args = {} if extra_args is None else extra_args
-
- ttm_reference_latents = extra_args.get("ttm_reference_latents")
- ttm_start_step = extra_args.get("ttm_start_step")
- ttm_end_step = extra_args.get("ttm_end_step")
- latent_image = extra_args.get("latent_image")
- motion_mask = extra_args.get("motion_mask")
-
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
- for (i, (idx, _)) in zip(trange(len(sigmas) - 1, disable=disable), enumerate(sigmas[ttm_start_step:])):
-
- if ttm_reference_latents is not None and (idx + ttm_start_step) < ttm_end_step:
- if idx + ttm_start_step + 1 < len(sigmas):
- noise = x.to(ttm_reference_latents.device)
- sigma = sigmas[idx + ttm_start_step + 1].to(ttm_reference_latents.device)
- noisy_latents = add_noise_at_step(ttm_reference_latents,
- noise,
- sigma
- ).to(latent_image.device, latent_image.dtype)
- noise = latent_image * (1 - motion_mask) + noisy_latents * motion_mask
- else: # If you are at last step
- noise = latent_image * (1 - motion_mask) + ttm_reference_latents * motion_mask
- x = noise.to(s_in.device)
-
- denoised = model(x, sigmas[i] * s_in, **extra_args)
-
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
-
- x = denoised
- if sigmas[i + 1] > 0:
- x = model.inner_model.inner_model.model_sampling.noise_scaling(sigmas[i + 1], noise_sampler(sigmas[i], sigmas[i + 1]), x)
- return x
-
-
-
-@torch.no_grad()
-def sample_heunpp2(model, x, sigmas, extra_args=None, callback=None, disable=None, s_churn=0., s_tmin=0., s_tmax=float('inf'), s_noise=1.):
- # From MIT licensed: https://github.com/Carzit/sd-webui-samplers-scheduler/
- extra_args = {} if extra_args is None else extra_args
- s_in = x.new_ones([x.shape[0]])
- s_end = sigmas[-1]
- for i in trange(len(sigmas) - 1, disable=disable):
- gamma = min(s_churn / (len(sigmas) - 1), 2 ** 0.5 - 1) if s_tmin <= sigmas[i] <= s_tmax else 0.
- eps = torch.randn_like(x) * s_noise
- sigma_hat = sigmas[i] * (gamma + 1)
- if gamma > 0:
- x = x + eps * (sigma_hat ** 2 - sigmas[i] ** 2) ** 0.5
- denoised = model(x, sigma_hat * s_in, **extra_args)
- d = to_d(x, sigma_hat, denoised)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigma_hat, 'denoised': denoised})
- dt = sigmas[i + 1] - sigma_hat
- if sigmas[i + 1] == s_end:
- # Euler method
- x = x + d * dt
- elif sigmas[i + 2] == s_end:
-
- # Heun's method
- x_2 = x + d * dt
- denoised_2 = model(x_2, sigmas[i + 1] * s_in, **extra_args)
- d_2 = to_d(x_2, sigmas[i + 1], denoised_2)
-
- w = 2 * sigmas[0]
- w2 = sigmas[i+1]/w
- w1 = 1 - w2
-
- d_prime = d * w1 + d_2 * w2
-
-
- x = x + d_prime * dt
-
- else:
- # Heun++
- x_2 = x + d * dt
- denoised_2 = model(x_2, sigmas[i + 1] * s_in, **extra_args)
- d_2 = to_d(x_2, sigmas[i + 1], denoised_2)
- dt_2 = sigmas[i + 2] - sigmas[i + 1]
-
- x_3 = x_2 + d_2 * dt_2
- denoised_3 = model(x_3, sigmas[i + 2] * s_in, **extra_args)
- d_3 = to_d(x_3, sigmas[i + 2], denoised_3)
-
- w = 3 * sigmas[0]
- w2 = sigmas[i + 1] / w
- w3 = sigmas[i + 2] / w
- w1 = 1 - w2 - w3
-
- d_prime = w1 * d + w2 * d_2 + w3 * d_3
- x = x + d_prime * dt
- return x
-
-
-#From https://github.com/zju-pi/diff-sampler/blob/main/diff-solvers-main/solvers.py
-#under Apache 2 license
-def sample_ipndm(model, x, sigmas, extra_args=None, callback=None, disable=None, max_order=4):
- extra_args = {} if extra_args is None else extra_args
- s_in = x.new_ones([x.shape[0]])
-
- x_next = x
-
- buffer_model = []
- for i in trange(len(sigmas) - 1, disable=disable):
- t_cur = sigmas[i]
- t_next = sigmas[i + 1]
-
- x_cur = x_next
-
- denoised = model(x_cur, t_cur * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
-
- d_cur = (x_cur - denoised) / t_cur
-
- order = min(max_order, i+1)
- if t_next == 0: # Denoising step
- x_next = denoised
- elif order == 1: # First Euler step.
- x_next = x_cur + (t_next - t_cur) * d_cur
- elif order == 2: # Use one history point.
- x_next = x_cur + (t_next - t_cur) * (3 * d_cur - buffer_model[-1]) / 2
- elif order == 3: # Use two history points.
- x_next = x_cur + (t_next - t_cur) * (23 * d_cur - 16 * buffer_model[-1] + 5 * buffer_model[-2]) / 12
- elif order == 4: # Use three history points.
- x_next = x_cur + (t_next - t_cur) * (55 * d_cur - 59 * buffer_model[-1] + 37 * buffer_model[-2] - 9 * buffer_model[-3]) / 24
-
- if len(buffer_model) == max_order - 1:
- for k in range(max_order - 2):
- buffer_model[k] = buffer_model[k+1]
- buffer_model[-1] = d_cur
- else:
- buffer_model.append(d_cur)
-
- return x_next
-
-
-#From https://github.com/zju-pi/diff-sampler/blob/main/diff-solvers-main/solvers.py
-#under Apache 2 license
-def sample_ipndm_v(model, x, sigmas, extra_args=None, callback=None, disable=None, max_order=4):
- extra_args = {} if extra_args is None else extra_args
- s_in = x.new_ones([x.shape[0]])
-
- x_next = x
- t_steps = sigmas
-
- buffer_model = []
- for i in trange(len(sigmas) - 1, disable=disable):
- t_cur = sigmas[i]
- t_next = sigmas[i + 1]
-
- x_cur = x_next
-
- denoised = model(x_cur, t_cur * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
-
- d_cur = (x_cur - denoised) / t_cur
-
- order = min(max_order, i+1)
- if t_next == 0: # Denoising step
- x_next = denoised
- elif order == 1: # First Euler step.
- x_next = x_cur + (t_next - t_cur) * d_cur
- elif order == 2: # Use one history point.
- h_n = (t_next - t_cur)
- h_n_1 = (t_cur - t_steps[i-1])
- coeff1 = (2 + (h_n / h_n_1)) / 2
- coeff2 = -(h_n / h_n_1) / 2
- x_next = x_cur + (t_next - t_cur) * (coeff1 * d_cur + coeff2 * buffer_model[-1])
- elif order == 3: # Use two history points.
- h_n = (t_next - t_cur)
- h_n_1 = (t_cur - t_steps[i-1])
- h_n_2 = (t_steps[i-1] - t_steps[i-2])
- temp = (1 - h_n / (3 * (h_n + h_n_1)) * (h_n * (h_n + h_n_1)) / (h_n_1 * (h_n_1 + h_n_2))) / 2
- coeff1 = (2 + (h_n / h_n_1)) / 2 + temp
- coeff2 = -(h_n / h_n_1) / 2 - (1 + h_n_1 / h_n_2) * temp
- coeff3 = temp * h_n_1 / h_n_2
- x_next = x_cur + (t_next - t_cur) * (coeff1 * d_cur + coeff2 * buffer_model[-1] + coeff3 * buffer_model[-2])
- elif order == 4: # Use three history points.
- h_n = (t_next - t_cur)
- h_n_1 = (t_cur - t_steps[i-1])
- h_n_2 = (t_steps[i-1] - t_steps[i-2])
- h_n_3 = (t_steps[i-2] - t_steps[i-3])
- temp1 = (1 - h_n / (3 * (h_n + h_n_1)) * (h_n * (h_n + h_n_1)) / (h_n_1 * (h_n_1 + h_n_2))) / 2
- temp2 = ((1 - h_n / (3 * (h_n + h_n_1))) / 2 + (1 - h_n / (2 * (h_n + h_n_1))) * h_n / (6 * (h_n + h_n_1 + h_n_2))) \
- * (h_n * (h_n + h_n_1) * (h_n + h_n_1 + h_n_2)) / (h_n_1 * (h_n_1 + h_n_2) * (h_n_1 + h_n_2 + h_n_3))
- coeff1 = (2 + (h_n / h_n_1)) / 2 + temp1 + temp2
- coeff2 = -(h_n / h_n_1) / 2 - (1 + h_n_1 / h_n_2) * temp1 - (1 + (h_n_1 / h_n_2) + (h_n_1 * (h_n_1 + h_n_2) / (h_n_2 * (h_n_2 + h_n_3)))) * temp2
- coeff3 = temp1 * h_n_1 / h_n_2 + ((h_n_1 / h_n_2) + (h_n_1 * (h_n_1 + h_n_2) / (h_n_2 * (h_n_2 + h_n_3))) * (1 + h_n_2 / h_n_3)) * temp2
- coeff4 = -temp2 * (h_n_1 * (h_n_1 + h_n_2) / (h_n_2 * (h_n_2 + h_n_3))) * h_n_1 / h_n_2
- x_next = x_cur + (t_next - t_cur) * (coeff1 * d_cur + coeff2 * buffer_model[-1] + coeff3 * buffer_model[-2] + coeff4 * buffer_model[-3])
-
- if len(buffer_model) == max_order - 1:
- for k in range(max_order - 2):
- buffer_model[k] = buffer_model[k+1]
- buffer_model[-1] = d_cur.detach()
- else:
- buffer_model.append(d_cur.detach())
-
- return x_next
-
-
-#From https://github.com/zju-pi/diff-sampler/blob/main/diff-solvers-main/solvers.py
-#under Apache 2 license
-@torch.no_grad()
-def sample_deis(model, x, sigmas, extra_args=None, callback=None, disable=None, max_order=3, deis_mode='tab'):
- extra_args = {} if extra_args is None else extra_args
- s_in = x.new_ones([x.shape[0]])
-
- x_next = x
- t_steps = sigmas
-
- coeff_list = deis.get_deis_coeff_list(t_steps, max_order, deis_mode=deis_mode)
-
- buffer_model = []
- for i in trange(len(sigmas) - 1, disable=disable):
- t_cur = sigmas[i]
- t_next = sigmas[i + 1]
-
- x_cur = x_next
-
- denoised = model(x_cur, t_cur * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
-
- d_cur = (x_cur - denoised) / t_cur
-
- order = min(max_order, i+1)
- if t_next <= 0:
- order = 1
-
- if order == 1: # First Euler step.
- x_next = x_cur + (t_next - t_cur) * d_cur
- elif order == 2: # Use one history point.
- coeff_cur, coeff_prev1 = coeff_list[i]
- x_next = x_cur + coeff_cur * d_cur + coeff_prev1 * buffer_model[-1]
- elif order == 3: # Use two history points.
- coeff_cur, coeff_prev1, coeff_prev2 = coeff_list[i]
- x_next = x_cur + coeff_cur * d_cur + coeff_prev1 * buffer_model[-1] + coeff_prev2 * buffer_model[-2]
- elif order == 4: # Use three history points.
- coeff_cur, coeff_prev1, coeff_prev2, coeff_prev3 = coeff_list[i]
- x_next = x_cur + coeff_cur * d_cur + coeff_prev1 * buffer_model[-1] + coeff_prev2 * buffer_model[-2] + coeff_prev3 * buffer_model[-3]
-
- if len(buffer_model) == max_order - 1:
- for k in range(max_order - 2):
- buffer_model[k] = buffer_model[k+1]
- buffer_model[-1] = d_cur.detach()
- else:
- buffer_model.append(d_cur.detach())
-
- return x_next
-
-
-@torch.no_grad()
-def sample_euler_ancestral_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
- """Ancestral sampling with Euler method steps (CFG++)."""
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
-
- model_sampling = model.inner_model.model_patcher.get_model_object("model_sampling")
- lambda_fn = partial(sigma_to_half_log_snr, model_sampling=model_sampling)
-
- uncond_denoised = None
-
- def post_cfg_function(args):
- nonlocal uncond_denoised
- uncond_denoised = args["uncond_denoised"]
- return args["denoised"]
-
- model_options = extra_args.get("model_options", {}).copy()
- extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function(model_options, post_cfg_function, disable_cfg1_optimization=True)
-
- s_in = x.new_ones([x.shape[0]])
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- if sigmas[i + 1] == 0:
- # Denoising step
- x = denoised
- else:
- alpha_s = sigmas[i] * lambda_fn(sigmas[i]).exp()
- alpha_t = sigmas[i + 1] * lambda_fn(sigmas[i + 1]).exp()
- d = to_d(x, sigmas[i], alpha_s * uncond_denoised) # to noise
-
- # DDIM stochastic sampling
- sigma_down, sigma_up = get_ancestral_step(sigmas[i] / alpha_s, sigmas[i + 1] / alpha_t, eta=eta)
- sigma_down = alpha_t * sigma_down
-
- # Euler method
- x = alpha_t * denoised + sigma_down * d
- if eta > 0 and s_noise > 0:
- x = x + alpha_t * noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up
- return x
-
-
-@torch.no_grad()
-def sample_euler_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None):
- """Euler method steps (CFG++)."""
- return sample_euler_ancestral_cfg_pp(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, eta=0.0, s_noise=0.0, noise_sampler=None)
-
-
-@torch.no_grad()
-def sample_dpmpp_2s_ancestral_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
- """Ancestral sampling with DPM-Solver++(2S) second-order steps."""
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
-
- temp = [0]
- def post_cfg_function(args):
- temp[0] = args["uncond_denoised"]
- return args["denoised"]
-
- model_options = extra_args.get("model_options", {}).copy()
- extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function(model_options, post_cfg_function, disable_cfg1_optimization=True)
-
- s_in = x.new_ones([x.shape[0]])
- sigma_fn = lambda t: t.neg().exp()
- t_fn = lambda sigma: sigma.log().neg()
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- sigma_down, sigma_up = get_ancestral_step(sigmas[i], sigmas[i + 1], eta=eta)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- if sigma_down == 0:
- # Euler method
- d = to_d(x, sigmas[i], temp[0])
- x = denoised + d * sigma_down
- else:
- # DPM-Solver++(2S)
- t, t_next = t_fn(sigmas[i]), t_fn(sigma_down)
- # r = torch.sinh(1 + (2 - eta) * (t_next - t) / (t - t_fn(sigma_up))) works only on non-cfgpp, weird
- r = 1 / 2
- h = t_next - t
- s = t + r * h
- x_2 = (sigma_fn(s) / sigma_fn(t)) * (x + (denoised - temp[0])) - (-h * r).expm1() * denoised
- denoised_2 = model(x_2, sigma_fn(s) * s_in, **extra_args)
- x = (sigma_fn(t_next) / sigma_fn(t)) * (x + (denoised - temp[0])) - (-h).expm1() * denoised_2
- # Noise addition
- if sigmas[i + 1] > 0:
- x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up
- return x
-
-@torch.no_grad()
-def sample_dpmpp_2m_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None):
- """DPM-Solver++(2M)."""
- extra_args = {} if extra_args is None else extra_args
- s_in = x.new_ones([x.shape[0]])
- t_fn = lambda sigma: sigma.log().neg()
-
- old_uncond_denoised = None
- uncond_denoised = None
- def post_cfg_function(args):
- nonlocal uncond_denoised
- uncond_denoised = args["uncond_denoised"]
- return args["denoised"]
-
- model_options = extra_args.get("model_options", {}).copy()
- extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function(model_options, post_cfg_function, disable_cfg1_optimization=True)
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- t, t_next = t_fn(sigmas[i]), t_fn(sigmas[i + 1])
- h = t_next - t
- if old_uncond_denoised is None or sigmas[i + 1] == 0:
- denoised_mix = -torch.exp(-h) * uncond_denoised
- else:
- h_last = t - t_fn(sigmas[i - 1])
- r = h_last / h
- denoised_mix = -torch.exp(-h) * uncond_denoised - torch.expm1(-h) * (1 / (2 * r)) * (denoised - old_uncond_denoised)
- x = denoised + denoised_mix + torch.exp(-h) * x
- old_uncond_denoised = uncond_denoised
- return x
-
-@torch.no_grad()
-def res_multistep(model, x, sigmas, extra_args=None, callback=None, disable=None, s_noise=1., noise_sampler=None, eta=1., cfg_pp=False):
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
- sigma_fn = lambda t: t.neg().exp()
- t_fn = lambda sigma: sigma.log().neg()
- phi1_fn = lambda t: torch.expm1(t) / t
- phi2_fn = lambda t: (phi1_fn(t) - 1.0) / t
-
- old_sigma_down = None
- old_denoised = None
- uncond_denoised = None
- def post_cfg_function(args):
- nonlocal uncond_denoised
- uncond_denoised = args["uncond_denoised"]
- return args["denoised"]
-
- if cfg_pp:
- model_options = extra_args.get("model_options", {}).copy()
- extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function(model_options, post_cfg_function, disable_cfg1_optimization=True)
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- sigma_down, sigma_up = get_ancestral_step(sigmas[i], sigmas[i + 1], eta=eta)
- if callback is not None:
- callback({"x": x, "i": i, "sigma": sigmas[i], "sigma_hat": sigmas[i], "denoised": denoised})
- if sigma_down == 0 or old_denoised is None:
- # Euler method
- if cfg_pp:
- d = to_d(x, sigmas[i], uncond_denoised)
- x = denoised + d * sigma_down
- else:
- d = to_d(x, sigmas[i], denoised)
- dt = sigma_down - sigmas[i]
- x = x + d * dt
- else:
- # Second order multistep method in https://arxiv.org/pdf/2308.02157
- t, t_old, t_next, t_prev = t_fn(sigmas[i]), t_fn(old_sigma_down), t_fn(sigma_down), t_fn(sigmas[i - 1])
- h = t_next - t
- c2 = (t_prev - t_old) / h
-
- phi1_val, phi2_val = phi1_fn(-h), phi2_fn(-h)
- b1 = torch.nan_to_num(phi1_val - phi2_val / c2, nan=0.0)
- b2 = torch.nan_to_num(phi2_val / c2, nan=0.0)
-
- if cfg_pp:
- x = x + (denoised - uncond_denoised)
- x = sigma_fn(h) * x + h * (b1 * uncond_denoised + b2 * old_denoised)
- else:
- x = sigma_fn(h) * x + h * (b1 * denoised + b2 * old_denoised)
-
- # Noise addition
- if sigmas[i + 1] > 0:
- x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up
-
- if cfg_pp:
- old_denoised = uncond_denoised
- else:
- old_denoised = denoised
- old_sigma_down = sigma_down
- return x
-
-@torch.no_grad()
-def sample_res_multistep(model, x, sigmas, extra_args=None, callback=None, disable=None, s_noise=1., noise_sampler=None):
- return res_multistep(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, s_noise=s_noise, noise_sampler=noise_sampler, eta=0., cfg_pp=False)
-
-@torch.no_grad()
-def sample_res_multistep_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None, s_noise=1., noise_sampler=None):
- return res_multistep(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, s_noise=s_noise, noise_sampler=noise_sampler, eta=0., cfg_pp=True)
-
-@torch.no_grad()
-def sample_res_multistep_ancestral(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
- return res_multistep(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, s_noise=s_noise, noise_sampler=noise_sampler, eta=eta, cfg_pp=False)
-
-@torch.no_grad()
-def sample_res_multistep_ancestral_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None):
- return res_multistep(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, s_noise=s_noise, noise_sampler=noise_sampler, eta=eta, cfg_pp=True)
-
-
-@torch.no_grad()
-def sample_gradient_estimation(model, x, sigmas, extra_args=None, callback=None, disable=None, ge_gamma=2., cfg_pp=False):
- """Gradient-estimation sampler. Paper: https://openreview.net/pdf?id=o2ND9v0CeK"""
- extra_args = {} if extra_args is None else extra_args
- s_in = x.new_ones([x.shape[0]])
- old_d = None
-
- uncond_denoised = None
- def post_cfg_function(args):
- nonlocal uncond_denoised
- uncond_denoised = args["uncond_denoised"]
- return args["denoised"]
-
- if cfg_pp:
- model_options = extra_args.get("model_options", {}).copy()
- extra_args["model_options"] = comfy.model_patcher.set_model_options_post_cfg_function(model_options, post_cfg_function, disable_cfg1_optimization=True)
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- if cfg_pp:
- d = to_d(x, sigmas[i], uncond_denoised)
- else:
- d = to_d(x, sigmas[i], denoised)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- dt = sigmas[i + 1] - sigmas[i]
- if sigmas[i + 1] == 0:
- # Denoising step
- x = denoised
- else:
- # Euler method
- if cfg_pp:
- x = denoised + d * sigmas[i + 1]
- else:
- x = x + d * dt
-
- if i >= 1:
- # Gradient estimation
- d_bar = (ge_gamma - 1) * (d - old_d)
- x = x + d_bar * dt
- old_d = d
- return x
-
-
-@torch.no_grad()
-def sample_gradient_estimation_cfg_pp(model, x, sigmas, extra_args=None, callback=None, disable=None, ge_gamma=2.):
- return sample_gradient_estimation(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, ge_gamma=ge_gamma, cfg_pp=True)
-
-
-@torch.no_grad()
-def sample_er_sde(model, x, sigmas, extra_args=None, callback=None, disable=None, s_noise=1.0, noise_sampler=None, noise_scaler=None, max_stage=3):
- """Extended Reverse-Time SDE solver (VP ER-SDE-Solver-3). arXiv: https://arxiv.org/abs/2309.06169.
- Code reference: https://github.com/QinpengCui/ER-SDE-Solver/blob/main/er_sde_solver.py.
- """
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
-
- def default_er_sde_noise_scaler(x):
- return x * ((x ** 0.3).exp() + 10.0)
-
- noise_scaler = default_er_sde_noise_scaler if noise_scaler is None else noise_scaler
- num_integration_points = 200.0
- point_indice = torch.arange(0, num_integration_points, dtype=torch.float32, device=x.device)
-
- model_sampling = model.inner_model.model_patcher.get_model_object("model_sampling")
- sigmas = offset_first_sigma_for_snr(sigmas, model_sampling)
- half_log_snrs = sigma_to_half_log_snr(sigmas, model_sampling)
- er_lambdas = half_log_snrs.neg().exp() # er_lambda_t = sigma_t / alpha_t
-
- old_denoised = None
- old_denoised_d = None
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
- stage_used = min(max_stage, i + 1)
- if sigmas[i + 1] == 0:
- x = denoised
- else:
- er_lambda_s, er_lambda_t = er_lambdas[i], er_lambdas[i + 1]
- alpha_s = sigmas[i] / er_lambda_s
- alpha_t = sigmas[i + 1] / er_lambda_t
- r_alpha = alpha_t / alpha_s
- r = noise_scaler(er_lambda_t) / noise_scaler(er_lambda_s)
-
- # Stage 1 Euler
- x = r_alpha * r * x + alpha_t * (1 - r) * denoised
-
- if stage_used >= 2:
- dt = er_lambda_t - er_lambda_s
- lambda_step_size = -dt / num_integration_points
- lambda_pos = er_lambda_t + point_indice * lambda_step_size
- scaled_pos = noise_scaler(lambda_pos)
-
- # Stage 2
- s = torch.sum(1 / scaled_pos) * lambda_step_size
- denoised_d = (denoised - old_denoised) / (er_lambda_s - er_lambdas[i - 1])
- x = x + alpha_t * (dt + s * noise_scaler(er_lambda_t)) * denoised_d
-
- if stage_used >= 3:
- # Stage 3
- s_u = torch.sum((lambda_pos - er_lambda_s) / scaled_pos) * lambda_step_size
- denoised_u = (denoised_d - old_denoised_d) / ((er_lambda_s - er_lambdas[i - 2]) / 2)
- x = x + alpha_t * ((dt ** 2) / 2 + s_u * noise_scaler(er_lambda_t)) * denoised_u
- old_denoised_d = denoised_d
-
- if s_noise > 0:
- x = x + alpha_t * noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * (er_lambda_t ** 2 - er_lambda_s ** 2 * r ** 2).sqrt().nan_to_num(nan=0.0)
- old_denoised = denoised
- return x
-
-
-@torch.no_grad()
-def sample_seeds_2(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None, r=0.5):
- """SEEDS-2 - Stochastic Explicit Exponential Derivative-free Solvers (VP Data Prediction) stage 2.
- arXiv: https://arxiv.org/abs/2305.14267 (NeurIPS 2023)
- """
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
- inject_noise = eta > 0 and s_noise > 0
-
- model_sampling = model.inner_model.model_patcher.get_model_object('model_sampling')
- sigma_fn = partial(half_log_snr_to_sigma, model_sampling=model_sampling)
- lambda_fn = partial(sigma_to_half_log_snr, model_sampling=model_sampling)
- sigmas = offset_first_sigma_for_snr(sigmas, model_sampling)
-
- fac = 1 / (2 * r)
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
-
- if sigmas[i + 1] == 0:
- x = denoised
- continue
-
- lambda_s, lambda_t = lambda_fn(sigmas[i]), lambda_fn(sigmas[i + 1])
- h = lambda_t - lambda_s
- h_eta = h * (eta + 1)
- lambda_s_1 = torch.lerp(lambda_s, lambda_t, r)
- sigma_s_1 = sigma_fn(lambda_s_1)
-
- alpha_s_1 = sigma_s_1 * lambda_s_1.exp()
- alpha_t = sigmas[i + 1] * lambda_t.exp()
-
- # Step 1
- x_2 = sigma_s_1 / sigmas[i] * (-r * h * eta).exp() * x - alpha_s_1 * ei_h_phi_1(-r * h_eta) * denoised
- if inject_noise:
- sde_noise = (-2 * r * h * eta).expm1().neg().sqrt() * noise_sampler(sigmas[i], sigma_s_1)
- x_2 = x_2 + sde_noise * sigma_s_1 * s_noise
- denoised_2 = model(x_2, sigma_s_1 * s_in, **extra_args)
-
- # Step 2
- denoised_d = torch.lerp(denoised, denoised_2, fac)
- x = sigmas[i + 1] / sigmas[i] * (-h * eta).exp() * x - alpha_t * ei_h_phi_1(-h_eta) * denoised_d
- if inject_noise:
- segment_factor = (r - 1) * h * eta
- sde_noise = sde_noise * segment_factor.exp()
- sde_noise = sde_noise + segment_factor.mul(2).expm1().neg().sqrt() * noise_sampler(sigma_s_1, sigmas[i + 1])
- x = x + sde_noise * sigmas[i + 1] * s_noise
- return x
-
-
-@torch.no_grad()
-def sample_seeds_3(model, x, sigmas, extra_args=None, callback=None, disable=None, eta=1., s_noise=1., noise_sampler=None, r_1=1./3, r_2=2./3):
- """SEEDS-3 - Stochastic Explicit Exponential Derivative-free Solvers (VP Data Prediction) stage 3.
- arXiv: https://arxiv.org/abs/2305.14267 (NeurIPS 2023)
- """
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
- inject_noise = eta > 0 and s_noise > 0
-
- model_sampling = model.inner_model.model_patcher.get_model_object('model_sampling')
- sigma_fn = partial(half_log_snr_to_sigma, model_sampling=model_sampling)
- lambda_fn = partial(sigma_to_half_log_snr, model_sampling=model_sampling)
- sigmas = offset_first_sigma_for_snr(sigmas, model_sampling)
-
- for i in trange(len(sigmas) - 1, disable=disable):
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- if callback is not None:
- callback({'x': x, 'i': i, 'sigma': sigmas[i], 'sigma_hat': sigmas[i], 'denoised': denoised})
-
- if sigmas[i + 1] == 0:
- x = denoised
- continue
-
- lambda_s, lambda_t = lambda_fn(sigmas[i]), lambda_fn(sigmas[i + 1])
- h = lambda_t - lambda_s
- h_eta = h * (eta + 1)
- lambda_s_1 = torch.lerp(lambda_s, lambda_t, r_1)
- lambda_s_2 = torch.lerp(lambda_s, lambda_t, r_2)
- sigma_s_1, sigma_s_2 = sigma_fn(lambda_s_1), sigma_fn(lambda_s_2)
-
- alpha_s_1 = sigma_s_1 * lambda_s_1.exp()
- alpha_s_2 = sigma_s_2 * lambda_s_2.exp()
- alpha_t = sigmas[i + 1] * lambda_t.exp()
-
- # Step 1
- x_2 = sigma_s_1 / sigmas[i] * (-r_1 * h * eta).exp() * x - alpha_s_1 * ei_h_phi_1(-r_1 * h_eta) * denoised
- if inject_noise:
- sde_noise = (-2 * r_1 * h * eta).expm1().neg().sqrt() * noise_sampler(sigmas[i], sigma_s_1)
- x_2 = x_2 + sde_noise * sigma_s_1 * s_noise
- denoised_2 = model(x_2, sigma_s_1 * s_in, **extra_args)
-
- # Step 2
- a3_2 = r_2 / r_1 * ei_h_phi_2(-r_2 * h_eta)
- a3_1 = ei_h_phi_1(-r_2 * h_eta) - a3_2
- x_3 = sigma_s_2 / sigmas[i] * (-r_2 * h * eta).exp() * x - alpha_s_2 * (a3_1 * denoised + a3_2 * denoised_2)
- if inject_noise:
- segment_factor = (r_1 - r_2) * h * eta
- sde_noise = sde_noise * segment_factor.exp()
- sde_noise = sde_noise + segment_factor.mul(2).expm1().neg().sqrt() * noise_sampler(sigma_s_1, sigma_s_2)
- x_3 = x_3 + sde_noise * sigma_s_2 * s_noise
- denoised_3 = model(x_3, sigma_s_2 * s_in, **extra_args)
-
- # Step 3
- b3 = ei_h_phi_2(-h_eta) / r_2
- b1 = ei_h_phi_1(-h_eta) - b3
- x = sigmas[i + 1] / sigmas[i] * (-h * eta).exp() * x - alpha_t * (b1 * denoised + b3 * denoised_3)
- if inject_noise:
- segment_factor = (r_2 - 1) * h * eta
- sde_noise = sde_noise * segment_factor.exp()
- sde_noise = sde_noise + segment_factor.mul(2).expm1().neg().sqrt() * noise_sampler(sigma_s_2, sigmas[i + 1])
- x = x + sde_noise * sigmas[i + 1] * s_noise
- return x
-
-
-@torch.no_grad()
-def sample_sa_solver(model, x, sigmas, extra_args=None, callback=None, disable=False, tau_func=None, s_noise=1.0, noise_sampler=None, predictor_order=3, corrector_order=4, use_pece=False, simple_order_2=False):
- """Stochastic Adams Solver with predictor-corrector method (NeurIPS 2023)."""
- if len(sigmas) <= 1:
- return x
- extra_args = {} if extra_args is None else extra_args
- seed = extra_args.get("seed", None)
- noise_sampler = default_noise_sampler(x, seed=seed) if noise_sampler is None else noise_sampler
- s_in = x.new_ones([x.shape[0]])
-
- model_sampling = model.inner_model.model_patcher.get_model_object("model_sampling")
- sigmas = offset_first_sigma_for_snr(sigmas, model_sampling)
- lambdas = sigma_to_half_log_snr(sigmas, model_sampling=model_sampling)
-
- if tau_func is None:
- # Use default interval for stochastic sampling
- start_sigma = model_sampling.percent_to_sigma(0.2)
- end_sigma = model_sampling.percent_to_sigma(0.8)
- tau_func = sa_solver.get_tau_interval_func(start_sigma, end_sigma, eta=1.0)
-
- max_used_order = max(predictor_order, corrector_order)
- x_pred = x # x: current state, x_pred: predicted next state
-
- h = 0.0
- tau_t = 0.0
- noise = 0.0
- pred_list = []
-
- # Lower order near the end to improve stability
- lower_order_to_end = sigmas[-1].item() == 0
-
- for i in trange(len(sigmas) - 1, disable=disable):
- # Evaluation
- denoised = model(x_pred, sigmas[i] * s_in, **extra_args)
- if callback is not None:
- callback({"x": x_pred, "i": i, "sigma": sigmas[i], "sigma_hat": sigmas[i], "denoised": denoised})
- pred_list.append(denoised)
- pred_list = pred_list[-max_used_order:]
-
- predictor_order_used = min(predictor_order, len(pred_list))
- if i == 0 or (sigmas[i + 1] == 0 and not use_pece):
- corrector_order_used = 0
- else:
- corrector_order_used = min(corrector_order, len(pred_list))
-
- if lower_order_to_end:
- predictor_order_used = min(predictor_order_used, len(sigmas) - 2 - i)
- corrector_order_used = min(corrector_order_used, len(sigmas) - 1 - i)
-
- # Corrector
- if corrector_order_used == 0:
- # Update by the predicted state
- x = x_pred
- else:
- curr_lambdas = lambdas[i - corrector_order_used + 1:i + 1]
- b_coeffs = sa_solver.compute_stochastic_adams_b_coeffs(
- sigmas[i],
- curr_lambdas,
- lambdas[i - 1],
- lambdas[i],
- tau_t,
- simple_order_2,
- is_corrector_step=True,
- )
- pred_mat = torch.stack(pred_list[-corrector_order_used:], dim=1) # (B, K, ...)
- corr_res = torch.tensordot(pred_mat, b_coeffs, dims=([1], [0])) # (B, ...)
- x = sigmas[i] / sigmas[i - 1] * (-(tau_t ** 2) * h).exp() * x + corr_res
-
- if tau_t > 0 and s_noise > 0:
- # The noise from the previous predictor step
- x = x + noise
-
- if use_pece:
- # Evaluate the corrected state
- denoised = model(x, sigmas[i] * s_in, **extra_args)
- pred_list[-1] = denoised
-
- # Predictor
- if sigmas[i + 1] == 0:
- # Denoising step
- x = denoised
- else:
- tau_t = tau_func(sigmas[i + 1])
- curr_lambdas = lambdas[i - predictor_order_used + 1:i + 1]
- b_coeffs = sa_solver.compute_stochastic_adams_b_coeffs(
- sigmas[i + 1],
- curr_lambdas,
- lambdas[i],
- lambdas[i + 1],
- tau_t,
- simple_order_2,
- is_corrector_step=False,
- )
- pred_mat = torch.stack(pred_list[-predictor_order_used:], dim=1) # (B, K, ...)
- pred_res = torch.tensordot(pred_mat, b_coeffs, dims=([1], [0])) # (B, ...)
- h = lambdas[i + 1] - lambdas[i]
- x_pred = sigmas[i + 1] / sigmas[i] * (-(tau_t ** 2) * h).exp() * x + pred_res
-
- if tau_t > 0 and s_noise > 0:
- noise = noise_sampler(sigmas[i], sigmas[i + 1]) * sigmas[i + 1] * (-2 * tau_t ** 2 * h).expm1().neg().sqrt() * s_noise
- x_pred = x_pred + noise
- return x
-
-
-@torch.no_grad()
-def sample_sa_solver_pece(model, x, sigmas, extra_args=None, callback=None, disable=False, tau_func=None, s_noise=1.0, noise_sampler=None, predictor_order=3, corrector_order=4, simple_order_2=False):
- """Stochastic Adams Solver with PECE (Predict–Evaluate–Correct–Evaluate) mode (NeurIPS 2023)."""
- return sample_sa_solver(model, x, sigmas, extra_args=extra_args, callback=callback, disable=disable, tau_func=tau_func, s_noise=s_noise, noise_sampler=noise_sampler, predictor_order=predictor_order, corrector_order=corrector_order, use_pece=True, simple_order_2=simple_order_2)
diff --git a/nodes.py b/nodes.py
index ab9df6a..8fa476e 100644
--- a/nodes.py
+++ b/nodes.py
@@ -1,26 +1,10 @@
-import torch
-import logging
-from comfy_api.latest import io
-from comfy.utils import PROGRESS_BAR_ENABLED
import torch.nn.functional as F
-import latent_preview
-import comfy
-from nodes import VAEDecodeTiled, PreviewImage, VAEDecode
-from comfy_extras.nodes_custom_sampler import Noise_EmptyNoise, Noise_RandomNoise
-from comfy.samplers import SAMPLER_NAMES
-from PIL import Image
-from .utils import (pil2tensor, warning, set_preview_method, sample_custom_ultra,
- global_preview_method, store_ksampler_results, globals_cleanup,
- add_noise_at_step, add_noise_to_reference_video)
-from .samplers import sampler_object
-
-
-logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
-log = logging.getLogger(__name__)
+from .samplers import TTMGuider
+from .utils import add_noise_to_reference_video
# Copied from ComfyUI Wanvideo Wrapper
-class WanVideoEncode:
+class EncodeWanVideo:
@classmethod
def INPUT_TYPES(s):
return {"required": {
@@ -60,21 +44,21 @@ class WanVideoEncode:
if latent_strength != 1.0:
latents *= latent_strength
-
- log.info(f"WanVideo Encode: Encoded latents shape {latents.shape}")
+
+ print(f"WanVideo Encode: Encoded latents shape {latents.shape}")
return ({"samples": latents, "noise_mask": mask},)
-
+
# Copied from ComfyUI Wanvideo Wrapper
-class AddTTMLatent:
+class TTMLatentAdd:
@classmethod
def INPUT_TYPES(s):
return {"required": {
"latent": ("LATENT", {"tooltip": "wanvideo latent"}),
"reference_latents": ("LATENT", {"tooltip": "Reference image to encode"}),
- "start_step": ("INT", {"default": 0, "min": -1, "max": 1000, "step": 1, "tooltip": "Start step for whole denoising process"}),
- "end_step": ("INT", {"default": 2, "min": 1, "max": 1000, "step": 1, "tooltip": "The step to stop applying TTM"}),
+ "ttm_start_step": ("INT", {"default": 0, "min": 0, "max": 1000, "step": 1, "tooltip": "Start step to apply TTM latent guide"}),
+ "ttm_end_step": ("INT", {"default": 3, "min": 1, "max": 1000, "step": 1, "tooltip": "The step to stop applying TTM"}),
"ref_masks": ("MASK", {"tooltip": "Reference mask to encode"}),
}
}
@@ -84,9 +68,10 @@ class AddTTMLatent:
FUNCTION = "add"
CATEGORY = "Wan22 TimeToMove"
- def add(self, latent, reference_latents, start_step, end_step, ref_masks):
- if end_step < max(0, start_step):
- raise ValueError(f"`end_step` ({end_step}) must be >= `start_step` ({start_step}).")
+ def add(self, latent, reference_latents, ttm_start_step, ttm_end_step, ref_masks):
+
+ if ttm_end_step < max(0, ttm_start_step):
+ raise ValueError(f"`ttm_end_step` ({ttm_end_step}) must be >= `ttm_start_step` ({ttm_start_step}).")
mask_sampled = ref_masks[::4]
mask_sampled = mask_sampled.unsqueeze(1).unsqueeze(0) # [1, T, 1, H, W]
@@ -104,224 +89,99 @@ class AddTTMLatent:
mode="nearest"
)
- latent["ttm_reference_latents"] = reference_latents["samples"].squeeze(0) # [16, T, H, W]
- latent["ttm_mask"] = mask_latent.squeeze(0).movedim(1, 0) # [1, T, H, W]
- latent["ttm_start_step"] = start_step
- latent["ttm_end_step"] = end_step
-
+ latent["ttm_reference_latents"] = reference_latents["samples"]
+ latent["ttm_mask"] = mask_latent.movedim(2, 1)
+ latent["ttm_start_step"] = ttm_start_step
+ latent["ttm_end_step"] = ttm_end_step
+
return (latent,)
-class TTMKSamplerSelect(io.ComfyNode):
+class TimeToMoveGuider:
@classmethod
- def define_schema(cls):
- return io.Schema(
- node_id="TTMKSamplerSelect",
- category="Wan Animate End Reference",
- inputs=[
- io.Combo.Input("sampler_name", options=SAMPLER_NAMES, default="lcm"),
- io.Latent.Input("latent"),
- ],
- outputs=[
- io.Sampler.Output(),
- ]
- )
+ def INPUT_TYPES(s):
+ return {"required":
+ {"model": ("MODEL", ),
+ "positive": ("CONDITIONING", ),
+ "negative": ("CONDITIONING", ),
+ "cfg": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.1, "tooltip": "Works with a list of floats too (one cfg float per step)"}),
+ "latent": ("LATENT", {"tooltip": "You can connect here the latent from TTM Latent Add, to pass reference video and ttm options"}),
+ "start_sampler_step": ("INT", {"default": 0, "min": 0, "max": 1000, "step": 1, "tooltip": "Start step of the whole sampling process. It will automatically skip the selected number of sigmas (starting from the first ones); if the sampler has a start_step option and you changed its value, set the same here"}),
+ },
+ }
+
+ RETURN_TYPES = ("GUIDER",)
+ RETURN_NAMES = ("guider",)
+ FUNCTION = "guide"
+ CATEGORY = "Wan22 TimeToMove"
+
+ def guide(cls, model, positive, negative, cfg, latent, start_sampler_step):
+ guider = TTMGuider(model)
+ guider.set_conds(positive, negative)
+ guider.set_cfg(cfg)
- @classmethod
- def execute(cls, sampler_name, latent) -> io.NodeOutput:
ttm_options = {}
ttm_options["ttm_reference_latents"] = latent.get("ttm_reference_latents", None)
ttm_options["ttm_start_step"] = latent["ttm_start_step"]
ttm_options["ttm_end_step"] = latent["ttm_end_step"]
ttm_options["latent_image"] = latent["samples"]
ttm_options["motion_mask"] = latent["ttm_mask"]
+ ttm_options["start_sampler_step"] = start_sampler_step
+ guider.set_ttm_options(ttm_options)
- sampler = sampler_object(sampler_name, ttm_options)
- return io.NodeOutput(sampler)
-
- get_sampler = execute
+ return (guider,)
-class WanVideoSamplerCustomUltraAdvancedEfficient:
- # Image Preview code taken from jags111's efficiency-nodes (TSC_KSampler)
- empty_image = pil2tensor(Image.new('RGBA', (1, 1), (0, 0, 0, 0)))
-
+# Taken from kijai WanVideo-Wrapper
+class CFGFloatListScheduler:
@classmethod
def INPUT_TYPES(s):
- return {"required":
- {"model": ("MODEL",),
- "add_noise": ("BOOLEAN", {"default": True}),
- "noise_seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff, "control_after_generate": True}),
- "cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0, "step":0.1, "round": 0.01}),
- "positive": ("CONDITIONING", ),
- "negative": ("CONDITIONING", ),
- "sampler": ("SAMPLER", ),
- "sigmas": ("SIGMAS", ),
- "latent": ("LATENT", ),
- "start_at_step": ("INT", {"default": 0, "min": 0, "max": 10000}),
- "end_at_step": ("INT", {"default": 10000, "min": 0, "max": 10000}),
- "return_with_leftover_noise": ("BOOLEAN", {"default": False}),
- "preview_method": (["auto", "latent2rgb", "taesd", "vae_decoded_only", "none"],),
- "vae_decode": (["true", "true (tiled)", "false"],),
- },
- "optional": {
- "optional_vae": ("VAE",),
- },
- "hidden": {
- "prompt": "PROMPT",
- "extra_pnginfo": "EXTRA_PNGINFO",
- "my_unique_id": "UNIQUE_ID",
- },
- }
+ return {"required": {
+ "steps": ("INT", {"default": 30, "min": 2, "max": 1000, "step": 1, "tooltip": "Number of steps to schedule cfg for"} ),
+ "cfg_scale_start": ("FLOAT", {"default": 5.0, "min": 0.0, "max": 30.0, "step": 0.01, "round": 0.01, "tooltip": "CFG scale to use for the steps"}),
+ "cfg_scale_end": ("FLOAT", {"default": 5.0, "min": 0.0, "max": 30.0, "step": 0.01, "round": 0.01, "tooltip": "CFG scale to use for the steps"}),
+ "interpolation": (["linear", "ease_in", "ease_out"], {"default": "linear", "tooltip": "Interpolation method to use for the cfg scale"}),
+ "start_percent": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.01, "round": 0.01,"tooltip": "Start percent of the steps to apply cfg"}),
+ "end_percent": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01, "round": 0.01,"tooltip": "End percent of the steps to apply cfg"}),
+ },
+ "hidden": {
+ "unique_id": "UNIQUE_ID",
+ },
+ }
- RETURN_TYPES = ("MODEL", "CONDITIONING", "CONDITIONING", "SAMPLER", "SIGMAS", "LATENT","LATENT", "IMAGE", "VAE",)
- RETURN_NAMES = ("model", "positive", "negative", "sampler", "sigmas", "output", "denoised_output", "image", "vae", )
- FUNCTION = "sample"
+ RETURN_TYPES = ("FLOAT", )
+ RETURN_NAMES = ("float_list",)
+ FUNCTION = "process"
CATEGORY = "Wan22 TimeToMove"
+ DESCRIPTION = "Helper node to generate a list of floats that can be used to schedule cfg scale for the steps, outside the set range cfg is set to 1.0. Taken from Kijai WanVideo-Wrapper"
- def sample(self, model, add_noise, noise_seed, cfg, positive, negative, sampler, sigmas, latent, start_at_step, end_at_step, return_with_leftover_noise, preview_method, vae_decode, optional_vae=(None,), prompt=None, extra_pnginfo=None, my_unique_id=None):
- latent_image = latent["samples"]
- latent_image = comfy.sample.fix_empty_latent_channels(model, latent_image)
- latent["samples"] = latent_image
-
- # Rename the vae variable
- vae = optional_vae
- # If vae is not connected, disable vae decoding
- if vae == (None,) and vae_decode != "false":
- print(f"{warning('Sampler Custom Ultra Advanced Warning:')} No vae input detected, proceeding as if vae_decode was false.\n")
- vae_decode = "false"
-
- # ------------------------------------------------------------------------------------------------------
- def vae_decode_latent(vae, out, vae_decode):
- return VAEDecodeTiled().decode(vae,out,320)[0] if "tiled" in vae_decode else VAEDecode().decode(vae,out)[0]
- # ---------------------------------------------------------------------------------------------------------------
+ def process(self, steps, cfg_scale_start, cfg_scale_end, interpolation, start_percent, end_percent, unique_id):
- noise_mask = None
- if "noise_mask" in latent:
- noise_mask = latent["noise_mask"]
-
- def process_latents():
- x0_output = {}
- # Initialize output variables
- out = out_denoised = images = preview = previous_preview_method = None
+ # Create a list of floats for the cfg schedule
+ cfg_list = [1.0] * steps
+ start_idx = min(int(steps * start_percent), steps - 1)
+ end_idx = min(int(steps * end_percent), steps - 1)
- if not add_noise:
- noise = Noise_EmptyNoise().generate_noise(latent)
+ for i in range(start_idx, end_idx + 1):
+ if i >= steps:
+ break
+
+ if end_idx == start_idx:
+ t = 0
else:
- noise = Noise_RandomNoise(noise_seed).generate_noise(latent)
-
- #Time-to-move (TTM)
- ttm_start_step = 0
- ttm_reference_latents = latent.get("ttm_reference_latents", None)
- if ttm_reference_latents is not None:
- motion_mask = latent["ttm_mask"].to(latent_image.device, latent_image.dtype)
- ttm_start_step = max(latent["ttm_start_step"] - start_at_step, 0)
- ttm_end_step = latent["ttm_end_step"] - start_at_step
-
- if ttm_start_step > end_at_step:
- raise ValueError("TTM start step is beyond the total number of steps")
-
- sigma = sigmas[ttm_start_step]
+ t = (i - start_idx) / (end_idx - start_idx)
- if ttm_end_step > ttm_start_step:
- log.info("Using Time-to-move (TTM)")
- log.info(f"TTM reference latents shape: {ttm_reference_latents.shape}")
- log.info(f"TTM motion mask shape: {motion_mask.shape}")
- log.info(f"Applying TTM from step {ttm_start_step} to {ttm_end_step}")
+ if interpolation == "linear":
+ factor = t
+ elif interpolation == "ease_in":
+ factor = t * t
+ elif interpolation == "ease_out":
+ factor = t * (2 - t)
- noise = add_noise_at_step(ttm_reference_latents,
- noise,
- sigma
- ).to(latent_image.device, latent_image.dtype)
- #--------------------------------------------------------------
-
- try:
- # Change the global preview method (temporarily)
- set_preview_method(preview_method)
-
- x0_output = {}
- callback = latent_preview.prepare_callback(model, sigmas.shape[-1] - 1, x0_output)
+ cfg_list[i] = round(cfg_scale_start + factor * (cfg_scale_end - cfg_scale_start), 2)
- disable_pbar = not PROGRESS_BAR_ENABLED
-
- disable_noise = False
- if not add_noise:
- disable_noise = True
-
- # Prepare noise for img specified by batch_inds
- if disable_noise:
- noise = torch.zeros(latent_image.size(), dtype=latent_image.dtype, layout=latent_image.layout, device="cpu")
- else:
- batch_inds = latent["batch_index"] if "batch_index" in latent else None
- noise = comfy.sample.prepare_noise(latent_image, noise_seed, batch_inds)
-
- force_full_denoise = True
- if return_with_leftover_noise:
- force_full_denoise = False
-
- device = comfy.model_management.intermediate_device()
- model_options = model.model_options
- start_step = start_at_step
- last_step = end_at_step
- denoise_mask = noise_mask
+ # If start_percent > 0, always include the first step
+ if start_percent > 0:
+ cfg_list[0] = 1.0
- samples = sample_custom_ultra(model, device,
- noise,
- sampler,
- positive, negative,
- cfg, model_options,
- latent_image,
- start_step, last_step,
- force_full_denoise, denoise_mask,
- sigmas,
- callback, disable_pbar, noise_seed)
-
- samples = samples.to(comfy.model_management.intermediate_device())
-
- out = latent.copy()
- out["samples"] = samples
- if "x0" in x0_output:
- out_denoised = latent.copy()
- out_denoised["samples"] = model.model.process_latent_out(x0_output["x0"].cpu())
- else:
- out_denoised = out
-
- previous_preview_method = global_preview_method()
-
- # ---------------------------------------------------------------------------------------------------------------
- # Decode image if not yet decoded
- if "true" in vae_decode:
- if images is None:
- images = vae_decode_latent(vae, out, vae_decode)
- # Store decoded image as base image of no script is detected
- store_ksampler_results("image", my_unique_id, images)
-
- # Define preview images
- if preview_method == "none" or (preview_method == "vae_decoded_only" and vae_decode == "false"):
- preview = {"images": list()}
- elif images is not None:
- preview = PreviewImage().save_images(images, prompt=prompt, extra_pnginfo=extra_pnginfo)["ui"]
-
- # Define a dummy output image
- if images is None and vae_decode == "false":
- images = WanVideoSamplerCustomUltraAdvancedEfficient.empty_image
-
- finally:
- # Restore global changes
- set_preview_method(previous_preview_method)
-
- return out, out_denoised, preview, images
-
- # ---------------------------------------------------------------------------------------------------------------
- # Clean globally stored objects of non-existant nodes
- globals_cleanup(prompt)
- # ---------------------------------------------------------------------------------------------------------------
- out, out_denoised, preview, images = process_latents()
-
- result = (model, positive, negative, sampler, sigmas,
- out, out_denoised, images, vae,)
-
- if preview is None:
- return {"result": result}
- else:
- return {"ui": preview, "result": result}
+ return (cfg_list,)
diff --git a/samplers.py b/samplers.py
index 8db06df..c806b2a 100644
--- a/samplers.py
+++ b/samplers.py
@@ -1,109 +1,216 @@
import torch
-from comfy.samplers import Sampler
-from comfy.extra_samplers import uni_pc
-
-from .k_diffusion import sampling as k_diffusion_sampling
+import comfy
+from comfy.model_patcher import ModelPatcher
+from comfy.samplers import (sampling_function, process_conds, cast_to_load_options,
+ preprocess_conds_hooks, get_total_hook_groups_in_conds,
+ filter_registered_hooks_on_conds)
+from .utils import add_noise_at_step
-class KSamplerX0Inpaint:
- def __init__(self, model, sigmas):
- self.inner_model = model
- self.sigmas = sigmas
- # Add ttm_options to extra_args
- def __call__(self, x, sigma, denoise_mask, model_options={}, seed=None,
- ttm_reference_latents=None, ttm_start_step=None,
- ttm_end_step=None, latent_image=None, motion_mask=None):
-
- if denoise_mask is not None:
- if "denoise_mask_function" in model_options:
- denoise_mask = model_options["denoise_mask_function"](sigma, denoise_mask, extra_options={"model": self.inner_model, "sigmas": self.sigmas})
- latent_mask = 1. - denoise_mask
- x = x * denoise_mask + self.inner_model.inner_model.scale_latent_inpaint(x=x, sigma=sigma, noise=self.noise, latent_image=self.latent_image) * latent_mask
- model_options["ttm_reference_latents"] = ttm_reference_latents
- model_options["ttm_start_step"] = ttm_start_step
- model_options["ttm_end_step"] = ttm_end_step
- model_options["latent_image"] = latent_image
- model_options["motion_mask"] = motion_mask
- out = self.inner_model(x, sigma, model_options=model_options, seed=seed)
- if denoise_mask is not None:
- out = out * denoise_mask + self.latent_image * latent_mask
- return out
+class TTMGuider:
+ def __init__(self, model_patcher: ModelPatcher):
+ self.model_patcher = model_patcher
+ self.model_options = model_patcher.model_options
+ self.original_conds = {}
+ self.cfg = 1.0
+
+ def set_conds(self, positive, negative):
+ self.inner_set_conds({"positive": positive, "negative": negative})
+
+ def set_cfg(self, cfg):
+ self.cfg = cfg
+ def set_ttm_options(self, ttm_options):
+ self.ttm_reference_latents = ttm_options["ttm_reference_latents"]
+ self.ttm_start_step = ttm_options["ttm_start_step"]
+ self.ttm_end_step = ttm_options["ttm_end_step"]
+ self.latent_image = ttm_options["latent_image"]
+ self.motion_mask = ttm_options["motion_mask"]
+ self.start_sampler_step = ttm_options["start_sampler_step"]
-class KSAMPLER(Sampler):
- def __init__(self, sampler_function, extra_options={}, inpaint_options={}):
- self.sampler_function = sampler_function
- self.extra_options = extra_options
- self.inpaint_options = inpaint_options
+ def inner_set_conds(self, conds):
+ for k in conds:
+ self.original_conds[k] = comfy.sampler_helpers.convert_cond(conds[k])
- def sample(self, model_wrap, sigmas, extra_args, callback, noise, latent_image=None, denoise_mask=None, disable_pbar=False):
- extra_args["denoise_mask"] = denoise_mask
- model_k = KSamplerX0Inpaint(model_wrap, sigmas)
- model_k.latent_image = latent_image
- if self.inpaint_options.get("random", False): #TODO: Should this be the default?
- generator = torch.manual_seed(extra_args.get("seed", 41) + 1)
- model_k.noise = torch.randn(noise.shape, generator=generator, device="cpu").to(noise.dtype).to(noise.device)
+ def __call__(self, *args, **kwargs):
+ return self.outer_predict_noise(*args, **kwargs)
+
+ def outer_predict_noise(self, x, timestep, model_options={}, seed=None):
+ return comfy.patcher_extension.WrapperExecutor.new_class_executor(
+ self.predict_noise,
+ self,
+ comfy.patcher_extension.get_all_wrappers(comfy.patcher_extension.WrappersMP.PREDICT_NOISE, self.model_options, is_model_options=True)
+ ).execute(x, timestep, model_options, seed)
+
+ def predict_noise(self, x, timestep, model_options={}, seed=None):
+ #---------------------------------------------------------
+ sigmas = model_options["sigmas"]
+ noise = model_options["noise"]
+ i = torch.argmin(torch.abs(sigmas - timestep)).item()
+
+ ttm_ref_latent = model_options["ttm_reference_latents"]
+ ttm_start_step = model_options["ttm_start_step"]
+ ttm_end_step = model_options["ttm_end_step"]
+ ttm_mask = model_options["motion_mask"]
+ # Time-to-move (TTM)
+ if (i + ttm_start_step) < ttm_end_step:
+ if i + ttm_start_step < len(sigmas):
+ sigma_next = sigmas[i + ttm_start_step]
+ noisy_latents = add_noise_at_step(ttm_ref_latent,
+ noise,
+ sigma_next.to(x.device)
+ ).to(x)
+ x = x * (1 - ttm_mask) + noisy_latents * ttm_mask
+ else:
+ x = x * (1 - ttm_mask) + ttm_ref_latent * ttm_mask
+ #---------------------------------------------------------
+ return sampling_function(self.inner_model, x, timestep,
+ self.conds.get("negative", None),
+ self.conds.get("positive", None),
+ self.cfg[i],
+ model_options=model_options, seed=seed)
+
+ def inner_sample(self, noise, latent_image, device, sampler, sigmas, denoise_mask, callback, disable_pbar, seed, latent_shapes=None):
+ if latent_image is not None and torch.count_nonzero(latent_image) > 0: #Don't shift the empty latent image.
+ latent_image = self.inner_model.process_latent_in(latent_image)
+
+ self.conds = process_conds(self.inner_model, noise, self.conds, device, latent_image, denoise_mask, seed, latent_shapes=latent_shapes)
+
+ extra_model_options = comfy.model_patcher.create_model_options_clone(self.model_options)
+ extra_model_options.setdefault("transformer_options", {})["sample_sigmas"] = sigmas
+ extra_args = {"model_options": extra_model_options, "seed": seed}
+
+ #---------------------------------------------------------
+ skipped_sigmas = sigmas[self.start_sampler_step:]
+ # 4 < 5
+ if len(skipped_sigmas) < len(sigmas): # sampler doesn't have start_step option
+ sigmas = skipped_sigmas
+ # 4 == 4
+ elif len(skipped_sigmas) == len(sigmas): # sampler already has option
+ pass # we don't want another sigma less
+ steps = len(sigmas)-1
+ extra_args["model_options"]["steps"] = steps
+ #---------------------------------------------------------
+ # Pass ttm options to KSAMPLER.sample
+ ttm_start_step = max(self.ttm_start_step - self.start_sampler_step, 0)
+ ttm_end_step = self.ttm_end_step - self.start_sampler_step
+
+ extra_args["model_options"]["ttm_reference_latents"] = self.ttm_reference_latents.to(noise.device)
+ extra_args["model_options"]["ttm_start_step"] = ttm_start_step
+ extra_args["model_options"]["ttm_end_step"] = ttm_end_step
+ extra_args["model_options"]["motion_mask"] = self.motion_mask.to(noise.device)
+ extra_args["model_options"]["sigmas"] = sigmas
+ extra_args["model_options"]["noise"] = noise
+
+ if ttm_start_step > steps:
+ raise ValueError("TTM start step is beyond the total number of steps")
+
+ if ttm_end_step > ttm_start_step:
+ print("Using Time-to-move (TTM)")
+ print(f"TTM reference latents shape: {self.ttm_reference_latents.shape}")
+ print(f"TTM motion mask shape: {self.motion_mask.shape}")
+ print(f"Applying TTM from step {ttm_start_step} to {ttm_end_step}")
+ #---------------------------------------------------------
+ # Cfg schedule taken from Kijai WanVideo-Wrapper
+ if isinstance(self.cfg, list):
+ if steps < len(self.cfg):
+ print(f"Received {len(self.cfg)} cfg values, but only {steps} steps. Slicing cfg list to match steps.")
+ self.cfg = self.cfg[:steps]
+ elif steps > len(self.cfg):
+ print(f"Received only {len(self.cfg)} cfg values, but {steps} steps. Extending cfg list to match steps.")
+ self.cfg.extend([self.cfg[-1]] * (steps - len(self.cfg)))
+ print(f"Using per-step cfg list: {self.cfg}")
else:
- model_k.noise = noise
+ self.cfg = [self.cfg] * (steps + 1)
+ #---------------------------------------------------------
- noise = model_wrap.inner_model.model_sampling.noise_scaling(sigmas[0], noise, latent_image, self.max_denoise(model_wrap, sigmas))
-
- k_callback = None
- total_steps = len(sigmas) - 1
- if callback is not None:
- k_callback = lambda x: callback(x["i"], x["denoised"], x["x"], total_steps)
+ executor = comfy.patcher_extension.WrapperExecutor.new_class_executor(
+ sampler.sample,
+ sampler,
+ comfy.patcher_extension.get_all_wrappers(comfy.patcher_extension.WrappersMP.SAMPLER_SAMPLE, extra_args["model_options"], is_model_options=True)
+ )
- samples = self.sampler_function(model_k, noise, sigmas, extra_args=extra_args, callback=k_callback, disable=disable_pbar, **self.extra_options)
- samples = model_wrap.inner_model.model_sampling.inverse_noise_scaling(sigmas[-1], samples)
- return samples
-
+ # run steps and get final samples
+ samples = executor.execute(self, sigmas, extra_args, callback, noise, latent_image, denoise_mask, disable_pbar)
+
+ return self.inner_model.process_latent_out(samples.to(torch.float32))
-def ksampler(sampler_name, ttm_options, extra_options={}, inpaint_options={}):
- if sampler_name == "dpm_fast":
- def dpm_fast_function(model, noise, sigmas, extra_args, callback, disable):
- if len(sigmas) <= 1:
- return noise
+ def outer_sample(self, noise, latent_image, sampler, sigmas, denoise_mask=None, callback=None, disable_pbar=False, seed=None, latent_shapes=None):
+ self.inner_model, self.conds, self.loaded_models = comfy.sampler_helpers.prepare_sampling(self.model_patcher, noise.shape, self.conds, self.model_options)
+ device = self.model_patcher.load_device
- sigma_min = sigmas[-1]
- if sigma_min == 0:
- sigma_min = sigmas[-2]
- total_steps = len(sigmas) - 1
- return k_diffusion_sampling.sample_dpm_fast(model, noise, sigma_min, sigmas[0], total_steps, extra_args=extra_args, callback=callback, disable=disable)
- sampler_function = dpm_fast_function
- elif sampler_name == "dpm_adaptive":
- def dpm_adaptive_function(model, noise, sigmas, extra_args, callback, disable, **extra_options):
- if len(sigmas) <= 1:
- return noise
+ noise = noise.to(device)
+ latent_image = latent_image.to(device)
+ sigmas = sigmas.to(device)
+ cast_to_load_options(self.model_options, device=device, dtype=self.model_patcher.model_dtype())
- sigma_min = sigmas[-1]
- if sigma_min == 0:
- sigma_min = sigmas[-2]
- return k_diffusion_sampling.sample_dpm_adaptive(model, noise, sigma_min, sigmas[0], extra_args=extra_args, callback=callback, disable=disable, **extra_options)
- sampler_function = dpm_adaptive_function
- elif sampler_name == "lcm":
- def lcm_function(model, noise, sigmas, extra_args, callback, disable, **extra_options):
- extra_args["ttm_reference_latents"] = ttm_options["ttm_reference_latents"]
- extra_args["ttm_start_step"] = ttm_options["ttm_start_step"]
- extra_args["ttm_end_step"] = ttm_options["ttm_end_step"]
- extra_args["latent_image"] = ttm_options["latent_image"]
- extra_args["motion_mask"] = ttm_options["motion_mask"]
- return k_diffusion_sampling.sample_lcm(model, noise, sigmas, extra_args=extra_args, callback=callback, disable=disable, **extra_options)
- sampler_function = lcm_function
- else:
- sampler_function = getattr(k_diffusion_sampling, "sample_{}".format(sampler_name))
+ try:
+ self.model_patcher.pre_run()
+ output = self.inner_sample(noise, latent_image, device, sampler, sigmas, denoise_mask, callback, disable_pbar, seed, latent_shapes=latent_shapes)
+ finally:
+ self.model_patcher.cleanup()
- return KSAMPLER(sampler_function, extra_options, inpaint_options)
+ comfy.sampler_helpers.cleanup_models(self.conds, self.loaded_models)
+ del self.inner_model
+ del self.loaded_models
+ return output
+ def sample(self, noise, latent_image, sampler, sigmas, denoise_mask=None, callback=None, disable_pbar=False, seed=None):
+ if sigmas.shape[-1] == 0:
+ return latent_image
-def sampler_object(name, ttm_options):
- if name == "uni_pc":
- sampler = KSAMPLER(uni_pc.sample_unipc)
- elif name == "uni_pc_bh2":
- sampler = KSAMPLER(uni_pc.sample_unipc_bh2)
- elif name == "ddim":
- sampler = ksampler("euler", inpaint_options={"random": True})
- elif name == "lcm":
- sampler = ksampler(name, ttm_options)
- else:
- sampler = ksampler(name)
- return sampler
+ if latent_image.is_nested:
+ latent_image, latent_shapes = comfy.utils.pack_latents(latent_image.unbind())
+ noise, _ = comfy.utils.pack_latents(noise.unbind())
+ else:
+ latent_shapes = [latent_image.shape]
+
+ if denoise_mask is not None:
+ if denoise_mask.is_nested:
+ denoise_masks = denoise_mask.unbind()
+ denoise_masks = denoise_masks[:len(latent_shapes)]
+ else:
+ denoise_masks = [denoise_mask]
+
+ for i in range(len(denoise_masks), len(latent_shapes)):
+ denoise_masks.append(torch.ones(latent_shapes[i]))
+
+ for i in range(len(denoise_masks)):
+ denoise_masks[i] = comfy.sampler_helpers.prepare_mask(denoise_masks[i], latent_shapes[i], self.model_patcher.load_device)
+
+ if len(denoise_masks) > 1:
+ denoise_mask, _ = comfy.utils.pack_latents(denoise_masks)
+ else:
+ denoise_mask = denoise_masks[0]
+
+ self.conds = {}
+ for k in self.original_conds:
+ self.conds[k] = list(map(lambda a: a.copy(), self.original_conds[k]))
+ preprocess_conds_hooks(self.conds)
+
+ try:
+ orig_model_options = self.model_options
+ self.model_options = comfy.model_patcher.create_model_options_clone(self.model_options)
+ # if one hook type (or just None), then don't bother caching weights for hooks (will never change after first step)
+ orig_hook_mode = self.model_patcher.hook_mode
+ if get_total_hook_groups_in_conds(self.conds) <= 1:
+ self.model_patcher.hook_mode = comfy.hooks.EnumHookMode.MinVram
+ comfy.sampler_helpers.prepare_model_patcher(self.model_patcher, self.conds, self.model_options)
+ filter_registered_hooks_on_conds(self.conds, self.model_options)
+ executor = comfy.patcher_extension.WrapperExecutor.new_class_executor(
+ self.outer_sample,
+ self,
+ comfy.patcher_extension.get_all_wrappers(comfy.patcher_extension.WrappersMP.OUTER_SAMPLE, self.model_options, is_model_options=True)
+ )
+ output = executor.execute(noise, latent_image, sampler, sigmas, denoise_mask, callback, disable_pbar, seed, latent_shapes=latent_shapes)
+ finally:
+ cast_to_load_options(self.model_options, device=self.model_patcher.offload_device)
+ self.model_options = orig_model_options
+ self.model_patcher.hook_mode = orig_hook_mode
+ self.model_patcher.restore_hook_patches()
+
+ del self.conds
+
+ if len(latent_shapes) > 1:
+ output = comfy.nested_tensor.NestedTensor(comfy.utils.unpack_latents(output, latent_shapes))
+ return output
diff --git a/utils.py b/utils.py
index bd50bcd..954549d 100644
--- a/utils.py
+++ b/utils.py
@@ -1,121 +1,4 @@
import torch
-from PIL import Image
-import numpy as np
-import latent_preview
-from comfy.cli_args import args
-from comfy.samplers import sample
-
-
-# Convert PIL to Tensor (grabbed from WAS Suite)
-def pil2tensor(image: Image.Image) -> torch.Tensor:
- return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0)
-
-def format_message(text, color_code):
- RESET_COLOR = "\033[0m"
- return f"{color_code}{text}{RESET_COLOR}"
-
-WARNING_COLOR = "\033[93m" # Yellow
-
-def warning(text):
- return format_message(text, WARNING_COLOR)
-
-
-# Set global preview_method
-def set_preview_method(method):
- if method == 'auto' or method == 'LatentPreviewMethod.Auto':
- args.preview_method = latent_preview.LatentPreviewMethod.Auto
- elif method == 'latent2rgb' or method == 'LatentPreviewMethod.Latent2RGB':
- args.preview_method = latent_preview.LatentPreviewMethod.Latent2RGB
- elif method == 'taesd' or method == 'LatentPreviewMethod.TAESD':
- args.preview_method = latent_preview.LatentPreviewMethod.TAESD
- else:
- args.preview_method = latent_preview.LatentPreviewMethod.NoPreviews
-
-
-def sample_custom_ultra(model, device, noise, sampler, positive, negative, cfg, model_options={}, latent_image=None, start_step=None, last_step=None, force_full_denoise=False, denoise_mask=None, sigmas=None, callback=None, disable_pbar=False, seed=None):
- if last_step is not None and last_step < (len(sigmas) - 1):
- sigmas = sigmas[:last_step + 1]
- if force_full_denoise:
- sigmas[-1] = 0
-
- if start_step is not None:
- if start_step < (len(sigmas) - 1):
- sigmas = sigmas[start_step:]
- else:
- if latent_image is not None:
- return latent_image
- else:
- return torch.zeros_like(noise)
-
- return sample(model, noise, positive, negative, cfg, device, sampler, sigmas, model_options, latent_image=latent_image, denoise_mask=denoise_mask, callback=callback, disable_pbar=disable_pbar, seed=seed)
-
-
-# Extract global preview_method
-def global_preview_method():
- return args.preview_method
-
-
-# Cache for Efficiency Node models
-loaded_objects = {
- "ckpt": [], # (ckpt_name, ckpt_model, clip, bvae, [id])
- "refn": [], # (ckpt_name, ckpt_model, clip, bvae, [id])
- "vae": [], # (vae_name, vae, [id])
- "lora": [] # ([(lora_name, strength_model, strength_clip)], ckpt_name, lora_model, clip_lora, [id])
-}
-
-# Cache for Efficient Ksamplers
-last_helds = {
- "latent": [], # (latent, [parameters], id) # Base sampling latent results
- "image": [], # (image, id) # Base sampling image results
- "cnet_img": [] # (cnet_img, [parameters], id) # HiRes-Fix control net preprocessor image results
-}
-
-def store_ksampler_results(key: str, my_unique_id, value, parameters_list=None):
- global last_helds
-
- for i, data in enumerate(last_helds[key]):
- id_ = data[-1] # ID will always be the last in the tuple
- if id_ == my_unique_id:
- # Check if parameters_list is provided or not
- updated_data = (value, parameters_list, id_) if parameters_list is not None else (value, id_)
- last_helds[key][i] = updated_data
- return True
-
- # If parameters_list is given
- if parameters_list is not None:
- last_helds[key].append((value, parameters_list, my_unique_id))
- else:
- last_helds[key].append((value, my_unique_id))
- return True
-
-
-# This function cleans global variables associated with nodes that are no longer detected on UI
-def globals_cleanup(prompt):
- global loaded_objects
- global last_helds
-
- # Step 1: Clean up last_helds
- for key in list(last_helds.keys()):
- original_length = len(last_helds[key])
- last_helds[key] = [
- (*values, id_)
- for *values, id_ in last_helds[key]
- if str(id_) in prompt.keys()
- ]
-
- # Step 2: Clean up loaded_objects
- for key in list(loaded_objects.keys()):
- for i, tup in enumerate(list(loaded_objects[key])):
- # Remove ids from id array in each tuple that don't exist in prompt
- id_array = [id for id in tup[-1] if str(id) in prompt.keys()]
- if len(id_array) != len(tup[-1]):
- if id_array:
- loaded_objects[key][i] = tup[:-1] + (id_array,)
- #print(f'Updated tuple at index {i} in {key} in loaded_objects: {loaded_objects[key][i]}')
- else:
- # If id array becomes empty, delete the corresponding tuple
- loaded_objects[key].remove(tup)
- #print(f'Deleted tuple at index {i} in {key} in loaded_objects because its id array became empty.')
# Copied from ComfyUI Wanvideo Wrapper
diff --git a/Comfyui_WanTimeToMove_workflow.json b/wanvideo_2_2_I2V_A14B_TimeToMove_workflow1.json
similarity index 59%
rename from Comfyui_WanTimeToMove_workflow.json
rename to wanvideo_2_2_I2V_A14B_TimeToMove_workflow1.json
index 005f3b2..037c592 100644
--- a/Comfyui_WanTimeToMove_workflow.json
+++ b/wanvideo_2_2_I2V_A14B_TimeToMove_workflow1.json
@@ -1,635 +1,83 @@
{
- "id": "4cb2553d-c475-4a3d-a888-8d5ad15c9e44",
+ "id": "50c7e0a6-6c6a-44ee-a68c-6b9ccab41177",
"revision": 0,
- "last_node_id": 204,
- "last_link_id": 508,
+ "last_node_id": 83,
+ "last_link_id": 145,
"nodes": [
{
- "id": 23,
- "type": "CLIPTextEncode",
+ "id": 35,
+ "type": "CFGFloatListScheduler",
"pos": [
- 1770,
- 1170
+ 5940,
+ 1240
],
"size": [
- 410,
- 110
+ 232.167578125,
+ 182
],
"flags": {},
- "order": 26,
+ "order": 19,
"mode": 0,
"inputs": [
{
- "name": "clip",
- "type": "CLIP",
- "link": 477
- }
- ],
- "outputs": [
- {
- "name": "CONDITIONING",
- "type": "CONDITIONING",
- "links": [
- 294
- ]
- }
- ],
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.3.49",
- "Node name for S&R": "CLIPTextEncode",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {
- "text": true
- }
- }
- },
- "widgets_values": [
- "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走"
- ],
- "color": "#322",
- "bgcolor": "#533"
- },
- {
- "id": 32,
- "type": "TorchCompileModelWanVideoV2",
- "pos": [
- 2450,
- 840
- ],
- "size": [
- 380,
- 206
- ],
- "flags": {},
- "order": 37,
- "mode": 0,
- "inputs": [
- {
- "name": "model",
- "type": "MODEL",
- "link": 42
- }
- ],
- "outputs": [
- {
- "name": "MODEL",
- "type": "MODEL",
- "links": [
- 6,
- 483
- ]
- }
- ],
- "properties": {
- "cnr_id": "comfyui-kjnodes",
- "ver": "f7eb33abc80a2aded1b46dff0dd14d07856a7d50",
- "Node name for S&R": "TorchCompileModelWanVideoV2",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- "inductor",
- false,
- "default",
- false,
- true,
- 64,
- true
- ]
- },
- {
- "id": 5,
- "type": "FlowMatchSigmas",
- "pos": [
- 4140,
- 1190
- ],
- "size": [
- 278.73828125,
- 230
- ],
- "flags": {},
- "order": 41,
- "mode": 0,
- "inputs": [
- {
- "name": "MODEL",
- "type": "MODEL",
- "link": 3
- },
- {
- "name": "num_inference_steps",
+ "name": "steps",
"type": "INT",
"widget": {
- "name": "num_inference_steps"
+ "name": "steps"
},
- "link": 485
+ "link": 48
}
],
"outputs": [
{
- "name": "sigmas",
- "type": "SIGMAS",
+ "name": "float_list",
+ "type": "FLOAT",
"links": [
- 409
+ 53
]
}
],
"properties": {
- "aux_id": "BigStationW/flowmatch_scheduler-comfyui",
- "ver": "33b5bac24d40182aa519ef182ae3c5357f351d83",
- "Node name for S&R": "FlowMatchSigmas",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- 10,
- 10,
- 1,
- 1,
- 0,
- false,
- false,
- false
- ],
- "color": "#232",
- "bgcolor": "#353"
- },
- {
- "id": 37,
- "type": "CLIPTextEncode",
- "pos": [
- 1760,
- 960
- ],
- "size": [
- 422.84503173828125,
- 164.31304931640625
- ],
- "flags": {},
- "order": 25,
- "mode": 0,
- "inputs": [
- {
- "name": "clip",
- "type": "CLIP",
- "link": 476
- }
- ],
- "outputs": [
- {
- "name": "CONDITIONING",
- "type": "CONDITIONING",
- "slot_index": 0,
- "links": [
- 293
- ]
- }
- ],
- "title": "CLIP Text Encode (Positive Prompt)",
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.3.46",
- "Node name for S&R": "CLIPTextEncode",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- "A lively monkey energetically bounces on a neatly made bed, its limbs splayed in mid-air. As the monkey lands, the bed creases slightly under its weight, and it quickly prepares for another joyful leap, its eyes wide with excitement and mischief."
- ],
- "color": "#232",
- "bgcolor": "#353"
- },
- {
- "id": 65,
- "type": "LoadImage",
- "pos": [
- 600,
- 1090
- ],
- "size": [
- 269.1201171875,
- 420
- ],
- "flags": {},
- "order": 0,
- "mode": 0,
- "inputs": [],
- "outputs": [
- {
- "name": "IMAGE",
- "type": "IMAGE",
- "slot_index": 0,
- "links": [
- 86
- ]
- },
- {
- "name": "MASK",
- "type": "MASK",
- "slot_index": 1,
- "links": null
- }
- ],
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.3.46",
- "Node name for S&R": "LoadImage",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- "TimeToMove_Monkey-first_frame.png",
- "image"
- ]
- },
- {
- "id": 30,
- "type": "ImageResizeKJv2",
- "pos": [
- 890,
- 1090
- ],
- "size": [
- 270,
- 352.800048828125
- ],
- "flags": {},
- "order": 18,
- "mode": 0,
- "inputs": [
- {
- "name": "image",
- "type": "IMAGE",
- "link": 86
- },
- {
- "name": "mask",
- "shape": 7,
- "type": "MASK",
- "link": null
- }
- ],
- "outputs": [
- {
- "name": "IMAGE",
- "type": "IMAGE",
- "links": [
- 11,
- 375
- ]
- },
- {
- "name": "width",
- "type": "INT",
- "links": [
- 142,
- 161,
- 296
- ]
- },
- {
- "name": "height",
- "type": "INT",
- "links": [
- 143,
- 162,
- 297
- ]
- },
- {
- "name": "mask",
- "type": "MASK",
- "links": null
- }
- ],
- "properties": {
- "cnr_id": "comfyui-kjnodes",
- "ver": "5dcda71011870278c35d92ff77a677ed2e538f2d",
- "Node name for S&R": "ImageResizeKJv2",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- 1024,
- 576,
- "lanczos",
- "resize",
- "255, 255, 255",
- "center",
- 16,
- "cpu"
- ],
- "color": "#233",
- "bgcolor": "#355"
- },
- {
- "id": 14,
- "type": "PreviewImage",
- "pos": [
- 1190,
- 1090
- ],
- "size": [
- 270,
- 250.79999999999995
- ],
- "flags": {},
- "order": 23,
- "mode": 0,
- "inputs": [
- {
- "name": "images",
- "type": "IMAGE",
- "link": 11
- }
- ],
- "outputs": [],
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.3.50",
- "Node name for S&R": "PreviewImage",
+ "Node name for S&R": "CFGFloatListScheduler",
"ue_properties": {
"widget_ue_connectable": {},
- "version": "7.0.1"
- }
- },
- "widgets_values": []
- },
- {
- "id": 31,
- "type": "PatchModelPatcherOrder",
- "pos": [
- 2100,
- 830
- ],
- "size": [
- 310,
- 90
- ],
- "flags": {},
- "order": 30,
- "mode": 0,
- "inputs": [
- {
- "name": "model",
- "type": "MODEL",
- "link": 41
- }
- ],
- "outputs": [
- {
- "name": "MODEL",
- "type": "MODEL",
- "links": [
- 42
- ]
- }
- ],
- "properties": {
- "cnr_id": "comfyui-kjnodes",
- "ver": "f7eb33abc80a2aded1b46dff0dd14d07856a7d50",
- "Node name for S&R": "PatchModelPatcherOrder",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
}
},
"widgets_values": [
- "weight_patch_first",
- "disabled"
- ]
- },
- {
- "id": 12,
- "type": "ModelSamplingSD3",
- "pos": [
- 1820,
- 830
- ],
- "size": [
- 210,
- 62
- ],
- "flags": {},
- "order": 24,
- "mode": 0,
- "inputs": [
- {
- "name": "model",
- "type": "MODEL",
- "link": 478
- }
- ],
- "outputs": [
- {
- "name": "MODEL",
- "type": "MODEL",
- "slot_index": 0,
- "links": [
- 41
- ]
- }
- ],
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.3.34",
- "Node name for S&R": "ModelSamplingSD3",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- 8.000000000000002
- ]
- },
- {
- "id": 7,
- "type": "FlowMatchSigmas",
- "pos": [
- 2890,
- 1190
- ],
- "size": [
- 278.73828125,
- 230
- ],
- "flags": {},
- "order": 40,
- "mode": 0,
- "inputs": [
- {
- "name": "MODEL",
- "type": "MODEL",
- "link": 6
- },
- {
- "name": "num_inference_steps",
- "type": "INT",
- "widget": {
- "name": "num_inference_steps"
- },
- "link": 484
- }
- ],
- "outputs": [
- {
- "name": "sigmas",
- "type": "SIGMAS",
- "links": [
- 306
- ]
- }
- ],
- "properties": {
- "aux_id": "BigStationW/flowmatch_scheduler-comfyui",
- "ver": "33b5bac24d40182aa519ef182ae3c5357f351d83",
- "Node name for S&R": "FlowMatchSigmas",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- 10,
- 10,
- 1,
- 1,
+ 30,
+ 2,
+ 2,
+ "linear",
0,
- false,
- false,
- false
- ],
- "color": "#232",
- "bgcolor": "#353"
+ 0.1
+ ]
},
{
- "id": 92,
- "type": "ImageResizeKJv2",
+ "id": 13,
+ "type": "EncodeWanVideo",
"pos": [
- 1250,
- 1480
- ],
- "size": [
- 270,
- 352.800048828125
- ],
- "flags": {},
- "order": 28,
- "mode": 0,
- "inputs": [
- {
- "name": "image",
- "type": "IMAGE",
- "link": 404
- },
- {
- "name": "mask",
- "shape": 7,
- "type": "MASK",
- "link": null
- },
- {
- "name": "width",
- "type": "INT",
- "widget": {
- "name": "width"
- },
- "link": 161
- },
- {
- "name": "height",
- "type": "INT",
- "widget": {
- "name": "height"
- },
- "link": 162
- }
- ],
- "outputs": [
- {
- "name": "IMAGE",
- "type": "IMAGE",
- "links": [
- 457,
- 464
- ]
- },
- {
- "name": "width",
- "type": "INT",
- "links": []
- },
- {
- "name": "height",
- "type": "INT",
- "links": []
- },
- {
- "name": "mask",
- "type": "MASK",
- "links": null
- }
- ],
- "properties": {
- "cnr_id": "comfyui-kjnodes",
- "ver": "5dcda71011870278c35d92ff77a677ed2e538f2d",
- "Node name for S&R": "ImageResizeKJv2",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- 576,
- 1024,
- "lanczos",
- "stretch",
- "255, 255, 255",
- "center",
- 16,
- "cpu"
- ],
- "color": "#233",
- "bgcolor": "#355"
- },
- {
- "id": 165,
- "type": "WanVideoEncode",
- "pos": [
- 2280,
- 1430
+ 5600,
+ 1330
],
"size": [
249.06858825683594,
254
],
"flags": {},
- "order": 33,
+ "order": 28,
"mode": 0,
"inputs": [
{
"name": "vae",
"type": "VAE",
- "link": 455
+ "link": 13
},
{
"name": "image",
"type": "IMAGE",
- "link": 457
+ "link": 142
},
{
"name": "mask",
@@ -643,12 +91,12 @@
"name": "reference_latents",
"type": "LATENT",
"links": [
- 456
+ 23
]
}
],
"properties": {
- "Node name for S&R": "WanVideoEncode",
+ "Node name for S&R": "EncodeWanVideo",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
@@ -668,188 +116,80 @@
"bgcolor": "#535"
},
{
- "id": 169,
- "type": "VHS_VideoCombine",
+ "id": 21,
+ "type": "TTMLatentAdd",
"pos": [
- 1230,
- 1880
+ 5950,
+ 1050
],
"size": [
- 300,
- 551
- ],
- "flags": {},
- "order": 34,
- "mode": 0,
- "inputs": [
- {
- "name": "images",
- "type": "IMAGE",
- "link": 464
- },
- {
- "name": "audio",
- "shape": 7,
- "type": "AUDIO",
- "link": null
- },
- {
- "name": "meta_batch",
- "shape": 7,
- "type": "VHS_BatchManager",
- "link": null
- },
- {
- "name": "vae",
- "shape": 7,
- "type": "VAE",
- "link": null
- }
- ],
- "outputs": [
- {
- "name": "Filenames",
- "type": "VHS_FILENAMES",
- "links": null
- }
- ],
- "properties": {
- "cnr_id": "comfyui-videohelpersuite",
- "ver": "3234937ff5f3ca19068aaba5042771514de2429d",
- "Node name for S&R": "VHS_VideoCombine",
- "ue_properties": {
- "widget_ue_connectable": {},
- "input_ue_unconnectable": {},
- "version": "7.5.2"
- }
- },
- "widgets_values": {
- "frame_rate": 16,
- "loop_count": 0,
- "filename_prefix": "AnimateDiff",
- "format": "video/h264-mp4",
- "pix_fmt": "yuv420p",
- "crf": 13,
- "save_metadata": true,
- "trim_to_audio": false,
- "pingpong": false,
- "save_output": false,
- "videopreview": {
- "hidden": false,
- "paused": false,
- "params": {
- "filename": "AnimateDiff_00002.mp4",
- "subfolder": "",
- "type": "temp",
- "format": "video/h264-mp4",
- "frame_rate": 16,
- "workflow": "AnimateDiff_00002.png",
- "fullpath": "C:\\Users\\wgius\\Desktop\\GitHub\\ComfyUI\\ComfyUI\\temp\\AnimateDiff_00002.mp4"
- }
- }
- }
- },
- {
- "id": 170,
- "type": "VHS_VideoCombine",
- "pos": [
- 2230,
- 1830
- ],
- "size": [
- 290,
- 544
- ],
- "flags": {},
- "order": 36,
- "mode": 0,
- "inputs": [
- {
- "name": "images",
- "type": "IMAGE",
- "link": 465
- },
- {
- "name": "audio",
- "shape": 7,
- "type": "AUDIO",
- "link": null
- },
- {
- "name": "meta_batch",
- "shape": 7,
- "type": "VHS_BatchManager",
- "link": null
- },
- {
- "name": "vae",
- "shape": 7,
- "type": "VAE",
- "link": null
- }
- ],
- "outputs": [
- {
- "name": "Filenames",
- "type": "VHS_FILENAMES",
- "links": null
- }
- ],
- "properties": {
- "cnr_id": "comfyui-videohelpersuite",
- "ver": "3234937ff5f3ca19068aaba5042771514de2429d",
- "Node name for S&R": "VHS_VideoCombine",
- "ue_properties": {
- "widget_ue_connectable": {},
- "input_ue_unconnectable": {},
- "version": "7.5.2"
- }
- },
- "widgets_values": {
- "frame_rate": 16,
- "loop_count": 0,
- "filename_prefix": "AnimateDiff",
- "format": "video/h264-mp4",
- "pix_fmt": "yuv420p",
- "crf": 13,
- "save_metadata": true,
- "trim_to_audio": false,
- "pingpong": false,
- "save_output": false,
- "videopreview": {
- "hidden": false,
- "paused": false,
- "params": {
- "filename": "AnimateDiff_00001.mp4",
- "subfolder": "",
- "type": "temp",
- "format": "video/h264-mp4",
- "frame_rate": 16,
- "workflow": "AnimateDiff_00001.png",
- "fullpath": "C:\\Users\\wgius\\Desktop\\GitHub\\ComfyUI\\ComfyUI\\temp\\AnimateDiff_00001.mp4"
- }
- }
- }
- },
- {
- "id": 58,
- "type": "ImageToMask",
- "pos": [
- 2290,
- 1730
- ],
- "size": [
- 233.765234375,
- 62
+ 224.26475524902344,
+ 134
],
"flags": {},
"order": 35,
"mode": 0,
+ "inputs": [
+ {
+ "name": "latent",
+ "type": "LATENT",
+ "link": 22
+ },
+ {
+ "name": "reference_latents",
+ "type": "LATENT",
+ "link": 23
+ },
+ {
+ "name": "ref_masks",
+ "type": "MASK",
+ "link": 24
+ }
+ ],
+ "outputs": [
+ {
+ "name": "latent",
+ "type": "LATENT",
+ "links": [
+ 44,
+ 52
+ ]
+ }
+ ],
+ "properties": {
+ "Node name for S&R": "TTMLatentAdd",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ 0,
+ 3
+ ],
+ "color": "#323",
+ "bgcolor": "#535"
+ },
+ {
+ "id": 7,
+ "type": "ImageToMask",
+ "pos": [
+ 5620,
+ 1630
+ ],
+ "size": [
+ 233.765234375,
+ 62
+ ],
+ "flags": {},
+ "order": 29,
+ "mode": 0,
"inputs": [
{
"name": "image",
"type": "IMAGE",
- "link": 145
+ "link": 143
}
],
"outputs": [
@@ -857,7 +197,7 @@
"name": "MASK",
"type": "MASK",
"links": [
- 430
+ 24
]
}
],
@@ -876,639 +216,66 @@
]
},
{
- "id": 84,
- "type": "ImageResizeKJv2",
+ "id": 24,
+ "type": "INTConstant",
"pos": [
- 1900,
- 1730
+ 5970,
+ 1750
],
"size": [
- 270,
- 352.800048828125
+ 210,
+ 62
],
"flags": {},
- "order": 29,
+ "order": 0,
"mode": 0,
- "inputs": [
- {
- "name": "image",
- "type": "IMAGE",
- "link": 156
- },
- {
- "name": "mask",
- "shape": 7,
- "type": "MASK",
- "link": null
- },
- {
- "name": "width",
- "type": "INT",
- "widget": {
- "name": "width"
- },
- "link": 142
- },
- {
- "name": "height",
- "type": "INT",
- "widget": {
- "name": "height"
- },
- "link": 143
- }
- ],
+ "inputs": [],
"outputs": [
{
- "name": "IMAGE",
- "type": "IMAGE",
+ "name": "value",
+ "type": "INT",
"links": [
- 145,
- 465
+ 46,
+ 130
]
- },
- {
- "name": "width",
- "type": "INT",
- "links": []
- },
- {
- "name": "height",
- "type": "INT",
- "links": []
- },
- {
- "name": "mask",
- "type": "MASK",
- "links": null
}
],
+ "title": "Refiner step",
"properties": {
"cnr_id": "comfyui-kjnodes",
- "ver": "5dcda71011870278c35d92ff77a677ed2e538f2d",
- "Node name for S&R": "ImageResizeKJv2",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- 576,
- 1024,
- "lanczos",
- "stretch",
- "255, 255, 255",
- "center",
- 16,
- "cpu"
- ],
- "color": "#233",
- "bgcolor": "#355"
- },
- {
- "id": 154,
- "type": "AddTTMLatent",
- "pos": [
- 2590,
- 1410
- ],
- "size": [
- 230,
- 134
- ],
- "flags": {},
- "order": 39,
- "mode": 0,
- "inputs": [
- {
- "name": "latent",
- "type": "LATENT",
- "link": 428
- },
- {
- "name": "reference_latents",
- "type": "LATENT",
- "link": 456
- },
- {
- "name": "ref_masks",
- "type": "MASK",
- "link": 430
- }
- ],
- "outputs": [
- {
- "name": "latent",
- "type": "LATENT",
- "links": [
- 432,
- 462
- ]
- }
- ],
- "properties": {
- "Node name for S&R": "AddTTMLatent",
+ "ver": "a6b867b63a29ca48ddb15c589e17a9f2d8530d57",
+ "Node name for S&R": "INTConstant",
"ue_properties": {
"widget_ue_connectable": {},
- "input_ue_unconnectable": {},
- "version": "7.5.2"
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
}
},
"widgets_values": [
- 0,
- 2
+ 4
],
- "color": "#323",
- "bgcolor": "#535"
+ "color": "#1b4669",
+ "bgcolor": "#29699c"
},
{
- "id": 13,
- "type": "MarkdownNote",
- "pos": [
- 3280,
- 850
- ],
- "size": [
- 320,
- 92
- ],
- "flags": {},
- "order": 1,
- "mode": 0,
- "inputs": [],
- "outputs": [],
- "title": "Prompts",
- "properties": {
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- "### Wan 2.2 First-Last frames Time2Move 6 steps"
- ],
- "color": "#432",
- "bgcolor": "#653"
- },
- {
- "id": 15,
- "type": "VAELoader",
- "pos": [
- 1860,
- 1320
- ],
- "size": [
- 310,
- 62
- ],
- "flags": {},
- "order": 2,
- "mode": 0,
- "inputs": [],
- "outputs": [
- {
- "name": "VAE",
- "type": "VAE",
- "slot_index": 0,
- "links": [
- 298,
- 308,
- 455
- ]
- }
- ],
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.3.46",
- "Node name for S&R": "VAELoader",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- "wan_2.1_vae.safetensors"
- ],
- "color": "#223",
- "bgcolor": "#335"
- },
- {
- "id": 174,
- "type": "TrimVideoLatent",
- "pos": [
- 4880,
- 1120
- ],
- "size": [
- 210,
- 62
- ],
- "flags": {},
- "order": 45,
- "mode": 0,
- "inputs": [
- {
- "name": "samples",
- "type": "LATENT",
- "link": 466
- }
- ],
- "outputs": [
- {
- "name": "LATENT",
- "type": "LATENT",
- "links": [
- 467
- ]
- }
- ],
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.5.1",
- "Node name for S&R": "TrimVideoLatent",
- "ue_properties": {
- "widget_ue_connectable": {},
- "input_ue_unconnectable": {},
- "version": "7.5.2"
- }
- },
- "widgets_values": [
- 1
- ],
- "color": "#323",
- "bgcolor": "#535"
- },
- {
- "id": 175,
- "type": "VHS_VideoCombine",
- "pos": [
- 5120,
- 790
- ],
- "size": [
- 420,
- 631
- ],
- "flags": {},
- "order": 47,
- "mode": 0,
- "inputs": [
- {
- "name": "images",
- "type": "IMAGE",
- "link": 470
- },
- {
- "name": "audio",
- "shape": 7,
- "type": "AUDIO",
- "link": null
- },
- {
- "name": "meta_batch",
- "shape": 7,
- "type": "VHS_BatchManager",
- "link": null
- },
- {
- "name": "vae",
- "shape": 7,
- "type": "VAE",
- "link": null
- }
- ],
- "outputs": [
- {
- "name": "Filenames",
- "type": "VHS_FILENAMES",
- "links": null
- }
- ],
- "properties": {
- "cnr_id": "comfyui-videohelpersuite",
- "ver": "330bce6c3c0d47ebdedcc0348d9ab355707b7523",
- "Node name for S&R": "VHS_VideoCombine",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": {
- "frame_rate": 24,
- "loop_count": 0,
- "filename_prefix": "Wan2.2",
- "format": "video/h264-mp4",
- "pix_fmt": "yuv420p",
- "crf": 13,
- "save_metadata": true,
- "trim_to_audio": false,
- "pingpong": false,
- "save_output": false,
- "videopreview": {
- "hidden": false,
- "paused": false,
- "params": {
- "filename": "Wan2.2_00003.mp4",
- "subfolder": "",
- "type": "temp",
- "format": "video/h264-mp4",
- "frame_rate": 24,
- "workflow": "Wan2.2_00003.png",
- "fullpath": "C:\\Users\\wgius\\Desktop\\GitHub\\ComfyUI\\ComfyUI\\temp\\Wan2.2_00003.mp4"
- }
- }
- }
- },
- {
- "id": 20,
- "type": "UnetLoaderGGUF",
- "pos": [
- 990,
- 820
- ],
- "size": [
- 340,
- 62
- ],
- "flags": {},
- "order": 3,
- "mode": 0,
- "inputs": [],
- "outputs": [
- {
- "name": "MODEL",
- "type": "MODEL",
- "links": [
- 474
- ]
- }
- ],
- "properties": {
- "cnr_id": "ComfyUI-GGUF",
- "ver": "a2b75978fd50c0227a58316619b79d525b88e570",
- "Node name for S&R": "UnetLoaderGGUF",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- "wan2.2_i2v_high_noise_14B_Q6_K.gguf"
- ],
- "color": "#223",
- "bgcolor": "#335"
- },
- {
- "id": 18,
- "type": "ClipLoaderGGUF",
- "pos": [
- 990,
- 930
- ],
- "size": [
- 340,
- 110
- ],
- "flags": {},
- "order": 4,
- "mode": 0,
- "inputs": [],
- "outputs": [
- {
- "name": "CLIP",
- "type": "CLIP",
- "links": [
- 475
- ]
- }
- ],
- "properties": {
- "cnr_id": "gguf",
- "ver": "fc4b77e925741caef57f7200b963653a3fab7ed0",
- "Node name for S&R": "ClipLoaderGGUF",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- "umt5-xxl-encoder-Q8_0.gguf",
- "wan",
- "default"
- ],
- "color": "#223",
- "bgcolor": "#335"
- },
- {
- "id": 182,
- "type": "LoraLoader",
- "pos": [
- 1380,
- 850
- ],
- "size": [
- 330,
- 134
- ],
- "flags": {},
- "order": 19,
- "mode": 0,
- "inputs": [
- {
- "name": "model",
- "type": "MODEL",
- "link": 474
- },
- {
- "name": "clip",
- "type": "CLIP",
- "link": 475
- }
- ],
- "outputs": [
- {
- "name": "MODEL",
- "type": "MODEL",
- "links": [
- 478
- ]
- },
- {
- "name": "CLIP",
- "type": "CLIP",
- "links": [
- 476,
- 477
- ]
- }
- ],
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.5.1",
- "Node name for S&R": "LoraLoader",
- "ue_properties": {
- "widget_ue_connectable": {},
- "input_ue_unconnectable": {},
- "version": "7.5.2"
- }
- },
- "widgets_values": [
- "Wan\\lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
- 5.6,
- 1
- ],
- "color": "#223",
- "bgcolor": "#335"
- },
- {
- "id": 21,
- "type": "UnetLoaderGGUF",
- "pos": [
- 3330,
- 710
- ],
- "size": [
- 340,
- 62
- ],
- "flags": {},
- "order": 5,
- "mode": 0,
- "inputs": [],
- "outputs": [
- {
- "name": "MODEL",
- "type": "MODEL",
- "links": [
- 480
- ]
- }
- ],
- "properties": {
- "cnr_id": "ComfyUI-GGUF",
- "ver": "a2b75978fd50c0227a58316619b79d525b88e570",
- "Node name for S&R": "UnetLoaderGGUF",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- "wan2.2_i2v_low_noise_14B_Q6_K.gguf"
- ],
- "color": "#223",
- "bgcolor": "#335"
- },
- {
- "id": 184,
- "type": "LoraLoaderModelOnly",
- "pos": [
- 3700,
- 710
- ],
- "size": [
- 340,
- 86
- ],
- "flags": {},
- "order": 20,
- "mode": 0,
- "inputs": [
- {
- "name": "model",
- "type": "MODEL",
- "link": 480
- }
- ],
- "outputs": [
- {
- "name": "MODEL",
- "type": "MODEL",
- "links": [
- 481
- ]
- }
- ],
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.5.1",
- "Node name for S&R": "LoraLoaderModelOnly",
- "ue_properties": {
- "widget_ue_connectable": {},
- "input_ue_unconnectable": {},
- "version": "7.5.2"
- }
- },
- "widgets_values": [
- "Wan\\lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
- 2
- ],
- "color": "#223",
- "bgcolor": "#335"
- },
- {
- "id": 10,
- "type": "ModelSamplingSD3",
- "pos": [
- 3830,
- 840
- ],
- "size": [
- 210,
- 62
- ],
- "flags": {},
- "order": 27,
- "mode": 0,
- "inputs": [
- {
- "name": "model",
- "type": "MODEL",
- "link": 481
- }
- ],
- "outputs": [
- {
- "name": "MODEL",
- "type": "MODEL",
- "slot_index": 0,
- "links": [
- 9
- ]
- }
- ],
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.3.34",
- "Node name for S&R": "ModelSamplingSD3",
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- 8.000000000000002
- ]
- },
- {
- "id": 11,
+ "id": 1,
"type": "PatchModelPatcherOrder",
"pos": [
- 3740,
- 950
+ 5120,
+ 520
],
"size": [
310,
90
],
"flags": {},
- "order": 32,
+ "order": 31,
"mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
- "link": 9
+ "link": 1
}
],
"outputs": [
@@ -1526,7 +293,8 @@
"Node name for S&R": "PatchModelPatcherOrder",
"ue_properties": {
"version": "7.0.1",
- "widget_ue_connectable": {}
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
}
},
"widgets_values": [
@@ -1535,24 +303,175 @@
]
},
{
- "id": 6,
- "type": "TorchCompileModelWanVideoV2",
+ "id": 5,
+ "type": "ModelSamplingSD3",
"pos": [
- 3710,
- 1080
+ 4870,
+ 520
],
"size": [
- 380,
- 206
+ 210,
+ 62
+ ],
+ "flags": {},
+ "order": 25,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 79
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "slot_index": 0,
+ "links": [
+ 1
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.34",
+ "Node name for S&R": "ModelSamplingSD3",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ 8.000000000000002
+ ]
+ },
+ {
+ "id": 23,
+ "type": "FlowMatchSigmas",
+ "pos": [
+ 5930,
+ 1470
+ ],
+ "size": [
+ 250,
+ 230
],
"flags": {},
"order": 38,
"mode": 0,
+ "inputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "link": 78
+ },
+ {
+ "name": "num_inference_steps",
+ "type": "INT",
+ "widget": {
+ "name": "num_inference_steps"
+ },
+ "link": 26
+ }
+ ],
+ "outputs": [
+ {
+ "name": "sigmas",
+ "type": "SIGMAS",
+ "links": [
+ 45
+ ]
+ }
+ ],
+ "properties": {
+ "aux_id": "BigStationW/flowmatch_scheduler-comfyui",
+ "ver": "33b5bac24d40182aa519ef182ae3c5357f351d83",
+ "Node name for S&R": "FlowMatchSigmas",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ 6,
+ 8,
+ 1,
+ 1,
+ 0,
+ false,
+ false,
+ false
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 51,
+ "type": "ModelSamplingSD3",
+ "pos": [
+ 6970,
+ 780
+ ],
+ "size": [
+ 210,
+ 62
+ ],
+ "flags": {},
+ "order": 24,
+ "mode": 0,
"inputs": [
{
"name": "model",
"type": "MODEL",
- "link": 5
+ "link": 85
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "slot_index": 0,
+ "links": [
+ 83
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.34",
+ "Node name for S&R": "ModelSamplingSD3",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ 8.000000000000002
+ ]
+ },
+ {
+ "id": 43,
+ "type": "LoraLoaderModelOnly",
+ "pos": [
+ 6970,
+ 630
+ ],
+ "size": [
+ 310,
+ 86
+ ],
+ "flags": {},
+ "order": 18,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 82
}
],
"outputs": [
@@ -1560,8 +479,274 @@
"name": "MODEL",
"type": "MODEL",
"links": [
- 3,
- 482
+ 85
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "LoraLoaderModelOnly",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "Wan\\lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
+ 2
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
+ },
+ {
+ "id": 49,
+ "type": "UnetLoaderGGUF",
+ "pos": [
+ 6960,
+ 510
+ ],
+ "size": [
+ 340,
+ 62
+ ],
+ "flags": {},
+ "order": 1,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 82
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "ComfyUI-GGUF",
+ "ver": "a2b75978fd50c0227a58316619b79d525b88e570",
+ "Node name for S&R": "UnetLoaderGGUF",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "wan2.2_i2v_low_noise_14B_Q6_K.gguf"
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
+ },
+ {
+ "id": 52,
+ "type": "PatchModelPatcherOrder",
+ "pos": [
+ 6970,
+ 900
+ ],
+ "size": [
+ 310,
+ 90
+ ],
+ "flags": {},
+ "order": 30,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 83
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 84
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfyui-kjnodes",
+ "ver": "f7eb33abc80a2aded1b46dff0dd14d07856a7d50",
+ "Node name for S&R": "PatchModelPatcherOrder",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "weight_patch_first",
+ "disabled"
+ ]
+ },
+ {
+ "id": 17,
+ "type": "CLIPTextEncode",
+ "pos": [
+ 5020,
+ 990
+ ],
+ "size": [
+ 410,
+ 110
+ ],
+ "flags": {},
+ "order": 27,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "clip",
+ "type": "CLIP",
+ "link": 81
+ }
+ ],
+ "outputs": [
+ {
+ "name": "CONDITIONING",
+ "type": "CONDITIONING",
+ "links": [
+ 57
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.49",
+ "Node name for S&R": "CLIPTextEncode",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {
+ "text": true
+ },
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走"
+ ],
+ "color": "#322",
+ "bgcolor": "#533"
+ },
+ {
+ "id": 19,
+ "type": "INTConstant",
+ "pos": [
+ 5650,
+ 1750
+ ],
+ "size": [
+ 210,
+ 62
+ ],
+ "flags": {},
+ "order": 2,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "value",
+ "type": "INT",
+ "links": [
+ 26,
+ 48,
+ 103
+ ]
+ }
+ ],
+ "title": "Steps",
+ "properties": {
+ "cnr_id": "comfyui-kjnodes",
+ "ver": "a6b867b63a29ca48ddb15c589e17a9f2d8530d57",
+ "Node name for S&R": "INTConstant",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ 6
+ ],
+ "color": "#1b4669",
+ "bgcolor": "#29699c"
+ },
+ {
+ "id": 34,
+ "type": "RandomNoise",
+ "pos": [
+ 6220,
+ 800
+ ],
+ "size": [
+ 210,
+ 86
+ ],
+ "flags": {
+ "collapsed": false
+ },
+ "order": 3,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "NOISE",
+ "type": "NOISE",
+ "links": [
+ 40
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "RandomNoise",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ 287744432595674,
+ "fixed"
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 53,
+ "type": "TorchCompileModelWanVideoV2",
+ "pos": [
+ 7300,
+ 890
+ ],
+ "size": [
+ 380,
+ 206
+ ],
+ "flags": {},
+ "order": 33,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 84
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 123,
+ 136
]
}
],
@@ -1571,7 +756,8 @@
"Node name for S&R": "TorchCompileModelWanVideoV2",
"ue_properties": {
"version": "7.0.1",
- "widget_ue_connectable": {}
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
}
},
"widgets_values": [
@@ -1585,102 +771,705 @@
]
},
{
- "id": 186,
- "type": "MarkdownNote",
+ "id": 33,
+ "type": "SplitSigmas",
"pos": [
- 2550,
- 1590
+ 6240,
+ 1240
+ ],
+ "size": [
+ 210,
+ 86
+ ],
+ "flags": {},
+ "order": 41,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "sigmas",
+ "type": "SIGMAS",
+ "link": 45
+ },
+ {
+ "name": "step",
+ "type": "INT",
+ "widget": {
+ "name": "step"
+ },
+ "link": 46
+ }
+ ],
+ "outputs": [
+ {
+ "name": "high_sigmas",
+ "type": "SIGMAS",
+ "links": [
+ 43
+ ]
+ },
+ {
+ "name": "low_sigmas",
+ "type": "SIGMAS",
+ "links": []
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "SplitSigmas",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ 4
+ ]
+ },
+ {
+ "id": 54,
+ "type": "FlowMatchSigmas",
+ "pos": [
+ 7710,
+ 1030
+ ],
+ "size": [
+ 250,
+ 230
+ ],
+ "flags": {},
+ "order": 36,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "link": 123
+ },
+ {
+ "name": "num_inference_steps",
+ "type": "INT",
+ "widget": {
+ "name": "num_inference_steps"
+ },
+ "link": 103
+ }
+ ],
+ "outputs": [
+ {
+ "name": "sigmas",
+ "type": "SIGMAS",
+ "links": [
+ 131
+ ]
+ }
+ ],
+ "properties": {
+ "aux_id": "BigStationW/flowmatch_scheduler-comfyui",
+ "ver": "33b5bac24d40182aa519ef182ae3c5357f351d83",
+ "Node name for S&R": "FlowMatchSigmas",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ 6,
+ 8,
+ 1,
+ 1,
+ 0,
+ false,
+ false,
+ false
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 74,
+ "type": "SplitSigmas",
+ "pos": [
+ 7750,
+ 1310
+ ],
+ "size": [
+ 210,
+ 86
+ ],
+ "flags": {},
+ "order": 40,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "sigmas",
+ "type": "SIGMAS",
+ "link": 131
+ },
+ {
+ "name": "step",
+ "type": "INT",
+ "widget": {
+ "name": "step"
+ },
+ "link": 130
+ }
+ ],
+ "outputs": [
+ {
+ "name": "high_sigmas",
+ "type": "SIGMAS",
+ "links": []
+ },
+ {
+ "name": "low_sigmas",
+ "type": "SIGMAS",
+ "links": [
+ 132
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "SplitSigmas",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ 4
+ ]
+ },
+ {
+ "id": 73,
+ "type": "VAEDecode",
+ "pos": [
+ 8340,
+ 880
+ ],
+ "size": [
+ 150.248046875,
+ 54
+ ],
+ "flags": {},
+ "order": 45,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "samples",
+ "type": "LATENT",
+ "link": 127
+ },
+ {
+ "name": "vae",
+ "type": "VAE",
+ "link": 126
+ }
+ ],
+ "outputs": [
+ {
+ "name": "IMAGE",
+ "type": "IMAGE",
+ "links": [
+ 128
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "VAEDecode",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [],
+ "color": "#323",
+ "bgcolor": "#535"
+ },
+ {
+ "id": 64,
+ "type": "SaveAnimatedWEBP",
+ "pos": [
+ 8520,
+ 820
+ ],
+ "size": [
+ 320,
+ 158
+ ],
+ "flags": {},
+ "order": 47,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "images",
+ "type": "IMAGE",
+ "link": 128
+ }
+ ],
+ "outputs": [],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "SaveAnimatedWEBP",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "ComfyUI",
+ 24,
+ true,
+ 80,
+ "default"
+ ]
+ },
+ {
+ "id": 72,
+ "type": "CFGGuider",
+ "pos": [
+ 7740,
+ 880
+ ],
+ "size": [
+ 210,
+ 110
+ ],
+ "flags": {},
+ "order": 37,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 136
+ },
+ {
+ "name": "positive",
+ "type": "CONDITIONING",
+ "link": 135
+ },
+ {
+ "name": "negative",
+ "type": "CONDITIONING",
+ "link": 120
+ }
+ ],
+ "outputs": [
+ {
+ "name": "GUIDER",
+ "type": "GUIDER",
+ "links": [
+ 121
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "CFGGuider",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ 1
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 42,
+ "type": "LoraLoader",
+ "pos": [
+ 4520,
+ 520
+ ],
+ "size": [
+ 320,
+ 134
+ ],
+ "flags": {},
+ "order": 20,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 75
+ },
+ {
+ "name": "clip",
+ "type": "CLIP",
+ "link": 76
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 79
+ ]
+ },
+ {
+ "name": "CLIP",
+ "type": "CLIP",
+ "links": [
+ 80,
+ 81
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "LoraLoader",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "Wan\\lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
+ 5.6,
+ 1
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
+ },
+ {
+ "id": 16,
+ "type": "CLIPTextEncode",
+ "pos": [
+ 5010,
+ 780
+ ],
+ "size": [
+ 422.84503173828125,
+ 164.31304931640625
+ ],
+ "flags": {},
+ "order": 26,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "clip",
+ "type": "CLIP",
+ "link": 80
+ }
+ ],
+ "outputs": [
+ {
+ "name": "CONDITIONING",
+ "type": "CONDITIONING",
+ "slot_index": 0,
+ "links": [
+ 56
+ ]
+ }
+ ],
+ "title": "CLIP Text Encode (Positive Prompt)",
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.46",
+ "Node name for S&R": "CLIPTextEncode",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "A lively monkey energetically bounces on a neatly made bed, its limbs splayed in mid-air. As the monkey lands, the bed creases slightly under its weight, and it quickly prepares for another joyful leap, its eyes wide with excitement and mischief."
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 4,
+ "type": "UnetLoaderGGUF",
+ "pos": [
+ 4160,
+ 510
+ ],
+ "size": [
+ 340,
+ 62
+ ],
+ "flags": {},
+ "order": 4,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 75
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "ComfyUI-GGUF",
+ "ver": "a2b75978fd50c0227a58316619b79d525b88e570",
+ "Node name for S&R": "UnetLoaderGGUF",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "wan2.2_i2v_high_noise_14B_Q6_K.gguf"
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
+ },
+ {
+ "id": 3,
+ "type": "ClipLoaderGGUF",
+ "pos": [
+ 4160,
+ 620
+ ],
+ "size": [
+ 340,
+ 110
+ ],
+ "flags": {},
+ "order": 5,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "CLIP",
+ "type": "CLIP",
+ "links": [
+ 76
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "gguf",
+ "ver": "fc4b77e925741caef57f7200b963653a3fab7ed0",
+ "Node name for S&R": "ClipLoaderGGUF",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "umt5-xxl-encoder-Q8_0.gguf",
+ "wan",
+ "default"
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
+ },
+ {
+ "id": 57,
+ "type": "GetImageSize",
+ "pos": [
+ 5330,
+ 1210
+ ],
+ "size": [
+ 158.0615234375,
+ 80
+ ],
+ "flags": {},
+ "order": 21,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "image",
+ "type": "IMAGE",
+ "link": 95
+ }
+ ],
+ "outputs": [
+ {
+ "name": "width",
+ "type": "INT",
+ "links": [
+ 96
+ ]
+ },
+ {
+ "name": "height",
+ "type": "INT",
+ "links": [
+ 97
+ ]
+ },
+ {
+ "name": "batch_size",
+ "type": "INT",
+ "links": null
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "GetImageSize",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": []
+ },
+ {
+ "id": 11,
+ "type": "LoadImage",
+ "pos": [
+ 4970,
+ 1200
],
"size": [
310,
- 110
+ 334
],
"flags": {},
"order": 6,
"mode": 0,
"inputs": [],
- "outputs": [],
- "title": "Prompts",
+ "outputs": [
+ {
+ "name": "IMAGE",
+ "type": "IMAGE",
+ "slot_index": 0,
+ "links": [
+ 95,
+ 102
+ ]
+ },
+ {
+ "name": "MASK",
+ "type": "MASK",
+ "slot_index": 1,
+ "links": null
+ }
+ ],
"properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.46",
+ "Node name for S&R": "LoadImage",
"ue_properties": {
"version": "7.0.1",
- "widget_ue_connectable": {}
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
}
},
"widgets_values": [
- "### The ttm code is based on kijai wanvideo wrapper"
- ],
- "color": "#432",
- "bgcolor": "#653"
+ "TimeToMove_Monkey-first_frame.png",
+ "image"
+ ]
},
{
- "id": 161,
- "type": "MarkdownNote",
+ "id": 58,
+ "type": "LoadVideo",
"pos": [
- 2880,
- 930
+ 4720,
+ 1580
],
"size": [
- 300,
- 110
+ 400,
+ 503.5259399414063
],
"flags": {},
"order": 7,
"mode": 0,
"inputs": [],
- "outputs": [],
- "title": "Prompts",
+ "outputs": [
+ {
+ "name": "VIDEO",
+ "type": "VIDEO",
+ "links": [
+ 104
+ ]
+ }
+ ],
"properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "LoadVideo",
"ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
}
},
"widgets_values": [
- "### Still WIP: at the moment I added TTM support to lcm sampler only"
- ],
- "color": "#432",
- "bgcolor": "#653"
+ "TimeToMove_Monkey-Motion_signal (1).mp4",
+ "image"
+ ]
},
{
- "id": 173,
- "type": "MarkdownNote",
+ "id": 59,
+ "type": "LoadVideo",
"pos": [
- 3960,
- 1470
+ 5130,
+ 1650
],
"size": [
- 470,
- 140
+ 400,
+ 503.5259399414063
],
"flags": {},
"order": 8,
"mode": 0,
"inputs": [],
- "outputs": [],
- "title": "Prompts",
+ "outputs": [
+ {
+ "name": "VIDEO",
+ "type": "VIDEO",
+ "links": [
+ 105
+ ]
+ }
+ ],
"properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "LoadVideo",
"ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
}
},
"widgets_values": [
- "### The scheduler I'm passing is made for the models using lightx loras (https://github.com/BigStationW/flowmatch_scheduler-comfyui)."
- ],
- "color": "#432",
- "bgcolor": "#653"
+ "TimeToMove_Monkey-Mask (1).mp4",
+ "image"
+ ]
},
{
- "id": 188,
- "type": "PrimitiveInt",
+ "id": 31,
+ "type": "VAELoader",
"pos": [
- 2600,
- 1280
+ 5210,
+ 670
],
"size": [
210,
- 86
+ 62
],
"flags": {},
"order": 9,
@@ -1688,652 +1477,236 @@
"inputs": [],
"outputs": [
{
- "name": "INT",
- "type": "INT",
- "links": [
- 486,
- 487
- ]
- }
- ],
- "title": "Start Refiner Step",
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.5.1",
- "Node name for S&R": "PrimitiveInt",
- "ue_properties": {
- "widget_ue_connectable": {},
- "input_ue_unconnectable": {},
- "version": "7.5.2"
- }
- },
- "widgets_values": [
- 4,
- "fixed"
- ],
- "color": "#232",
- "bgcolor": "#353"
- },
- {
- "id": 88,
- "type": "VHS_LoadVideo",
- "pos": [
- 1590,
- 1730
- ],
- "size": [
- 288.1431640625,
- 519.0956207730877
- ],
- "flags": {},
- "order": 22,
- "mode": 0,
- "inputs": [
- {
- "name": "meta_batch",
- "shape": 7,
- "type": "VHS_BatchManager",
- "link": null
- },
- {
- "name": "vae",
- "shape": 7,
+ "name": "VAE",
"type": "VAE",
- "link": null
- },
- {
- "name": "frame_load_cap",
- "type": "INT",
- "widget": {
- "name": "frame_load_cap"
- },
- "link": 490
- }
- ],
- "outputs": [
- {
- "name": "IMAGE",
- "type": "IMAGE",
"links": [
- 156
+ 13,
+ 58,
+ 90,
+ 126
]
- },
- {
- "name": "frame_count",
- "type": "INT",
- "links": null
- },
- {
- "name": "audio",
- "type": "AUDIO",
- "links": null
- },
- {
- "name": "video_info",
- "type": "VHS_VIDEOINFO",
- "links": null
}
],
"properties": {
- "cnr_id": "comfyui-videohelpersuite",
- "ver": "537f3a02269e14ab4b0350d4189a52034e9a3b12",
- "Node name for S&R": "VHS_LoadVideo",
+ "cnr_id": "comfy-core",
+ "ver": "0.7.0",
+ "Node name for S&R": "VAELoader",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
"version": "7.5.2"
}
},
- "widgets_values": {
- "video": "TimeToMove_Monkey-Mask (1).mp4",
- "force_rate": 0,
- "custom_width": 0,
- "custom_height": 0,
- "frame_load_cap": 81,
- "skip_first_frames": 0,
- "select_every_nth": 1,
- "format": "AnimateDiff",
- "videopreview": {
- "hidden": false,
- "paused": false,
- "params": {
- "filename": "TimeToMove_Monkey-Mask (1).mp4",
- "type": "input",
- "format": "video/mp4",
- "force_rate": 0,
- "custom_width": 0,
- "custom_height": 0,
- "frame_load_cap": 81,
- "skip_first_frames": 0,
- "select_every_nth": 1
- }
- }
- }
+ "widgets_values": [
+ "wan_2.1_vae.safetensors"
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
},
{
- "id": 90,
- "type": "VHS_LoadVideo",
+ "id": 32,
+ "type": "SamplerCustomAdvanced",
"pos": [
- 900,
- 1540
+ 6490,
+ 1040
],
"size": [
- 288.1431640625,
- 519.0956207730877
+ 272.62757873535156,
+ 126
],
"flags": {},
- "order": 21,
+ "order": 42,
"mode": 0,
"inputs": [
{
- "name": "meta_batch",
- "shape": 7,
- "type": "VHS_BatchManager",
- "link": null
+ "name": "noise",
+ "type": "NOISE",
+ "link": 40
},
{
- "name": "vae",
- "shape": 7,
- "type": "VAE",
- "link": null
- },
- {
- "name": "frame_load_cap",
- "type": "INT",
- "widget": {
- "name": "frame_load_cap"
- },
- "link": 489
- }
- ],
- "outputs": [
- {
- "name": "IMAGE",
- "type": "IMAGE",
- "links": [
- 404
- ]
- },
- {
- "name": "frame_count",
- "type": "INT",
- "links": null
- },
- {
- "name": "audio",
- "type": "AUDIO",
- "links": null
- },
- {
- "name": "video_info",
- "type": "VHS_VIDEOINFO",
- "links": null
- }
- ],
- "properties": {
- "cnr_id": "comfyui-videohelpersuite",
- "ver": "537f3a02269e14ab4b0350d4189a52034e9a3b12",
- "Node name for S&R": "VHS_LoadVideo",
- "ue_properties": {
- "widget_ue_connectable": {},
- "input_ue_unconnectable": {},
- "version": "7.5.2"
- }
- },
- "widgets_values": {
- "video": "TimeToMove_Monkey-Motion_signal (1).mp4",
- "force_rate": 0,
- "custom_width": 0,
- "custom_height": 0,
- "frame_load_cap": 81,
- "skip_first_frames": 0,
- "select_every_nth": 1,
- "format": "AnimateDiff",
- "videopreview": {
- "hidden": false,
- "paused": false,
- "params": {
- "filename": "TimeToMove_Monkey-Motion_signal (1).mp4",
- "type": "input",
- "format": "video/mp4",
- "force_rate": 0,
- "custom_width": 0,
- "custom_height": 0,
- "frame_load_cap": 81,
- "skip_first_frames": 0,
- "select_every_nth": 1
- }
- }
- }
- },
- {
- "id": 187,
- "type": "PrimitiveInt",
- "pos": [
- 2600,
- 1150
- ],
- "size": [
- 210,
- 86
- ],
- "flags": {},
- "order": 10,
- "mode": 0,
- "inputs": [],
- "outputs": [
- {
- "name": "INT",
- "type": "INT",
- "links": [
- 484,
- 485
- ]
- }
- ],
- "title": "Steps",
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.5.1",
- "Node name for S&R": "PrimitiveInt",
- "ue_properties": {
- "widget_ue_connectable": {},
- "input_ue_unconnectable": {},
- "version": "7.5.2"
- }
- },
- "widgets_values": [
- 6,
- "fixed"
- ],
- "color": "#232",
- "bgcolor": "#353"
- },
- {
- "id": 189,
- "type": "PrimitiveInt",
- "pos": [
- 660,
- 1560
- ],
- "size": [
- 210,
- 86
- ],
- "flags": {},
- "order": 11,
- "mode": 0,
- "inputs": [],
- "outputs": [
- {
- "name": "INT",
- "type": "INT",
- "links": [
- 488,
- 489,
- 490
- ]
- }
- ],
- "title": "Num frames",
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.5.1",
- "Node name for S&R": "PrimitiveInt",
- "ue_properties": {
- "widget_ue_connectable": {},
- "input_ue_unconnectable": {},
- "version": "7.5.2"
- }
- },
- "widgets_values": [
- 81,
- "fixed"
- ],
- "color": "#232",
- "bgcolor": "#353"
- },
- {
- "id": 24,
- "type": "Seed (rgthree)",
- "pos": [
- 2930,
- 1480
- ],
- "size": [
- 230,
- 134
- ],
- "flags": {},
- "order": 12,
- "mode": 0,
- "inputs": [],
- "outputs": [
- {
- "dir": 4,
- "name": "SEED",
- "shape": 3,
- "type": "INT",
- "links": [
- 309,
- 416
- ]
- }
- ],
- "properties": {
- "cnr_id": "rgthree-comfy",
- "ver": "944d5353a1b0a668f40844018c3dc956b95a67d7",
- "randomMax": 1125899906842624,
- "randomMin": 0,
- "ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- -1,
- "",
- "",
- ""
- ],
- "color": "#232",
- "bgcolor": "#353"
- },
- {
- "id": 123,
- "type": "WanVideoSamplerCustomUltraAdvancedEfficient",
- "pos": [
- 3210,
- 1000
- ],
- "size": [
- 470.1861328125,
- 984.1240885416667
- ],
- "flags": {},
- "order": 43,
- "mode": 0,
- "inputs": [
- {
- "name": "model",
- "type": "MODEL",
- "link": 483
- },
- {
- "name": "positive",
- "type": "CONDITIONING",
- "link": 303
- },
- {
- "name": "negative",
- "type": "CONDITIONING",
- "link": 304
+ "name": "guider",
+ "type": "GUIDER",
+ "link": 41
},
{
"name": "sampler",
"type": "SAMPLER",
- "link": 463
+ "link": 42
},
{
"name": "sigmas",
"type": "SIGMAS",
- "link": 306
+ "link": 43
},
{
- "name": "latent",
+ "name": "latent_image",
"type": "LATENT",
- "link": 462
- },
- {
- "name": "optional_vae",
- "shape": 7,
- "type": "VAE",
- "link": 308
- },
- {
- "name": "noise_seed",
- "type": "INT",
- "widget": {
- "name": "noise_seed"
- },
- "link": 309
- },
- {
- "name": "end_at_step",
- "type": "INT",
- "widget": {
- "name": "end_at_step"
- },
- "link": 486
+ "link": 44
}
],
"outputs": [
- {
- "name": "model",
- "type": "MODEL",
- "links": null
- },
- {
- "name": "positive",
- "type": "CONDITIONING",
- "links": [
- 412
- ]
- },
- {
- "name": "negative",
- "type": "CONDITIONING",
- "links": [
- 413
- ]
- },
- {
- "name": "sampler",
- "type": "SAMPLER",
- "links": []
- },
- {
- "name": "sigmas",
- "type": "SIGMAS",
- "links": null
- },
{
"name": "output",
"type": "LATENT",
"links": [
- 410
+ 125
]
},
{
"name": "denoised_output",
"type": "LATENT",
- "links": null
- },
- {
- "name": "image",
- "type": "IMAGE",
- "links": []
- },
- {
- "name": "vae",
- "type": "VAE",
"links": [
- 414
+ 89
]
}
],
"properties": {
- "Node name for S&R": "WanVideoSamplerCustomUltraAdvancedEfficient",
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "SamplerCustomAdvanced",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
"version": "7.5.2"
}
},
- "widgets_values": [
- true,
- 772565087426431,
- "randomize",
- 1,
- 0,
- 10000,
- true,
- "auto",
- "false"
- ],
+ "widgets_values": [],
"color": "#232",
"bgcolor": "#353"
},
{
- "id": 180,
+ "id": 68,
"type": "MarkdownNote",
"pos": [
- 4210,
- 790
+ 6200,
+ 1490
],
"size": [
- 580,
+ 270,
170
],
"flags": {},
- "order": 13,
+ "order": 10,
"mode": 0,
"inputs": [],
"outputs": [],
- "title": "Prompts",
"properties": {
"ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
}
},
"widgets_values": [
- "### Those samplers are based on Efficient Samplers' node, and accept a custom sampler, a custom scheduler (more info below), and a start-stop step (https://github.com/GiusTex/ComfyUI-MoreEfficientSamplers)"
+ "This scheduler is made for models using lightx loras. You can find it here: https://github.com/BigStationW/flowmatch_scheduler-comfyui"
],
"color": "#432",
"bgcolor": "#653"
},
{
- "id": 149,
- "type": "SamplerCustomUltraAdvancedEfficient",
+ "id": 76,
+ "type": "MarkdownNote",
"pos": [
- 4440,
- 1000
+ 7990,
+ 1310
],
"size": [
- 398.405859375,
- 936.2705729166667
+ 210,
+ 92
+ ],
+ "flags": {},
+ "order": 11,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [],
+ "properties": {
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "Refine last 2 steps"
+ ],
+ "color": "#432",
+ "bgcolor": "#653"
+ },
+ {
+ "id": 55,
+ "type": "VAEDecode",
+ "pos": [
+ 6780,
+ 1060
+ ],
+ "size": [
+ 150.248046875,
+ 54
],
"flags": {},
"order": 44,
"mode": 0,
"inputs": [
{
- "name": "model",
- "type": "MODEL",
- "link": 482
- },
- {
- "name": "positive",
- "type": "CONDITIONING",
- "link": 412
- },
- {
- "name": "negative",
- "type": "CONDITIONING",
- "link": 413
- },
- {
- "name": "sampler",
- "type": "SAMPLER",
- "link": 408
- },
- {
- "name": "sigmas",
- "type": "SIGMAS",
- "link": 409
- },
- {
- "name": "latent_image",
+ "name": "samples",
"type": "LATENT",
- "link": 410
- },
- {
- "name": "optional_vae",
- "shape": 7,
- "type": "VAE",
- "link": 414
- },
- {
- "name": "noise_seed",
- "type": "INT",
- "widget": {
- "name": "noise_seed"
- },
- "link": 416
- },
- {
- "name": "start_at_step",
- "type": "INT",
- "widget": {
- "name": "start_at_step"
- },
- "link": 487
- }
- ],
- "outputs": [
- {
- "name": "model",
- "type": "MODEL",
- "links": null
- },
- {
- "name": "positive",
- "type": "CONDITIONING",
- "links": null
- },
- {
- "name": "negative",
- "type": "CONDITIONING",
- "links": null
- },
- {
- "name": "sampler",
- "type": "SAMPLER",
- "links": null
- },
- {
- "name": "sigmas",
- "type": "SIGMAS",
- "links": null
- },
- {
- "name": "output",
- "type": "LATENT",
- "links": [
- 466
- ]
- },
- {
- "name": "denoised_output",
- "type": "LATENT",
- "links": null
- },
- {
- "name": "image",
- "type": "IMAGE",
- "links": []
+ "link": 89
},
{
"name": "vae",
"type": "VAE",
+ "link": 90
+ }
+ ],
+ "outputs": [
+ {
+ "name": "IMAGE",
+ "type": "IMAGE",
"links": [
- 471
+ 109
]
}
],
"properties": {
- "Node name for S&R": "SamplerCustomUltraAdvancedEfficient",
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "VAEDecode",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [],
+ "color": "#323",
+ "bgcolor": "#535"
+ },
+ {
+ "id": 63,
+ "type": "SaveAnimatedWEBP",
+ "pos": [
+ 6970,
+ 1160
+ ],
+ "size": [
+ 320,
+ 158
+ ],
+ "flags": {},
+ "order": 46,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "images",
+ "type": "IMAGE",
+ "link": 109
+ }
+ ],
+ "outputs": [],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "SaveAnimatedWEBP",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
@@ -2341,48 +1714,296 @@
}
},
"widgets_values": [
+ "ComfyUI",
+ 24,
+ true,
+ 80,
+ "default"
+ ]
+ },
+ {
+ "id": 69,
+ "type": "MarkdownNote",
+ "pos": [
+ 7310,
+ 1190
+ ],
+ "size": [
+ 260,
+ 92
+ ],
+ "flags": {},
+ "order": 12,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [],
+ "properties": {
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "The lora at 5.6 generates more motion but speeds up the fps too"
+ ],
+ "color": "#432",
+ "bgcolor": "#653"
+ },
+ {
+ "id": 77,
+ "type": "MarkdownNote",
+ "pos": [
+ 5930,
+ 860
+ ],
+ "size": [
+ 250,
+ 140
+ ],
+ "flags": {},
+ "order": 13,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [],
+ "properties": {
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "Encode WanVideo, TTM Latent Add, CFGFloatListScheduler come from Kijai's wanvideo-wrapper"
+ ],
+ "color": "#432",
+ "bgcolor": "#653"
+ },
+ {
+ "id": 6,
+ "type": "TorchCompileModelWanVideoV2",
+ "pos": [
+ 5460,
+ 520
+ ],
+ "size": [
+ 380,
+ 206
+ ],
+ "flags": {},
+ "order": 34,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 5
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 78,
+ 144
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfyui-kjnodes",
+ "ver": "f7eb33abc80a2aded1b46dff0dd14d07856a7d50",
+ "Node name for S&R": "TorchCompileModelWanVideoV2",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "inductor",
false,
- 1079472255540447,
- "randomize",
- 1,
- 0,
- 10000,
+ "default",
false,
- "auto",
- "false"
+ true,
+ 64,
+ true
+ ]
+ },
+ {
+ "id": 22,
+ "type": "KSamplerSelect",
+ "pos": [
+ 6230,
+ 1130
+ ],
+ "size": [
+ 213.15882873535156,
+ 62
+ ],
+ "flags": {},
+ "order": 14,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "SAMPLER",
+ "type": "SAMPLER",
+ "links": [
+ 42,
+ 137
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.10.0",
+ "Node name for S&R": "KSamplerSelect",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "lcm"
],
"color": "#232",
"bgcolor": "#353"
},
{
- "id": 122,
+ "id": 60,
+ "type": "GetVideoComponents",
+ "pos": [
+ 5330,
+ 1410
+ ],
+ "size": [
+ 205.93125,
+ 78
+ ],
+ "flags": {},
+ "order": 22,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "video",
+ "type": "VIDEO",
+ "link": 104
+ }
+ ],
+ "outputs": [
+ {
+ "name": "images",
+ "type": "IMAGE",
+ "links": [
+ 142
+ ]
+ },
+ {
+ "name": "audio",
+ "type": "AUDIO",
+ "links": null
+ },
+ {
+ "name": "fps",
+ "type": "FLOAT",
+ "links": null
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "GetVideoComponents",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": []
+ },
+ {
+ "id": 61,
+ "type": "GetVideoComponents",
+ "pos": [
+ 5330,
+ 1530
+ ],
+ "size": [
+ 205.93125,
+ 78
+ ],
+ "flags": {},
+ "order": 23,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "video",
+ "type": "VIDEO",
+ "link": 105
+ }
+ ],
+ "outputs": [
+ {
+ "name": "images",
+ "type": "IMAGE",
+ "links": [
+ 143
+ ]
+ },
+ {
+ "name": "audio",
+ "type": "AUDIO",
+ "links": null
+ },
+ {
+ "name": "fps",
+ "type": "FLOAT",
+ "links": null
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "GetVideoComponents",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": []
+ },
+ {
+ "id": 40,
"type": "WanFirstLastFrameToVideo",
"pos": [
- 2230,
- 1100
+ 5590,
+ 1010
],
"size": [
287.9513702392578,
278
],
"flags": {},
- "order": 31,
+ "order": 32,
"mode": 0,
"inputs": [
{
"name": "positive",
"type": "CONDITIONING",
- "link": 293
+ "link": 56
},
{
"name": "negative",
"type": "CONDITIONING",
- "link": 294
+ "link": 57
},
{
"name": "vae",
"type": "VAE",
- "link": 298
+ "link": 58
},
{
"name": "clip_vision_start_image",
@@ -2400,7 +2021,7 @@
"name": "start_image",
"shape": 7,
"type": "IMAGE",
- "link": 375
+ "link": 102
},
{
"name": "end_image",
@@ -2414,7 +2035,7 @@
"widget": {
"name": "width"
},
- "link": 296
+ "link": 96
},
{
"name": "height",
@@ -2422,15 +2043,7 @@
"widget": {
"name": "height"
},
- "link": 297
- },
- {
- "name": "length",
- "type": "INT",
- "widget": {
- "name": "length"
- },
- "link": 488
+ "link": 97
}
],
"outputs": [
@@ -2438,21 +2051,23 @@
"name": "positive",
"type": "CONDITIONING",
"links": [
- 303
+ 50,
+ 135
]
},
{
"name": "negative",
"type": "CONDITIONING",
"links": [
- 304
+ 51,
+ 120
]
},
{
"name": "latent",
"type": "LATENT",
"links": [
- 428
+ 22
]
}
],
@@ -2476,37 +2091,60 @@
"bgcolor": "#535"
},
{
- "id": 143,
- "type": "TTMKSamplerSelect",
+ "id": 36,
+ "type": "TimeToMoveGuider",
"pos": [
- 2900,
- 1090
+ 6220,
+ 930
],
"size": [
- 213.15882873535156,
- 62
+ 223.0546875,
+ 158
],
"flags": {},
- "order": 42,
+ "order": 39,
"mode": 0,
"inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 144
+ },
+ {
+ "name": "positive",
+ "type": "CONDITIONING",
+ "link": 50
+ },
+ {
+ "name": "negative",
+ "type": "CONDITIONING",
+ "link": 51
+ },
{
"name": "latent",
"type": "LATENT",
- "link": 432
+ "link": 52
+ },
+ {
+ "name": "cfg",
+ "type": "FLOAT",
+ "widget": {
+ "name": "cfg"
+ },
+ "link": 53
}
],
"outputs": [
{
- "name": "SAMPLER",
- "type": "SAMPLER",
+ "name": "guider",
+ "type": "GUIDER",
"links": [
- 463
+ 41
]
}
],
"properties": {
- "Node name for S&R": "TTMKSamplerSelect",
+ "Node name for S&R": "TimeToMoveGuider",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
@@ -2514,91 +2152,71 @@
}
},
"widgets_values": [
- "lcm"
+ 1,
+ 0
],
"color": "#232",
"bgcolor": "#353"
},
{
- "id": 148,
- "type": "KSamplerSelect",
+ "id": 71,
+ "type": "SamplerCustomAdvanced",
"pos": [
- 4190,
- 1080
+ 8030,
+ 860
],
"size": [
- 213.15882873535156,
- 62
+ 272.62757873535156,
+ 126
],
"flags": {},
- "order": 14,
- "mode": 0,
- "inputs": [],
- "outputs": [
- {
- "name": "SAMPLER",
- "type": "SAMPLER",
- "links": [
- 408
- ]
- }
- ],
- "properties": {
- "cnr_id": "comfy-core",
- "ver": "0.4.0",
- "Node name for S&R": "KSamplerSelect",
- "ue_properties": {
- "widget_ue_connectable": {},
- "input_ue_unconnectable": {},
- "version": "7.5.2"
- }
- },
- "widgets_values": [
- "lcm"
- ],
- "color": "#232",
- "bgcolor": "#353"
- },
- {
- "id": 176,
- "type": "VAEDecode",
- "pos": [
- 4940,
- 1240
- ],
- "size": [
- 165.86024475097656,
- 54
- ],
- "flags": {},
- "order": 46,
+ "order": 43,
"mode": 0,
"inputs": [
{
- "name": "samples",
- "type": "LATENT",
- "link": 467
+ "name": "noise",
+ "type": "NOISE",
+ "link": 145
},
{
- "name": "vae",
- "type": "VAE",
- "link": 471
+ "name": "guider",
+ "type": "GUIDER",
+ "link": 121
+ },
+ {
+ "name": "sampler",
+ "type": "SAMPLER",
+ "link": 137
+ },
+ {
+ "name": "sigmas",
+ "type": "SIGMAS",
+ "link": 132
+ },
+ {
+ "name": "latent_image",
+ "type": "LATENT",
+ "link": 125
}
],
"outputs": [
{
- "name": "IMAGE",
- "type": "IMAGE",
+ "name": "output",
+ "type": "LATENT",
+ "links": []
+ },
+ {
+ "name": "denoised_output",
+ "type": "LATENT",
"links": [
- 470,
- 508
+ 127
]
}
],
"properties": {
"cnr_id": "comfy-core",
- "ver": "0.5.1",
- "Node name for S&R": "VAEDecode",
+ "ver": "0.11.0",
+ "Node name for S&R": "SamplerCustomAdvanced",
"ue_properties": {
"widget_ue_connectable": {},
"input_ue_unconnectable": {},
@@ -2606,705 +2224,643 @@
}
},
"widgets_values": [],
- "color": "#323",
- "bgcolor": "#535"
+ "color": "#232",
+ "bgcolor": "#353"
},
{
- "id": 202,
- "type": "VRAM_Debug",
- "pos": [
- 5130,
- 740
- ],
- "size": [
- 231.2060546875,
- 206
- ],
- "flags": {
- "collapsed": true
- },
- "order": 48,
- "mode": 0,
- "inputs": [
- {
- "name": "any_input",
- "shape": 7,
- "type": "*",
- "link": null
- },
- {
- "name": "image_pass",
- "shape": 7,
- "type": "IMAGE",
- "link": 508
- },
- {
- "name": "model_pass",
- "shape": 7,
- "type": "MODEL",
- "link": null
- }
- ],
- "outputs": [
- {
- "name": "any_output",
- "type": "*",
- "links": null
- },
- {
- "name": "image_pass",
- "type": "IMAGE",
- "links": null
- },
- {
- "name": "model_pass",
- "type": "MODEL",
- "links": null
- },
- {
- "label": "freemem_before",
- "name": "freemem_before",
- "type": "INT",
- "links": null
- },
- {
- "label": "freemem_after",
- "name": "freemem_after",
- "type": "INT",
- "links": null
- }
- ],
- "properties": {
- "cnr_id": "comfyui-kjnodes",
- "ver": "7533dbdd79de10997d25ef9b65e7126668fb8c1d",
- "ue_properties": {
- "widget_ue_connectable": {},
- "input_ue_unconnectable": {}
- },
- "Node name for S&R": "VRAM_Debug"
- },
- "widgets_values": [
- true,
- true,
- true
- ]
- },
- {
- "id": 203,
+ "id": 82,
"type": "MarkdownNote",
"pos": [
- 5560,
- 890
+ 4510,
+ 370
],
"size": [
- 360,
- 110
+ 370,
+ 100
],
"flags": {},
"order": 15,
"mode": 0,
"inputs": [],
"outputs": [],
- "title": "Prompts",
"properties": {
"ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
}
},
"widgets_values": [
- "### Using lightx at 5.6 and 2 strength the video is better saved at 24 fps, instead of 16."
+ "You can find the lora here: https://huggingface.co/Kijai/WanVideo_comfy/tree/main/Lightx2v"
],
"color": "#432",
"bgcolor": "#653"
},
{
- "id": 204,
+ "id": 81,
"type": "MarkdownNote",
"pos": [
- 5280,
- 640
+ 4150,
+ 330
],
"size": [
- 320,
- 110
+ 350,
+ 92
],
"flags": {},
"order": 16,
"mode": 0,
"inputs": [],
"outputs": [],
- "title": "Prompts",
"properties": {
"ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
}
},
"widgets_values": [
- "### If you don't use gguf models you don't need to clear the cache at the end."
+ "If you have enough vram you can use bigger versions (fp8, etc) or quantizations (q8, etc) of the model"
],
"color": "#432",
"bgcolor": "#653"
},
{
- "id": 181,
- "type": "MarkdownNote",
+ "id": 83,
+ "type": "DisableNoise",
"pos": [
- 4860,
- 1470
+ 7790,
+ 790
],
"size": [
- 340,
- 170
+ 160,
+ 30
],
"flags": {},
"order": 17,
"mode": 0,
"inputs": [],
- "outputs": [],
- "title": "Prompts",
+ "outputs": [
+ {
+ "name": "NOISE",
+ "type": "NOISE",
+ "links": [
+ 145
+ ]
+ }
+ ],
"properties": {
"ue_properties": {
- "version": "7.0.1",
- "widget_ue_connectable": {}
- }
- },
- "widgets_values": [
- "### The generated frames are a bit darker than the given one; I removed it. If you didn't pass a first frame you don't need to trim the latent."
- ],
- "color": "#432",
- "bgcolor": "#653"
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ },
+ "cnr_id": "comfy-core",
+ "ver": "0.11.1",
+ "Node name for S&R": "DisableNoise"
+ }
}
],
"links": [
[
- 3,
- 6,
- 0,
+ 1,
5,
0,
+ 1,
+ 0,
"MODEL"
],
[
5,
- 11,
+ 1,
0,
6,
0,
"MODEL"
],
[
- 6,
- 32,
- 0,
- 7,
- 0,
- "MODEL"
- ],
- [
- 9,
- 10,
- 0,
- 11,
- 0,
- "MODEL"
- ],
- [
- 11,
- 30,
- 0,
- 14,
- 0,
- "IMAGE"
- ],
- [
- 41,
- 12,
- 0,
+ 13,
31,
0,
- "MODEL"
+ 13,
+ 0,
+ "VAE"
],
[
- 42,
- 31,
- 0,
- 32,
- 0,
- "MODEL"
- ],
- [
- 86,
- 65,
- 0,
- 30,
- 0,
- "IMAGE"
- ],
- [
- 142,
- 30,
- 1,
- 84,
+ 22,
+ 40,
2,
- "INT"
- ],
- [
- 143,
- 30,
- 2,
- 84,
- 3,
- "INT"
- ],
- [
- 145,
- 84,
+ 21,
0,
- 58,
- 0,
- "IMAGE"
+ "LATENT"
],
[
- 156,
- 88,
- 0,
- 84,
- 0,
- "IMAGE"
- ],
- [
- 161,
- 30,
- 1,
- 92,
- 2,
- "INT"
- ],
- [
- 162,
- 30,
- 2,
- 92,
- 3,
- "INT"
- ],
- [
- 293,
- 37,
- 0,
- 122,
- 0,
- "CONDITIONING"
- ],
- [
- 294,
23,
+ 13,
0,
- 122,
+ 21,
1,
- "CONDITIONING"
- ],
- [
- 296,
- 30,
- 1,
- 122,
- 7,
- "INT"
- ],
- [
- 297,
- 30,
- 2,
- 122,
- 8,
- "INT"
- ],
- [
- 298,
- 15,
- 0,
- 122,
- 2,
- "VAE"
- ],
- [
- 303,
- 122,
- 0,
- 123,
- 1,
- "CONDITIONING"
- ],
- [
- 304,
- 122,
- 1,
- 123,
- 2,
- "CONDITIONING"
- ],
- [
- 306,
- 7,
- 0,
- 123,
- 4,
- "SIGMAS"
- ],
- [
- 308,
- 15,
- 0,
- 123,
- 6,
- "VAE"
- ],
- [
- 309,
- 24,
- 0,
- 123,
- 7,
- "INT"
- ],
- [
- 375,
- 30,
- 0,
- 122,
- 5,
- "IMAGE"
- ],
- [
- 404,
- 90,
- 0,
- 92,
- 0,
- "IMAGE"
- ],
- [
- 408,
- 148,
- 0,
- 149,
- 3,
- "SAMPLER"
- ],
- [
- 409,
- 5,
- 0,
- 149,
- 4,
- "SIGMAS"
- ],
- [
- 410,
- 123,
- 5,
- 149,
- 5,
"LATENT"
],
[
- 412,
- 123,
- 1,
- 149,
- 1,
- "CONDITIONING"
- ],
- [
- 413,
- 123,
- 2,
- 149,
- 2,
- "CONDITIONING"
- ],
- [
- 414,
- 123,
- 8,
- 149,
- 6,
- "VAE"
- ],
- [
- 416,
24,
- 0,
- 149,
7,
- "INT"
- ],
- [
- 428,
- 122,
- 2,
- 154,
0,
- "LATENT"
- ],
- [
- 430,
- 58,
- 0,
- 154,
+ 21,
2,
"MASK"
],
[
- 432,
- 154,
+ 26,
+ 19,
0,
- 143,
- 0,
- "LATENT"
- ],
- [
- 455,
- 15,
- 0,
- 165,
- 0,
- "VAE"
- ],
- [
- 456,
- 165,
- 0,
- 154,
+ 23,
1,
- "LATENT"
+ "INT"
],
[
- 457,
- 92,
+ 40,
+ 34,
0,
- 165,
+ 32,
+ 0,
+ "NOISE"
+ ],
+ [
+ 41,
+ 36,
+ 0,
+ 32,
1,
- "IMAGE"
+ "GUIDER"
],
[
- 462,
- 154,
+ 42,
+ 22,
0,
- 123,
- 5,
- "LATENT"
- ],
- [
- 463,
- 143,
- 0,
- 123,
- 3,
+ 32,
+ 2,
"SAMPLER"
],
[
- 464,
- 92,
+ 43,
+ 33,
0,
- 169,
- 0,
- "IMAGE"
+ 32,
+ 3,
+ "SIGMAS"
],
[
- 465,
- 84,
+ 44,
+ 21,
0,
- 170,
- 0,
- "IMAGE"
+ 32,
+ 4,
+ "LATENT"
],
[
- 466,
- 149,
+ 45,
+ 23,
+ 0,
+ 33,
+ 0,
+ "SIGMAS"
+ ],
+ [
+ 46,
+ 24,
+ 0,
+ 33,
+ 1,
+ "INT"
+ ],
+ [
+ 48,
+ 19,
+ 0,
+ 35,
+ 0,
+ "INT"
+ ],
+ [
+ 50,
+ 40,
+ 0,
+ 36,
+ 1,
+ "CONDITIONING"
+ ],
+ [
+ 51,
+ 40,
+ 1,
+ 36,
+ 2,
+ "CONDITIONING"
+ ],
+ [
+ 52,
+ 21,
+ 0,
+ 36,
+ 3,
+ "LATENT"
+ ],
+ [
+ 53,
+ 35,
+ 0,
+ 36,
+ 4,
+ "FLOAT"
+ ],
+ [
+ 56,
+ 16,
+ 0,
+ 40,
+ 0,
+ "CONDITIONING"
+ ],
+ [
+ 57,
+ 17,
+ 0,
+ 40,
+ 1,
+ "CONDITIONING"
+ ],
+ [
+ 58,
+ 31,
+ 0,
+ 40,
+ 2,
+ "VAE"
+ ],
+ [
+ 75,
+ 4,
+ 0,
+ 42,
+ 0,
+ "MODEL"
+ ],
+ [
+ 76,
+ 3,
+ 0,
+ 42,
+ 1,
+ "CLIP"
+ ],
+ [
+ 78,
+ 6,
+ 0,
+ 23,
+ 0,
+ "MODEL"
+ ],
+ [
+ 79,
+ 42,
+ 0,
5,
- 174,
+ 0,
+ "MODEL"
+ ],
+ [
+ 80,
+ 42,
+ 1,
+ 16,
+ 0,
+ "CLIP"
+ ],
+ [
+ 81,
+ 42,
+ 1,
+ 17,
+ 0,
+ "CLIP"
+ ],
+ [
+ 82,
+ 49,
+ 0,
+ 43,
+ 0,
+ "MODEL"
+ ],
+ [
+ 83,
+ 51,
+ 0,
+ 52,
+ 0,
+ "MODEL"
+ ],
+ [
+ 84,
+ 52,
+ 0,
+ 53,
+ 0,
+ "MODEL"
+ ],
+ [
+ 85,
+ 43,
+ 0,
+ 51,
+ 0,
+ "MODEL"
+ ],
+ [
+ 89,
+ 32,
+ 1,
+ 55,
0,
"LATENT"
],
[
- 467,
- 174,
+ 90,
+ 31,
0,
- 176,
- 0,
- "LATENT"
- ],
- [
- 470,
- 176,
- 0,
- 175,
- 0,
- "IMAGE"
- ],
- [
- 471,
- 149,
- 8,
- 176,
+ 55,
1,
"VAE"
],
[
- 474,
- 20,
+ 95,
+ 11,
0,
- 182,
+ 57,
0,
- "MODEL"
+ "IMAGE"
],
[
- 475,
- 18,
+ 96,
+ 57,
0,
- 182,
+ 40,
+ 7,
+ "INT"
+ ],
+ [
+ 97,
+ 57,
1,
- "CLIP"
+ 40,
+ 8,
+ "INT"
],
[
- 476,
- 182,
+ 102,
+ 11,
+ 0,
+ 40,
+ 5,
+ "IMAGE"
+ ],
+ [
+ 103,
+ 19,
+ 0,
+ 54,
1,
- 37,
- 0,
- "CLIP"
+ "INT"
],
[
- 477,
- 182,
+ 104,
+ 58,
+ 0,
+ 60,
+ 0,
+ "VIDEO"
+ ],
+ [
+ 105,
+ 59,
+ 0,
+ 61,
+ 0,
+ "VIDEO"
+ ],
+ [
+ 109,
+ 55,
+ 0,
+ 63,
+ 0,
+ "IMAGE"
+ ],
+ [
+ 120,
+ 40,
1,
- 23,
- 0,
- "CLIP"
+ 72,
+ 2,
+ "CONDITIONING"
],
[
- 478,
- 182,
+ 121,
+ 72,
0,
- 12,
+ 71,
+ 1,
+ "GUIDER"
+ ],
+ [
+ 123,
+ 53,
+ 0,
+ 54,
0,
"MODEL"
],
[
- 480,
- 21,
- 0,
- 184,
- 0,
- "MODEL"
- ],
- [
- 481,
- 184,
- 0,
- 10,
- 0,
- "MODEL"
- ],
- [
- 482,
- 6,
- 0,
- 149,
- 0,
- "MODEL"
- ],
- [
- 483,
+ 125,
32,
0,
- 123,
+ 71,
+ 4,
+ "LATENT"
+ ],
+ [
+ 126,
+ 31,
+ 0,
+ 73,
+ 1,
+ "VAE"
+ ],
+ [
+ 127,
+ 71,
+ 1,
+ 73,
+ 0,
+ "LATENT"
+ ],
+ [
+ 128,
+ 73,
+ 0,
+ 64,
+ 0,
+ "IMAGE"
+ ],
+ [
+ 130,
+ 24,
+ 0,
+ 74,
+ 1,
+ "INT"
+ ],
+ [
+ 131,
+ 54,
+ 0,
+ 74,
+ 0,
+ "SIGMAS"
+ ],
+ [
+ 132,
+ 74,
+ 1,
+ 71,
+ 3,
+ "SIGMAS"
+ ],
+ [
+ 135,
+ 40,
+ 0,
+ 72,
+ 1,
+ "CONDITIONING"
+ ],
+ [
+ 136,
+ 53,
+ 0,
+ 72,
0,
"MODEL"
],
[
- 484,
- 187,
+ 137,
+ 22,
0,
- 7,
- 1,
- "INT"
- ],
- [
- 485,
- 187,
- 0,
- 5,
- 1,
- "INT"
- ],
- [
- 486,
- 188,
- 0,
- 123,
- 8,
- "INT"
- ],
- [
- 487,
- 188,
- 0,
- 149,
- 8,
- "INT"
- ],
- [
- 488,
- 189,
- 0,
- 122,
- 9,
- "INT"
- ],
- [
- 489,
- 189,
- 0,
- 90,
+ 71,
2,
- "INT"
+ "SAMPLER"
],
[
- 490,
- 189,
+ 142,
+ 60,
0,
- 88,
- 2,
- "INT"
- ],
- [
- 508,
- 176,
- 0,
- 202,
+ 13,
1,
"IMAGE"
+ ],
+ [
+ 143,
+ 61,
+ 0,
+ 7,
+ 0,
+ "IMAGE"
+ ],
+ [
+ 144,
+ 6,
+ 0,
+ 36,
+ 0,
+ "MODEL"
+ ],
+ [
+ 145,
+ 83,
+ 0,
+ 71,
+ 0,
+ "NOISE"
]
],
- "groups": [],
+ "groups": [
+ {
+ "id": 1,
+ "title": "Load high noise model",
+ "bounding": [
+ 4140,
+ 430,
+ 1710,
+ 310
+ ],
+ "color": "#3f789e",
+ "font_size": 24,
+ "flags": {}
+ },
+ {
+ "id": 2,
+ "title": "Load image and videos",
+ "bounding": [
+ 4710,
+ 1130,
+ 830,
+ 1030
+ ],
+ "color": "#88A",
+ "font_size": 24,
+ "flags": {}
+ },
+ {
+ "id": 3,
+ "title": "Prepare latent & add TTM guide",
+ "bounding": [
+ 5580,
+ 770,
+ 890,
+ 1050
+ ],
+ "color": "#a1309b",
+ "font_size": 24,
+ "flags": {}
+ },
+ {
+ "id": 4,
+ "title": "Load low noise model (as refiner)",
+ "bounding": [
+ 6960,
+ 440,
+ 730,
+ 670
+ ],
+ "color": "#3f789e",
+ "font_size": 24,
+ "flags": {}
+ }
+ ],
"config": {},
"extra": {
"workflowRendererVersion": "LG",
"ue_links": [],
"ds": {
- "scale": 0.5989500000000005,
+ "scale": 0.5989500000000002,
"offset": [
- -3089.383845545266,
- -521.2651651523321
+ -5305.673502198465,
+ -416.34084648134194
]
},
"links_added_by_ue": [],
- "frontendVersion": "1.34.9",
+ "frontendVersion": "1.37.11",
"VHS_latentpreview": true,
"VHS_latentpreviewrate": 0,
"VHS_MetadataImage": true,
diff --git a/wanvideo_2_2_I2V_A14B_TimeToMove_workflow2.json b/wanvideo_2_2_I2V_A14B_TimeToMove_workflow2.json
new file mode 100644
index 0000000..17261f5
--- /dev/null
+++ b/wanvideo_2_2_I2V_A14B_TimeToMove_workflow2.json
@@ -0,0 +1,2653 @@
+{
+ "id": "c6e410bc-5e2c-460b-ae81-c91b6094fbb1",
+ "revision": 0,
+ "last_node_id": 385,
+ "last_link_id": 977,
+ "nodes": [
+ {
+ "id": 120,
+ "type": "CLIPTextEncode",
+ "pos": [
+ 930,
+ 100
+ ],
+ "size": [
+ 422.84503173828125,
+ 164.31304931640625
+ ],
+ "flags": {},
+ "order": 26,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "clip",
+ "type": "CLIP",
+ "link": 899
+ }
+ ],
+ "outputs": [
+ {
+ "name": "CONDITIONING",
+ "type": "CONDITIONING",
+ "slot_index": 0,
+ "links": [
+ 779
+ ]
+ }
+ ],
+ "title": "CLIP Text Encode (Positive Prompt)",
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.46",
+ "Node name for S&R": "CLIPTextEncode",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "A lively monkey energetically bounces on a neatly made bed, its limbs splayed in mid-air. As the monkey lands, the bed creases slightly under its weight, and it quickly prepares for another joyful leap, its eyes wide with excitement and mischief."
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 121,
+ "type": "CLIPTextEncode",
+ "pos": [
+ 940,
+ 310
+ ],
+ "size": [
+ 410,
+ 110
+ ],
+ "flags": {},
+ "order": 27,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "clip",
+ "type": "CLIP",
+ "link": 900
+ }
+ ],
+ "outputs": [
+ {
+ "name": "CONDITIONING",
+ "type": "CONDITIONING",
+ "links": [
+ 640
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.49",
+ "Node name for S&R": "CLIPTextEncode",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {
+ "text": true
+ },
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "色调艳丽,过曝,静态,细节模糊不清,字幕,风格,作品,画作,画面,静止,整体发灰,最差质量,低质量,JPEG压缩残留,丑陋的,残缺的,多余的手指,画得不好的手部,画得不好的脸部,畸形的,毁容的,形态畸形的肢体,手指融合,静止不动的画面,杂乱的背景,三条腿,背景人很多,倒着走"
+ ],
+ "color": "#322",
+ "bgcolor": "#533"
+ },
+ {
+ "id": 142,
+ "type": "ImageToMask",
+ "pos": [
+ 1480,
+ 780
+ ],
+ "size": [
+ 233.765234375,
+ 62
+ ],
+ "flags": {},
+ "order": 28,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "image",
+ "type": "IMAGE",
+ "link": 966
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MASK",
+ "type": "MASK",
+ "links": [
+ 775
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.76",
+ "Node name for S&R": "ImageToMask",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "red"
+ ]
+ },
+ {
+ "id": 168,
+ "type": "PatchModelPatcherOrder",
+ "pos": [
+ 1060,
+ -180
+ ],
+ "size": [
+ 310,
+ 90
+ ],
+ "flags": {},
+ "order": 31,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 272
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 273
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfyui-kjnodes",
+ "ver": "f7eb33abc80a2aded1b46dff0dd14d07856a7d50",
+ "Node name for S&R": "PatchModelPatcherOrder",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "weight_patch_first",
+ "disabled"
+ ]
+ },
+ {
+ "id": 167,
+ "type": "ModelSamplingSD3",
+ "pos": [
+ 820,
+ -180
+ ],
+ "size": [
+ 210,
+ 62
+ ],
+ "flags": {},
+ "order": 25,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 898
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "slot_index": 0,
+ "links": [
+ 272
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.34",
+ "Node name for S&R": "ModelSamplingSD3",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ 8.000000000000002
+ ]
+ },
+ {
+ "id": 94,
+ "type": "INTConstant",
+ "pos": [
+ 1520,
+ 890
+ ],
+ "size": [
+ 210,
+ 62
+ ],
+ "flags": {},
+ "order": 0,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "value",
+ "type": "INT",
+ "links": [
+ 711,
+ 728,
+ 913
+ ]
+ }
+ ],
+ "title": "Steps",
+ "properties": {
+ "cnr_id": "comfyui-kjnodes",
+ "ver": "a6b867b63a29ca48ddb15c589e17a9f2d8530d57",
+ "Node name for S&R": "INTConstant",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ 6
+ ],
+ "color": "#1b4669",
+ "bgcolor": "#29699c"
+ },
+ {
+ "id": 165,
+ "type": "UnetLoaderGGUF",
+ "pos": [
+ 80,
+ -170
+ ],
+ "size": [
+ 340,
+ 62
+ ],
+ "flags": {},
+ "order": 1,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 896
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "ComfyUI-GGUF",
+ "ver": "a2b75978fd50c0227a58316619b79d525b88e570",
+ "Node name for S&R": "UnetLoaderGGUF",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "wan2.2_i2v_high_noise_14B_Q6_K.gguf"
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
+ },
+ {
+ "id": 340,
+ "type": "PatchModelPatcherOrder",
+ "pos": [
+ 2990,
+ 110
+ ],
+ "size": [
+ 310,
+ 90
+ ],
+ "flags": {},
+ "order": 30,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 904
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 905
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfyui-kjnodes",
+ "ver": "f7eb33abc80a2aded1b46dff0dd14d07856a7d50",
+ "Node name for S&R": "PatchModelPatcherOrder",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "weight_patch_first",
+ "disabled"
+ ]
+ },
+ {
+ "id": 339,
+ "type": "ModelSamplingSD3",
+ "pos": [
+ 2940,
+ 0
+ ],
+ "size": [
+ 210,
+ 62
+ ],
+ "flags": {},
+ "order": 24,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 907
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "slot_index": 0,
+ "links": [
+ 904
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.34",
+ "Node name for S&R": "ModelSamplingSD3",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ 8.000000000000002
+ ]
+ },
+ {
+ "id": 337,
+ "type": "LoraLoaderModelOnly",
+ "pos": [
+ 2930,
+ -150
+ ],
+ "size": [
+ 310,
+ 86
+ ],
+ "flags": {},
+ "order": 19,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 906
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 907
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "LoraLoaderModelOnly",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "Wan\\lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
+ 2
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
+ },
+ {
+ "id": 338,
+ "type": "UnetLoaderGGUF",
+ "pos": [
+ 2920,
+ -270
+ ],
+ "size": [
+ 340,
+ 62
+ ],
+ "flags": {},
+ "order": 2,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 906
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "ComfyUI-GGUF",
+ "ver": "a2b75978fd50c0227a58316619b79d525b88e570",
+ "Node name for S&R": "UnetLoaderGGUF",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "wan2.2_i2v_low_noise_14B_Q6_K.gguf"
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
+ },
+ {
+ "id": 170,
+ "type": "FlowMatchSigmas",
+ "pos": [
+ 2050,
+ 420
+ ],
+ "size": [
+ 278.73828125,
+ 230
+ ],
+ "flags": {},
+ "order": 37,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "link": 901
+ },
+ {
+ "name": "num_inference_steps",
+ "type": "INT",
+ "widget": {
+ "name": "num_inference_steps"
+ },
+ "link": 711
+ }
+ ],
+ "outputs": [
+ {
+ "name": "sigmas",
+ "type": "SIGMAS",
+ "links": [
+ 850
+ ]
+ }
+ ],
+ "properties": {
+ "aux_id": "BigStationW/flowmatch_scheduler-comfyui",
+ "ver": "33b5bac24d40182aa519ef182ae3c5357f351d83",
+ "Node name for S&R": "FlowMatchSigmas",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ 6,
+ 8,
+ 1,
+ 1,
+ 0,
+ false,
+ false,
+ false
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 341,
+ "type": "TorchCompileModelWanVideoV2",
+ "pos": [
+ 3360,
+ 110
+ ],
+ "size": [
+ 380,
+ 206
+ ],
+ "flags": {},
+ "order": 33,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 905
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 908,
+ 914
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfyui-kjnodes",
+ "ver": "f7eb33abc80a2aded1b46dff0dd14d07856a7d50",
+ "Node name for S&R": "TorchCompileModelWanVideoV2",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "inductor",
+ false,
+ "default",
+ false,
+ true,
+ 64,
+ true
+ ]
+ },
+ {
+ "id": 343,
+ "type": "FlowMatchSigmas",
+ "pos": [
+ 3490,
+ 360
+ ],
+ "size": [
+ 278.73828125,
+ 230
+ ],
+ "flags": {},
+ "order": 36,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "link": 914
+ },
+ {
+ "name": "num_inference_steps",
+ "type": "INT",
+ "widget": {
+ "name": "num_inference_steps"
+ },
+ "link": 913
+ }
+ ],
+ "outputs": [
+ {
+ "name": "sigmas",
+ "type": "SIGMAS",
+ "links": [
+ 915
+ ]
+ }
+ ],
+ "properties": {
+ "aux_id": "BigStationW/flowmatch_scheduler-comfyui",
+ "ver": "33b5bac24d40182aa519ef182ae3c5357f351d83",
+ "Node name for S&R": "FlowMatchSigmas",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ 6,
+ 8,
+ 1,
+ 1,
+ 0,
+ false,
+ false,
+ false
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 118,
+ "type": "ClipLoaderGGUF",
+ "pos": [
+ 90,
+ -60
+ ],
+ "size": [
+ 340,
+ 110
+ ],
+ "flags": {},
+ "order": 3,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "CLIP",
+ "type": "CLIP",
+ "links": [
+ 897
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "gguf",
+ "ver": "fc4b77e925741caef57f7200b963653a3fab7ed0",
+ "Node name for S&R": "ClipLoaderGGUF",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "umt5-xxl-encoder-Q8_0.gguf",
+ "wan",
+ "default"
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
+ },
+ {
+ "id": 189,
+ "type": "VAELoader",
+ "pos": [
+ 1150,
+ -30
+ ],
+ "size": [
+ 210,
+ 62
+ ],
+ "flags": {},
+ "order": 4,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "VAE",
+ "type": "VAE",
+ "links": [
+ 641,
+ 731,
+ 852
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.7.0",
+ "Node name for S&R": "VAELoader",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "wan_2.1_vae.safetensors"
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
+ },
+ {
+ "id": 349,
+ "type": "LoadVideo",
+ "pos": [
+ 980,
+ 1030
+ ],
+ "size": [
+ 400,
+ 503.5259399414063
+ ],
+ "flags": {},
+ "order": 5,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "VIDEO",
+ "type": "VIDEO",
+ "links": [
+ 923
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "LoadVideo",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "TimeToMove_Monkey-Mask (1).mp4",
+ "image"
+ ]
+ },
+ {
+ "id": 347,
+ "type": "LoadVideo",
+ "pos": [
+ 570,
+ 910
+ ],
+ "size": [
+ 400,
+ 503.5259399414063
+ ],
+ "flags": {},
+ "order": 6,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "VIDEO",
+ "type": "VIDEO",
+ "links": [
+ 921
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "LoadVideo",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "TimeToMove_Monkey-Motion_signal (1).mp4",
+ "image"
+ ]
+ },
+ {
+ "id": 334,
+ "type": "GetImageSize",
+ "pos": [
+ 1190,
+ 540
+ ],
+ "size": [
+ 178.06163024902344,
+ 136.79999999999995
+ ],
+ "flags": {},
+ "order": 23,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "image",
+ "type": "IMAGE",
+ "link": 967
+ }
+ ],
+ "outputs": [
+ {
+ "name": "width",
+ "type": "INT",
+ "links": [
+ 894
+ ]
+ },
+ {
+ "name": "height",
+ "type": "INT",
+ "links": [
+ 895
+ ]
+ },
+ {
+ "name": "batch_size",
+ "type": "INT",
+ "links": null
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "GetImageSize",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "width: 720, height: 480\n batch size: 1"
+ ]
+ },
+ {
+ "id": 91,
+ "type": "INTConstant",
+ "pos": [
+ 2110,
+ 890
+ ],
+ "size": [
+ 210,
+ 62
+ ],
+ "flags": {},
+ "order": 7,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "value",
+ "type": "INT",
+ "links": [
+ 857,
+ 918
+ ]
+ }
+ ],
+ "title": "Refiner step",
+ "properties": {
+ "cnr_id": "comfyui-kjnodes",
+ "ver": "a6b867b63a29ca48ddb15c589e17a9f2d8530d57",
+ "Node name for S&R": "INTConstant",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ 4
+ ],
+ "color": "#1b4669",
+ "bgcolor": "#29699c"
+ },
+ {
+ "id": 356,
+ "type": "MarkdownNote",
+ "pos": [
+ 3840,
+ -40
+ ],
+ "size": [
+ 210,
+ 92
+ ],
+ "flags": {},
+ "order": 8,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [],
+ "properties": {
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "Refine last 2 steps"
+ ],
+ "color": "#432",
+ "bgcolor": "#653"
+ },
+ {
+ "id": 353,
+ "type": "MarkdownNote",
+ "pos": [
+ 2040,
+ 690
+ ],
+ "size": [
+ 280,
+ 160
+ ],
+ "flags": {},
+ "order": 9,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [],
+ "properties": {
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "This scheduler is made for models using lightx loras. You can find it here: https://github.com/BigStationW/flowmatch_scheduler-comfyui"
+ ],
+ "color": "#432",
+ "bgcolor": "#653"
+ },
+ {
+ "id": 297,
+ "type": "EncodeWanVideo",
+ "pos": [
+ 1470,
+ 470
+ ],
+ "size": [
+ 249.06858825683594,
+ 254
+ ],
+ "flags": {},
+ "order": 29,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "vae",
+ "type": "VAE",
+ "link": 731
+ },
+ {
+ "name": "image",
+ "type": "IMAGE",
+ "link": 965
+ },
+ {
+ "name": "mask",
+ "shape": 7,
+ "type": "M",
+ "link": null
+ }
+ ],
+ "outputs": [
+ {
+ "name": "reference_latents",
+ "type": "LATENT",
+ "links": [
+ 774
+ ]
+ }
+ ],
+ "properties": {
+ "Node name for S&R": "EncodeWanVideo",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ false,
+ 272,
+ 272,
+ 144,
+ 128,
+ 0,
+ 1
+ ],
+ "color": "#323",
+ "bgcolor": "#535"
+ },
+ {
+ "id": 305,
+ "type": "TTMLatentAdd",
+ "pos": [
+ 1790,
+ 220
+ ],
+ "size": [
+ 224.26475524902344,
+ 134
+ ],
+ "flags": {},
+ "order": 35,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "latent",
+ "type": "LATENT",
+ "link": 797
+ },
+ {
+ "name": "reference_latents",
+ "type": "LATENT",
+ "link": 774
+ },
+ {
+ "name": "ref_masks",
+ "type": "MASK",
+ "link": 775
+ }
+ ],
+ "outputs": [
+ {
+ "name": "latent",
+ "type": "LATENT",
+ "links": [
+ 851,
+ 882
+ ]
+ }
+ ],
+ "properties": {
+ "Node name for S&R": "TTMLatentAdd",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ 0,
+ 3
+ ],
+ "color": "#323",
+ "bgcolor": "#535"
+ },
+ {
+ "id": 295,
+ "type": "CFGFloatListScheduler",
+ "pos": [
+ 1800,
+ 400
+ ],
+ "size": [
+ 232.167578125,
+ 182
+ ],
+ "flags": {},
+ "order": 18,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "steps",
+ "type": "INT",
+ "widget": {
+ "name": "steps"
+ },
+ "link": 728
+ }
+ ],
+ "outputs": [
+ {
+ "name": "float_list",
+ "type": "FLOAT",
+ "links": [
+ 883
+ ]
+ }
+ ],
+ "properties": {
+ "Node name for S&R": "CFGFloatListScheduler",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ 30,
+ 2,
+ 2,
+ "linear",
+ 0,
+ 0.1
+ ]
+ },
+ {
+ "id": 357,
+ "type": "MarkdownNote",
+ "pos": [
+ 1750,
+ 630
+ ],
+ "size": [
+ 250,
+ 140
+ ],
+ "flags": {},
+ "order": 10,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [],
+ "properties": {
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "Encode WanVideo, TTM Latent Add, CFGFloatListScheduler come from Kijai's wanvideo-wrapper"
+ ],
+ "color": "#432",
+ "bgcolor": "#653"
+ },
+ {
+ "id": 290,
+ "type": "KSamplerSelect",
+ "pos": [
+ 2090,
+ 320
+ ],
+ "size": [
+ 213.15882873535156,
+ 62
+ ],
+ "flags": {},
+ "order": 11,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "SAMPLER",
+ "type": "SAMPLER",
+ "links": [
+ 849
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.10.0",
+ "Node name for S&R": "KSamplerSelect",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "lcm"
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 169,
+ "type": "TorchCompileModelWanVideoV2",
+ "pos": [
+ 1400,
+ -180
+ ],
+ "size": [
+ 380,
+ 206
+ ],
+ "flags": {},
+ "order": 34,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 273
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 901,
+ 969,
+ 970
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfyui-kjnodes",
+ "ver": "f7eb33abc80a2aded1b46dff0dd14d07856a7d50",
+ "Node name for S&R": "TorchCompileModelWanVideoV2",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "inductor",
+ false,
+ "default",
+ false,
+ true,
+ 64,
+ true
+ ]
+ },
+ {
+ "id": 333,
+ "type": "TimeToMoveGuider",
+ "pos": [
+ 2070,
+ 120
+ ],
+ "size": [
+ 244.82553100585938,
+ 158
+ ],
+ "flags": {},
+ "order": 38,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 969
+ },
+ {
+ "name": "positive",
+ "type": "CONDITIONING",
+ "link": 880
+ },
+ {
+ "name": "negative",
+ "type": "CONDITIONING",
+ "link": 881
+ },
+ {
+ "name": "latent",
+ "type": "LATENT",
+ "link": 882
+ },
+ {
+ "name": "cfg",
+ "type": "FLOAT",
+ "widget": {
+ "name": "cfg"
+ },
+ "link": 883
+ }
+ ],
+ "outputs": [
+ {
+ "name": "guider",
+ "type": "GUIDER",
+ "links": [
+ 884
+ ]
+ }
+ ],
+ "properties": {
+ "Node name for S&R": "TimeToMoveGuider",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ 1,
+ 0
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 348,
+ "type": "GetVideoComponents",
+ "pos": [
+ 1160,
+ 770
+ ],
+ "size": [
+ 234.4283203125,
+ 78
+ ],
+ "flags": {},
+ "order": 22,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "video",
+ "type": "VIDEO",
+ "link": 921
+ }
+ ],
+ "outputs": [
+ {
+ "name": "images",
+ "type": "IMAGE",
+ "links": [
+ 965
+ ]
+ },
+ {
+ "name": "audio",
+ "type": "AUDIO",
+ "links": null
+ },
+ {
+ "name": "fps",
+ "type": "FLOAT",
+ "links": null
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "GetVideoComponents",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": []
+ },
+ {
+ "id": 350,
+ "type": "GetVideoComponents",
+ "pos": [
+ 1170,
+ 900
+ ],
+ "size": [
+ 234.4283203125,
+ 78
+ ],
+ "flags": {},
+ "order": 21,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "video",
+ "type": "VIDEO",
+ "link": 923
+ }
+ ],
+ "outputs": [
+ {
+ "name": "images",
+ "type": "IMAGE",
+ "links": [
+ 966
+ ]
+ },
+ {
+ "name": "audio",
+ "type": "AUDIO",
+ "links": null
+ },
+ {
+ "name": "fps",
+ "type": "FLOAT",
+ "links": null
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "GetVideoComponents",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": []
+ },
+ {
+ "id": 301,
+ "type": "SamplerCustomUltraAdvancedPlusEfficient",
+ "pos": [
+ 2430,
+ 110
+ ],
+ "size": [
+ 438.7125,
+ 891.1416666666667
+ ],
+ "flags": {},
+ "order": 39,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 970
+ },
+ {
+ "name": "guider",
+ "type": "GUIDER",
+ "link": 884
+ },
+ {
+ "name": "sampler",
+ "type": "SAMPLER",
+ "link": 849
+ },
+ {
+ "name": "sigmas",
+ "type": "SIGMAS",
+ "link": 850
+ },
+ {
+ "name": "latent_image",
+ "type": "LATENT",
+ "link": 851
+ },
+ {
+ "name": "optional_vae",
+ "shape": 7,
+ "type": "VAE",
+ "link": 852
+ },
+ {
+ "name": "end_at_step",
+ "type": "INT",
+ "widget": {
+ "name": "end_at_step"
+ },
+ "link": 857
+ }
+ ],
+ "outputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "links": null
+ },
+ {
+ "name": "sampler",
+ "type": "SAMPLER",
+ "links": [
+ 909
+ ]
+ },
+ {
+ "name": "sigmas",
+ "type": "SIGMAS",
+ "links": null
+ },
+ {
+ "name": "output",
+ "type": "LATENT",
+ "links": [
+ 910
+ ]
+ },
+ {
+ "name": "denoised_output",
+ "type": "LATENT",
+ "links": null
+ },
+ {
+ "name": "image",
+ "type": "IMAGE",
+ "links": [
+ 941
+ ]
+ },
+ {
+ "name": "vae",
+ "type": "VAE",
+ "links": [
+ 911
+ ]
+ }
+ ],
+ "properties": {
+ "Node name for S&R": "SamplerCustomUltraAdvancedPlusEfficient",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ true,
+ 287744432595674,
+ "fixed",
+ 0,
+ 10000,
+ false,
+ "auto",
+ "true"
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 364,
+ "type": "SaveAnimatedWEBP",
+ "pos": [
+ 2890,
+ 260
+ ],
+ "size": [
+ 410,
+ 430
+ ],
+ "flags": {},
+ "order": 40,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "images",
+ "type": "IMAGE",
+ "link": 941
+ }
+ ],
+ "outputs": [],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "SaveAnimatedWEBP",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "ComfyUI",
+ 24,
+ true,
+ 80,
+ "default"
+ ]
+ },
+ {
+ "id": 336,
+ "type": "SamplerCustomUltraAdvancedEfficient",
+ "pos": [
+ 3790,
+ 100
+ ],
+ "size": [
+ 398.405859375,
+ 925.0705729166666
+ ],
+ "flags": {},
+ "order": 41,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 908
+ },
+ {
+ "name": "positive",
+ "type": "CONDITIONING",
+ "link": 916
+ },
+ {
+ "name": "negative",
+ "type": "CONDITIONING",
+ "link": 917
+ },
+ {
+ "name": "sampler",
+ "type": "SAMPLER",
+ "link": 909
+ },
+ {
+ "name": "sigmas",
+ "type": "SIGMAS",
+ "link": 915
+ },
+ {
+ "name": "latent_image",
+ "type": "LATENT",
+ "link": 910
+ },
+ {
+ "name": "optional_vae",
+ "shape": 7,
+ "type": "VAE",
+ "link": 911
+ },
+ {
+ "name": "start_at_step",
+ "type": "INT",
+ "widget": {
+ "name": "start_at_step"
+ },
+ "link": 918
+ }
+ ],
+ "outputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "links": null
+ },
+ {
+ "name": "positive",
+ "type": "CONDITIONING",
+ "links": null
+ },
+ {
+ "name": "negative",
+ "type": "CONDITIONING",
+ "links": null
+ },
+ {
+ "name": "sampler",
+ "type": "SAMPLER",
+ "links": null
+ },
+ {
+ "name": "sigmas",
+ "type": "SIGMAS",
+ "links": null
+ },
+ {
+ "name": "output",
+ "type": "LATENT",
+ "links": []
+ },
+ {
+ "name": "denoised_output",
+ "type": "LATENT",
+ "links": []
+ },
+ {
+ "name": "image",
+ "type": "IMAGE",
+ "links": [
+ 926
+ ]
+ },
+ {
+ "name": "vae",
+ "type": "VAE",
+ "links": []
+ }
+ ],
+ "properties": {
+ "Node name for S&R": "SamplerCustomUltraAdvancedEfficient",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ false,
+ 287744432595674,
+ "fixed",
+ 1,
+ 0,
+ 10000,
+ false,
+ "auto",
+ "true"
+ ],
+ "color": "#232",
+ "bgcolor": "#353"
+ },
+ {
+ "id": 352,
+ "type": "SaveAnimatedWEBP",
+ "pos": [
+ 4240,
+ 110
+ ],
+ "size": [
+ 360,
+ 410
+ ],
+ "flags": {},
+ "order": 42,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "images",
+ "type": "IMAGE",
+ "link": 926
+ }
+ ],
+ "outputs": [],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "SaveAnimatedWEBP",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "ComfyUI",
+ 24,
+ true,
+ 80,
+ "default"
+ ]
+ },
+ {
+ "id": 354,
+ "type": "MarkdownNote",
+ "pos": [
+ 3290,
+ 630
+ ],
+ "size": [
+ 260,
+ 100
+ ],
+ "flags": {},
+ "order": 12,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [],
+ "properties": {
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "The lora at 5.6 generates more motion but speeds up the fps too"
+ ],
+ "color": "#432",
+ "bgcolor": "#653"
+ },
+ {
+ "id": 133,
+ "type": "LoadImage",
+ "pos": [
+ 830,
+ 540
+ ],
+ "size": [
+ 310,
+ 334
+ ],
+ "flags": {},
+ "order": 13,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [
+ {
+ "name": "IMAGE",
+ "type": "IMAGE",
+ "slot_index": 0,
+ "links": [
+ 967,
+ 968
+ ]
+ },
+ {
+ "name": "MASK",
+ "type": "MASK",
+ "slot_index": 1,
+ "links": null
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.46",
+ "Node name for S&R": "LoadImage",
+ "ue_properties": {
+ "version": "7.0.1",
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "TimeToMove_Monkey-first_frame.png",
+ "image"
+ ]
+ },
+ {
+ "id": 355,
+ "type": "MarkdownNote",
+ "pos": [
+ 2470,
+ -40
+ ],
+ "size": [
+ 370,
+ 100
+ ],
+ "flags": {},
+ "order": 14,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [],
+ "properties": {
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "You can find the samplers used here: https://github.com/GiusTex/ComfyUI-MoreEfficientSamplers"
+ ],
+ "color": "#432",
+ "bgcolor": "#653"
+ },
+ {
+ "id": 273,
+ "type": "WanFirstLastFrameToVideo",
+ "pos": [
+ 1450,
+ 150
+ ],
+ "size": [
+ 287.9513702392578,
+ 278
+ ],
+ "flags": {},
+ "order": 32,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "positive",
+ "type": "CONDITIONING",
+ "link": 779
+ },
+ {
+ "name": "negative",
+ "type": "CONDITIONING",
+ "link": 640
+ },
+ {
+ "name": "vae",
+ "type": "VAE",
+ "link": 641
+ },
+ {
+ "name": "clip_vision_start_image",
+ "shape": 7,
+ "type": "CLIP_VISION_OUTPUT",
+ "link": null
+ },
+ {
+ "name": "clip_vision_end_image",
+ "shape": 7,
+ "type": "CLIP_VISION_OUTPUT",
+ "link": null
+ },
+ {
+ "name": "start_image",
+ "shape": 7,
+ "type": "IMAGE",
+ "link": 968
+ },
+ {
+ "name": "end_image",
+ "shape": 7,
+ "type": "IMAGE",
+ "link": null
+ },
+ {
+ "name": "width",
+ "type": "INT",
+ "widget": {
+ "name": "width"
+ },
+ "link": 894
+ },
+ {
+ "name": "height",
+ "type": "INT",
+ "widget": {
+ "name": "height"
+ },
+ "link": 895
+ }
+ ],
+ "outputs": [
+ {
+ "name": "positive",
+ "type": "CONDITIONING",
+ "links": [
+ 880,
+ 916
+ ]
+ },
+ {
+ "name": "negative",
+ "type": "CONDITIONING",
+ "links": [
+ 881,
+ 917
+ ]
+ },
+ {
+ "name": "latent",
+ "type": "LATENT",
+ "links": [
+ 797
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.3.76",
+ "Node name for S&R": "WanFirstLastFrameToVideo",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ 832,
+ 480,
+ 81,
+ 1
+ ],
+ "color": "#323",
+ "bgcolor": "#535"
+ },
+ {
+ "id": 335,
+ "type": "LoraLoader",
+ "pos": [
+ 470,
+ -170
+ ],
+ "size": [
+ 320,
+ 134
+ ],
+ "flags": {},
+ "order": 20,
+ "mode": 0,
+ "inputs": [
+ {
+ "name": "model",
+ "type": "MODEL",
+ "link": 896
+ },
+ {
+ "name": "clip",
+ "type": "CLIP",
+ "link": 897
+ }
+ ],
+ "outputs": [
+ {
+ "name": "MODEL",
+ "type": "MODEL",
+ "links": [
+ 898
+ ]
+ },
+ {
+ "name": "CLIP",
+ "type": "CLIP",
+ "links": [
+ 899,
+ 900
+ ]
+ }
+ ],
+ "properties": {
+ "cnr_id": "comfy-core",
+ "ver": "0.11.0",
+ "Node name for S&R": "LoraLoader",
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "input_ue_unconnectable": {},
+ "version": "7.5.2"
+ }
+ },
+ "widgets_values": [
+ "Wan\\lightx2v_I2V_14B_480p_cfg_step_distill_rank128_bf16.safetensors",
+ 5.6,
+ 1
+ ],
+ "color": "#223",
+ "bgcolor": "#335"
+ },
+ {
+ "id": 378,
+ "type": "MarkdownNote",
+ "pos": [
+ 450,
+ -320
+ ],
+ "size": [
+ 370,
+ 100
+ ],
+ "flags": {},
+ "order": 15,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [],
+ "properties": {
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "You can find the lora here: https://huggingface.co/Kijai/WanVideo_comfy/tree/main/Lightx2v"
+ ],
+ "color": "#432",
+ "bgcolor": "#653"
+ },
+ {
+ "id": 384,
+ "type": "MarkdownNote",
+ "pos": [
+ 170,
+ 100
+ ],
+ "size": [
+ 250,
+ 92
+ ],
+ "flags": {},
+ "order": 16,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [],
+ "properties": {
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "You can use the default comfyui clip loader too"
+ ],
+ "color": "#432",
+ "bgcolor": "#653"
+ },
+ {
+ "id": 385,
+ "type": "MarkdownNote",
+ "pos": [
+ 60,
+ -370
+ ],
+ "size": [
+ 350,
+ 92
+ ],
+ "flags": {},
+ "order": 17,
+ "mode": 0,
+ "inputs": [],
+ "outputs": [],
+ "properties": {
+ "ue_properties": {
+ "widget_ue_connectable": {},
+ "version": "7.5.2",
+ "input_ue_unconnectable": {}
+ }
+ },
+ "widgets_values": [
+ "If you have enough vram you can use bigger versions (fp8, etc) or quantizations (q8, etc) of the model"
+ ],
+ "color": "#432",
+ "bgcolor": "#653"
+ }
+ ],
+ "links": [
+ [
+ 272,
+ 167,
+ 0,
+ 168,
+ 0,
+ "MODEL"
+ ],
+ [
+ 273,
+ 168,
+ 0,
+ 169,
+ 0,
+ "MODEL"
+ ],
+ [
+ 640,
+ 121,
+ 0,
+ 273,
+ 1,
+ "CONDITIONING"
+ ],
+ [
+ 641,
+ 189,
+ 0,
+ 273,
+ 2,
+ "VAE"
+ ],
+ [
+ 711,
+ 94,
+ 0,
+ 170,
+ 1,
+ "INT"
+ ],
+ [
+ 728,
+ 94,
+ 0,
+ 295,
+ 0,
+ "INT"
+ ],
+ [
+ 731,
+ 189,
+ 0,
+ 297,
+ 0,
+ "VAE"
+ ],
+ [
+ 774,
+ 297,
+ 0,
+ 305,
+ 1,
+ "LATENT"
+ ],
+ [
+ 775,
+ 142,
+ 0,
+ 305,
+ 2,
+ "MASK"
+ ],
+ [
+ 779,
+ 120,
+ 0,
+ 273,
+ 0,
+ "CONDITIONING"
+ ],
+ [
+ 797,
+ 273,
+ 2,
+ 305,
+ 0,
+ "LATENT"
+ ],
+ [
+ 849,
+ 290,
+ 0,
+ 301,
+ 2,
+ "SAMPLER"
+ ],
+ [
+ 850,
+ 170,
+ 0,
+ 301,
+ 3,
+ "SIGMAS"
+ ],
+ [
+ 851,
+ 305,
+ 0,
+ 301,
+ 4,
+ "LATENT"
+ ],
+ [
+ 852,
+ 189,
+ 0,
+ 301,
+ 5,
+ "VAE"
+ ],
+ [
+ 857,
+ 91,
+ 0,
+ 301,
+ 6,
+ "INT"
+ ],
+ [
+ 880,
+ 273,
+ 0,
+ 333,
+ 1,
+ "CONDITIONING"
+ ],
+ [
+ 881,
+ 273,
+ 1,
+ 333,
+ 2,
+ "CONDITIONING"
+ ],
+ [
+ 882,
+ 305,
+ 0,
+ 333,
+ 3,
+ "LATENT"
+ ],
+ [
+ 883,
+ 295,
+ 0,
+ 333,
+ 4,
+ "FLOAT"
+ ],
+ [
+ 884,
+ 333,
+ 0,
+ 301,
+ 1,
+ "GUIDER"
+ ],
+ [
+ 894,
+ 334,
+ 0,
+ 273,
+ 7,
+ "INT"
+ ],
+ [
+ 895,
+ 334,
+ 1,
+ 273,
+ 8,
+ "INT"
+ ],
+ [
+ 896,
+ 165,
+ 0,
+ 335,
+ 0,
+ "MODEL"
+ ],
+ [
+ 897,
+ 118,
+ 0,
+ 335,
+ 1,
+ "CLIP"
+ ],
+ [
+ 898,
+ 335,
+ 0,
+ 167,
+ 0,
+ "MODEL"
+ ],
+ [
+ 899,
+ 335,
+ 1,
+ 120,
+ 0,
+ "CLIP"
+ ],
+ [
+ 900,
+ 335,
+ 1,
+ 121,
+ 0,
+ "CLIP"
+ ],
+ [
+ 901,
+ 169,
+ 0,
+ 170,
+ 0,
+ "MODEL"
+ ],
+ [
+ 904,
+ 339,
+ 0,
+ 340,
+ 0,
+ "MODEL"
+ ],
+ [
+ 905,
+ 340,
+ 0,
+ 341,
+ 0,
+ "MODEL"
+ ],
+ [
+ 906,
+ 338,
+ 0,
+ 337,
+ 0,
+ "MODEL"
+ ],
+ [
+ 907,
+ 337,
+ 0,
+ 339,
+ 0,
+ "MODEL"
+ ],
+ [
+ 908,
+ 341,
+ 0,
+ 336,
+ 0,
+ "MODEL"
+ ],
+ [
+ 909,
+ 301,
+ 1,
+ 336,
+ 3,
+ "SAMPLER"
+ ],
+ [
+ 910,
+ 301,
+ 3,
+ 336,
+ 5,
+ "LATENT"
+ ],
+ [
+ 911,
+ 301,
+ 6,
+ 336,
+ 6,
+ "VAE"
+ ],
+ [
+ 913,
+ 94,
+ 0,
+ 343,
+ 1,
+ "INT"
+ ],
+ [
+ 914,
+ 341,
+ 0,
+ 343,
+ 0,
+ "MODEL"
+ ],
+ [
+ 915,
+ 343,
+ 0,
+ 336,
+ 4,
+ "SIGMAS"
+ ],
+ [
+ 916,
+ 273,
+ 0,
+ 336,
+ 1,
+ "CONDITIONING"
+ ],
+ [
+ 917,
+ 273,
+ 1,
+ 336,
+ 2,
+ "CONDITIONING"
+ ],
+ [
+ 918,
+ 91,
+ 0,
+ 336,
+ 7,
+ "INT"
+ ],
+ [
+ 921,
+ 347,
+ 0,
+ 348,
+ 0,
+ "VIDEO"
+ ],
+ [
+ 923,
+ 349,
+ 0,
+ 350,
+ 0,
+ "VIDEO"
+ ],
+ [
+ 926,
+ 336,
+ 7,
+ 352,
+ 0,
+ "IMAGE"
+ ],
+ [
+ 941,
+ 301,
+ 5,
+ 364,
+ 0,
+ "IMAGE"
+ ],
+ [
+ 965,
+ 348,
+ 0,
+ 297,
+ 1,
+ "IMAGE"
+ ],
+ [
+ 966,
+ 350,
+ 0,
+ 142,
+ 0,
+ "IMAGE"
+ ],
+ [
+ 967,
+ 133,
+ 0,
+ 334,
+ 0,
+ "IMAGE"
+ ],
+ [
+ 968,
+ 133,
+ 0,
+ 273,
+ 5,
+ "IMAGE"
+ ],
+ [
+ 969,
+ 169,
+ 0,
+ 333,
+ 0,
+ "MODEL"
+ ],
+ [
+ 970,
+ 169,
+ 0,
+ 301,
+ 0,
+ "MODEL"
+ ]
+ ],
+ "groups": [
+ {
+ "id": 1,
+ "title": "Load high noise model",
+ "bounding": [
+ 50,
+ -270,
+ 1760,
+ 320
+ ],
+ "color": "#3f789e",
+ "font_size": 24,
+ "flags": {}
+ },
+ {
+ "id": 2,
+ "title": "Load image and videos",
+ "bounding": [
+ 550,
+ 450,
+ 840,
+ 1090
+ ],
+ "color": "#88A",
+ "font_size": 24,
+ "flags": {}
+ },
+ {
+ "id": 3,
+ "title": "Prepare latent & add TTM guide",
+ "bounding": [
+ 1430,
+ 80,
+ 920,
+ 880
+ ],
+ "color": "#a1309b",
+ "font_size": 24,
+ "flags": {}
+ },
+ {
+ "id": 4,
+ "title": "Load low noise model (as refiner)",
+ "bounding": [
+ 2910,
+ -340,
+ 840,
+ 660
+ ],
+ "color": "#3f789e",
+ "font_size": 24,
+ "flags": {}
+ }
+ ],
+ "config": {},
+ "extra": {
+ "ds": {
+ "scale": 0.5989500000000004,
+ "offset": [
+ -859.8618480384729,
+ 258.50971914348713
+ ]
+ },
+ "frontendVersion": "1.37.11",
+ "node_versions": {
+ "ComfyUI-WanVideoWrapper": "5a2383621a05825d0d0437781afcb8552d9590fd",
+ "comfy-core": "0.3.26",
+ "ComfyUI-VideoHelperSuite": "0a75c7958fe320efcb052f1d9f8451fd20c730a8"
+ },
+ "VHS_latentpreview": true,
+ "VHS_latentpreviewrate": 0,
+ "VHS_MetadataImage": true,
+ "VHS_KeepIntermediate": true,
+ "workflowRendererVersion": "LG",
+ "ue_links": [],
+ "links_added_by_ue": []
+ },
+ "version": 0.4
+}
\ No newline at end of file