Refactor loading strategies in mergers and LoRA resize nodes.
This commit is contained in:
@@ -121,6 +121,15 @@ When merging models with different layer structures (e.g., fine-tuned models wit
|
||||
|
||||
---
|
||||
|
||||
## Dtype Preservation & Override
|
||||
|
||||
By default, the merger preserves the highest precision `dtype` for each key found across all active source models (Model A and Model B) and the requested `save_dtype`.
|
||||
|
||||
- **Preserve Higher Precision**: If a key is `float32` in any of the source models, but you requested `save_dtype="bf16"` or `"fp16"`, that key will be saved as `float32` anyway. This prevents degrading critical high-precision layers (such as normalization layers or layers with restored outliers).
|
||||
- **Explicit Override**: If you prefer to force the entire model to be saved strictly as the selected `save_dtype` (e.g. for complete downcasting to `bf16`), toggle `override_dtype` to `True`.
|
||||
|
||||
---
|
||||
|
||||
## Layer Filtering (Regex Patterns)
|
||||
|
||||
Use regex patterns to control which layers are merged:
|
||||
|
||||
@@ -67,6 +67,15 @@ When merging models with different layer structures, the `mismatch_mode` paramet
|
||||
|
||||
---
|
||||
|
||||
## Dtype Preservation & Override
|
||||
|
||||
By default, the merger preserves the highest precision `dtype` for each key found across all active source models (Model A, B, and C) and the requested `save_dtype`.
|
||||
|
||||
- **Preserve Higher Precision**: If a key is `float32` in any of the active source models, but you requested `save_dtype="bf16"` or `"fp16"`, that key will be saved as `float32` anyway. This prevents degrading critical high-precision layers (such as normalization layers or layers with restored outliers).
|
||||
- **Explicit Override**: If you prefer to force the entire model to be saved strictly as the selected `save_dtype` (e.g. for complete downcasting to `bf16`), toggle `override_dtype` to `True`.
|
||||
|
||||
---
|
||||
|
||||
## Layer Filtering (Regex Patterns)
|
||||
|
||||
Use regex patterns to control which layers are merged:
|
||||
|
||||
+54
-20
@@ -377,6 +377,8 @@ def resize_lora_file(
|
||||
output_filename: str,
|
||||
verbose: bool = True,
|
||||
svd_niter: int = 2,
|
||||
lazy_load: bool = True,
|
||||
force_clear_cache: bool = False,
|
||||
) -> str:
|
||||
"""
|
||||
Resize a LoRA file to a new rank.
|
||||
@@ -391,6 +393,8 @@ def resize_lora_file(
|
||||
output_filename: Output filename (without extension)
|
||||
verbose: Print progress info
|
||||
svd_niter: Power iterations for SVD accuracy
|
||||
lazy_load: Low memory mode: load tensors from disk on demand
|
||||
force_clear_cache: Clear CUDA cache after each layer
|
||||
|
||||
Returns:
|
||||
Path to saved resized LoRA
|
||||
@@ -399,7 +403,7 @@ def resize_lora_file(
|
||||
lora_size_gb = estimate_model_size(lora_path)
|
||||
prepare_for_large_operation(lora_size_gb * 2, torch.device(device))
|
||||
|
||||
handler = MemoryEfficientSafeOpen(lora_path)
|
||||
handler = MemoryEfficientSafeOpen(lora_path, low_memory=lazy_load)
|
||||
|
||||
try:
|
||||
metadata = handler.metadata().copy()
|
||||
@@ -484,10 +488,11 @@ def resize_lora_file(
|
||||
writer.write_dict(block_sd)
|
||||
|
||||
del result
|
||||
import gc
|
||||
gc.collect()
|
||||
if torch.cuda.is_available():
|
||||
torch.cuda.empty_cache()
|
||||
if force_clear_cache:
|
||||
import gc
|
||||
gc.collect()
|
||||
if torch.cuda.is_available():
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
pbar.update(1)
|
||||
finally:
|
||||
@@ -531,17 +536,22 @@ class LoRAResizeFixed(io.ComfyNode):
|
||||
io.String.Input("output_filename", default="resized_lora"),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16"),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda"),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=False, tooltip="Clear CUDA cache after each layer (slower but saves VRAM)"),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
is_output_node=True,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, lora_name, new_rank, svd_niter, output_filename, save_dtype, device) -> io.NodeOutput:
|
||||
def execute(cls, lora_name, new_rank, svd_niter, output_filename, save_dtype, device, lazy_load, force_clear_cache) -> io.NodeOutput:
|
||||
lora_path = folder_paths.get_full_path_or_raise("loras", lora_name)
|
||||
dtype = {"fp16": torch.float16, "bf16": torch.bfloat16, "fp32": torch.float32}[save_dtype]
|
||||
|
||||
path = resize_lora_file(lora_path, new_rank, None, None, device, dtype, output_filename, svd_niter=svd_niter)
|
||||
path = resize_lora_file(
|
||||
lora_path, new_rank, None, None, device, dtype, output_filename,
|
||||
svd_niter=svd_niter, lazy_load=lazy_load, force_clear_cache=force_clear_cache
|
||||
)
|
||||
return io.NodeOutput(path)
|
||||
|
||||
|
||||
@@ -565,17 +575,22 @@ class LoRAResizeRatio(io.ComfyNode):
|
||||
io.String.Input("output_filename", default="resized_lora_ratio"),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16"),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda"),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=False, tooltip="Clear CUDA cache after each layer (slower but saves VRAM)"),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
is_output_node=True,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, lora_name, max_rank, ratio, output_filename, save_dtype, device) -> io.NodeOutput:
|
||||
def execute(cls, lora_name, max_rank, ratio, output_filename, save_dtype, device, lazy_load, force_clear_cache) -> io.NodeOutput:
|
||||
lora_path = folder_paths.get_full_path_or_raise("loras", lora_name)
|
||||
dtype = {"fp16": torch.float16, "bf16": torch.bfloat16, "fp32": torch.float32}[save_dtype]
|
||||
|
||||
path = resize_lora_file(lora_path, max_rank, "sv_ratio", ratio, device, dtype, output_filename)
|
||||
path = resize_lora_file(
|
||||
lora_path, max_rank, "sv_ratio", ratio, device, dtype, output_filename,
|
||||
lazy_load=lazy_load, force_clear_cache=force_clear_cache
|
||||
)
|
||||
return io.NodeOutput(path)
|
||||
|
||||
|
||||
@@ -599,17 +614,22 @@ class LoRAResizeFrobenius(io.ComfyNode):
|
||||
io.String.Input("output_filename", default="resized_lora_fro"),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16"),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda"),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=False, tooltip="Clear CUDA cache after each layer (slower but saves VRAM)"),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
is_output_node=True,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, lora_name, max_rank, target, output_filename, save_dtype, device) -> io.NodeOutput:
|
||||
def execute(cls, lora_name, max_rank, target, output_filename, save_dtype, device, lazy_load, force_clear_cache) -> io.NodeOutput:
|
||||
lora_path = folder_paths.get_full_path_or_raise("loras", lora_name)
|
||||
dtype = {"fp16": torch.float16, "bf16": torch.bfloat16, "fp32": torch.float32}[save_dtype]
|
||||
|
||||
path = resize_lora_file(lora_path, max_rank, "sv_fro", target, device, dtype, output_filename)
|
||||
path = resize_lora_file(
|
||||
lora_path, max_rank, "sv_fro", target, device, dtype, output_filename,
|
||||
lazy_load=lazy_load, force_clear_cache=force_clear_cache
|
||||
)
|
||||
return io.NodeOutput(path)
|
||||
|
||||
|
||||
@@ -633,17 +653,22 @@ class LoRAResizeCumulative(io.ComfyNode):
|
||||
io.String.Input("output_filename", default="resized_lora_cumulative"),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16"),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda"),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=False, tooltip="Clear CUDA cache after each layer (slower but saves VRAM)"),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
is_output_node=True,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, lora_name, max_rank, target, output_filename, save_dtype, device) -> io.NodeOutput:
|
||||
def execute(cls, lora_name, max_rank, target, output_filename, save_dtype, device, lazy_load, force_clear_cache) -> io.NodeOutput:
|
||||
lora_path = folder_paths.get_full_path_or_raise("loras", lora_name)
|
||||
dtype = {"fp16": torch.float16, "bf16": torch.bfloat16, "fp32": torch.float32}[save_dtype]
|
||||
|
||||
path = resize_lora_file(lora_path, max_rank, "sv_cumulative", target, device, dtype, output_filename)
|
||||
path = resize_lora_file(
|
||||
lora_path, max_rank, "sv_cumulative", target, device, dtype, output_filename,
|
||||
lazy_load=lazy_load, force_clear_cache=force_clear_cache
|
||||
)
|
||||
return io.NodeOutput(path)
|
||||
|
||||
|
||||
@@ -662,6 +687,8 @@ def merge_loras_to_model(
|
||||
output_filename: str,
|
||||
skip_patterns_str: str = "",
|
||||
verbose: bool = True,
|
||||
lazy_load: bool = True,
|
||||
force_clear_cache: bool = False,
|
||||
) -> str:
|
||||
"""
|
||||
Merge multiple LoRAs into a base model and save the result directly.
|
||||
@@ -679,6 +706,8 @@ def merge_loras_to_model(
|
||||
output_filename: Output filename (without extension)
|
||||
skip_patterns_str: Regex patterns for layers to skip
|
||||
verbose: Print progress info
|
||||
lazy_load: Low memory mode: load tensors from disk on demand
|
||||
force_clear_cache: Clear CUDA cache after each layer
|
||||
|
||||
Returns:
|
||||
Path to saved merged model
|
||||
@@ -694,8 +723,8 @@ def merge_loras_to_model(
|
||||
prepare_for_large_operation(total_size_gb * 1.5, torch.device(device))
|
||||
|
||||
# Open all files - use low_memory for base model to avoid OS page caching
|
||||
base_handler = MemoryEfficientSafeOpen(base_model_path, low_memory=True)
|
||||
lora_handlers = [MemoryEfficientSafeOpen(lp) for lp in lora_paths]
|
||||
base_handler = MemoryEfficientSafeOpen(base_model_path, low_memory=lazy_load)
|
||||
lora_handlers = [MemoryEfficientSafeOpen(lp, low_memory=lazy_load) for lp in lora_paths]
|
||||
|
||||
|
||||
try:
|
||||
@@ -874,10 +903,11 @@ def merge_loras_to_model(
|
||||
del cpu_base
|
||||
stats["copied"] += 1
|
||||
|
||||
import gc
|
||||
gc.collect()
|
||||
if torch.cuda.is_available():
|
||||
torch.cuda.empty_cache()
|
||||
if force_clear_cache:
|
||||
import gc
|
||||
gc.collect()
|
||||
if torch.cuda.is_available():
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
pbar.update(1)
|
||||
finally:
|
||||
@@ -957,6 +987,8 @@ class LoRAMergeToModel(io.ComfyNode):
|
||||
io.String.Input("output_filename", default="merged_model"),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16"),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda"),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=False, tooltip="Clear CUDA cache after each layer (slower but saves VRAM)"),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
is_output_node=True,
|
||||
@@ -966,7 +998,7 @@ class LoRAMergeToModel(io.ComfyNode):
|
||||
def execute(cls, base_model, lora_count,
|
||||
lora_1, weight_1, lora_2, weight_2, lora_3, weight_3, lora_4, weight_4,
|
||||
lora_5, weight_5, lora_6, weight_6, lora_7, weight_7, lora_8, weight_8,
|
||||
skip_patterns, output_filename, save_dtype, device) -> io.NodeOutput:
|
||||
skip_patterns, output_filename, save_dtype, device, lazy_load, force_clear_cache) -> io.NodeOutput:
|
||||
|
||||
# Build LoRA list based on count
|
||||
count = int(lora_count)
|
||||
@@ -991,5 +1023,7 @@ class LoRAMergeToModel(io.ComfyNode):
|
||||
save_dtype=dtype,
|
||||
output_filename=output_filename,
|
||||
skip_patterns_str=skip_patterns,
|
||||
lazy_load=lazy_load,
|
||||
force_clear_cache=force_clear_cache,
|
||||
)
|
||||
return io.NodeOutput(path)
|
||||
|
||||
+61
-23
@@ -132,6 +132,25 @@ class MergerLogic:
|
||||
pbar = comfy.utils.ProgressBar(len(all_keys))
|
||||
save_dtype = recipe_params.pop('save_dtype')
|
||||
save_torch_dtype = {"fp32": torch.float32, "fp16": torch.float16, "bf16": torch.bfloat16}.get(save_dtype)
|
||||
override_dtype = recipe_params.pop('override_dtype', False)
|
||||
|
||||
def determine_target_dtype(original_dtypes, target_dtype, override):
|
||||
if override:
|
||||
return target_dtype
|
||||
priority_map = {
|
||||
torch.float32: 3,
|
||||
torch.bfloat16: 2,
|
||||
torch.float16: 2,
|
||||
}
|
||||
highest_dtype = target_dtype
|
||||
highest_priority = priority_map.get(highest_dtype, 1)
|
||||
for dtype in original_dtypes:
|
||||
p = priority_map.get(dtype, 1)
|
||||
if p > highest_priority:
|
||||
highest_priority = p
|
||||
highest_dtype = dtype
|
||||
return highest_dtype
|
||||
|
||||
recipe_params.update({"handlers": handlers})
|
||||
process_device = recipe_params.get('device', 'cpu')
|
||||
process_dtype = recipe_params.get('dtype', torch.float32)
|
||||
@@ -181,6 +200,15 @@ class MergerLogic:
|
||||
|
||||
# Pre-load Model A's tensor with pinned memory for CUDA
|
||||
cpu_tensor = primary_handler.get_tensor(key)
|
||||
|
||||
# Determine original dtypes across all active models for this key
|
||||
original_dtypes = [primary_handler.get_dtype(key)]
|
||||
for name, handler in handlers.items():
|
||||
if name != primary_model_name and key in handler.keys():
|
||||
original_dtypes.append(handler.get_dtype(key))
|
||||
|
||||
target_dtype = determine_target_dtype(original_dtypes, save_torch_dtype, override_dtype)
|
||||
|
||||
if process_device == 'cuda':
|
||||
tensor_a = transfer_to_gpu_pinned(cpu_tensor, process_device, process_dtype)
|
||||
else:
|
||||
@@ -189,7 +217,7 @@ class MergerLogic:
|
||||
|
||||
# Check exclude patterns - use Model A only, no merge
|
||||
if _matches_any_pattern(key, exclude_patterns, glob_mode=glob_mode):
|
||||
t = tensor_a.detach().to(save_torch_dtype).cpu()
|
||||
t = tensor_a.detach().to(target_dtype).cpu()
|
||||
|
||||
batch_buffer[key] = t
|
||||
batch_bytes += t.numel() * t.element_size()
|
||||
@@ -224,7 +252,7 @@ class MergerLogic:
|
||||
|
||||
if isinstance(result, dict):
|
||||
for r_key, r_tensor in result.items():
|
||||
t = r_tensor.detach().to(save_torch_dtype).cpu()
|
||||
t = r_tensor.detach().to(target_dtype).cpu()
|
||||
|
||||
batch_buffer[r_key] = t
|
||||
batch_bytes += t.numel() * t.element_size()
|
||||
@@ -238,7 +266,7 @@ class MergerLogic:
|
||||
slices = tuple(slice(0, min(res_s, tgt_s)) for res_s, tgt_s in zip(result.shape, target_shape))
|
||||
result = result[slices]
|
||||
|
||||
t = result.detach().to(save_torch_dtype).cpu()
|
||||
t = result.detach().to(target_dtype).cpu()
|
||||
|
||||
batch_buffer[key] = t
|
||||
batch_bytes += t.numel() * t.element_size()
|
||||
@@ -323,6 +351,7 @@ class CheckpointTwoMerger(io.ComfyNode):
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=True, tooltip="Clear CUDA cache after each layer"),
|
||||
io.Boolean.Input("override_dtype", default=False, tooltip="Force the entire model to be saved as the selected save_dtype. If False (default), higher precision dtypes are preserved."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_filename"),
|
||||
@@ -335,7 +364,7 @@ class CheckpointTwoMerger(io.ComfyNode):
|
||||
calc_mode: str, mismatch_mode: str, alignment_mode: str, alpha: float, beta: float,
|
||||
gamma: float, delta: float, epsilon: float, zeta: float, seed: int, output_filename: str, save_dtype: str,
|
||||
process_device: str, exclude_patterns: str, discard_patterns: str,
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool) -> io.NodeOutput:
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool, override_dtype: bool) -> io.NodeOutput:
|
||||
doc = load_documentation_from_file('merger_2_model_modes.md')
|
||||
if execution_mode == "DOCUMENTATION ONLY":
|
||||
return io.NodeOutput("Documentation mode active. No merge performed.", doc)
|
||||
@@ -344,7 +373,7 @@ class CheckpointTwoMerger(io.ComfyNode):
|
||||
"model_a": model_a, "model_b": model_b, "calc_mode": calc_mode,
|
||||
"mismatch_mode": mismatch_mode, "alignment_mode": alignment_mode,
|
||||
"alpha": alpha, "beta": beta, "gamma": gamma, "delta": delta, "epsilon": epsilon, "zeta": zeta, "seed": seed,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype, "override_dtype": override_dtype,
|
||||
"device": process_device, "dtype": torch.float32,
|
||||
"exclude_patterns": exclude_patterns, "discard_patterns": discard_patterns,
|
||||
"glob_patterns": glob_patterns,
|
||||
@@ -388,6 +417,7 @@ class ModelTwoMerger(io.ComfyNode):
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=True, tooltip="Clear CUDA cache after each layer"),
|
||||
io.Boolean.Input("override_dtype", default=False, tooltip="Force the entire model to be saved as the selected save_dtype. If False (default), higher precision dtypes are preserved."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_filename"),
|
||||
@@ -400,7 +430,7 @@ class ModelTwoMerger(io.ComfyNode):
|
||||
calc_mode: str, mismatch_mode: str, alignment_mode: str, alpha: float, beta: float,
|
||||
gamma: float, delta: float, epsilon: float, zeta: float, seed: int, output_filename: str, save_dtype: str,
|
||||
process_device: str, exclude_patterns: str, discard_patterns: str,
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool) -> io.NodeOutput:
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool, override_dtype: bool) -> io.NodeOutput:
|
||||
doc = load_documentation_from_file('merger_2_model_modes.md')
|
||||
if execution_mode == "DOCUMENTATION ONLY":
|
||||
return io.NodeOutput("Documentation mode active. No merge performed.", doc)
|
||||
@@ -409,7 +439,7 @@ class ModelTwoMerger(io.ComfyNode):
|
||||
"model_a": model_a, "model_b": model_b, "calc_mode": calc_mode,
|
||||
"mismatch_mode": mismatch_mode, "alignment_mode": alignment_mode,
|
||||
"alpha": alpha, "beta": beta, "gamma": gamma, "delta": delta, "epsilon": epsilon, "zeta": zeta, "seed": seed,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype, "override_dtype": override_dtype,
|
||||
"device": process_device, "dtype": torch.float32,
|
||||
"exclude_patterns": exclude_patterns, "discard_patterns": discard_patterns,
|
||||
"glob_patterns": glob_patterns,
|
||||
@@ -453,6 +483,7 @@ class TextEncoderTwoMerger(io.ComfyNode):
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=True, tooltip="Clear CUDA cache after each layer"),
|
||||
io.Boolean.Input("override_dtype", default=False, tooltip="Force the entire model to be saved as the selected save_dtype. If False (default), higher precision dtypes are preserved."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_filename"),
|
||||
@@ -465,7 +496,7 @@ class TextEncoderTwoMerger(io.ComfyNode):
|
||||
calc_mode: str, mismatch_mode: str, alignment_mode: str, alpha: float, beta: float,
|
||||
gamma: float, delta: float, epsilon: float, zeta: float, seed: int, output_filename: str, save_dtype: str,
|
||||
process_device: str, exclude_patterns: str, discard_patterns: str,
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool) -> io.NodeOutput:
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool, override_dtype: bool) -> io.NodeOutput:
|
||||
doc = load_documentation_from_file('merger_2_model_modes.md')
|
||||
if execution_mode == "DOCUMENTATION ONLY":
|
||||
return io.NodeOutput("Documentation mode active. No merge performed.", doc)
|
||||
@@ -474,7 +505,7 @@ class TextEncoderTwoMerger(io.ComfyNode):
|
||||
"model_a": model_a, "model_b": model_b, "calc_mode": calc_mode,
|
||||
"mismatch_mode": mismatch_mode, "alignment_mode": alignment_mode,
|
||||
"alpha": alpha, "beta": beta, "gamma": gamma, "delta": delta, "epsilon": epsilon, "zeta": zeta, "seed": seed,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype, "override_dtype": override_dtype,
|
||||
"device": process_device, "dtype": torch.float32,
|
||||
"exclude_patterns": exclude_patterns, "discard_patterns": discard_patterns,
|
||||
"glob_patterns": glob_patterns,
|
||||
@@ -518,6 +549,7 @@ class LoRATwoMerger(io.ComfyNode):
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=True, tooltip="Clear CUDA cache after each layer"),
|
||||
io.Boolean.Input("override_dtype", default=False, tooltip="Force the entire model to be saved as the selected save_dtype. If False (default), higher precision dtypes are preserved."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_filename"),
|
||||
@@ -530,7 +562,7 @@ class LoRATwoMerger(io.ComfyNode):
|
||||
calc_mode: str, mismatch_mode: str, alignment_mode: str, alpha: float, beta: float,
|
||||
gamma: float, delta: float, epsilon: float, zeta: float, seed: int, output_filename: str, save_dtype: str,
|
||||
process_device: str, exclude_patterns: str, discard_patterns: str,
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool) -> io.NodeOutput:
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool, override_dtype: bool) -> io.NodeOutput:
|
||||
doc = load_documentation_from_file('merger_2_model_modes.md')
|
||||
if execution_mode == "DOCUMENTATION ONLY":
|
||||
return io.NodeOutput("Documentation mode active. No merge performed.", doc)
|
||||
@@ -539,7 +571,7 @@ class LoRATwoMerger(io.ComfyNode):
|
||||
"model_a": model_a, "model_b": model_b, "calc_mode": calc_mode,
|
||||
"mismatch_mode": mismatch_mode, "alignment_mode": alignment_mode,
|
||||
"alpha": alpha, "beta": beta, "gamma": gamma, "delta": delta, "epsilon": epsilon, "zeta": zeta, "seed": seed,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype, "override_dtype": override_dtype,
|
||||
"device": process_device, "dtype": torch.float32,
|
||||
"exclude_patterns": exclude_patterns, "discard_patterns": discard_patterns,
|
||||
"glob_patterns": glob_patterns,
|
||||
@@ -583,6 +615,7 @@ class EmbeddingTwoMerger(io.ComfyNode):
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=True, tooltip="Clear CUDA cache after each layer"),
|
||||
io.Boolean.Input("override_dtype", default=False, tooltip="Force the entire model to be saved as the selected save_dtype. If False (default), higher precision dtypes are preserved."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_filename"),
|
||||
@@ -595,7 +628,7 @@ class EmbeddingTwoMerger(io.ComfyNode):
|
||||
calc_mode: str, mismatch_mode: str, alignment_mode: str, alpha: float, beta: float,
|
||||
gamma: float, delta: float, epsilon: float, zeta: float, seed: int, output_filename: str, save_dtype: str,
|
||||
process_device: str, exclude_patterns: str, discard_patterns: str,
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool) -> io.NodeOutput:
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool, override_dtype: bool) -> io.NodeOutput:
|
||||
doc = load_documentation_from_file('merger_2_model_modes.md')
|
||||
if execution_mode == "DOCUMENTATION ONLY":
|
||||
return io.NodeOutput("Documentation mode active. No merge performed.", doc)
|
||||
@@ -604,7 +637,7 @@ class EmbeddingTwoMerger(io.ComfyNode):
|
||||
"model_a": model_a, "model_b": model_b, "calc_mode": calc_mode,
|
||||
"mismatch_mode": mismatch_mode, "alignment_mode": alignment_mode,
|
||||
"alpha": alpha, "beta": beta, "gamma": gamma, "delta": delta, "epsilon": epsilon, "zeta": zeta, "seed": seed,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype, "override_dtype": override_dtype,
|
||||
"device": process_device, "dtype": torch.float32,
|
||||
"exclude_patterns": exclude_patterns, "discard_patterns": discard_patterns,
|
||||
"glob_patterns": glob_patterns,
|
||||
@@ -651,6 +684,7 @@ class CheckpointThreeMerger(io.ComfyNode):
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=True, tooltip="Clear CUDA cache after each layer"),
|
||||
io.Boolean.Input("override_dtype", default=False, tooltip="Force the entire model to be saved as the selected save_dtype. If False (default), higher precision dtypes are preserved."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_filename"),
|
||||
@@ -663,7 +697,7 @@ class CheckpointThreeMerger(io.ComfyNode):
|
||||
calc_mode: str, mismatch_mode: str, alignment_mode: str, alpha: float, beta: float,
|
||||
gamma: float, delta: float, epsilon: float, zeta: float, seed: int, output_filename: str, save_dtype: str,
|
||||
process_device: str, exclude_patterns: str, discard_patterns: str,
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool) -> io.NodeOutput:
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool, override_dtype: bool) -> io.NodeOutput:
|
||||
doc = load_documentation_from_file('merger_3_model_modes.md')
|
||||
if execution_mode == "DOCUMENTATION ONLY":
|
||||
return io.NodeOutput("Documentation mode active. No merge performed.", doc)
|
||||
@@ -672,7 +706,7 @@ class CheckpointThreeMerger(io.ComfyNode):
|
||||
"model_a": model_a, "model_b": model_b, "model_c": model_c, "calc_mode": calc_mode,
|
||||
"mismatch_mode": mismatch_mode, "alignment_mode": alignment_mode,
|
||||
"alpha": alpha, "beta": beta, "gamma": gamma, "delta": delta, "epsilon": epsilon, "zeta": zeta, "seed": seed,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype, "override_dtype": override_dtype,
|
||||
"device": process_device, "dtype": torch.float32,
|
||||
"exclude_patterns": exclude_patterns, "discard_patterns": discard_patterns,
|
||||
"glob_patterns": glob_patterns,
|
||||
@@ -717,6 +751,7 @@ class ModelThreeMerger(io.ComfyNode):
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=True, tooltip="Clear CUDA cache after each layer"),
|
||||
io.Boolean.Input("override_dtype", default=False, tooltip="Force the entire model to be saved as the selected save_dtype. If False (default), higher precision dtypes are preserved."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_filename"),
|
||||
@@ -729,7 +764,7 @@ class ModelThreeMerger(io.ComfyNode):
|
||||
calc_mode: str, mismatch_mode: str, alignment_mode: str, alpha: float, beta: float,
|
||||
gamma: float, delta: float, epsilon: float, zeta: float, seed: int, output_filename: str, save_dtype: str,
|
||||
process_device: str, exclude_patterns: str, discard_patterns: str,
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool) -> io.NodeOutput:
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool, override_dtype: bool) -> io.NodeOutput:
|
||||
doc = load_documentation_from_file('merger_3_model_modes.md')
|
||||
if execution_mode == "DOCUMENTATION ONLY":
|
||||
return io.NodeOutput("Documentation mode active. No merge performed.", doc)
|
||||
@@ -738,7 +773,7 @@ class ModelThreeMerger(io.ComfyNode):
|
||||
"model_a": model_a, "model_b": model_b, "model_c": model_c, "calc_mode": calc_mode,
|
||||
"mismatch_mode": mismatch_mode, "alignment_mode": alignment_mode,
|
||||
"alpha": alpha, "beta": beta, "gamma": gamma, "delta": delta, "epsilon": epsilon, "zeta": zeta, "seed": seed,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype, "override_dtype": override_dtype,
|
||||
"device": process_device, "dtype": torch.float32,
|
||||
"exclude_patterns": exclude_patterns, "discard_patterns": discard_patterns,
|
||||
"glob_patterns": glob_patterns,
|
||||
@@ -783,6 +818,7 @@ class TextEncoderThreeMerger(io.ComfyNode):
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=True, tooltip="Clear CUDA cache after each layer"),
|
||||
io.Boolean.Input("override_dtype", default=False, tooltip="Force the entire model to be saved as the selected save_dtype. If False (default), higher precision dtypes are preserved."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_filename"),
|
||||
@@ -795,7 +831,7 @@ class TextEncoderThreeMerger(io.ComfyNode):
|
||||
calc_mode: str, mismatch_mode: str, alignment_mode: str, alpha: float, beta: float,
|
||||
gamma: float, delta: float, epsilon: float, zeta: float, seed: int, output_filename: str, save_dtype: str,
|
||||
process_device: str, exclude_patterns: str, discard_patterns: str,
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool) -> io.NodeOutput:
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool, override_dtype: bool) -> io.NodeOutput:
|
||||
doc = load_documentation_from_file('merger_3_model_modes.md')
|
||||
if execution_mode == "DOCUMENTATION ONLY":
|
||||
return io.NodeOutput("Documentation mode active. No merge performed.", doc)
|
||||
@@ -804,7 +840,7 @@ class TextEncoderThreeMerger(io.ComfyNode):
|
||||
"model_a": model_a, "model_b": model_b, "model_c": model_c, "calc_mode": calc_mode,
|
||||
"mismatch_mode": mismatch_mode, "alignment_mode": alignment_mode,
|
||||
"alpha": alpha, "beta": beta, "gamma": gamma, "delta": delta, "epsilon": epsilon, "zeta": zeta, "seed": seed,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype, "override_dtype": override_dtype,
|
||||
"device": process_device, "dtype": torch.float32,
|
||||
"exclude_patterns": exclude_patterns, "discard_patterns": discard_patterns,
|
||||
"glob_patterns": glob_patterns,
|
||||
@@ -849,6 +885,7 @@ class LoRAThreeMerger(io.ComfyNode):
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=True, tooltip="Clear CUDA cache after each layer"),
|
||||
io.Boolean.Input("override_dtype", default=False, tooltip="Force the entire model to be saved as the selected save_dtype. If False (default), higher precision dtypes are preserved."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_filename"),
|
||||
@@ -861,7 +898,7 @@ class LoRAThreeMerger(io.ComfyNode):
|
||||
calc_mode: str, mismatch_mode: str, alignment_mode: str, alpha: float, beta: float,
|
||||
gamma: float, delta: float, epsilon: float, zeta: float, seed: int, output_filename: str, save_dtype: str,
|
||||
process_device: str, exclude_patterns: str, discard_patterns: str,
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool) -> io.NodeOutput:
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool, override_dtype: bool) -> io.NodeOutput:
|
||||
doc = load_documentation_from_file('merger_3_model_modes.md')
|
||||
if execution_mode == "DOCUMENTATION ONLY":
|
||||
return io.NodeOutput("Documentation mode active. No merge performed.", doc)
|
||||
@@ -870,7 +907,7 @@ class LoRAThreeMerger(io.ComfyNode):
|
||||
"model_a": model_a, "model_b": model_b, "model_c": model_c, "calc_mode": calc_mode,
|
||||
"mismatch_mode": mismatch_mode, "alignment_mode": alignment_mode,
|
||||
"alpha": alpha, "beta": beta, "gamma": gamma, "delta": delta, "epsilon": epsilon, "zeta": zeta, "seed": seed,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype, "override_dtype": override_dtype,
|
||||
"device": process_device, "dtype": torch.float32,
|
||||
"exclude_patterns": exclude_patterns, "discard_patterns": discard_patterns,
|
||||
"glob_patterns": glob_patterns,
|
||||
@@ -915,6 +952,7 @@ class EmbeddingThreeMerger(io.ComfyNode):
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
io.Boolean.Input("lazy_load", default=True, tooltip="Low memory mode: load tensors from disk on demand"),
|
||||
io.Boolean.Input("force_clear_cache", default=True, tooltip="Clear CUDA cache after each layer"),
|
||||
io.Boolean.Input("override_dtype", default=False, tooltip="Force the entire model to be saved as the selected save_dtype. If False (default), higher precision dtypes are preserved."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_filename"),
|
||||
@@ -927,7 +965,7 @@ class EmbeddingThreeMerger(io.ComfyNode):
|
||||
calc_mode: str, mismatch_mode: str, alignment_mode: str, alpha: float, beta: float,
|
||||
gamma: float, delta: float, epsilon: float, zeta: float, seed: int, output_filename: str, save_dtype: str,
|
||||
process_device: str, exclude_patterns: str, discard_patterns: str,
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool) -> io.NodeOutput:
|
||||
glob_patterns: bool, lazy_load: bool, force_clear_cache: bool, override_dtype: bool) -> io.NodeOutput:
|
||||
doc = load_documentation_from_file('merger_3_model_modes.md')
|
||||
if execution_mode == "DOCUMENTATION ONLY":
|
||||
return io.NodeOutput("Documentation mode active. No merge performed.", doc)
|
||||
@@ -936,7 +974,7 @@ class EmbeddingThreeMerger(io.ComfyNode):
|
||||
"model_a": model_a, "model_b": model_b, "model_c": model_c, "calc_mode": calc_mode,
|
||||
"mismatch_mode": mismatch_mode, "alignment_mode": alignment_mode,
|
||||
"alpha": alpha, "beta": beta, "gamma": gamma, "delta": delta, "epsilon": epsilon, "zeta": zeta, "seed": seed,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype,
|
||||
"output_filename": output_filename, "save_dtype": save_dtype, "override_dtype": override_dtype,
|
||||
"device": process_device, "dtype": torch.float32,
|
||||
"exclude_patterns": exclude_patterns, "discard_patterns": discard_patterns,
|
||||
"glob_patterns": glob_patterns,
|
||||
|
||||
Reference in New Issue
Block a user