mirror of
https://git.datalinker.icu/comfyanonymous/ComfyUI
synced 2026-09-13 12:27:10 +08:00
Merge branch 'master' into master
This commit is contained in:
commit
c8f8cc2326
@ -228,6 +228,12 @@ Just execute the command below:
|
|||||||
|
|
||||||
```LISTEN_IP``` - IP address for ComfyUI to listen
|
```LISTEN_IP``` - IP address for ComfyUI to listen
|
||||||
|
|
||||||
|
### AMD ROCm Tips
|
||||||
|
|
||||||
|
You can enable experimental memory efficient attention on pytorch 2.5 in ComfyUI on RDNA3 and potentially other AMD GPUs using this command:
|
||||||
|
|
||||||
|
```TORCH_ROCM_AOTRITON_ENABLE_EXPERIMENTAL=1 python main.py --use-pytorch-cross-attention```
|
||||||
|
|
||||||
# Notes
|
# Notes
|
||||||
|
|
||||||
Only parts of the graph that have an output with all the correct inputs will be executed.
|
Only parts of the graph that have an output with all the correct inputs will be executed.
|
||||||
|
|||||||
@ -16,13 +16,18 @@ class Output:
|
|||||||
def __setitem__(self, key, item):
|
def __setitem__(self, key, item):
|
||||||
setattr(self, key, item)
|
setattr(self, key, item)
|
||||||
|
|
||||||
def clip_preprocess(image, size=224, mean=[0.48145466, 0.4578275, 0.40821073], std=[0.26862954, 0.26130258, 0.27577711]):
|
def clip_preprocess(image, size=224, mean=[0.48145466, 0.4578275, 0.40821073], std=[0.26862954, 0.26130258, 0.27577711], crop=True):
|
||||||
mean = torch.tensor(mean, device=image.device, dtype=image.dtype)
|
mean = torch.tensor(mean, device=image.device, dtype=image.dtype)
|
||||||
std = torch.tensor(std, device=image.device, dtype=image.dtype)
|
std = torch.tensor(std, device=image.device, dtype=image.dtype)
|
||||||
image = image.movedim(-1, 1)
|
image = image.movedim(-1, 1)
|
||||||
if not (image.shape[2] == size and image.shape[3] == size):
|
if not (image.shape[2] == size and image.shape[3] == size):
|
||||||
|
if crop:
|
||||||
scale = (size / min(image.shape[2], image.shape[3]))
|
scale = (size / min(image.shape[2], image.shape[3]))
|
||||||
image = torch.nn.functional.interpolate(image, size=(round(scale * image.shape[2]), round(scale * image.shape[3])), mode="bicubic", antialias=True)
|
scale_size = (round(scale * image.shape[2]), round(scale * image.shape[3]))
|
||||||
|
else:
|
||||||
|
scale_size = (size, size)
|
||||||
|
|
||||||
|
image = torch.nn.functional.interpolate(image, size=scale_size, mode="bicubic", antialias=True)
|
||||||
h = (image.shape[2] - size)//2
|
h = (image.shape[2] - size)//2
|
||||||
w = (image.shape[3] - size)//2
|
w = (image.shape[3] - size)//2
|
||||||
image = image[:,:,h:h+size,w:w+size]
|
image = image[:,:,h:h+size,w:w+size]
|
||||||
@ -51,9 +56,9 @@ class ClipVisionModel():
|
|||||||
def get_sd(self):
|
def get_sd(self):
|
||||||
return self.model.state_dict()
|
return self.model.state_dict()
|
||||||
|
|
||||||
def encode_image(self, image):
|
def encode_image(self, image, crop=True):
|
||||||
comfy.model_management.load_model_gpu(self.patcher)
|
comfy.model_management.load_model_gpu(self.patcher)
|
||||||
pixel_values = clip_preprocess(image.to(self.load_device), size=self.image_size, mean=self.image_mean, std=self.image_std).float()
|
pixel_values = clip_preprocess(image.to(self.load_device), size=self.image_size, mean=self.image_mean, std=self.image_std, crop=crop).float()
|
||||||
out = self.model(pixel_values=pixel_values, intermediate_output=-2)
|
out = self.model(pixel_values=pixel_values, intermediate_output=-2)
|
||||||
|
|
||||||
outputs = Output()
|
outputs = Output()
|
||||||
|
|||||||
@ -280,6 +280,9 @@ def sample_dpm_2(model, x, sigmas, extra_args=None, callback=None, disable=None,
|
|||||||
|
|
||||||
@torch.no_grad()
|
@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):
|
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."""
|
"""Ancestral sampling with DPM-Solver second-order steps."""
|
||||||
extra_args = {} if extra_args is None else extra_args
|
extra_args = {} if extra_args is None else extra_args
|
||||||
noise_sampler = default_noise_sampler(x) if noise_sampler is None else noise_sampler
|
noise_sampler = default_noise_sampler(x) if noise_sampler is None else noise_sampler
|
||||||
@ -306,6 +309,39 @@ def sample_dpm_2_ancestral(model, x, sigmas, extra_args=None, callback=None, dis
|
|||||||
x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up
|
x = x + noise_sampler(sigmas[i], sigmas[i + 1]) * s_noise * sigma_up
|
||||||
return x
|
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
|
||||||
|
noise_sampler = default_noise_sampler(x) 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)
|
||||||
|
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):
|
def linear_multistep_coeff(order, t, i, j):
|
||||||
if order - 1 > i:
|
if order - 1 > i:
|
||||||
|
|||||||
19
nodes.py
19
nodes.py
@ -392,7 +392,7 @@ class InpaintModelConditioning:
|
|||||||
|
|
||||||
CATEGORY = "conditioning/inpaint"
|
CATEGORY = "conditioning/inpaint"
|
||||||
|
|
||||||
def encode(self, positive, negative, pixels, vae, mask, noise_mask):
|
def encode(self, positive, negative, pixels, vae, mask, noise_mask=True):
|
||||||
x = (pixels.shape[1] // 8) * 8
|
x = (pixels.shape[1] // 8) * 8
|
||||||
y = (pixels.shape[2] // 8) * 8
|
y = (pixels.shape[2] // 8) * 8
|
||||||
mask = torch.nn.functional.interpolate(mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])), size=(pixels.shape[1], pixels.shape[2]), mode="bilinear")
|
mask = torch.nn.functional.interpolate(mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])), size=(pixels.shape[1], pixels.shape[2]), mode="bilinear")
|
||||||
@ -971,15 +971,19 @@ class CLIPVisionEncode:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def INPUT_TYPES(s):
|
||||||
return {"required": { "clip_vision": ("CLIP_VISION",),
|
return {"required": { "clip_vision": ("CLIP_VISION",),
|
||||||
"image": ("IMAGE",)
|
"image": ("IMAGE",),
|
||||||
|
"crop": (["center", "none"],)
|
||||||
}}
|
}}
|
||||||
RETURN_TYPES = ("CLIP_VISION_OUTPUT",)
|
RETURN_TYPES = ("CLIP_VISION_OUTPUT",)
|
||||||
FUNCTION = "encode"
|
FUNCTION = "encode"
|
||||||
|
|
||||||
CATEGORY = "conditioning"
|
CATEGORY = "conditioning"
|
||||||
|
|
||||||
def encode(self, clip_vision, image):
|
def encode(self, clip_vision, image, crop):
|
||||||
output = clip_vision.encode_image(image)
|
crop_image = True
|
||||||
|
if crop != "center":
|
||||||
|
crop_image = False
|
||||||
|
output = clip_vision.encode_image(image, crop=crop_image)
|
||||||
return (output,)
|
return (output,)
|
||||||
|
|
||||||
class StyleModelLoader:
|
class StyleModelLoader:
|
||||||
@ -1004,14 +1008,19 @@ class StyleModelApply:
|
|||||||
return {"required": {"conditioning": ("CONDITIONING", ),
|
return {"required": {"conditioning": ("CONDITIONING", ),
|
||||||
"style_model": ("STYLE_MODEL", ),
|
"style_model": ("STYLE_MODEL", ),
|
||||||
"clip_vision_output": ("CLIP_VISION_OUTPUT", ),
|
"clip_vision_output": ("CLIP_VISION_OUTPUT", ),
|
||||||
|
"strength": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.001}),
|
||||||
|
"strength_type": (["multiply"], ),
|
||||||
}}
|
}}
|
||||||
RETURN_TYPES = ("CONDITIONING",)
|
RETURN_TYPES = ("CONDITIONING",)
|
||||||
FUNCTION = "apply_stylemodel"
|
FUNCTION = "apply_stylemodel"
|
||||||
|
|
||||||
CATEGORY = "conditioning/style_model"
|
CATEGORY = "conditioning/style_model"
|
||||||
|
|
||||||
def apply_stylemodel(self, clip_vision_output, style_model, conditioning):
|
def apply_stylemodel(self, clip_vision_output, style_model, conditioning, strength, strength_type):
|
||||||
cond = style_model.get_cond(clip_vision_output).flatten(start_dim=0, end_dim=1).unsqueeze(dim=0)
|
cond = style_model.get_cond(clip_vision_output).flatten(start_dim=0, end_dim=1).unsqueeze(dim=0)
|
||||||
|
if strength_type == "multiply":
|
||||||
|
cond *= strength
|
||||||
|
|
||||||
c = []
|
c = []
|
||||||
for t in conditioning:
|
for t in conditioning:
|
||||||
n = [torch.cat((t[0], cond), dim=1), t[1].copy()]
|
n = [torch.cat((t[0], cond), dim=1), t[1].copy()]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user