mirror of
https://git.datalinker.icu/comfyanonymous/ComfyUI
synced 2026-09-09 23:07:15 +08:00
Merge branch 'master' into api-nodes-early
This commit is contained in:
commit
0bca89ebbb
@ -66,6 +66,7 @@ fpunet_group.add_argument("--bf16-unet", action="store_true", help="Run the diff
|
|||||||
fpunet_group.add_argument("--fp16-unet", action="store_true", help="Run the diffusion model in fp16")
|
fpunet_group.add_argument("--fp16-unet", action="store_true", help="Run the diffusion model in fp16")
|
||||||
fpunet_group.add_argument("--fp8_e4m3fn-unet", action="store_true", help="Store unet weights in fp8_e4m3fn.")
|
fpunet_group.add_argument("--fp8_e4m3fn-unet", action="store_true", help="Store unet weights in fp8_e4m3fn.")
|
||||||
fpunet_group.add_argument("--fp8_e5m2-unet", action="store_true", help="Store unet weights in fp8_e5m2.")
|
fpunet_group.add_argument("--fp8_e5m2-unet", action="store_true", help="Store unet weights in fp8_e5m2.")
|
||||||
|
fpunet_group.add_argument("--fp8_e8m0fnu-unet", action="store_true", help="Store unet weights in fp8_e8m0fnu.")
|
||||||
|
|
||||||
fpvae_group = parser.add_mutually_exclusive_group()
|
fpvae_group = parser.add_mutually_exclusive_group()
|
||||||
fpvae_group.add_argument("--fp16-vae", action="store_true", help="Run the VAE in fp16, might cause black images.")
|
fpvae_group.add_argument("--fp16-vae", action="store_true", help="Run the VAE in fp16, might cause black images.")
|
||||||
|
|||||||
@ -725,6 +725,8 @@ def unet_dtype(device=None, model_params=0, supported_dtypes=[torch.float16, tor
|
|||||||
return torch.float8_e4m3fn
|
return torch.float8_e4m3fn
|
||||||
if args.fp8_e5m2_unet:
|
if args.fp8_e5m2_unet:
|
||||||
return torch.float8_e5m2
|
return torch.float8_e5m2
|
||||||
|
if args.fp8_e8m0fnu_unet:
|
||||||
|
return torch.float8_e8m0fnu
|
||||||
|
|
||||||
fp8_dtype = None
|
fp8_dtype = None
|
||||||
if weight_dtype in FLOAT8_TYPES:
|
if weight_dtype in FLOAT8_TYPES:
|
||||||
|
|||||||
@ -3,6 +3,8 @@ from .lora import LoRAAdapter
|
|||||||
from .loha import LoHaAdapter
|
from .loha import LoHaAdapter
|
||||||
from .lokr import LoKrAdapter
|
from .lokr import LoKrAdapter
|
||||||
from .glora import GLoRAAdapter
|
from .glora import GLoRAAdapter
|
||||||
|
from .oft import OFTAdapter
|
||||||
|
from .boft import BOFTAdapter
|
||||||
|
|
||||||
|
|
||||||
adapters: list[type[WeightAdapterBase]] = [
|
adapters: list[type[WeightAdapterBase]] = [
|
||||||
@ -10,4 +12,6 @@ adapters: list[type[WeightAdapterBase]] = [
|
|||||||
LoHaAdapter,
|
LoHaAdapter,
|
||||||
LoKrAdapter,
|
LoKrAdapter,
|
||||||
GLoRAAdapter,
|
GLoRAAdapter,
|
||||||
|
OFTAdapter,
|
||||||
|
BOFTAdapter,
|
||||||
]
|
]
|
||||||
|
|||||||
@ -43,6 +43,15 @@ def weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediat
|
|||||||
dora_scale = comfy.model_management.cast_to_device(dora_scale, weight.device, intermediate_dtype)
|
dora_scale = comfy.model_management.cast_to_device(dora_scale, weight.device, intermediate_dtype)
|
||||||
lora_diff *= alpha
|
lora_diff *= alpha
|
||||||
weight_calc = weight + function(lora_diff).type(weight.dtype)
|
weight_calc = weight + function(lora_diff).type(weight.dtype)
|
||||||
|
|
||||||
|
wd_on_output_axis = dora_scale.shape[0] == weight_calc.shape[0]
|
||||||
|
if wd_on_output_axis:
|
||||||
|
weight_norm = (
|
||||||
|
weight.reshape(weight.shape[0], -1)
|
||||||
|
.norm(dim=1, keepdim=True)
|
||||||
|
.reshape(weight.shape[0], *[1] * (weight.dim() - 1))
|
||||||
|
)
|
||||||
|
else:
|
||||||
weight_norm = (
|
weight_norm = (
|
||||||
weight_calc.transpose(0, 1)
|
weight_calc.transpose(0, 1)
|
||||||
.reshape(weight_calc.shape[1], -1)
|
.reshape(weight_calc.shape[1], -1)
|
||||||
@ -50,6 +59,7 @@ def weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediat
|
|||||||
.reshape(weight_calc.shape[1], *[1] * (weight_calc.dim() - 1))
|
.reshape(weight_calc.shape[1], *[1] * (weight_calc.dim() - 1))
|
||||||
.transpose(0, 1)
|
.transpose(0, 1)
|
||||||
)
|
)
|
||||||
|
weight_norm = weight_norm + torch.finfo(weight.dtype).eps
|
||||||
|
|
||||||
weight_calc *= (dora_scale / weight_norm).type(weight.dtype)
|
weight_calc *= (dora_scale / weight_norm).type(weight.dtype)
|
||||||
if strength != 1.0:
|
if strength != 1.0:
|
||||||
|
|||||||
115
comfy/weight_adapter/boft.py
Normal file
115
comfy/weight_adapter/boft.py
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import torch
|
||||||
|
import comfy.model_management
|
||||||
|
from .base import WeightAdapterBase, weight_decompose
|
||||||
|
|
||||||
|
|
||||||
|
class BOFTAdapter(WeightAdapterBase):
|
||||||
|
name = "boft"
|
||||||
|
|
||||||
|
def __init__(self, loaded_keys, weights):
|
||||||
|
self.loaded_keys = loaded_keys
|
||||||
|
self.weights = weights
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(
|
||||||
|
cls,
|
||||||
|
x: str,
|
||||||
|
lora: dict[str, torch.Tensor],
|
||||||
|
alpha: float,
|
||||||
|
dora_scale: torch.Tensor,
|
||||||
|
loaded_keys: set[str] = None,
|
||||||
|
) -> Optional["BOFTAdapter"]:
|
||||||
|
if loaded_keys is None:
|
||||||
|
loaded_keys = set()
|
||||||
|
blocks_name = "{}.boft_blocks".format(x)
|
||||||
|
rescale_name = "{}.rescale".format(x)
|
||||||
|
|
||||||
|
blocks = None
|
||||||
|
if blocks_name in lora.keys():
|
||||||
|
blocks = lora[blocks_name]
|
||||||
|
if blocks.ndim == 4:
|
||||||
|
loaded_keys.add(blocks_name)
|
||||||
|
|
||||||
|
rescale = None
|
||||||
|
if rescale_name in lora.keys():
|
||||||
|
rescale = lora[rescale_name]
|
||||||
|
loaded_keys.add(rescale_name)
|
||||||
|
|
||||||
|
if blocks is not None:
|
||||||
|
weights = (blocks, rescale, alpha, dora_scale)
|
||||||
|
return cls(loaded_keys, weights)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def calculate_weight(
|
||||||
|
self,
|
||||||
|
weight,
|
||||||
|
key,
|
||||||
|
strength,
|
||||||
|
strength_model,
|
||||||
|
offset,
|
||||||
|
function,
|
||||||
|
intermediate_dtype=torch.float32,
|
||||||
|
original_weight=None,
|
||||||
|
):
|
||||||
|
v = self.weights
|
||||||
|
blocks = v[0]
|
||||||
|
rescale = v[1]
|
||||||
|
alpha = v[2]
|
||||||
|
dora_scale = v[3]
|
||||||
|
|
||||||
|
blocks = comfy.model_management.cast_to_device(blocks, weight.device, intermediate_dtype)
|
||||||
|
if rescale is not None:
|
||||||
|
rescale = comfy.model_management.cast_to_device(rescale, weight.device, intermediate_dtype)
|
||||||
|
|
||||||
|
boft_m, block_num, boft_b, *_ = blocks.shape
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Get r
|
||||||
|
I = torch.eye(boft_b, device=blocks.device, dtype=blocks.dtype)
|
||||||
|
# for Q = -Q^T
|
||||||
|
q = blocks - blocks.transpose(1, 2)
|
||||||
|
normed_q = q
|
||||||
|
if alpha > 0: # alpha in boft/bboft is for constraint
|
||||||
|
q_norm = torch.norm(q) + 1e-8
|
||||||
|
if q_norm > alpha:
|
||||||
|
normed_q = q * alpha / q_norm
|
||||||
|
# use float() to prevent unsupported type in .inverse()
|
||||||
|
r = (I + normed_q) @ (I - normed_q).float().inverse()
|
||||||
|
r = r.to(original_weight)
|
||||||
|
|
||||||
|
inp = org = original_weight
|
||||||
|
|
||||||
|
r_b = boft_b//2
|
||||||
|
for i in range(boft_m):
|
||||||
|
bi = r[i]
|
||||||
|
g = 2
|
||||||
|
k = 2**i * r_b
|
||||||
|
if strength != 1:
|
||||||
|
bi = bi * strength + (1-strength) * I
|
||||||
|
inp = (
|
||||||
|
inp.unflatten(-1, (-1, g, k))
|
||||||
|
.transpose(-2, -1)
|
||||||
|
.flatten(-3)
|
||||||
|
.unflatten(-1, (-1, boft_b))
|
||||||
|
)
|
||||||
|
inp = torch.einsum("b n m, b n ... -> b m ...", inp, bi)
|
||||||
|
inp = (
|
||||||
|
inp.flatten(-2).unflatten(-1, (-1, k, g)).transpose(-2, -1).flatten(-3)
|
||||||
|
)
|
||||||
|
|
||||||
|
if rescale is not None:
|
||||||
|
inp = inp * rescale
|
||||||
|
|
||||||
|
lora_diff = inp - org
|
||||||
|
lora_diff = comfy.model_management.cast_to_device(lora_diff, weight.device, intermediate_dtype)
|
||||||
|
if dora_scale is not None:
|
||||||
|
weight = weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype, function)
|
||||||
|
else:
|
||||||
|
weight += function(((strength * alpha) * lora_diff).type(weight.dtype))
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("ERROR {} {} {}".format(self.name, key, e))
|
||||||
|
return weight
|
||||||
94
comfy/weight_adapter/oft.py
Normal file
94
comfy/weight_adapter/oft.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import torch
|
||||||
|
import comfy.model_management
|
||||||
|
from .base import WeightAdapterBase, weight_decompose
|
||||||
|
|
||||||
|
|
||||||
|
class OFTAdapter(WeightAdapterBase):
|
||||||
|
name = "oft"
|
||||||
|
|
||||||
|
def __init__(self, loaded_keys, weights):
|
||||||
|
self.loaded_keys = loaded_keys
|
||||||
|
self.weights = weights
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(
|
||||||
|
cls,
|
||||||
|
x: str,
|
||||||
|
lora: dict[str, torch.Tensor],
|
||||||
|
alpha: float,
|
||||||
|
dora_scale: torch.Tensor,
|
||||||
|
loaded_keys: set[str] = None,
|
||||||
|
) -> Optional["OFTAdapter"]:
|
||||||
|
if loaded_keys is None:
|
||||||
|
loaded_keys = set()
|
||||||
|
blocks_name = "{}.oft_blocks".format(x)
|
||||||
|
rescale_name = "{}.rescale".format(x)
|
||||||
|
|
||||||
|
blocks = None
|
||||||
|
if blocks_name in lora.keys():
|
||||||
|
blocks = lora[blocks_name]
|
||||||
|
if blocks.ndim == 3:
|
||||||
|
loaded_keys.add(blocks_name)
|
||||||
|
|
||||||
|
rescale = None
|
||||||
|
if rescale_name in lora.keys():
|
||||||
|
rescale = lora[rescale_name]
|
||||||
|
loaded_keys.add(rescale_name)
|
||||||
|
|
||||||
|
if blocks is not None:
|
||||||
|
weights = (blocks, rescale, alpha, dora_scale)
|
||||||
|
return cls(loaded_keys, weights)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def calculate_weight(
|
||||||
|
self,
|
||||||
|
weight,
|
||||||
|
key,
|
||||||
|
strength,
|
||||||
|
strength_model,
|
||||||
|
offset,
|
||||||
|
function,
|
||||||
|
intermediate_dtype=torch.float32,
|
||||||
|
original_weight=None,
|
||||||
|
):
|
||||||
|
v = self.weights
|
||||||
|
blocks = v[0]
|
||||||
|
rescale = v[1]
|
||||||
|
alpha = v[2]
|
||||||
|
dora_scale = v[3]
|
||||||
|
|
||||||
|
blocks = comfy.model_management.cast_to_device(blocks, weight.device, intermediate_dtype)
|
||||||
|
if rescale is not None:
|
||||||
|
rescale = comfy.model_management.cast_to_device(rescale, weight.device, intermediate_dtype)
|
||||||
|
|
||||||
|
block_num, block_size, *_ = blocks.shape
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Get r
|
||||||
|
I = torch.eye(block_size, device=blocks.device, dtype=blocks.dtype)
|
||||||
|
# for Q = -Q^T
|
||||||
|
q = blocks - blocks.transpose(1, 2)
|
||||||
|
normed_q = q
|
||||||
|
if alpha > 0: # alpha in oft/boft is for constraint
|
||||||
|
q_norm = torch.norm(q) + 1e-8
|
||||||
|
if q_norm > alpha:
|
||||||
|
normed_q = q * alpha / q_norm
|
||||||
|
# use float() to prevent unsupported type in .inverse()
|
||||||
|
r = (I + normed_q) @ (I - normed_q).float().inverse()
|
||||||
|
r = r.to(original_weight)
|
||||||
|
lora_diff = torch.einsum(
|
||||||
|
"k n m, k n ... -> k m ...",
|
||||||
|
(r * strength) - strength * I,
|
||||||
|
original_weight,
|
||||||
|
)
|
||||||
|
if dora_scale is not None:
|
||||||
|
weight = weight_decompose(dora_scale, weight, lora_diff, alpha, strength, intermediate_dtype, function)
|
||||||
|
else:
|
||||||
|
weight += function(((strength * alpha) * lora_diff).type(weight.dtype))
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("ERROR {} {} {}".format(self.name, key, e))
|
||||||
|
return weight
|
||||||
@ -3,7 +3,10 @@ import scipy.ndimage
|
|||||||
import torch
|
import torch
|
||||||
import comfy.utils
|
import comfy.utils
|
||||||
import node_helpers
|
import node_helpers
|
||||||
|
import folder_paths
|
||||||
|
import random
|
||||||
|
|
||||||
|
import nodes
|
||||||
from nodes import MAX_RESOLUTION
|
from nodes import MAX_RESOLUTION
|
||||||
|
|
||||||
def composite(destination, source, x, y, mask = None, multiplier = 8, resize_source = False):
|
def composite(destination, source, x, y, mask = None, multiplier = 8, resize_source = False):
|
||||||
@ -362,6 +365,30 @@ class ThresholdMask:
|
|||||||
mask = (mask > value).float()
|
mask = (mask > value).float()
|
||||||
return (mask,)
|
return (mask,)
|
||||||
|
|
||||||
|
# Mask Preview - original implement from
|
||||||
|
# https://github.com/cubiq/ComfyUI_essentials/blob/9d9f4bedfc9f0321c19faf71855e228c93bd0dc9/mask.py#L81
|
||||||
|
# upstream requested in https://github.com/Kosinkadink/rfcs/blob/main/rfcs/0000-corenodes.md#preview-nodes
|
||||||
|
class MaskPreview(nodes.SaveImage):
|
||||||
|
def __init__(self):
|
||||||
|
self.output_dir = folder_paths.get_temp_directory()
|
||||||
|
self.type = "temp"
|
||||||
|
self.prefix_append = "_temp_" + ''.join(random.choice("abcdefghijklmnopqrstupvxyz") for x in range(5))
|
||||||
|
self.compress_level = 4
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(s):
|
||||||
|
return {
|
||||||
|
"required": {"mask": ("MASK",), },
|
||||||
|
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION = "execute"
|
||||||
|
CATEGORY = "mask"
|
||||||
|
|
||||||
|
def execute(self, mask, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None):
|
||||||
|
preview = mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])).movedim(1, -1).expand(-1, -1, -1, 3)
|
||||||
|
return self.save_images(preview, filename_prefix, prompt, extra_pnginfo)
|
||||||
|
|
||||||
|
|
||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
"LatentCompositeMasked": LatentCompositeMasked,
|
"LatentCompositeMasked": LatentCompositeMasked,
|
||||||
@ -376,6 +403,7 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
"FeatherMask": FeatherMask,
|
"FeatherMask": FeatherMask,
|
||||||
"GrowMask": GrowMask,
|
"GrowMask": GrowMask,
|
||||||
"ThresholdMask": ThresholdMask,
|
"ThresholdMask": ThresholdMask,
|
||||||
|
"MaskPreview": MaskPreview
|
||||||
}
|
}
|
||||||
|
|
||||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
|
|||||||
@ -50,13 +50,15 @@ class SaveWEBM:
|
|||||||
for x in extra_pnginfo:
|
for x in extra_pnginfo:
|
||||||
container.metadata[x] = json.dumps(extra_pnginfo[x])
|
container.metadata[x] = json.dumps(extra_pnginfo[x])
|
||||||
|
|
||||||
codec_map = {"vp9": "libvpx-vp9", "av1": "libaom-av1"}
|
codec_map = {"vp9": "libvpx-vp9", "av1": "libsvtav1"}
|
||||||
stream = container.add_stream(codec_map[codec], rate=Fraction(round(fps * 1000), 1000))
|
stream = container.add_stream(codec_map[codec], rate=Fraction(round(fps * 1000), 1000))
|
||||||
stream.width = images.shape[-2]
|
stream.width = images.shape[-2]
|
||||||
stream.height = images.shape[-3]
|
stream.height = images.shape[-3]
|
||||||
stream.pix_fmt = "yuv420p"
|
stream.pix_fmt = "yuv420p10le" if codec == "av1" else "yuv420p"
|
||||||
stream.bit_rate = 0
|
stream.bit_rate = 0
|
||||||
stream.options = {'crf': str(crf)}
|
stream.options = {'crf': str(crf)}
|
||||||
|
if codec == "av1":
|
||||||
|
stream.options["preset"] = "6"
|
||||||
|
|
||||||
for frame in images:
|
for frame in images:
|
||||||
frame = av.VideoFrame.from_ndarray(torch.clamp(frame[..., :3] * 255, min=0, max=255).to(device=torch.device("cpu"), dtype=torch.uint8).numpy(), format="rgb24")
|
frame = av.VideoFrame.from_ndarray(torch.clamp(frame[..., :3] * 255, min=0, max=255).to(device=torch.device("cpu"), dtype=torch.uint8).numpy(), format="rgb24")
|
||||||
|
|||||||
@ -22,5 +22,5 @@ psutil
|
|||||||
kornia>=0.7.1
|
kornia>=0.7.1
|
||||||
spandrel
|
spandrel
|
||||||
soundfile
|
soundfile
|
||||||
av
|
av>=14.1.0
|
||||||
pydantic~=2.0
|
pydantic~=2.0
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user