mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-02-10 21:42:37 +08:00
Merge branch 'master' into issue-1608-mask-composite-error-on-nonsquare-masks
This commit is contained in:
commit
f12a453312
@ -1,6 +1,6 @@
|
|||||||
ComfyUI
|
ComfyUI
|
||||||
=======
|
=======
|
||||||
A powerful and modular stable diffusion GUI and backend.
|
The most powerful and modular stable diffusion GUI and backend.
|
||||||
-----------
|
-----------
|
||||||

|

|
||||||
|
|
||||||
@ -94,8 +94,8 @@ AMD users can install rocm and pytorch with pip if you don't have it already ins
|
|||||||
|
|
||||||
```pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/rocm5.4.2```
|
```pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/rocm5.4.2```
|
||||||
|
|
||||||
This is the command to install the nightly with ROCm 5.6 that supports the 7000 series and might have some performance improvements:
|
This is the command to install the nightly with ROCm 5.7 that supports the 7000 series and might have some performance improvements:
|
||||||
```pip install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/rocm5.6```
|
```pip install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/rocm5.7```
|
||||||
|
|
||||||
### NVIDIA
|
### NVIDIA
|
||||||
|
|
||||||
|
|||||||
@ -688,7 +688,7 @@ class UniPC:
|
|||||||
x_t = x_t_ - expand_dims(alpha_t * B_h, dims) * (corr_res + rhos_c[-1] * D1_t)
|
x_t = x_t_ - expand_dims(alpha_t * B_h, dims) * (corr_res + rhos_c[-1] * D1_t)
|
||||||
else:
|
else:
|
||||||
x_t_ = (
|
x_t_ = (
|
||||||
expand_dims(torch.exp(log_alpha_t - log_alpha_prev_0), dimss) * x
|
expand_dims(torch.exp(log_alpha_t - log_alpha_prev_0), dims) * x
|
||||||
- expand_dims(sigma_t * h_phi_1, dims) * model_prev_0
|
- expand_dims(sigma_t * h_phi_1, dims) * model_prev_0
|
||||||
)
|
)
|
||||||
if x_t is None:
|
if x_t is None:
|
||||||
|
|||||||
@ -598,7 +598,7 @@ KSAMPLER_NAMES = ["euler", "euler_ancestral", "heun", "dpm_2", "dpm_2_ancestral"
|
|||||||
"lms", "dpm_fast", "dpm_adaptive", "dpmpp_2s_ancestral", "dpmpp_sde", "dpmpp_sde_gpu",
|
"lms", "dpm_fast", "dpm_adaptive", "dpmpp_2s_ancestral", "dpmpp_sde", "dpmpp_sde_gpu",
|
||||||
"dpmpp_2m", "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", "dpmpp_3m_sde_gpu", "ddpm"]
|
"dpmpp_2m", "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", "dpmpp_3m_sde_gpu", "ddpm"]
|
||||||
|
|
||||||
def ksampler(sampler_name):
|
def ksampler(sampler_name, extra_options={}):
|
||||||
class KSAMPLER(Sampler):
|
class KSAMPLER(Sampler):
|
||||||
def sample(self, model_wrap, sigmas, extra_args, callback, noise, latent_image=None, denoise_mask=None, disable_pbar=False):
|
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
|
extra_args["denoise_mask"] = denoise_mask
|
||||||
@ -627,7 +627,7 @@ def ksampler(sampler_name):
|
|||||||
elif sampler_name == "dpm_adaptive":
|
elif sampler_name == "dpm_adaptive":
|
||||||
samples = k_diffusion_sampling.sample_dpm_adaptive(model_k, noise, sigma_min, sigmas[0], extra_args=extra_args, callback=k_callback, disable=disable_pbar)
|
samples = k_diffusion_sampling.sample_dpm_adaptive(model_k, noise, sigma_min, sigmas[0], extra_args=extra_args, callback=k_callback, disable=disable_pbar)
|
||||||
else:
|
else:
|
||||||
samples = getattr(k_diffusion_sampling, "sample_{}".format(sampler_name))(model_k, noise, sigmas, extra_args=extra_args, callback=k_callback, disable=disable_pbar)
|
samples = getattr(k_diffusion_sampling, "sample_{}".format(sampler_name))(model_k, noise, sigmas, extra_args=extra_args, callback=k_callback, disable=disable_pbar, **extra_options)
|
||||||
return samples
|
return samples
|
||||||
return KSAMPLER
|
return KSAMPLER
|
||||||
|
|
||||||
|
|||||||
@ -152,7 +152,9 @@ class VAE:
|
|||||||
sd = comfy.utils.load_torch_file(ckpt_path)
|
sd = comfy.utils.load_torch_file(ckpt_path)
|
||||||
if 'decoder.up_blocks.0.resnets.0.norm1.weight' in sd.keys(): #diffusers format
|
if 'decoder.up_blocks.0.resnets.0.norm1.weight' in sd.keys(): #diffusers format
|
||||||
sd = diffusers_convert.convert_vae_state_dict(sd)
|
sd = diffusers_convert.convert_vae_state_dict(sd)
|
||||||
self.first_stage_model.load_state_dict(sd, strict=False)
|
m, u = self.first_stage_model.load_state_dict(sd, strict=False)
|
||||||
|
if len(m) > 0:
|
||||||
|
print("Missing VAE keys", m)
|
||||||
|
|
||||||
if device is None:
|
if device is None:
|
||||||
device = model_management.vae_device()
|
device = model_management.vae_device()
|
||||||
@ -181,7 +183,7 @@ class VAE:
|
|||||||
steps += pixel_samples.shape[0] * comfy.utils.get_tiled_scale_steps(pixel_samples.shape[3], pixel_samples.shape[2], tile_x * 2, tile_y // 2, overlap)
|
steps += pixel_samples.shape[0] * comfy.utils.get_tiled_scale_steps(pixel_samples.shape[3], pixel_samples.shape[2], tile_x * 2, tile_y // 2, overlap)
|
||||||
pbar = comfy.utils.ProgressBar(steps)
|
pbar = comfy.utils.ProgressBar(steps)
|
||||||
|
|
||||||
encode_fn = lambda a: self.first_stage_model.encode(2. * a.to(self.vae_dtype).to(self.device) - 1.).sample().float()
|
encode_fn = lambda a: self.first_stage_model.encode((2. * a - 1.).to(self.vae_dtype).to(self.device)).sample().float()
|
||||||
samples = comfy.utils.tiled_scale(pixel_samples, encode_fn, tile_x, tile_y, overlap, upscale_amount = (1/8), out_channels=4, pbar=pbar)
|
samples = comfy.utils.tiled_scale(pixel_samples, encode_fn, tile_x, tile_y, overlap, upscale_amount = (1/8), out_channels=4, pbar=pbar)
|
||||||
samples += comfy.utils.tiled_scale(pixel_samples, encode_fn, tile_x * 2, tile_y // 2, overlap, upscale_amount = (1/8), out_channels=4, pbar=pbar)
|
samples += comfy.utils.tiled_scale(pixel_samples, encode_fn, tile_x * 2, tile_y // 2, overlap, upscale_amount = (1/8), out_channels=4, pbar=pbar)
|
||||||
samples += comfy.utils.tiled_scale(pixel_samples, encode_fn, tile_x // 2, tile_y * 2, overlap, upscale_amount = (1/8), out_channels=4, pbar=pbar)
|
samples += comfy.utils.tiled_scale(pixel_samples, encode_fn, tile_x // 2, tile_y * 2, overlap, upscale_amount = (1/8), out_channels=4, pbar=pbar)
|
||||||
@ -200,7 +202,7 @@ class VAE:
|
|||||||
pixel_samples = torch.empty((samples_in.shape[0], 3, round(samples_in.shape[2] * 8), round(samples_in.shape[3] * 8)), device="cpu")
|
pixel_samples = torch.empty((samples_in.shape[0], 3, round(samples_in.shape[2] * 8), round(samples_in.shape[3] * 8)), device="cpu")
|
||||||
for x in range(0, samples_in.shape[0], batch_number):
|
for x in range(0, samples_in.shape[0], batch_number):
|
||||||
samples = samples_in[x:x+batch_number].to(self.vae_dtype).to(self.device)
|
samples = samples_in[x:x+batch_number].to(self.vae_dtype).to(self.device)
|
||||||
pixel_samples[x:x+batch_number] = torch.clamp((self.first_stage_model.decode(samples) + 1.0) / 2.0, min=0.0, max=1.0).cpu().float()
|
pixel_samples[x:x+batch_number] = torch.clamp((self.first_stage_model.decode(samples).cpu().float() + 1.0) / 2.0, min=0.0, max=1.0)
|
||||||
except model_management.OOM_EXCEPTION as e:
|
except model_management.OOM_EXCEPTION as e:
|
||||||
print("Warning: Ran out of memory when regular VAE decoding, retrying with tiled VAE decoding.")
|
print("Warning: Ran out of memory when regular VAE decoding, retrying with tiled VAE decoding.")
|
||||||
pixel_samples = self.decode_tiled_(samples_in)
|
pixel_samples = self.decode_tiled_(samples_in)
|
||||||
|
|||||||
@ -43,6 +43,62 @@ class KarrasScheduler:
|
|||||||
sigmas = k_diffusion_sampling.get_sigmas_karras(n=steps, sigma_min=sigma_min, sigma_max=sigma_max, rho=rho)
|
sigmas = k_diffusion_sampling.get_sigmas_karras(n=steps, sigma_min=sigma_min, sigma_max=sigma_max, rho=rho)
|
||||||
return (sigmas, )
|
return (sigmas, )
|
||||||
|
|
||||||
|
class ExponentialScheduler:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {"required":
|
||||||
|
{"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}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RETURN_TYPES = ("SIGMAS",)
|
||||||
|
CATEGORY = "_for_testing/custom_sampling"
|
||||||
|
|
||||||
|
FUNCTION = "get_sigmas"
|
||||||
|
|
||||||
|
def get_sigmas(self, steps, sigma_max, sigma_min):
|
||||||
|
sigmas = k_diffusion_sampling.get_sigmas_exponential(n=steps, sigma_min=sigma_min, sigma_max=sigma_max)
|
||||||
|
return (sigmas, )
|
||||||
|
|
||||||
|
class PolyexponentialScheduler:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {"required":
|
||||||
|
{"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": 1.0, "min": 0.0, "max": 100.0, "step":0.01, "round": False}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RETURN_TYPES = ("SIGMAS",)
|
||||||
|
CATEGORY = "_for_testing/custom_sampling"
|
||||||
|
|
||||||
|
FUNCTION = "get_sigmas"
|
||||||
|
|
||||||
|
def get_sigmas(self, steps, sigma_max, sigma_min, rho):
|
||||||
|
sigmas = k_diffusion_sampling.get_sigmas_polyexponential(n=steps, sigma_min=sigma_min, sigma_max=sigma_max, rho=rho)
|
||||||
|
return (sigmas, )
|
||||||
|
|
||||||
|
class VPScheduler:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {"required":
|
||||||
|
{"steps": ("INT", {"default": 20, "min": 1, "max": 10000}),
|
||||||
|
"beta_d": ("FLOAT", {"default": 19.9, "min": 0.0, "max": 1000.0, "step":0.01, "round": False}), #TODO: fix default values
|
||||||
|
"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}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RETURN_TYPES = ("SIGMAS",)
|
||||||
|
CATEGORY = "_for_testing/custom_sampling"
|
||||||
|
|
||||||
|
FUNCTION = "get_sigmas"
|
||||||
|
|
||||||
|
def get_sigmas(self, steps, beta_d, beta_min, eps_s):
|
||||||
|
sigmas = k_diffusion_sampling.get_sigmas_vp(n=steps, beta_d=beta_d, beta_min=beta_min, eps_s=eps_s)
|
||||||
|
return (sigmas, )
|
||||||
|
|
||||||
class SplitSigmas:
|
class SplitSigmas:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
@ -58,7 +114,7 @@ class SplitSigmas:
|
|||||||
|
|
||||||
def get_sigmas(self, sigmas, step):
|
def get_sigmas(self, sigmas, step):
|
||||||
sigmas1 = sigmas[:step + 1]
|
sigmas1 = sigmas[:step + 1]
|
||||||
sigmas2 = sigmas[step + 1:]
|
sigmas2 = sigmas[step:]
|
||||||
return (sigmas1, sigmas2)
|
return (sigmas1, sigmas2)
|
||||||
|
|
||||||
class KSamplerSelect:
|
class KSamplerSelect:
|
||||||
@ -77,6 +133,53 @@ class KSamplerSelect:
|
|||||||
sampler = comfy.samplers.sampler_class(sampler_name)()
|
sampler = comfy.samplers.sampler_class(sampler_name)()
|
||||||
return (sampler, )
|
return (sampler, )
|
||||||
|
|
||||||
|
class SamplerDPMPP_2M_SDE:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {"required":
|
||||||
|
{"solver_type": (['midpoint', 'heun'], ),
|
||||||
|
"eta": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step":0.01, "round": False}),
|
||||||
|
"s_noise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step":0.01, "round": False}),
|
||||||
|
"noise_device": (['gpu', 'cpu'], ),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RETURN_TYPES = ("SAMPLER",)
|
||||||
|
CATEGORY = "_for_testing/custom_sampling"
|
||||||
|
|
||||||
|
FUNCTION = "get_sampler"
|
||||||
|
|
||||||
|
def get_sampler(self, solver_type, eta, s_noise, noise_device):
|
||||||
|
if noise_device == 'cpu':
|
||||||
|
sampler_name = "dpmpp_2m_sde"
|
||||||
|
else:
|
||||||
|
sampler_name = "dpmpp_2m_sde_gpu"
|
||||||
|
sampler = comfy.samplers.ksampler(sampler_name, {"eta": eta, "s_noise": s_noise, "solver_type": solver_type})()
|
||||||
|
return (sampler, )
|
||||||
|
|
||||||
|
|
||||||
|
class SamplerDPMPP_SDE:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {"required":
|
||||||
|
{"eta": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step":0.01, "round": False}),
|
||||||
|
"s_noise": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 100.0, "step":0.01, "round": False}),
|
||||||
|
"r": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 100.0, "step":0.01, "round": False}),
|
||||||
|
"noise_device": (['gpu', 'cpu'], ),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RETURN_TYPES = ("SAMPLER",)
|
||||||
|
CATEGORY = "_for_testing/custom_sampling"
|
||||||
|
|
||||||
|
FUNCTION = "get_sampler"
|
||||||
|
|
||||||
|
def get_sampler(self, eta, s_noise, r, noise_device):
|
||||||
|
if noise_device == 'cpu':
|
||||||
|
sampler_name = "dpmpp_sde"
|
||||||
|
else:
|
||||||
|
sampler_name = "dpmpp_sde_gpu"
|
||||||
|
sampler = comfy.samplers.ksampler(sampler_name, {"eta": eta, "s_noise": s_noise, "r": r})()
|
||||||
|
return (sampler, )
|
||||||
|
|
||||||
class SamplerCustom:
|
class SamplerCustom:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
@ -131,7 +234,12 @@ class SamplerCustom:
|
|||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
"SamplerCustom": SamplerCustom,
|
"SamplerCustom": SamplerCustom,
|
||||||
"KarrasScheduler": KarrasScheduler,
|
"KarrasScheduler": KarrasScheduler,
|
||||||
|
"ExponentialScheduler": ExponentialScheduler,
|
||||||
|
"PolyexponentialScheduler": PolyexponentialScheduler,
|
||||||
|
"VPScheduler": VPScheduler,
|
||||||
"KSamplerSelect": KSamplerSelect,
|
"KSamplerSelect": KSamplerSelect,
|
||||||
|
"SamplerDPMPP_2M_SDE": SamplerDPMPP_2M_SDE,
|
||||||
|
"SamplerDPMPP_SDE": SamplerDPMPP_SDE,
|
||||||
"BasicScheduler": BasicScheduler,
|
"BasicScheduler": BasicScheduler,
|
||||||
"SplitSigmas": SplitSigmas,
|
"SplitSigmas": SplitSigmas,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -331,15 +331,14 @@ class GrowMask:
|
|||||||
out = []
|
out = []
|
||||||
for m in mask:
|
for m in mask:
|
||||||
output = m.numpy()
|
output = m.numpy()
|
||||||
while expand < 0:
|
for _ in range(abs(expand)):
|
||||||
output = scipy.ndimage.grey_erosion(output, footprint=kernel)
|
if expand < 0:
|
||||||
expand += 1
|
output = scipy.ndimage.grey_erosion(output, footprint=kernel)
|
||||||
while expand > 0:
|
else:
|
||||||
output = scipy.ndimage.grey_dilation(output, footprint=kernel)
|
output = scipy.ndimage.grey_dilation(output, footprint=kernel)
|
||||||
expand -= 1
|
|
||||||
output = torch.from_numpy(output)
|
output = torch.from_numpy(output)
|
||||||
out.append(output)
|
out.append(output)
|
||||||
return (torch.cat(out, dim=0),)
|
return (torch.stack(out, dim=0),)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
31
nodes.py
31
nodes.py
@ -1781,16 +1781,23 @@ def load_custom_nodes():
|
|||||||
print()
|
print()
|
||||||
|
|
||||||
def init_custom_nodes():
|
def init_custom_nodes():
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_latent.py"))
|
extras_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras")
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_hypernetwork.py"))
|
extras_files = [
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_upscale_model.py"))
|
"nodes_latent.py",
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_post_processing.py"))
|
"nodes_hypernetwork.py",
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_mask.py"))
|
"nodes_upscale_model.py",
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_rebatch.py"))
|
"nodes_post_processing.py",
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_model_merging.py"))
|
"nodes_mask.py",
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_tomesd.py"))
|
"nodes_rebatch.py",
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_clip_sdxl.py"))
|
"nodes_model_merging.py",
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_canny.py"))
|
"nodes_tomesd.py",
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_freelunch.py"))
|
"nodes_clip_sdxl.py",
|
||||||
load_custom_node(os.path.join(os.path.join(os.path.dirname(os.path.realpath(__file__)), "comfy_extras"), "nodes_custom_sampler.py"))
|
"nodes_canny.py",
|
||||||
|
"nodes_freelunch.py",
|
||||||
|
"nodes_custom_sampler.py"
|
||||||
|
]
|
||||||
|
|
||||||
|
for node_file in extras_files:
|
||||||
|
load_custom_node(os.path.join(extras_dir, node_file))
|
||||||
|
|
||||||
load_custom_nodes()
|
load_custom_nodes()
|
||||||
|
|||||||
@ -413,7 +413,11 @@ class PromptServer():
|
|||||||
async def get_object_info(request):
|
async def get_object_info(request):
|
||||||
out = {}
|
out = {}
|
||||||
for x in nodes.NODE_CLASS_MAPPINGS:
|
for x in nodes.NODE_CLASS_MAPPINGS:
|
||||||
out[x] = node_info(x)
|
try:
|
||||||
|
out[x] = node_info(x)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[ERROR] An error occurred while retrieving information for the '{x}' node.", file=sys.stderr)
|
||||||
|
traceback.print_exc()
|
||||||
return web.json_response(out)
|
return web.json_response(out)
|
||||||
|
|
||||||
@routes.get("/object_info/{node_class}")
|
@routes.get("/object_info/{node_class}")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user