| import torch |
| import numpy as np |
| import comfy.utils, comfy.sample, comfy.samplers, comfy.controlnet, comfy.model_base, comfy.model_management, comfy.sampler_helpers, comfy.supported_models |
| from comfy.model_patcher import ModelPatcher |
|
|
| from nodes import RepeatLatentBatch, CLIPTextEncode, VAEEncodeForInpaint |
| from ..modules.layer_diffuse import LayerMethod |
| from ..config import * |
|
|
| from .. import easyCache, sampler |
|
|
|
|
| |
| class samplerSettings: |
|
|
| def __init__(self): |
| pass |
|
|
| @classmethod |
| def INPUT_TYPES(cls): |
| return {"required": |
| {"pipe": ("PIPE_LINE",), |
| "steps": ("INT", {"default": 20, "min": 1, "max": 10000}), |
| "cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}), |
| "sampler_name": (comfy.samplers.KSampler.SAMPLERS,), |
| "scheduler": (comfy.samplers.KSampler.SCHEDULERS + NEW_SCHEDULERS,), |
| "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), |
| "seed": ("INT", {"default": 0, "min": 0, "max": MAX_SEED_NUM}), |
| }, |
| "optional": { |
| "image_to_latent": ("IMAGE",), |
| "latent": ("LATENT",), |
| }, |
| "hidden": |
| {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"}, |
| } |
|
|
| RETURN_TYPES = ("PIPE_LINE", ) |
| RETURN_NAMES = ("pipe",) |
|
|
| FUNCTION = "settings" |
| CATEGORY = "EasyUse/PreSampling" |
|
|
| def settings(self, pipe, steps, cfg, sampler_name, scheduler, denoise, seed, image_to_latent=None, latent=None, prompt=None, extra_pnginfo=None, my_unique_id=None): |
| |
| vae = pipe["vae"] |
| batch_size = pipe["loader_settings"]["batch_size"] if "batch_size" in pipe["loader_settings"] else 1 |
| if image_to_latent is not None: |
| _, height, width, _ = image_to_latent.shape |
| if height == 1 and width == 1: |
| samples = pipe["samples"] |
| images = pipe["images"] |
| else: |
| samples = {"samples": vae.encode(image_to_latent[:, :, :, :3])} |
| samples = RepeatLatentBatch().repeat(samples, batch_size)[0] |
| images = image_to_latent |
| elif latent is not None: |
| samples = latent |
| images = pipe["images"] |
| else: |
| samples = pipe["samples"] |
| images = pipe["images"] |
|
|
| new_pipe = { |
| "model": pipe['model'], |
| "positive": pipe['positive'], |
| "negative": pipe['negative'], |
| "vae": pipe['vae'], |
| "clip": pipe['clip'], |
|
|
| "samples": samples, |
| "images": images, |
| "seed": seed, |
|
|
| "loader_settings": { |
| **pipe["loader_settings"], |
| "steps": steps, |
| "cfg": cfg, |
| "sampler_name": sampler_name, |
| "scheduler": scheduler, |
| "denoise": denoise, |
| "add_noise": "enabled" |
| } |
| } |
|
|
| del pipe |
|
|
| return {"ui": {"value": [seed]}, "result": (new_pipe,)} |
|
|
| |
| class samplerSettingsAdvanced: |
|
|
| def __init__(self): |
| pass |
|
|
| @classmethod |
| def INPUT_TYPES(cls): |
| return {"required": |
| {"pipe": ("PIPE_LINE",), |
| "steps": ("INT", {"default": 20, "min": 1, "max": 10000}), |
| "cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}), |
| "sampler_name": (comfy.samplers.KSampler.SAMPLERS,), |
| "scheduler": (comfy.samplers.KSampler.SCHEDULERS + NEW_SCHEDULERS,), |
| "start_at_step": ("INT", {"default": 0, "min": 0, "max": 10000}), |
| "end_at_step": ("INT", {"default": 10000, "min": 0, "max": 10000}), |
| "add_noise": (["enable (CPU)", "enable (GPU=A1111)", "disable"], {"default": "enable (CPU)"}), |
| "seed": ("INT", {"default": 0, "min": 0, "max": MAX_SEED_NUM}), |
| "return_with_leftover_noise": (["disable", "enable"], ), |
| }, |
| "optional": { |
| "image_to_latent": ("IMAGE",), |
| "latent": ("LATENT",) |
| }, |
| "hidden": |
| {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"}, |
| } |
|
|
| RETURN_TYPES = ("PIPE_LINE", ) |
| RETURN_NAMES = ("pipe",) |
|
|
| FUNCTION = "settings" |
| CATEGORY = "EasyUse/PreSampling" |
|
|
| def settings(self, pipe, steps, cfg, sampler_name, scheduler, start_at_step, end_at_step, add_noise, seed, return_with_leftover_noise, image_to_latent=None, latent=None, prompt=None, extra_pnginfo=None, my_unique_id=None): |
| |
| vae = pipe["vae"] |
| batch_size = pipe["loader_settings"]["batch_size"] if "batch_size" in pipe["loader_settings"] else 1 |
| if image_to_latent is not None: |
| _, height, width, _ = image_to_latent.shape |
| if height == 1 and width == 1: |
| samples = pipe["samples"] |
| images = pipe["images"] |
| else: |
| samples = {"samples": vae.encode(image_to_latent[:, :, :, :3])} |
| samples = RepeatLatentBatch().repeat(samples, batch_size)[0] |
| images = image_to_latent |
| elif latent is not None: |
| samples = latent |
| images = pipe["images"] |
| else: |
| samples = pipe["samples"] |
| images = pipe["images"] |
|
|
| force_full_denoise = True |
| if return_with_leftover_noise == "enable": |
| force_full_denoise = False |
|
|
| new_pipe = { |
| "model": pipe['model'], |
| "positive": pipe['positive'], |
| "negative": pipe['negative'], |
| "vae": pipe['vae'], |
| "clip": pipe['clip'], |
|
|
| "samples": samples, |
| "images": images, |
| "seed": seed, |
|
|
| "loader_settings": { |
| **pipe["loader_settings"], |
| "steps": steps, |
| "cfg": cfg, |
| "sampler_name": sampler_name, |
| "scheduler": scheduler, |
| "start_step": start_at_step, |
| "last_step": end_at_step, |
| "denoise": 1.0, |
| "add_noise": add_noise, |
| "force_full_denoise": force_full_denoise |
| } |
| } |
|
|
| del pipe |
|
|
| return {"ui": {"value": [seed]}, "result": (new_pipe,)} |
|
|
| |
| class samplerSettingsNoiseIn: |
|
|
| def __init__(self): |
| pass |
|
|
| @classmethod |
| def INPUT_TYPES(cls): |
| return {"required": |
| {"pipe": ("PIPE_LINE",), |
| "factor": ("FLOAT", {"default": 0.1, "min": 0.0, "max": 1.0, "step":0.01, "round": 0.01}), |
| "steps": ("INT", {"default": 20, "min": 1, "max": 10000}), |
| "cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}), |
| "sampler_name": (comfy.samplers.KSampler.SAMPLERS,), |
| "scheduler": (comfy.samplers.KSampler.SCHEDULERS+NEW_SCHEDULERS,), |
| "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), |
| "seed": ("INT", {"default": 0, "min": 0, "max": MAX_SEED_NUM}), |
| }, |
| "optional": { |
| "optional_noise_seed": ("INT",{"forceInput": True}), |
| "optional_latent": ("LATENT",), |
| }, |
| "hidden": |
| {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"}, |
| } |
|
|
| RETURN_TYPES = ("PIPE_LINE", ) |
| RETURN_NAMES = ("pipe",) |
|
|
| FUNCTION = "settings" |
| CATEGORY = "EasyUse/PreSampling" |
|
|
| def slerp(self, val, low, high): |
| dims = low.shape |
|
|
| low = low.reshape(dims[0], -1) |
| high = high.reshape(dims[0], -1) |
|
|
| low_norm = low / torch.norm(low, dim=1, keepdim=True) |
| high_norm = high / torch.norm(high, dim=1, keepdim=True) |
|
|
| low_norm[low_norm != low_norm] = 0.0 |
| high_norm[high_norm != high_norm] = 0.0 |
|
|
| omega = torch.acos((low_norm * high_norm).sum(1)) |
| so = torch.sin(omega) |
| res = (torch.sin((1.0 - val) * omega) / so).unsqueeze(1) * low + (torch.sin(val * omega) / so).unsqueeze( |
| 1) * high |
|
|
| return res.reshape(dims) |
|
|
| def prepare_mask(self, mask, shape): |
| mask = torch.nn.functional.interpolate(mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])), |
| size=(shape[2], shape[3]), mode="bilinear") |
| mask = mask.expand((-1, shape[1], -1, -1)) |
| if mask.shape[0] < shape[0]: |
| mask = mask.repeat((shape[0] - 1) // mask.shape[0] + 1, 1, 1, 1)[:shape[0]] |
| return mask |
|
|
| def expand_mask(self, mask, expand, tapered_corners): |
| try: |
| import scipy |
|
|
| c = 0 if tapered_corners else 1 |
| kernel = np.array([[c, 1, c], |
| [1, 1, 1], |
| [c, 1, c]]) |
| mask = mask.reshape((-1, mask.shape[-2], mask.shape[-1])) |
| out = [] |
| for m in mask: |
| output = m.numpy() |
| for _ in range(abs(expand)): |
| if expand < 0: |
| output = scipy.ndimage.grey_erosion(output, footprint=kernel) |
| else: |
| output = scipy.ndimage.grey_dilation(output, footprint=kernel) |
| output = torch.from_numpy(output) |
| out.append(output) |
|
|
| return torch.stack(out, dim=0) |
| except: |
| return None |
|
|
| def settings(self, pipe, factor, steps, cfg, sampler_name, scheduler, denoise, seed, optional_noise_seed=None, optional_latent=None, prompt=None, extra_pnginfo=None, my_unique_id=None): |
| latent = optional_latent if optional_latent is not None else pipe["samples"] |
| model = pipe["model"] |
|
|
| |
| batch_size, _, height, width = latent["samples"].shape |
| generator = torch.manual_seed(seed) |
| base_noise = torch.randn((1, 4, height, width), dtype=torch.float32, device="cpu", generator=generator).repeat(batch_size, 1, 1, 1).cpu() |
|
|
| |
| if optional_noise_seed is None or optional_noise_seed == seed: |
| optional_noise_seed = seed+1 |
| generator = torch.manual_seed(optional_noise_seed) |
| variation_noise = torch.randn((batch_size, 4, height, width), dtype=torch.float32, device="cpu", |
| generator=generator).cpu() |
|
|
| slerp_noise = self.slerp(factor, base_noise, variation_noise) |
|
|
| end_at_step = steps |
| start_at_step = round(end_at_step - end_at_step * denoise) |
|
|
| device = comfy.model_management.get_torch_device() |
| comfy.model_management.load_model_gpu(model) |
| model_patcher = comfy.model_patcher.ModelPatcher(model.model, load_device=device, offload_device=comfy.model_management.unet_offload_device()) |
| sampler = comfy.samplers.KSampler(model_patcher, steps=steps, device=device, sampler=sampler_name, |
| scheduler=scheduler, denoise=1.0, model_options=model.model_options) |
| sigmas = sampler.sigmas |
| sigma = sigmas[start_at_step] - sigmas[end_at_step] |
| sigma /= model.model.latent_format.scale_factor |
| sigma = sigma.cpu().numpy() |
|
|
| work_latent = latent.copy() |
| work_latent["samples"] = latent["samples"].clone() + slerp_noise * sigma |
|
|
| if "noise_mask" in latent: |
| noise_mask = self.prepare_mask(latent["noise_mask"], latent['samples'].shape) |
| work_latent["samples"] = noise_mask * work_latent["samples"] + (1-noise_mask) * latent["samples"] |
| work_latent['noise_mask'] = self.expand_mask(latent["noise_mask"].clone(), 5, True) |
|
|
| if pipe is None: |
| pipe = {} |
|
|
| new_pipe = { |
| "model": pipe['model'], |
| "positive": pipe['positive'], |
| "negative": pipe['negative'], |
| "vae": pipe['vae'], |
| "clip": pipe['clip'], |
|
|
| "samples": work_latent, |
| "images": pipe['images'], |
| "seed": seed, |
|
|
| "loader_settings": { |
| **pipe["loader_settings"], |
| "steps": steps, |
| "cfg": cfg, |
| "sampler_name": sampler_name, |
| "scheduler": scheduler, |
| "denoise": denoise, |
| "add_noise": "disable" |
| } |
| } |
|
|
| return (new_pipe,) |
|
|
| |
| class samplerCustomSettings: |
|
|
| def __init__(self): |
| pass |
|
|
| @classmethod |
| def INPUT_TYPES(cls): |
| return {"required": { |
| "pipe": ("PIPE_LINE",), |
| "guider": (['CFG','DualCFG','Basic', 'IP2P+CFG', 'IP2P+DualCFG','IP2P+Basic'],{"default":"Basic"}), |
| "cfg": ("FLOAT", {"default": 3.5, "min": 0.0, "max": 100.0}), |
| "cfg_negative": ("FLOAT", {"default": 1.5, "min": 0.0, "max": 100.0}), |
| "sampler_name": (comfy.samplers.KSampler.SAMPLERS + ['inversed_euler'],), |
| "scheduler": (comfy.samplers.KSampler.SCHEDULERS + ['karrasADV','exponentialADV','polyExponential', 'sdturbo', 'vp', 'alignYourSteps', 'gits'],), |
| "coeff": ("FLOAT", {"default": 1.20, "min": 0.80, "max": 1.50, "step": 0.05}), |
| "steps": ("INT", {"default": 20, "min": 1, "max": 10000}), |
| "sigma_max": ("FLOAT", {"default": 14.614642, "min": 0.0, "max": 1000.0, "step": 0.01, "round": False}), |
| "sigma_min": ("FLOAT", {"default": 0.0291675, "min": 0.0, "max": 1000.0, "step": 0.01, "round": False}), |
| "rho": ("FLOAT", {"default": 7.0, "min": 0.0, "max": 100.0, "step": 0.01, "round": False}), |
| "beta_d": ("FLOAT", {"default": 19.9, "min": 0.0, "max": 1000.0, "step": 0.01, "round": False}), |
| "beta_min": ("FLOAT", {"default": 0.1, "min": 0.0, "max": 1000.0, "step": 0.01, "round": False}), |
| "eps_s": ("FLOAT", {"default": 0.001, "min": 0.0, "max": 1.0, "step": 0.0001, "round": False}), |
| "flip_sigmas": ("BOOLEAN", {"default": False}), |
| "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), |
| "add_noise": (["enable (CPU)", "enable (GPU=A1111)", "disable"], {"default": "enable (CPU)"}), |
| "seed": ("INT", {"default": 0, "min": 0, "max": MAX_SEED_NUM}), |
| }, |
| "optional": { |
| "image_to_latent": ("IMAGE",), |
| "latent": ("LATENT",), |
| "optional_sampler":("SAMPLER",), |
| "optional_sigmas":("SIGMAS",), |
| }, |
| "hidden": |
| {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"}, |
| } |
|
|
| RETURN_TYPES = ("PIPE_LINE", ) |
| RETURN_NAMES = ("pipe",) |
|
|
| FUNCTION = "settings" |
| CATEGORY = "EasyUse/PreSampling" |
|
|
| def ip2p(self, positive, negative, vae, pixels, latent=None): |
| if latent is not None: |
| concat_latent = latent |
| else: |
| x = (pixels.shape[1] // 8) * 8 |
| y = (pixels.shape[2] // 8) * 8 |
|
|
| if pixels.shape[1] != x or pixels.shape[2] != y: |
| x_offset = (pixels.shape[1] % 8) // 2 |
| y_offset = (pixels.shape[2] % 8) // 2 |
| pixels = pixels[:,x_offset:x + x_offset, y_offset:y + y_offset,:] |
|
|
| concat_latent = vae.encode(pixels) |
|
|
| out_latent = {} |
| out_latent["samples"] = torch.zeros_like(concat_latent) |
|
|
| out = [] |
| for conditioning in [positive, negative]: |
| c = [] |
| for t in conditioning: |
| d = t[1].copy() |
| d["concat_latent_image"] = concat_latent |
| n = [t[0], d] |
| c.append(n) |
| out.append(c) |
| return (out[0], out[1], out_latent) |
|
|
|
|
| def settings(self, pipe, guider, cfg, cfg_negative, sampler_name, scheduler, coeff, steps, sigma_max, sigma_min, rho, beta_d, beta_min, eps_s, flip_sigmas, denoise, add_noise, seed, image_to_latent=None, latent=None, optional_sampler=None, optional_sigmas=None, prompt=None, extra_pnginfo=None, my_unique_id=None): |
|
|
| |
| vae = pipe["vae"] |
| model = pipe["model"] |
| positive = pipe['positive'] |
| negative = pipe['negative'] |
| batch_size = pipe["loader_settings"]["batch_size"] if "batch_size" in pipe["loader_settings"] else 1 |
|
|
| if image_to_latent is not None: |
| _, height, width, _ = image_to_latent.shape |
| if height == 1 and width == 1: |
| samples = pipe["samples"] |
| images = pipe["images"] |
| else: |
| if "IP2P" in guider: |
| positive, negative, latent = self.ip2p(pipe['positive'], pipe['negative'], vae, image_to_latent) |
| samples = latent |
| else: |
| samples = {"samples": vae.encode(image_to_latent[:, :, :, :3])} |
| samples = RepeatLatentBatch().repeat(samples, batch_size)[0] |
| images = image_to_latent |
| elif latent is not None: |
| if "IP2P" in guider: |
| positive, negative, latent = self.ip2p(pipe['positive'], pipe['negative'], latent=latent) |
| samples = latent |
| else: |
| samples = latent |
| images = pipe["images"] |
| else: |
| samples = pipe["samples"] |
| images = pipe["images"] |
|
|
|
|
| new_pipe = { |
| "model": model, |
| "positive": positive, |
| "negative": negative, |
| "vae": pipe['vae'], |
| "clip": pipe['clip'], |
|
|
| "samples": samples, |
| "images": images, |
| "seed": seed, |
|
|
| "loader_settings": { |
| **pipe["loader_settings"], |
| "middle": pipe['negative'], |
| "steps": steps, |
| "cfg": cfg, |
| "cfg_negative": cfg_negative, |
| "sampler_name": sampler_name, |
| "scheduler": scheduler, |
| "denoise": denoise, |
| "add_noise": add_noise, |
| "custom": { |
| "guider": guider, |
| "coeff": coeff, |
| "sigma_max": sigma_max, |
| "sigma_min": sigma_min, |
| "rho": rho, |
| "beta_d": beta_d, |
| "beta_min": beta_min, |
| "eps_s": beta_min, |
| "flip_sigmas": flip_sigmas |
| }, |
| "optional_sampler": optional_sampler, |
| "optional_sigmas": optional_sigmas |
| } |
| } |
|
|
| del pipe |
|
|
| return {"ui": {"value": [seed]}, "result": (new_pipe,)} |
|
|
| |
| from ..libs.gradual_latent_hires_fix import sample_dpmpp_2s_ancestral, sample_dpmpp_2m_sde, sample_lcm, sample_euler_ancestral |
| class sdTurboSettings: |
| def __init__(self): |
| pass |
|
|
| @classmethod |
| def INPUT_TYPES(cls): |
| return {"required": { |
| "pipe": ("PIPE_LINE",), |
| "steps": ("INT", {"default": 1, "min": 1, "max": 10}), |
| "cfg": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0}), |
| "sampler_name": (comfy.samplers.SAMPLER_NAMES,), |
| "eta": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01, "round": False}), |
| "s_noise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01, "round": False}), |
| "upscale_ratio": ("FLOAT", {"default": 2.0, "min": 0.0, "max": 16.0, "step": 0.01, "round": False}), |
| "start_step": ("INT", {"default": 5, "min": 0, "max": 1000, "step": 1}), |
| "end_step": ("INT", {"default": 15, "min": 0, "max": 1000, "step": 1}), |
| "upscale_n_step": ("INT", {"default": 3, "min": 0, "max": 1000, "step": 1}), |
| "unsharp_kernel_size": ("INT", {"default": 3, "min": 1, "max": 21, "step": 1}), |
| "unsharp_sigma": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 10.0, "step": 0.01, "round": False}), |
| "unsharp_strength": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 10.0, "step": 0.01, "round": False}), |
| "seed": ("INT", {"default": 0, "min": 0, "max": MAX_SEED_NUM}), |
| }, |
| "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"}, |
| } |
|
|
| RETURN_TYPES = ("PIPE_LINE",) |
| RETURN_NAMES = ("pipe",) |
|
|
| FUNCTION = "settings" |
| CATEGORY = "EasyUse/PreSampling" |
|
|
| def settings(self, pipe, steps, cfg, sampler_name, eta, s_noise, upscale_ratio, start_step, end_step, upscale_n_step, unsharp_kernel_size, unsharp_sigma, unsharp_strength, seed, prompt=None, extra_pnginfo=None, my_unique_id=None): |
| model = pipe['model'] |
| |
| timesteps = torch.flip(torch.arange(1, 11) * 100 - 1, (0,))[:steps] |
| sigmas = model.model.model_sampling.sigma(timesteps) |
| sigmas = torch.cat([sigmas, sigmas.new_zeros([1])]) |
|
|
| |
| sample_function = None |
| extra_options = { |
| "eta": eta, |
| "s_noise": s_noise, |
| "upscale_ratio": upscale_ratio, |
| "start_step": start_step, |
| "end_step": end_step, |
| "upscale_n_step": upscale_n_step, |
| "unsharp_kernel_size": unsharp_kernel_size, |
| "unsharp_sigma": unsharp_sigma, |
| "unsharp_strength": unsharp_strength, |
| } |
| if sampler_name == "euler_ancestral": |
| sample_function = sample_euler_ancestral |
| elif sampler_name == "dpmpp_2s_ancestral": |
| sample_function = sample_dpmpp_2s_ancestral |
| elif sampler_name == "dpmpp_2m_sde": |
| sample_function = sample_dpmpp_2m_sde |
| elif sampler_name == "lcm": |
| sample_function = sample_lcm |
|
|
| if sample_function is not None: |
| unsharp_kernel_size = unsharp_kernel_size if unsharp_kernel_size % 2 == 1 else unsharp_kernel_size + 1 |
| extra_options["unsharp_kernel_size"] = unsharp_kernel_size |
| _sampler = comfy.samplers.KSAMPLER(sample_function, extra_options) |
| else: |
| _sampler = comfy.samplers.sampler_object(sampler_name) |
| extra_options = None |
|
|
| new_pipe = { |
| "model": pipe['model'], |
| "positive": pipe['positive'], |
| "negative": pipe['negative'], |
| "vae": pipe['vae'], |
| "clip": pipe['clip'], |
|
|
| "samples": pipe["samples"], |
| "images": pipe["images"], |
| "seed": seed, |
|
|
| "loader_settings": { |
| **pipe["loader_settings"], |
| "extra_options": extra_options, |
| "sampler": _sampler, |
| "sigmas": sigmas, |
| "steps": steps, |
| "cfg": cfg, |
| "add_noise": "enabled" |
| } |
| } |
|
|
| del pipe |
|
|
| return {"ui": {"value": [seed]}, "result": (new_pipe,)} |
|
|
|
|
| |
| class cascadeSettings: |
|
|
| def __init__(self): |
| pass |
|
|
| @classmethod |
| def INPUT_TYPES(cls): |
| return {"required": |
| {"pipe": ("PIPE_LINE",), |
| "encode_vae_name": (["None"] + folder_paths.get_filename_list("vae"),), |
| "decode_vae_name": (["None"] + folder_paths.get_filename_list("vae"),), |
| "steps": ("INT", {"default": 20, "min": 1, "max": 10000}), |
| "cfg": ("FLOAT", {"default": 4.0, "min": 0.0, "max": 100.0}), |
| "sampler_name": (comfy.samplers.KSampler.SAMPLERS, {"default":"euler_ancestral"}), |
| "scheduler": (comfy.samplers.KSampler.SCHEDULERS, {"default":"simple"}), |
| "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), |
| "seed": ("INT", {"default": 0, "min": 0, "max": MAX_SEED_NUM}), |
| }, |
| "optional": { |
| "image_to_latent_c": ("IMAGE",), |
| "latent_c": ("LATENT",), |
| }, |
| "hidden":{"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"}, |
| } |
|
|
| RETURN_TYPES = ("PIPE_LINE",) |
| RETURN_NAMES = ("pipe",) |
|
|
| FUNCTION = "settings" |
| CATEGORY = "EasyUse/PreSampling" |
|
|
| def settings(self, pipe, encode_vae_name, decode_vae_name, steps, cfg, sampler_name, scheduler, denoise, seed, model=None, image_to_latent_c=None, latent_c=None, prompt=None, extra_pnginfo=None, my_unique_id=None): |
| images, samples_c = None, None |
| samples = pipe['samples'] |
| batch_size = pipe["loader_settings"]["batch_size"] if "batch_size" in pipe["loader_settings"] else 1 |
|
|
| encode_vae_name = encode_vae_name if encode_vae_name is not None else pipe['loader_settings']['encode_vae_name'] |
| decode_vae_name = decode_vae_name if decode_vae_name is not None else pipe['loader_settings']['decode_vae_name'] |
|
|
| if image_to_latent_c is not None: |
| if encode_vae_name != 'None': |
| encode_vae = easyCache.load_vae(encode_vae_name) |
| else: |
| encode_vae = pipe['vae'][0] |
| if "compression" not in pipe["loader_settings"]: |
| raise Exception("compression is not found") |
| compression = pipe["loader_settings"]['compression'] |
| width = image_to_latent_c.shape[-2] |
| height = image_to_latent_c.shape[-3] |
| out_width = (width // compression) * encode_vae.downscale_ratio |
| out_height = (height // compression) * encode_vae.downscale_ratio |
|
|
| s = comfy.utils.common_upscale(image_to_latent_c.movedim(-1, 1), out_width, out_height, "bicubic", |
| "center").movedim(1, |
| -1) |
| c_latent = encode_vae.encode(s[:, :, :, :3]) |
| b_latent = torch.zeros([c_latent.shape[0], 4, height // 4, width // 4]) |
|
|
| samples_c = {"samples": c_latent} |
| samples_c = RepeatLatentBatch().repeat(samples_c, batch_size)[0] |
|
|
| samples_b = {"samples": b_latent} |
| samples_b = RepeatLatentBatch().repeat(samples_b, batch_size)[0] |
| samples = (samples_c, samples_b) |
| images = image_to_latent_c |
| elif latent_c is not None: |
| samples_c = latent_c |
| samples = (samples_c, samples[1]) |
| images = pipe["images"] |
| if samples_c is not None: |
| samples = (samples_c, samples[1]) |
|
|
| new_pipe = { |
| "model": pipe['model'], |
| "positive": pipe['positive'], |
| "negative": pipe['negative'], |
| "vae": pipe['vae'], |
| "clip": pipe['clip'], |
|
|
| "samples": samples, |
| "images": images, |
| "seed": seed, |
|
|
| "loader_settings": { |
| **pipe["loader_settings"], |
| "encode_vae_name": encode_vae_name, |
| "decode_vae_name": decode_vae_name, |
| "steps": steps, |
| "cfg": cfg, |
| "sampler_name": sampler_name, |
| "scheduler": scheduler, |
| "denoise": denoise, |
| "add_noise": "enabled" |
| } |
| } |
|
|
| sampler.update_value_by_id("pipe_line", my_unique_id, new_pipe) |
|
|
| del pipe |
|
|
| return {"ui": {"value": [seed]}, "result": (new_pipe,)} |
|
|
| |
| class layerDiffusionSettings: |
|
|
| def __init__(self): |
| pass |
|
|
| @classmethod |
| def INPUT_TYPES(cls): |
| return {"required": |
| { |
| "pipe": ("PIPE_LINE",), |
| "method": ([LayerMethod.FG_ONLY_ATTN.value, LayerMethod.FG_ONLY_CONV.value, LayerMethod.EVERYTHING.value, LayerMethod.FG_TO_BLEND.value, LayerMethod.BG_TO_BLEND.value],), |
| "weight": ("FLOAT",{"default": 1.0, "min": -1, "max": 3, "step": 0.05},), |
| "steps": ("INT", {"default": 20, "min": 1, "max": 10000}), |
| "cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}), |
| "sampler_name": (comfy.samplers.KSampler.SAMPLERS, {"default": "euler"}), |
| "scheduler": (comfy.samplers.KSampler.SCHEDULERS+ NEW_SCHEDULERS, {"default": "normal"}), |
| "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), |
| "seed": ("INT", {"default": 0, "min": 0, "max": MAX_SEED_NUM}), |
| }, |
| "optional": { |
| "image": ("IMAGE",), |
| "blended_image": ("IMAGE",), |
| "mask": ("MASK",), |
| |
| |
| }, |
| "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"}, |
| } |
|
|
| RETURN_TYPES = ("PIPE_LINE",) |
| RETURN_NAMES = ("pipe",) |
|
|
| FUNCTION = "settings" |
| CATEGORY = "EasyUse/PreSampling" |
|
|
| def get_layer_diffusion_method(self, method, has_blend_latent): |
| method = LayerMethod(method) |
| if has_blend_latent: |
| if method == LayerMethod.BG_TO_BLEND: |
| method = LayerMethod.BG_BLEND_TO_FG |
| elif method == LayerMethod.FG_TO_BLEND: |
| method = LayerMethod.FG_BLEND_TO_BG |
| return method |
|
|
| def settings(self, pipe, method, weight, steps, cfg, sampler_name, scheduler, denoise, seed, image=None, blended_image=None, mask=None, prompt=None, extra_pnginfo=None, my_unique_id=None): |
| blend_samples = pipe['blend_samples'] if "blend_samples" in pipe else None |
| vae = pipe["vae"] |
| batch_size = pipe["loader_settings"]["batch_size"] if "batch_size" in pipe["loader_settings"] else 1 |
|
|
| method = self.get_layer_diffusion_method(method, blend_samples is not None or blended_image is not None) |
|
|
| if image is not None or "image" in pipe: |
| image = image if image is not None else pipe['image'] |
| if mask is not None: |
| print('inpaint') |
| samples, = VAEEncodeForInpaint().encode(vae, image, mask) |
| else: |
| samples = {"samples": vae.encode(image[:,:,:,:3])} |
| samples = RepeatLatentBatch().repeat(samples, batch_size)[0] |
| images = image |
| elif "samp_images" in pipe: |
| samples = {"samples": vae.encode(pipe["samp_images"][:,:,:,:3])} |
| samples = RepeatLatentBatch().repeat(samples, batch_size)[0] |
| images = pipe["samp_images"] |
| else: |
| if method not in [LayerMethod.FG_ONLY_ATTN, LayerMethod.FG_ONLY_CONV, LayerMethod.EVERYTHING]: |
| raise Exception("image is missing") |
|
|
| samples = pipe["samples"] |
| images = pipe["images"] |
|
|
| if method in [LayerMethod.BG_BLEND_TO_FG, LayerMethod.FG_BLEND_TO_BG]: |
| if blended_image is None and blend_samples is None: |
| raise Exception("blended_image is missing") |
| elif blended_image is not None: |
| blend_samples = {"samples": vae.encode(blended_image[:,:,:,:3])} |
| blend_samples = RepeatLatentBatch().repeat(blend_samples, batch_size)[0] |
|
|
| new_pipe = { |
| "model": pipe['model'], |
| "positive": pipe['positive'], |
| "negative": pipe['negative'], |
| "vae": pipe['vae'], |
| "clip": pipe['clip'], |
|
|
| "samples": samples, |
| "blend_samples": blend_samples, |
| "images": images, |
| "seed": seed, |
|
|
| "loader_settings": { |
| **pipe["loader_settings"], |
| "steps": steps, |
| "cfg": cfg, |
| "sampler_name": sampler_name, |
| "scheduler": scheduler, |
| "denoise": denoise, |
| "add_noise": "enabled", |
| "layer_diffusion_method": method, |
| "layer_diffusion_weight": weight, |
| } |
| } |
|
|
| del pipe |
|
|
| return {"ui": {"value": [seed]}, "result": (new_pipe,)} |
|
|
| |
| class layerDiffusionSettingsADDTL: |
| def __init__(self): |
| pass |
|
|
| @classmethod |
| def INPUT_TYPES(cls): |
| return {"required": |
| { |
| "pipe": ("PIPE_LINE",), |
| "foreground_prompt": ("STRING", {"default": "", "placeholder": "Foreground Additional Prompt", "multiline": True}), |
| "background_prompt": ("STRING", {"default": "", "placeholder": "Background Additional Prompt", "multiline": True}), |
| "blended_prompt": ("STRING", {"default": "", "placeholder": "Blended Additional Prompt", "multiline": True}), |
| }, |
| "optional": { |
| "optional_fg_cond": ("CONDITIONING",), |
| "optional_bg_cond": ("CONDITIONING",), |
| "optional_blended_cond": ("CONDITIONING",), |
| }, |
| "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"}, |
| } |
|
|
| RETURN_TYPES = ("PIPE_LINE",) |
| RETURN_NAMES = ("pipe",) |
|
|
| FUNCTION = "settings" |
| CATEGORY = "EasyUse/PreSampling" |
|
|
| def settings(self, pipe, foreground_prompt, background_prompt, blended_prompt, optional_fg_cond=None, optional_bg_cond=None, optional_blended_cond=None, prompt=None, extra_pnginfo=None, my_unique_id=None): |
| fg_cond, bg_cond, blended_cond = None, None, None |
| clip = pipe['clip'] |
| if optional_fg_cond is not None: |
| fg_cond = optional_fg_cond |
| elif foreground_prompt != "": |
| fg_cond, = CLIPTextEncode().encode(clip, foreground_prompt) |
| if optional_bg_cond is not None: |
| bg_cond = optional_bg_cond |
| elif background_prompt != "": |
| bg_cond, = CLIPTextEncode().encode(clip, background_prompt) |
| if optional_blended_cond is not None: |
| blended_cond = optional_blended_cond |
| elif blended_prompt != "": |
| blended_cond, = CLIPTextEncode().encode(clip, blended_prompt) |
|
|
| new_pipe = { |
| **pipe, |
| "loader_settings": { |
| **pipe["loader_settings"], |
| "layer_diffusion_cond": (fg_cond, bg_cond, blended_cond) |
| } |
| } |
|
|
| del pipe |
|
|
| return (new_pipe,) |
|
|
| |
| from ..libs.dynthres_core import DynThresh |
| class dynamicCFGSettings: |
| def __init__(self): |
| pass |
|
|
| @classmethod |
| def INPUT_TYPES(cls): |
| return {"required": |
| {"pipe": ("PIPE_LINE",), |
| "steps": ("INT", {"default": 20, "min": 1, "max": 10000}), |
| "cfg": ("FLOAT", {"default": 8.0, "min": 0.0, "max": 100.0}), |
| "cfg_mode": (DynThresh.Modes,), |
| "cfg_scale_min": ("FLOAT", {"default": 3.5, "min": 0.0, "max": 100.0, "step": 0.5}), |
| "sampler_name": (comfy.samplers.KSampler.SAMPLERS,), |
| "scheduler": (comfy.samplers.KSampler.SCHEDULERS+NEW_SCHEDULERS,), |
| "denoise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), |
| "seed": ("INT", {"default": 0, "min": 0, "max": MAX_SEED_NUM}), |
| }, |
| "optional":{ |
| "image_to_latent": ("IMAGE",), |
| "latent": ("LATENT",) |
| }, |
| "hidden": |
| {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", "my_unique_id": "UNIQUE_ID"}, |
| } |
|
|
| RETURN_TYPES = ("PIPE_LINE",) |
| RETURN_NAMES = ("pipe",) |
|
|
| FUNCTION = "settings" |
| CATEGORY = "EasyUse/PreSampling" |
|
|
| def settings(self, pipe, steps, cfg, cfg_mode, cfg_scale_min,sampler_name, scheduler, denoise, seed, image_to_latent=None, latent=None, prompt=None, extra_pnginfo=None, my_unique_id=None): |
|
|
|
|
| dynamic_thresh = DynThresh(7.0, 1.0,"CONSTANT", 0, cfg_mode, cfg_scale_min, 0, 0, 999, False, |
| "MEAN", "AD", 1) |
|
|
| def sampler_dyn_thresh(args): |
| input = args["input"] |
| cond = input - args["cond"] |
| uncond = input - args["uncond"] |
| cond_scale = args["cond_scale"] |
| time_step = args["timestep"] |
| dynamic_thresh.step = 999 - time_step[0] |
|
|
| return input - dynamic_thresh.dynthresh(cond, uncond, cond_scale, None) |
|
|
| model = pipe['model'] |
|
|
| m = model.clone() |
| m.set_model_sampler_cfg_function(sampler_dyn_thresh) |
|
|
| |
| vae = pipe["vae"] |
| batch_size = pipe["loader_settings"]["batch_size"] if "batch_size" in pipe["loader_settings"] else 1 |
| if image_to_latent is not None: |
| samples = {"samples": vae.encode(image_to_latent[:, :, :, :3])} |
| samples = RepeatLatentBatch().repeat(samples, batch_size)[0] |
| images = image_to_latent |
| elif latent is not None: |
| samples = RepeatLatentBatch().repeat(latent, batch_size)[0] |
| images = pipe["images"] |
| else: |
| samples = pipe["samples"] |
| images = pipe["images"] |
|
|
| new_pipe = { |
| "model": m, |
| "positive": pipe['positive'], |
| "negative": pipe['negative'], |
| "vae": pipe['vae'], |
| "clip": pipe['clip'], |
|
|
| "samples": samples, |
| "images": images, |
| "seed": seed, |
|
|
| "loader_settings": { |
| **pipe["loader_settings"], |
| "steps": steps, |
| "cfg": cfg, |
| "sampler_name": sampler_name, |
| "scheduler": scheduler, |
| "denoise": denoise |
| }, |
| } |
|
|
| del pipe |
|
|
| return {"ui": {"value": [seed]}, "result": (new_pipe,)} |
|
|
| |
| class dynamicThresholdingFull: |
| @classmethod |
| def INPUT_TYPES(s): |
| return { |
| "required": { |
| "model": ("MODEL",), |
| "mimic_scale": ("FLOAT", {"default": 7.0, "min": 0.0, "max": 100.0, "step": 0.5}), |
| "threshold_percentile": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), |
| "mimic_mode": (DynThresh.Modes,), |
| "mimic_scale_min": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 100.0, "step": 0.5}), |
| "cfg_mode": (DynThresh.Modes,), |
| "cfg_scale_min": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 100.0, "step": 0.5}), |
| "sched_val": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step": 0.01}), |
| "separate_feature_channels": (["enable", "disable"],), |
| "scaling_startpoint": (DynThresh.Startpoints,), |
| "variability_measure": (DynThresh.Variabilities,), |
| "interpolate_phi": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.01}), |
| } |
| } |
|
|
| RETURN_TYPES = ("MODEL",) |
| FUNCTION = "patch" |
| CATEGORY = "EasyUse/PreSampling" |
|
|
| def patch(self, model, mimic_scale, threshold_percentile, mimic_mode, mimic_scale_min, cfg_mode, cfg_scale_min, |
| sched_val, separate_feature_channels, scaling_startpoint, variability_measure, interpolate_phi): |
| dynamic_thresh = DynThresh(mimic_scale, threshold_percentile, mimic_mode, mimic_scale_min, cfg_mode, |
| cfg_scale_min, sched_val, 0, 999, separate_feature_channels == "enable", |
| scaling_startpoint, variability_measure, interpolate_phi) |
|
|
| def sampler_dyn_thresh(args): |
| input = args["input"] |
| cond = input - args["cond"] |
| uncond = input - args["uncond"] |
| cond_scale = args["cond_scale"] |
| time_step = args["timestep"] |
| dynamic_thresh.step = 999 - time_step[0] |
|
|
| return input - dynamic_thresh.dynthresh(cond, uncond, cond_scale, None) |
|
|
| m = model.clone() |
| m.set_model_sampler_cfg_function(sampler_dyn_thresh) |
| return (m,) |
|
|
|
|
|
|
| NODE_CLASS_MAPPINGS = { |
| "easy preSampling": samplerSettings, |
| "easy preSamplingAdvanced": samplerSettingsAdvanced, |
| "easy preSamplingNoiseIn": samplerSettingsNoiseIn, |
| "easy preSamplingCustom": samplerCustomSettings, |
| "easy preSamplingSdTurbo": sdTurboSettings, |
| "easy preSamplingDynamicCFG": dynamicCFGSettings, |
| "easy preSamplingCascade": cascadeSettings, |
| "easy preSamplingLayerDiffusion": layerDiffusionSettings, |
| "easy preSamplingLayerDiffusionADDTL": layerDiffusionSettingsADDTL, |
| "dynamicThresholdingFull": dynamicThresholdingFull, |
| } |
|
|
| NODE_DISPLAY_NAME_MAPPINGS = { |
| "easy preSampling": "PreSampling", |
| "easy preSamplingAdvanced": "PreSampling (Advanced)", |
| "easy preSamplingNoiseIn": "PreSampling (NoiseIn)", |
| "easy preSamplingCustom": "PreSampling (Custom)", |
| "easy preSamplingSdTurbo": "PreSampling (SDTurbo)", |
| "easy preSamplingDynamicCFG": "PreSampling (DynamicCFG)", |
| "easy preSamplingCascade": "PreSampling (Cascade)", |
| "easy preSamplingLayerDiffusion": "PreSampling (LayerDiffuse)", |
| "easy preSamplingLayerDiffusionADDTL": "PreSampling (LayerDiffuse ADDTL)", |
| "dynamicThresholdingFull": "DynamicThresholdingFull", |
| } |