docs(nodes): add schema tooltips
This commit is contained in:
@@ -5,6 +5,12 @@ Consensus-Weighted Blending. They calculate an element-wise mean or median
|
||||
consensus, compare each aligned source vector to that consensus, and normalize
|
||||
similarity-derived weights before producing the output vector.
|
||||
|
||||
The broad mathematical and integration reference is maintained in
|
||||
[`references/Spec-CWB`](../references/Spec-CWB/README.md). This document
|
||||
describes the behavior actually exposed by this repository's offline merger
|
||||
nodes. The specification covers additional contexts, including online
|
||||
conditioning and spatial fusion, which are not controls of these nodes.
|
||||
|
||||
## Node families
|
||||
|
||||
Two-input and three-input variants are provided for checkpoints, standalone
|
||||
@@ -37,6 +43,138 @@ Inputs have equal prior weight. The similarity calculation supplies the
|
||||
effective contribution for each aligned vector. If every candidate is rejected
|
||||
or receives zero weight, CWB falls back to equal weighting.
|
||||
|
||||
### Weighting sequence
|
||||
|
||||
For each aligned vector group, the merger performs these operations in order:
|
||||
|
||||
1. Compute an element-wise mean or median consensus.
|
||||
2. Measure each vector's cosine similarity to that consensus.
|
||||
3. Reject similarities below `similarity_threshold`.
|
||||
4. Optionally remap unequal accepted similarities with Dynamic Similarity
|
||||
Contrast.
|
||||
5. Apply `similarity^power_alpha` and, when enabled, the diversity bandpass.
|
||||
6. Normalize the resulting contributor weights and calculate their weighted
|
||||
sum. If no usable weight remains, use equal contributor weights.
|
||||
7. Optionally apply `rescale_norm`.
|
||||
8. Apply `global_scale`.
|
||||
|
||||
### Complete control reference
|
||||
|
||||
- **Execution Mode**: `MERGE` writes an output. `DOCUMENTATION ONLY` returns
|
||||
this document without opening model inputs.
|
||||
- **Model A**: primary contributor and preservation anchor. It supplies output
|
||||
metadata and anchors shared names and shapes. The output key set remains the
|
||||
union of all inputs.
|
||||
- **Model B / Model C**: additional equal-prior contributors. CWB derives their
|
||||
effective per-vector influence from consensus similarity; these nodes do not
|
||||
expose model-level weights.
|
||||
- **CWB Preset**: `custom` makes all manual CWB controls authoritative. A named
|
||||
preset sets consensus, similarity cutoff, alpha/beta, norm rescaling, and its
|
||||
DSC fields. Named presets force similarity alignment. Only `power_blend`
|
||||
supplies an alignment threshold (0.9); other presets retain the manual
|
||||
alignment threshold. `position_weight` and `preserve_common_prefix` remain
|
||||
explicit extensions. A manually selected `global_scale` other than 1.0 also
|
||||
remains active.
|
||||
- **Consensus Type**: `mean` uses the arithmetic center; `median` uses the
|
||||
element-wise median and is less sensitive to coordinate outliers.
|
||||
- **Alignment Method**: `index` pairs first-axis vectors by position;
|
||||
`similarity` uses greedy one-to-one cosine matching. Row reordering is
|
||||
enabled only for embeddings and paired LoRA rank components. Ordinary
|
||||
checkpoint, diffusion-model, and text-encoder tensors retain fixed
|
||||
coordinates.
|
||||
- **Alignment Threshold**: minimum original cosine score for accepting a
|
||||
greedy row match. It does not filter already-paired contributors during CWB
|
||||
weighting; that is `similarity_threshold`.
|
||||
- **Similarity Threshold**: minimum cosine similarity between a participating
|
||||
vector and the group consensus. Rejected vectors receive zero weight. If all
|
||||
are rejected, the implementation falls back to equal weights.
|
||||
- **Power Alpha**: exponent applied to accepted non-negative similarities.
|
||||
Values above 1 increasingly favor contributors closest to consensus. Zero
|
||||
makes every accepted contributor's similarity term equal to one.
|
||||
- **Diversity Beta**: exponent for the diversity bandpass. Values above zero
|
||||
suppress vectors extremely close to consensus relative to more varied
|
||||
accepted vectors. Zero disables this term.
|
||||
- **Rescale Norm**: after blending, preserve the merged direction but replace
|
||||
its L2 magnitude with the mean L2 magnitude of the participating vectors:
|
||||
|
||||
`merged = merged / ||merged|| × mean(||source_i||)`
|
||||
|
||||
A zero merged vector remains unchanged. This is performed per aligned row,
|
||||
not once per complete tensor. For LoRA, it is performed separately for each
|
||||
paired A row and B column, so enabling it can materially change the effective
|
||||
low-rank delta magnitude.
|
||||
- **Global Scale**: multiplies the merged result after CWB. For LoRA it is
|
||||
applied once through B/up so the represented delta is scaled once rather
|
||||
than once per factor.
|
||||
- **Dynamic Similarity Contrast**: when consensus similarities differ, remaps
|
||||
them into the range 0.7–1.0 before alpha/beta weighting. It does not alter
|
||||
row-alignment scores.
|
||||
- **Soft Comfort Bandpass**: when beta is positive, uses
|
||||
`(1.5 - similarity)^beta` instead of the narrower
|
||||
`(1.001 - similarity)^beta`. It has no effect when beta is zero.
|
||||
- **Position Weight**: blends normalized positional affinity into greedy row
|
||||
selection. Zero uses cosine only and one uses positional affinity only. It
|
||||
affects only similarity-aligned embeddings and LoRA rank components; the
|
||||
original cosine score is still checked against the alignment threshold.
|
||||
- **Preserve Common Prefix**: copies Model A's longest numerically identical
|
||||
leading first-axis span before CWB. The current implementation applies this
|
||||
to all tensors with at least two dimensions, including fixed-coordinate
|
||||
model tensors.
|
||||
- **Mismatch Mode**: for anchored tensors that are missing or incompatible,
|
||||
`skip` preserves the anchor, `zeros` supplies a compatible zero contribution
|
||||
where possible, and `error` aborts. A valid tensor supplied by only one
|
||||
secondary input is copied unchanged.
|
||||
- **Output Filename**: filename without extension, written atomically beneath
|
||||
the matching category in ComfyUI's models directory.
|
||||
- **Save Dtype**: requested dtype for generated floating tensors. Unless
|
||||
Override Dtype is enabled, any participating FP32 source keeps the generated
|
||||
logical result FP32.
|
||||
- **Process Device**: device for per-layer FP32 arithmetic. A CUDA OOM releases
|
||||
the failed working set and retries only that layer on CPU.
|
||||
- **Exclude Patterns**: matching layers are preserved from their anchor instead
|
||||
of merged.
|
||||
- **Discard Patterns**: matching tensors or logical LoRA groups are absent from
|
||||
the output.
|
||||
- **Glob Patterns**: switches exclude/discard syntax from regular expressions
|
||||
to shell-style globs. Pattern fields accept one entry per line.
|
||||
- **Lazy Load**: enables UEL low-memory loading so tensors are streamed by work
|
||||
unit and explicitly released.
|
||||
- **Force Clear Cache**: runs garbage collection and clears the CUDA allocator
|
||||
cache before each layer. This can reduce retained memory at a substantial
|
||||
speed cost.
|
||||
- **Override Dtype**: forces generated floating tensors to Save Dtype. Guarded
|
||||
low-bit tensors and enabled 1D direct differences are exempt.
|
||||
- **Include 1D Diffs** (LoRA nodes): enables CWB merging of recognized 1D
|
||||
direct-difference tensors in FP32. When disabled, shared tensors preserve
|
||||
Model A and secondary-only tensors preserve their earliest provider.
|
||||
|
||||
Scalars and 1D generic tensors use direct mean/median handling. Alignment,
|
||||
similarity weighting, alpha/beta, DSC, and norm rescaling apply to vector groups
|
||||
in tensors with at least two dimensions, not to those scalar/1D paths.
|
||||
|
||||
### Presets implemented by these nodes
|
||||
|
||||
All named file-merger presets use a neutral `global_scale` of 1.0. This is an
|
||||
intentional repository safety difference from the broad specification's 0.7
|
||||
calibration for some conditioning-oriented presets: persisted model and LoRA
|
||||
strength is not reduced unless the user explicitly changes Global Scale.
|
||||
|
||||
| Preset | Consensus | Alpha | Similarity cutoff | Beta | Norm rescale | DSC | Soft comfort | Alignment cutoff |
|
||||
| --- | --- | ---: | ---: | ---: | --- | --- | --- | --- |
|
||||
| `baseline` | median | 2.0 | 0.0 | 0.0 | no | no | no | manual value |
|
||||
| `power_blend` | median | 8.0 | 0.75 | 0.0 | yes | yes | no | 0.9 |
|
||||
| `high_clarity` | median | 3.0 | 0.3 | 0.0 | no | no | no | manual value |
|
||||
| `smooth` | mean | 1.5 | 0.0 | 0.0 | no | no | no | manual value |
|
||||
| `varied_merge` | median | 2.0 | 0.0 | 0.0 | yes | no | no | manual value |
|
||||
| `diverse_concept` | median | 2.0 | 0.0 | 1.0 | yes | no | no | manual value |
|
||||
| `high_diversity_concept` | median | 2.0 | 0.0 | 2.0 | yes | no | no | manual value |
|
||||
| `dsc_baseline` | median | 2.0 | 0.0 | 0.0 | no | yes | yes | manual value |
|
||||
| `dsc_high_clarity` | median | 4.0 | 0.3 | 0.0 | no | yes | yes | manual value |
|
||||
| `dsc_smooth` | mean | 1.0 | 0.0 | 0.0 | no | yes | yes | manual value |
|
||||
| `dsc_varied_merge` | median | 2.5 | 0.0 | 0.0 | yes | yes | yes | manual value |
|
||||
| `dsc_diverse_concept` | median | 2.0 | 0.0 | 1.5 | yes | yes | yes | manual value |
|
||||
| `dsc_high_diversity_concept` | median | 2.0 | 0.0 | 3.0 | yes | yes | yes | manual value |
|
||||
|
||||
## Missing tensors and filtering
|
||||
|
||||
- `skip` preserves Model A when an anchored input is missing or incompatible.
|
||||
|
||||
+155
-26
@@ -1324,35 +1324,163 @@ class ConsensusMergerLogic:
|
||||
def _common_inputs(model_type: str, input_count: int, default_filename: str):
|
||||
label = model_type
|
||||
inputs = [
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=folder_paths.get_filename_list(label)),
|
||||
io.Combo.Input("model_b", options=folder_paths.get_filename_list(label)),
|
||||
io.Combo.Input(
|
||||
"execution_mode",
|
||||
options=["MERGE", "DOCUMENTATION ONLY"],
|
||||
tooltip="MERGE writes a new safetensors file. DOCUMENTATION ONLY returns the CWB reference without loading or merging inputs.",
|
||||
),
|
||||
io.Combo.Input(
|
||||
"model_a",
|
||||
options=folder_paths.get_filename_list(label),
|
||||
tooltip="Primary contributor and preservation anchor. Supplies output metadata and anchors shared tensor names and shapes.",
|
||||
),
|
||||
io.Combo.Input(
|
||||
"model_b",
|
||||
options=folder_paths.get_filename_list(label),
|
||||
tooltip="Second equal-prior contributor. CWB derives its effective per-vector influence from consensus similarity.",
|
||||
),
|
||||
]
|
||||
if input_count == 3:
|
||||
inputs.append(io.Combo.Input("model_c", options=folder_paths.get_filename_list(label)))
|
||||
inputs.append(io.Combo.Input(
|
||||
"model_c",
|
||||
options=folder_paths.get_filename_list(label),
|
||||
tooltip="Third equal-prior contributor. CWB derives its effective per-vector influence from consensus similarity.",
|
||||
))
|
||||
inputs.extend([
|
||||
io.Combo.Input("cwb_preset", options=CWB_PRESET_OPTIONS, default="baseline"),
|
||||
io.Combo.Input("consensus_type", options=["mean", "median"], default="median"),
|
||||
io.Combo.Input("alignment_method", options=["index", "similarity"], default="similarity"),
|
||||
io.Float.Input("alignment_threshold", default=0.4, min=0.0, max=1.0, step=0.01),
|
||||
io.Float.Input("similarity_threshold", default=0.0, min=-1.0, max=1.0, step=0.01),
|
||||
io.Float.Input("power_alpha", default=2.0, min=0.0, max=10.0, step=0.1),
|
||||
io.Float.Input("diversity_beta", default=0.0, min=0.0, max=10.0, step=0.1),
|
||||
io.Boolean.Input("rescale_norm", default=False),
|
||||
io.Float.Input("global_scale", default=1.0, min=0.0, max=10.0, step=0.01),
|
||||
io.Boolean.Input("dynamic_similarity_contrast", default=False),
|
||||
io.Boolean.Input("soft_comfort_bandpass", default=False),
|
||||
io.Float.Input("position_weight", default=0.0, min=0.0, max=1.0, step=0.01),
|
||||
io.Boolean.Input("preserve_common_prefix", default=False),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.String.Input("output_filename", default=default_filename),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"]),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True),
|
||||
io.String.Input("discard_patterns", default="", multiline=True),
|
||||
io.Boolean.Input("glob_patterns", default=False),
|
||||
io.Boolean.Input("lazy_load", default=True),
|
||||
io.Boolean.Input("force_clear_cache", default=True),
|
||||
io.Combo.Input(
|
||||
"cwb_preset",
|
||||
options=CWB_PRESET_OPTIONS,
|
||||
default="baseline",
|
||||
tooltip="Select custom to use every manual CWB control. Named presets set their listed controls; position/prefix controls, most alignment thresholds, and any explicit non-1.0 global scale remain active.",
|
||||
),
|
||||
io.Combo.Input(
|
||||
"consensus_type",
|
||||
options=["mean", "median"],
|
||||
default="median",
|
||||
tooltip="Baseline vector used to score contributors. Median resists coordinate outliers; mean represents their arithmetic center. Manual value requires the custom preset.",
|
||||
),
|
||||
io.Combo.Input(
|
||||
"alignment_method",
|
||||
options=["index", "similarity"],
|
||||
default="similarity",
|
||||
tooltip="Pair rows by original index or greedy cosine similarity. Row reordering applies only to embeddings and LoRA rank components; ordinary model tensors keep fixed coordinates.",
|
||||
),
|
||||
io.Float.Input(
|
||||
"alignment_threshold",
|
||||
default=0.4,
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
step=0.01,
|
||||
tooltip="Minimum original cosine score for a greedy row match. Applies only to similarity-aligned embeddings and LoRA rank components; unmatched rows do not contribute.",
|
||||
),
|
||||
io.Float.Input(
|
||||
"similarity_threshold",
|
||||
default=0.0,
|
||||
min=-1.0,
|
||||
max=1.0,
|
||||
step=0.01,
|
||||
tooltip="Minimum cosine similarity to the mean/median consensus for a paired vector to receive weight. If every vector is rejected, CWB falls back to equal weights.",
|
||||
),
|
||||
io.Float.Input(
|
||||
"power_alpha",
|
||||
default=2.0,
|
||||
min=0.0,
|
||||
max=10.0,
|
||||
step=0.1,
|
||||
tooltip="Exponent applied to accepted non-negative consensus similarities. Higher values concentrate weight on vectors closest to consensus. Manual value requires the custom preset.",
|
||||
),
|
||||
io.Float.Input(
|
||||
"diversity_beta",
|
||||
default=0.0,
|
||||
min=0.0,
|
||||
max=10.0,
|
||||
step=0.1,
|
||||
tooltip="Bandpass exponent that suppresses near-consensus dominance to retain more variation. Zero disables diversity weighting. Manual value requires the custom preset.",
|
||||
),
|
||||
io.Boolean.Input(
|
||||
"rescale_norm",
|
||||
default=False,
|
||||
tooltip="Preserve vector energy after blending: keep the merged direction but set its L2 norm to the mean norm of participating vectors. Applied per row; for LoRA, separately per paired A row and B column.",
|
||||
),
|
||||
io.Float.Input(
|
||||
"global_scale",
|
||||
default=1.0,
|
||||
min=0.0,
|
||||
max=10.0,
|
||||
step=0.01,
|
||||
tooltip="Multiply the final merged contribution. For LoRA it is applied once through B/up, not to both factors. Named presets remain neutral unless this is explicitly set away from 1.0.",
|
||||
),
|
||||
io.Boolean.Input(
|
||||
"dynamic_similarity_contrast",
|
||||
default=False,
|
||||
tooltip="Remap unequal consensus similarities into 0.7-1.0 before alpha/beta weighting to increase relative separation. It does not change row-alignment scores.",
|
||||
),
|
||||
io.Boolean.Input(
|
||||
"soft_comfort_bandpass",
|
||||
default=False,
|
||||
tooltip="When diversity_beta is positive, broaden its distance term from 1.001-similarity to 1.5-similarity. Has no effect when diversity_beta is zero.",
|
||||
),
|
||||
io.Float.Input(
|
||||
"position_weight",
|
||||
default=0.0,
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
step=0.01,
|
||||
tooltip="Blend positional proximity into greedy row selection: 0 uses cosine only; 1 uses position affinity only. Relevant only to similarity-aligned embeddings and LoRA rank components.",
|
||||
),
|
||||
io.Boolean.Input(
|
||||
"preserve_common_prefix",
|
||||
default=False,
|
||||
tooltip="Copy the longest numerically identical leading first-axis span from Model A before CWB. The current merger applies this to all tensors with at least two dimensions.",
|
||||
),
|
||||
io.Combo.Input(
|
||||
"mismatch_mode",
|
||||
options=["skip", "zeros", "error"],
|
||||
default="skip",
|
||||
tooltip="For missing or incompatible anchored inputs: skip preserves the anchor, zeros inserts a zero contribution where possible, and error aborts. A lone secondary-only tensor is copied unchanged.",
|
||||
),
|
||||
io.String.Input(
|
||||
"output_filename",
|
||||
default=default_filename,
|
||||
tooltip="Filename without extension. The result is atomically written to this model category under ComfyUI's models directory.",
|
||||
),
|
||||
io.Combo.Input(
|
||||
"save_dtype",
|
||||
options=["fp32", "fp16", "bf16"],
|
||||
tooltip="Requested dtype for generated floating tensors. Participating FP32 inputs keep a result FP32 unless Override Dtype is enabled.",
|
||||
),
|
||||
io.Combo.Input(
|
||||
"process_device",
|
||||
options=["cuda", "cpu"],
|
||||
tooltip="Device used for per-layer FP32 CWB arithmetic. A CUDA out-of-memory error retries only the affected layer on CPU.",
|
||||
),
|
||||
io.String.Input(
|
||||
"exclude_patterns",
|
||||
default="",
|
||||
multiline=True,
|
||||
tooltip="One pattern per line. Matching layers are preserved from the anchor instead of merged. Uses regex unless Glob Patterns is enabled.",
|
||||
),
|
||||
io.String.Input(
|
||||
"discard_patterns",
|
||||
default="",
|
||||
multiline=True,
|
||||
tooltip="One pattern per line. Matching tensors or logical LoRA groups are omitted from the output. Uses regex unless Glob Patterns is enabled.",
|
||||
),
|
||||
io.Boolean.Input(
|
||||
"glob_patterns",
|
||||
default=False,
|
||||
tooltip="Interpret exclude and discard entries as shell-style glob patterns instead of regular expressions.",
|
||||
),
|
||||
io.Boolean.Input(
|
||||
"lazy_load",
|
||||
default=True,
|
||||
tooltip="Use UEL low-memory loading so tensors are read and released per work unit instead of retaining the complete inputs in RAM.",
|
||||
),
|
||||
io.Boolean.Input(
|
||||
"force_clear_cache",
|
||||
default=True,
|
||||
tooltip="Run Python garbage collection and clear the CUDA allocator cache before each layer. Reduces retained memory but can substantially slow merging.",
|
||||
),
|
||||
io.Boolean.Input(
|
||||
"override_dtype",
|
||||
default=False,
|
||||
@@ -1384,6 +1512,7 @@ class _CWBMergerNode(io.ComfyNode):
|
||||
node_id=cls.NODE_ID,
|
||||
display_name=cls.DISPLAY_NAME,
|
||||
category="ModelUtils/Merging",
|
||||
description="Merge two or three safetensors files with Consensus-Weighted Blending. Use each input tooltip or Documentation Only for exact control scope.",
|
||||
inputs=inputs,
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_filename"),
|
||||
|
||||
@@ -752,10 +752,10 @@ def _get_common_inputs():
|
||||
tooltip="Clamp outlier singular values"),
|
||||
io.Float.Input("min_diff", default=0.0, min=0.0, max=1.0, step=0.001,
|
||||
tooltip="Skip layers with max difference below this"),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.String.Input("output_filename", default="extracted_lora"),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16"),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda"),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible model tensors by skipping them, substituting zeros where supported, or aborting."),
|
||||
io.String.Input("output_filename", default="extracted_lora", tooltip="Output filename without extension, written under ComfyUI's LoRA directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16", tooltip="Data type used to save the extracted DoRA tensors."),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda", tooltip="Device used for extraction arithmetic; CUDA out-of-memory processing falls back per affected layer where supported."),
|
||||
io.String.Input("skip_patterns", default="", multiline=True,
|
||||
tooltip="Patterns for layers to skip (regex or glob depending on glob_skip_patterns)"),
|
||||
io.Boolean.Input("glob_skip_patterns", default=False,
|
||||
|
||||
+15
-15
@@ -632,10 +632,10 @@ class DoRALearnedExtractRatio(io.ComfyNode):
|
||||
is_experimental=True,
|
||||
inputs=[
|
||||
*_get_model_inputs(),
|
||||
io.Float.Input("linear_ratio", default=2.0, min=1.0, max=100.0, step=0.1),
|
||||
io.Float.Input("conv_ratio", default=2.0, min=1.0, max=100.0, step=0.1),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Float.Input("linear_ratio", default=2.0, min=1.0, max=100.0, step=0.1, tooltip="Ratio threshold for linear layers; higher values retain more singular values."),
|
||||
io.Float.Input("conv_ratio", default=2.0, min=1.0, max=100.0, step=0.1, tooltip="Ratio threshold for convolution layers; higher values retain more singular values."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_learned_inputs(),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
@@ -675,10 +675,10 @@ class DoRALearnedExtractQuantile(io.ComfyNode):
|
||||
is_experimental=True,
|
||||
inputs=[
|
||||
*_get_model_inputs(),
|
||||
io.Float.Input("linear_quantile", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Float.Input("conv_quantile", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Float.Input("linear_quantile", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target cumulative singular-value fraction for linear layers."),
|
||||
io.Float.Input("conv_quantile", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target cumulative singular-value fraction for convolution layers."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_learned_inputs(),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
@@ -718,9 +718,9 @@ class DoRALearnedExtractKnee(io.ComfyNode):
|
||||
is_experimental=True,
|
||||
inputs=[
|
||||
*_get_model_inputs(),
|
||||
io.Combo.Input("knee_method", options=["sv_knee", "sv_cumulative_knee"], default="sv_knee"),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Combo.Input("knee_method", options=["sv_knee", "sv_cumulative_knee"], default="sv_knee", tooltip="Detect the knee from raw singular values or their cumulative distribution."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_learned_inputs(),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
@@ -760,10 +760,10 @@ class DoRALearnedExtractFrobenius(io.ComfyNode):
|
||||
is_experimental=True,
|
||||
inputs=[
|
||||
*_get_model_inputs(),
|
||||
io.Float.Input("linear_target", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Float.Input("conv_target", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Float.Input("linear_target", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target Frobenius-norm fraction retained for linear layers."),
|
||||
io.Float.Input("conv_target", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target Frobenius-norm fraction retained for convolution layers."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_learned_inputs(),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
|
||||
@@ -89,7 +89,7 @@ class CheckpointInfoMetaDownloader(BaseInfoMetaDownloaderNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
inputs = list(cls.get_common_inputs().values())
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("checkpoints"), default="/"))
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("checkpoints"), default="/", tooltip="Checkpoint subdirectory to scan; Recursive also includes its descendants."))
|
||||
return io.Schema(
|
||||
node_id=cls.__name__,
|
||||
display_name="Checkpoint Downloader",
|
||||
@@ -126,7 +126,7 @@ class DiffusionModelInfoMetaDownloader(BaseInfoMetaDownloaderNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
inputs = list(cls.get_common_inputs().values())
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("diffusion_models"), default="/"))
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("diffusion_models"), default="/", tooltip="Diffusion-model subdirectory to scan; Recursive also includes its descendants."))
|
||||
return io.Schema(
|
||||
node_id=cls.__name__,
|
||||
display_name="Diffusion Model Downloader",
|
||||
@@ -163,7 +163,7 @@ class LoRAInfoMetaDownloader(BaseInfoMetaDownloaderNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
inputs = list(cls.get_common_inputs().values())
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("loras"), default="/"))
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("loras"), default="/", tooltip="LoRA subdirectory to scan; Recursive also includes its descendants."))
|
||||
return io.Schema(
|
||||
node_id=cls.__name__,
|
||||
display_name="LoRA Downloader",
|
||||
@@ -200,7 +200,7 @@ class EmbeddingInfoMetaDownloader(BaseInfoMetaDownloaderNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
inputs = list(cls.get_common_inputs().values())
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("embeddings"), default="/"))
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("embeddings"), default="/", tooltip="Embedding subdirectory to scan; Recursive also includes its descendants."))
|
||||
return io.Schema(
|
||||
node_id=cls.__name__,
|
||||
display_name="Embedding Downloader",
|
||||
@@ -237,7 +237,7 @@ class VAEInfoMetaDownloader(BaseInfoMetaDownloaderNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
inputs = list(cls.get_common_inputs().values())
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("vae"), default="/"))
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("vae"), default="/", tooltip="VAE subdirectory to scan; Recursive also includes its descendants."))
|
||||
return io.Schema(
|
||||
node_id=cls.__name__,
|
||||
display_name="VAE Downloader",
|
||||
@@ -274,7 +274,7 @@ class ControlNetInfoMetaDownloader(BaseInfoMetaDownloaderNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
inputs = list(cls.get_common_inputs().values())
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("controlnet"), default="/"))
|
||||
inputs.insert(0, io.Combo.Input("subdirectory", options=get_subdirectories("controlnet"), default="/", tooltip="ControlNet subdirectory to scan; Recursive also includes its descendants."))
|
||||
return io.Schema(
|
||||
node_id=cls.__name__,
|
||||
display_name="ControlNet Downloader",
|
||||
@@ -311,7 +311,7 @@ class ManualPathInfoMetaDownloader(BaseInfoMetaDownloaderNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
inputs = list(cls.get_common_inputs().values())
|
||||
inputs.append(io.String.Input("scan_dir", default=""))
|
||||
inputs.append(io.String.Input("scan_dir", default="", tooltip="Absolute directory to scan for supported model files."))
|
||||
return io.Schema(
|
||||
node_id=cls.__name__,
|
||||
display_name="Manual Path Downloader",
|
||||
|
||||
@@ -755,11 +755,11 @@ def _get_common_inputs():
|
||||
tooltip="Clamp outlier singular values"),
|
||||
io.Float.Input("min_diff", default=0.0, min=0.0, max=1.0, step=0.001,
|
||||
tooltip="Skip layers with max difference below this"),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.String.Input("output_filename", default="extracted_lora"),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible model tensors by skipping them, substituting zeros where supported, or aborting."),
|
||||
io.String.Input("output_filename", default="extracted_lora", tooltip="Output filename without extension, written under ComfyUI's LoRA directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16",
|
||||
tooltip="Output dtype; layers stored as FP32 in either source remain FP32"),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda"),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda", tooltip="Device used for extraction arithmetic; CUDA out-of-memory processing falls back per affected layer where supported."),
|
||||
io.String.Input("skip_patterns", default="", multiline=True,
|
||||
tooltip="Patterns for layers to skip (regex or glob depending on glob_skip_patterns)"),
|
||||
io.Boolean.Input("glob_skip_patterns", default=False,
|
||||
|
||||
@@ -104,8 +104,9 @@ class AnimaLoraRename(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"lora_name",
|
||||
options=folder_paths.get_filename_list("loras"),
|
||||
tooltip="Diffusers-format Anima LoRA whose tensor keys will be renamed.",
|
||||
),
|
||||
io.String.Input("output_filename", default="anima_lora_non_diffusers"),
|
||||
io.String.Input("output_filename", default="anima_lora_non_diffusers", tooltip="Output filename without extension, written under ComfyUI's LoRA directory."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_path"),
|
||||
|
||||
+15
-15
@@ -920,9 +920,9 @@ class LoRAResizeFixed(io.ComfyNode):
|
||||
tooltip="LoRA to resize"),
|
||||
io.Int.Input("new_rank", default=64, min=1, max=3072,
|
||||
tooltip="Target rank"),
|
||||
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.String.Input("output_filename", default="resized_lora", tooltip="Output filename without extension, written under ComfyUI's LoRA directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16", tooltip="Data type used to save resized LoRA tensors."),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda", tooltip="Device used for per-layer resize arithmetic; CUDA out-of-memory retries the affected layer on CPU."),
|
||||
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")],
|
||||
@@ -958,9 +958,9 @@ class LoRAResizeRatio(io.ComfyNode):
|
||||
tooltip="Maximum allowed rank"),
|
||||
io.Float.Input("ratio", default=2.0, min=1.0, max=100.0, step=0.1,
|
||||
tooltip="Keep SVs where S[i] > S[0]/ratio"),
|
||||
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.String.Input("output_filename", default="resized_lora_ratio", tooltip="Output filename without extension, written under ComfyUI's LoRA directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16", tooltip="Data type used to save resized LoRA tensors."),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda", tooltip="Device used for per-layer resize arithmetic; CUDA out-of-memory retries the affected layer on CPU."),
|
||||
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")],
|
||||
@@ -998,9 +998,9 @@ class LoRAResizeFrobenius(io.ComfyNode):
|
||||
tooltip="Minimum retained rank when layer dimensions permit"),
|
||||
io.Float.Input("target", default=0.9, min=0.1, max=1.0, step=0.01,
|
||||
tooltip="Target Frobenius norm retention (0.9 = 90%)"),
|
||||
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.String.Input("output_filename", default="resized_lora_fro", tooltip="Output filename without extension, written under ComfyUI's LoRA directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16", tooltip="Data type used to save resized LoRA tensors."),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda", tooltip="Device used for per-layer resize arithmetic; CUDA out-of-memory retries the affected layer on CPU."),
|
||||
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")],
|
||||
@@ -1037,9 +1037,9 @@ class LoRAResizeCumulative(io.ComfyNode):
|
||||
tooltip="Maximum allowed rank"),
|
||||
io.Float.Input("target", default=0.9, min=0.1, max=1.0, step=0.01,
|
||||
tooltip="Target cumulative SV retention (0.9 = 90%)"),
|
||||
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.String.Input("output_filename", default="resized_lora_cumulative", tooltip="Output filename without extension, written under ComfyUI's LoRA directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16", tooltip="Data type used to save resized LoRA tensors."),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda", tooltip="Device used for per-layer resize arithmetic; CUDA out-of-memory retries the affected layer on CPU."),
|
||||
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")],
|
||||
@@ -1842,9 +1842,9 @@ class LoRAMergeToModel(io.ComfyNode):
|
||||
# Settings
|
||||
io.String.Input("skip_patterns", default="", multiline=True,
|
||||
tooltip="Regex patterns for layers to skip"),
|
||||
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.String.Input("output_filename", default="merged_model", tooltip="Output filename without extension, written under ComfyUI's diffusion-model directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16", tooltip="Data type used to save the model after applying the LoRA."),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda", tooltip="Device used for per-layer LoRA application; CUDA out-of-memory retries the affected layer on CPU."),
|
||||
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)"),
|
||||
io.Boolean.Input("include_1d_diffs", default=False,
|
||||
|
||||
+185
-185
@@ -357,24 +357,24 @@ class CheckpointTwoMerger(io.ComfyNode):
|
||||
display_name="Merge Checkpoints (2 Models)",
|
||||
category="ModelUtils/Merging",
|
||||
inputs=[
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("checkpoints")),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("checkpoints")),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in TWO_MODEL_MODES]),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop"),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
|
||||
io.String.Input("output_filename", default="merged_2_checkpoint"),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"]),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True),
|
||||
io.String.Input("discard_patterns", default="", multiline=True),
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"], tooltip="MERGE writes the selected result; DOCUMENTATION ONLY returns the operation reference without loading model files."),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("checkpoints"), tooltip="Primary checkpoint; anchors metadata, tensor shapes, and values preserved by exclusions or skip handling."),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("checkpoints"), tooltip="Second checkpoint contributing to the selected calculation mode."),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in TWO_MODEL_MODES], tooltip="Two-model operation to apply per comparable tensor; DOCUMENTATION ONLY shows its formula and coefficient meanings."),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible tensors: preserve Model A, substitute zeros where supported, or abort with an error."),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop", tooltip="Resolve compatible shape differences by zero-padding/cropping or by interpolating Model B and Model C to Model A shape."),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; use DOCUMENTATION ONLY for its exact role in the selected calculation mode."),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff, tooltip="Random seed used only by calculation modes with stochastic behavior."),
|
||||
io.String.Input("output_filename", default="merged_2_checkpoint", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"], tooltip="Output tensor dtype; when Override Dtype is disabled, source tensors with higher precision remain at that precision."),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"], tooltip="Device used for per-tensor merge arithmetic; CUDA out-of-memory retries the affected tensor on CPU."),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors excluded from merging and preserved from Model A."),
|
||||
io.String.Input("discard_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors omitted entirely from the output."),
|
||||
io.Boolean.Input("glob_patterns", default=False,
|
||||
tooltip="When True, exclude/discard patterns use glob syntax (* = any sequence, dots are literal). "
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
@@ -423,24 +423,24 @@ class ModelTwoMerger(io.ComfyNode):
|
||||
display_name="Merge Models (2 Models)",
|
||||
category="ModelUtils/Merging",
|
||||
inputs=[
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("diffusion_models")),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("diffusion_models")),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in TWO_MODEL_MODES]),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop"),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
|
||||
io.String.Input("output_filename", default="merged_2_model"),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"]),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True),
|
||||
io.String.Input("discard_patterns", default="", multiline=True),
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"], tooltip="MERGE writes the selected result; DOCUMENTATION ONLY returns the operation reference without loading model files."),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("diffusion_models"), tooltip="Primary diffusion model; anchors metadata, tensor shapes, and values preserved by exclusions or skip handling."),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("diffusion_models"), tooltip="Second diffusion model contributing to the selected calculation mode."),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in TWO_MODEL_MODES], tooltip="Two-model operation to apply per comparable tensor; DOCUMENTATION ONLY shows its formula and coefficient meanings."),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible tensors: preserve Model A, substitute zeros where supported, or abort with an error."),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop", tooltip="Resolve compatible shape differences by zero-padding/cropping or by interpolating Model B and Model C to Model A shape."),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; use DOCUMENTATION ONLY for its exact role in the selected calculation mode."),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff, tooltip="Random seed used only by calculation modes with stochastic behavior."),
|
||||
io.String.Input("output_filename", default="merged_2_model", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"], tooltip="Output tensor dtype; when Override Dtype is disabled, source tensors with higher precision remain at that precision."),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"], tooltip="Device used for per-tensor merge arithmetic; CUDA out-of-memory retries the affected tensor on CPU."),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors excluded from merging and preserved from Model A."),
|
||||
io.String.Input("discard_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors omitted entirely from the output."),
|
||||
io.Boolean.Input("glob_patterns", default=False,
|
||||
tooltip="When True, exclude/discard patterns use glob syntax (* = any sequence, dots are literal). "
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
@@ -489,24 +489,24 @@ class TextEncoderTwoMerger(io.ComfyNode):
|
||||
display_name="Merge Text Encoders (2 Models)",
|
||||
category="ModelUtils/Merging",
|
||||
inputs=[
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("text_encoders")),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("text_encoders")),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in TWO_MODEL_MODES]),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop"),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
|
||||
io.String.Input("output_filename", default="merged_2_textencoder"),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"]),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True),
|
||||
io.String.Input("discard_patterns", default="", multiline=True),
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"], tooltip="MERGE writes the selected result; DOCUMENTATION ONLY returns the operation reference without loading model files."),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("text_encoders"), tooltip="Primary text encoder; anchors metadata, tensor shapes, and values preserved by exclusions or skip handling."),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("text_encoders"), tooltip="Second text encoder contributing to the selected calculation mode."),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in TWO_MODEL_MODES], tooltip="Two-model operation to apply per comparable tensor; DOCUMENTATION ONLY shows its formula and coefficient meanings."),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible tensors: preserve Model A, substitute zeros where supported, or abort with an error."),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop", tooltip="Resolve compatible shape differences by zero-padding/cropping or by interpolating Model B and Model C to Model A shape."),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; use DOCUMENTATION ONLY for its exact role in the selected calculation mode."),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff, tooltip="Random seed used only by calculation modes with stochastic behavior."),
|
||||
io.String.Input("output_filename", default="merged_2_textencoder", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"], tooltip="Output tensor dtype; when Override Dtype is disabled, source tensors with higher precision remain at that precision."),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"], tooltip="Device used for per-tensor merge arithmetic; CUDA out-of-memory retries the affected tensor on CPU."),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors excluded from merging and preserved from Model A."),
|
||||
io.String.Input("discard_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors omitted entirely from the output."),
|
||||
io.Boolean.Input("glob_patterns", default=False,
|
||||
tooltip="When True, exclude/discard patterns use glob syntax (* = any sequence, dots are literal). "
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
@@ -555,24 +555,24 @@ class LoRATwoMerger(io.ComfyNode):
|
||||
display_name="Merge LoRAs (2 Models)",
|
||||
category="ModelUtils/Merging",
|
||||
inputs=[
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("loras")),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("loras")),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in TWO_MODEL_MODES]),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop"),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
|
||||
io.String.Input("output_filename", default="merged_2_lora"),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"]),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True),
|
||||
io.String.Input("discard_patterns", default="", multiline=True),
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"], tooltip="MERGE writes the selected result; DOCUMENTATION ONLY returns the operation reference without loading model files."),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("loras"), tooltip="Primary LoRA; anchors metadata, tensor shapes, and values preserved by exclusions or skip handling."),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("loras"), tooltip="Second LoRA contributing to the selected calculation mode."),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in TWO_MODEL_MODES], tooltip="Two-model operation to apply per comparable tensor; DOCUMENTATION ONLY shows its formula and coefficient meanings."),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible tensors: preserve Model A, substitute zeros where supported, or abort with an error."),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop", tooltip="Resolve compatible shape differences by zero-padding/cropping or by interpolating Model B and Model C to Model A shape."),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; use DOCUMENTATION ONLY for its exact role in the selected calculation mode."),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff, tooltip="Random seed used only by calculation modes with stochastic behavior."),
|
||||
io.String.Input("output_filename", default="merged_2_lora", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"], tooltip="Output tensor dtype; when Override Dtype is disabled, source tensors with higher precision remain at that precision."),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"], tooltip="Device used for per-tensor merge arithmetic; CUDA out-of-memory retries the affected tensor on CPU."),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors excluded from merging and preserved from Model A."),
|
||||
io.String.Input("discard_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors omitted entirely from the output."),
|
||||
io.Boolean.Input("glob_patterns", default=False,
|
||||
tooltip="When True, exclude/discard patterns use glob syntax (* = any sequence, dots are literal). "
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
@@ -625,24 +625,24 @@ class EmbeddingTwoMerger(io.ComfyNode):
|
||||
display_name="Merge Embeddings (2 Models)",
|
||||
category="ModelUtils/Merging",
|
||||
inputs=[
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("embeddings")),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("embeddings")),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in TWO_MODEL_MODES]),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop"),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
|
||||
io.String.Input("output_filename", default="merged_2_embedding"),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"]),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True),
|
||||
io.String.Input("discard_patterns", default="", multiline=True),
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"], tooltip="MERGE writes the selected result; DOCUMENTATION ONLY returns the operation reference without loading model files."),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("embeddings"), tooltip="Primary embedding; anchors metadata, tensor shapes, and values preserved by exclusions or skip handling."),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("embeddings"), tooltip="Second embedding contributing to the selected calculation mode."),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in TWO_MODEL_MODES], tooltip="Two-model operation to apply per comparable tensor; DOCUMENTATION ONLY shows its formula and coefficient meanings."),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible tensors: preserve Model A, substitute zeros where supported, or abort with an error."),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop", tooltip="Resolve compatible shape differences by zero-padding/cropping or by interpolating Model B and Model C to Model A shape."),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; use DOCUMENTATION ONLY for its exact role in the selected calculation mode."),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff, tooltip="Random seed used only by calculation modes with stochastic behavior."),
|
||||
io.String.Input("output_filename", default="merged_2_embedding", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"], tooltip="Output tensor dtype; when Override Dtype is disabled, source tensors with higher precision remain at that precision."),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"], tooltip="Device used for per-tensor merge arithmetic; CUDA out-of-memory retries the affected tensor on CPU."),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors excluded from merging and preserved from Model A."),
|
||||
io.String.Input("discard_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors omitted entirely from the output."),
|
||||
io.Boolean.Input("glob_patterns", default=False,
|
||||
tooltip="When True, exclude/discard patterns use glob syntax (* = any sequence, dots are literal). "
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
@@ -693,25 +693,25 @@ class CheckpointThreeMerger(io.ComfyNode):
|
||||
display_name="Merge Checkpoints (3 Models)",
|
||||
category="ModelUtils/Merging",
|
||||
inputs=[
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("checkpoints")),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("checkpoints")),
|
||||
io.Combo.Input("model_c", options=["None"] + folder_paths.get_filename_list("checkpoints")),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in THREE_MODEL_MODES]),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop"),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("gamma", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
|
||||
io.String.Input("output_filename", default="merged_3_checkpoint"),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"]),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True),
|
||||
io.String.Input("discard_patterns", default="", multiline=True),
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"], tooltip="MERGE writes the selected result; DOCUMENTATION ONLY returns the operation reference without loading model files."),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("checkpoints"), tooltip="Primary checkpoint; anchors metadata, tensor shapes, and values preserved by exclusions or skip handling."),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("checkpoints"), tooltip="Second checkpoint contributing to the selected calculation mode."),
|
||||
io.Combo.Input("model_c", options=["None"] + folder_paths.get_filename_list("checkpoints"), tooltip="Third checkpoint contributing to the selected three-model calculation mode."),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in THREE_MODEL_MODES], tooltip="Three-model operation to apply per comparable tensor; DOCUMENTATION ONLY shows its formula and coefficient meanings."),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible tensors: preserve Model A, substitute zeros where supported, or abort with an error."),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop", tooltip="Resolve compatible shape differences by zero-padding/cropping or by interpolating Model B and Model C to Model A shape."),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; use DOCUMENTATION ONLY for its exact role in the selected calculation mode."),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("gamma", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff, tooltip="Random seed used only by calculation modes with stochastic behavior."),
|
||||
io.String.Input("output_filename", default="merged_3_checkpoint", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"], tooltip="Output tensor dtype; when Override Dtype is disabled, source tensors with higher precision remain at that precision."),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"], tooltip="Device used for per-tensor merge arithmetic; CUDA out-of-memory retries the affected tensor on CPU."),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors excluded from merging and preserved from Model A."),
|
||||
io.String.Input("discard_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors omitted entirely from the output."),
|
||||
io.Boolean.Input("glob_patterns", default=False,
|
||||
tooltip="When True, exclude/discard patterns use glob syntax (* = any sequence, dots are literal). "
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
@@ -760,25 +760,25 @@ class ModelThreeMerger(io.ComfyNode):
|
||||
display_name="Merge Models (3 Models)",
|
||||
category="ModelUtils/Merging",
|
||||
inputs=[
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("diffusion_models")),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("diffusion_models")),
|
||||
io.Combo.Input("model_c", options=["None"] + folder_paths.get_filename_list("diffusion_models")),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in THREE_MODEL_MODES]),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop"),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("gamma", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
|
||||
io.String.Input("output_filename", default="merged_3_model"),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"]),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True),
|
||||
io.String.Input("discard_patterns", default="", multiline=True),
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"], tooltip="MERGE writes the selected result; DOCUMENTATION ONLY returns the operation reference without loading model files."),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("diffusion_models"), tooltip="Primary diffusion model; anchors metadata, tensor shapes, and values preserved by exclusions or skip handling."),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("diffusion_models"), tooltip="Second diffusion model contributing to the selected calculation mode."),
|
||||
io.Combo.Input("model_c", options=["None"] + folder_paths.get_filename_list("diffusion_models"), tooltip="Third diffusion model contributing to the selected three-model calculation mode."),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in THREE_MODEL_MODES], tooltip="Three-model operation to apply per comparable tensor; DOCUMENTATION ONLY shows its formula and coefficient meanings."),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible tensors: preserve Model A, substitute zeros where supported, or abort with an error."),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop", tooltip="Resolve compatible shape differences by zero-padding/cropping or by interpolating Model B and Model C to Model A shape."),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; use DOCUMENTATION ONLY for its exact role in the selected calculation mode."),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("gamma", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff, tooltip="Random seed used only by calculation modes with stochastic behavior."),
|
||||
io.String.Input("output_filename", default="merged_3_model", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"], tooltip="Output tensor dtype; when Override Dtype is disabled, source tensors with higher precision remain at that precision."),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"], tooltip="Device used for per-tensor merge arithmetic; CUDA out-of-memory retries the affected tensor on CPU."),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors excluded from merging and preserved from Model A."),
|
||||
io.String.Input("discard_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors omitted entirely from the output."),
|
||||
io.Boolean.Input("glob_patterns", default=False,
|
||||
tooltip="When True, exclude/discard patterns use glob syntax (* = any sequence, dots are literal). "
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
@@ -827,25 +827,25 @@ class TextEncoderThreeMerger(io.ComfyNode):
|
||||
display_name="Merge Text Encoders (3 Models)",
|
||||
category="ModelUtils/Merging",
|
||||
inputs=[
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("text_encoders")),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("text_encoders")),
|
||||
io.Combo.Input("model_c", options=["None"] + folder_paths.get_filename_list("text_encoders")),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in THREE_MODEL_MODES]),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop"),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
|
||||
io.String.Input("output_filename", default="merged_3_textencoder"),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"]),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True),
|
||||
io.String.Input("discard_patterns", default="", multiline=True),
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"], tooltip="MERGE writes the selected result; DOCUMENTATION ONLY returns the operation reference without loading model files."),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("text_encoders"), tooltip="Primary text encoder; anchors metadata, tensor shapes, and values preserved by exclusions or skip handling."),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("text_encoders"), tooltip="Second text encoder contributing to the selected calculation mode."),
|
||||
io.Combo.Input("model_c", options=["None"] + folder_paths.get_filename_list("text_encoders"), tooltip="Third text encoder contributing to the selected three-model calculation mode."),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in THREE_MODEL_MODES], tooltip="Three-model operation to apply per comparable tensor; DOCUMENTATION ONLY shows its formula and coefficient meanings."),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible tensors: preserve Model A, substitute zeros where supported, or abort with an error."),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop", tooltip="Resolve compatible shape differences by zero-padding/cropping or by interpolating Model B and Model C to Model A shape."),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; use DOCUMENTATION ONLY for its exact role in the selected calculation mode."),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("gamma", default=0.99, min=-10.0, max=10.0, step=0.001, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff, tooltip="Random seed used only by calculation modes with stochastic behavior."),
|
||||
io.String.Input("output_filename", default="merged_3_textencoder", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"], tooltip="Output tensor dtype; when Override Dtype is disabled, source tensors with higher precision remain at that precision."),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"], tooltip="Device used for per-tensor merge arithmetic; CUDA out-of-memory retries the affected tensor on CPU."),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors excluded from merging and preserved from Model A."),
|
||||
io.String.Input("discard_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors omitted entirely from the output."),
|
||||
io.Boolean.Input("glob_patterns", default=False,
|
||||
tooltip="When True, exclude/discard patterns use glob syntax (* = any sequence, dots are literal). "
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
@@ -894,25 +894,25 @@ class LoRAThreeMerger(io.ComfyNode):
|
||||
display_name="Merge LoRAs (3 Models)",
|
||||
category="ModelUtils/Merging",
|
||||
inputs=[
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("loras")),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("loras")),
|
||||
io.Combo.Input("model_c", options=["None"] + folder_paths.get_filename_list("loras")),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in THREE_MODEL_MODES]),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop"),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("gamma", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
|
||||
io.String.Input("output_filename", default="merged_3_lora"),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"]),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True),
|
||||
io.String.Input("discard_patterns", default="", multiline=True),
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"], tooltip="MERGE writes the selected result; DOCUMENTATION ONLY returns the operation reference without loading model files."),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("loras"), tooltip="Primary LoRA; anchors metadata, tensor shapes, and values preserved by exclusions or skip handling."),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("loras"), tooltip="Second LoRA contributing to the selected calculation mode."),
|
||||
io.Combo.Input("model_c", options=["None"] + folder_paths.get_filename_list("loras"), tooltip="Third LoRA contributing to the selected three-model calculation mode."),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in THREE_MODEL_MODES], tooltip="Three-model operation to apply per comparable tensor; DOCUMENTATION ONLY shows its formula and coefficient meanings."),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible tensors: preserve Model A, substitute zeros where supported, or abort with an error."),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop", tooltip="Resolve compatible shape differences by zero-padding/cropping or by interpolating Model B and Model C to Model A shape."),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; use DOCUMENTATION ONLY for its exact role in the selected calculation mode."),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("gamma", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff, tooltip="Random seed used only by calculation modes with stochastic behavior."),
|
||||
io.String.Input("output_filename", default="merged_3_lora", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"], tooltip="Output tensor dtype; when Override Dtype is disabled, source tensors with higher precision remain at that precision."),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"], tooltip="Device used for per-tensor merge arithmetic; CUDA out-of-memory retries the affected tensor on CPU."),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors excluded from merging and preserved from Model A."),
|
||||
io.String.Input("discard_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors omitted entirely from the output."),
|
||||
io.Boolean.Input("glob_patterns", default=False,
|
||||
tooltip="When True, exclude/discard patterns use glob syntax (* = any sequence, dots are literal). "
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
@@ -965,25 +965,25 @@ class EmbeddingThreeMerger(io.ComfyNode):
|
||||
display_name="Merge Embeddings (3 Models)",
|
||||
category="ModelUtils/Merging",
|
||||
inputs=[
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("embeddings")),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("embeddings")),
|
||||
io.Combo.Input("model_c", options=["None"] + folder_paths.get_filename_list("embeddings")),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in THREE_MODEL_MODES]),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop"),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("gamma", default=0.5, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff),
|
||||
io.String.Input("output_filename", default="merged_3_embedding"),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"]),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True),
|
||||
io.String.Input("discard_patterns", default="", multiline=True),
|
||||
io.Combo.Input("execution_mode", options=["MERGE", "DOCUMENTATION ONLY"], tooltip="MERGE writes the selected result; DOCUMENTATION ONLY returns the operation reference without loading model files."),
|
||||
io.Combo.Input("model_a", options=["None"] + folder_paths.get_filename_list("embeddings"), tooltip="Primary embedding; anchors metadata, tensor shapes, and values preserved by exclusions or skip handling."),
|
||||
io.Combo.Input("model_b", options=["None"] + folder_paths.get_filename_list("embeddings"), tooltip="Second embedding contributing to the selected calculation mode."),
|
||||
io.Combo.Input("model_c", options=["None"] + folder_paths.get_filename_list("embeddings"), tooltip="Third embedding contributing to the selected three-model calculation mode."),
|
||||
io.Combo.Input("calc_mode", options=[m.name for m in THREE_MODEL_MODES], tooltip="Three-model operation to apply per comparable tensor; DOCUMENTATION ONLY shows its formula and coefficient meanings."),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible tensors: preserve Model A, substitute zeros where supported, or abort with an error."),
|
||||
io.Combo.Input("alignment_mode", options=["pad/crop", "interpolate"], default="pad/crop", tooltip="Resolve compatible shape differences by zero-padding/cropping or by interpolating Model B and Model C to Model A shape."),
|
||||
io.Float.Input("alpha", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; use DOCUMENTATION ONLY for its exact role in the selected calculation mode."),
|
||||
io.Float.Input("beta", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("gamma", default=0.5, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("delta", default=2.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("epsilon", default=0.01, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Float.Input("zeta", default=0.0, min=-10.0, max=10.0, step=0.01, tooltip="Mode-specific coefficient; some calculation modes ignore it. See DOCUMENTATION ONLY for the selected formula."),
|
||||
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff, tooltip="Random seed used only by calculation modes with stochastic behavior."),
|
||||
io.String.Input("output_filename", default="merged_3_embedding", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp32", "fp16", "bf16"], tooltip="Output tensor dtype; when Override Dtype is disabled, source tensors with higher precision remain at that precision."),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"], tooltip="Device used for per-tensor merge arithmetic; CUDA out-of-memory retries the affected tensor on CPU."),
|
||||
io.String.Input("exclude_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors excluded from merging and preserved from Model A."),
|
||||
io.String.Input("discard_patterns", default="", multiline=True, tooltip="Newline-separated regex or glob patterns for tensors omitted entirely from the output."),
|
||||
io.Boolean.Input("glob_patterns", default=False,
|
||||
tooltip="When True, exclude/discard patterns use glob syntax (* = any sequence, dots are literal). "
|
||||
"When False (default), patterns are Python regex matched as substrings."),
|
||||
|
||||
@@ -56,6 +56,7 @@ class ModelMetaKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"diffusionmodel_name",
|
||||
options=folder_paths.get_filename_list("diffusion_models"),
|
||||
tooltip="Diffusion model whose safetensors metadata and tensor keys will be listed.",
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
@@ -82,6 +83,7 @@ class TextEncoderMetaKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"textencoder_name",
|
||||
options=folder_paths.get_filename_list("text_encoders"),
|
||||
tooltip="Text encoder whose safetensors metadata and tensor keys will be listed.",
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
@@ -108,6 +110,7 @@ class LoRAMetaKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"lora_name",
|
||||
options=folder_paths.get_filename_list("loras"),
|
||||
tooltip="LoRA whose safetensors metadata and tensor keys will be listed.",
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
@@ -134,6 +137,7 @@ class CheckpointMetaKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"ckpt_name",
|
||||
options=folder_paths.get_filename_list("checkpoints"),
|
||||
tooltip="Checkpoint whose safetensors metadata and tensor keys will be listed.",
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
@@ -160,6 +164,7 @@ class EmbeddingMetaKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"embedding",
|
||||
options=folder_paths.get_filename_list("embeddings"),
|
||||
tooltip="Embedding whose safetensors metadata and tensor keys will be listed.",
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
|
||||
+33
-6
@@ -1025,9 +1025,21 @@ class ModelAnalysisLogic:
|
||||
|
||||
def _common_inputs(model_type: str, *, alignment_control: bool):
|
||||
inputs = [
|
||||
io.Combo.Input("execution_mode", options=["ANALYZE", "DOCUMENTATION ONLY"]),
|
||||
io.Combo.Input("model_a", options=folder_paths.get_filename_list(model_type)),
|
||||
io.Combo.Input("model_b", options=folder_paths.get_filename_list(model_type)),
|
||||
io.Combo.Input(
|
||||
"execution_mode",
|
||||
options=["ANALYZE", "DOCUMENTATION ONLY"],
|
||||
tooltip="ANALYZE streams both files and produces standard and CWB diagnostic reports. DOCUMENTATION ONLY performs no model loading.",
|
||||
),
|
||||
io.Combo.Input(
|
||||
"model_a",
|
||||
options=folder_paths.get_filename_list(model_type),
|
||||
tooltip="First file in the comparison. Reports identify values and keys unique to this input separately from Model B.",
|
||||
),
|
||||
io.Combo.Input(
|
||||
"model_b",
|
||||
options=folder_paths.get_filename_list(model_type),
|
||||
tooltip="Second file in the comparison. Inputs are analyzed only; neither file is modified or merged.",
|
||||
),
|
||||
]
|
||||
if alignment_control:
|
||||
inputs.append(io.Boolean.Input(
|
||||
@@ -1039,9 +1051,23 @@ def _common_inputs(model_type: str, *, alignment_control: bool):
|
||||
),
|
||||
))
|
||||
inputs.extend([
|
||||
io.Int.Input("top_weight_differences", default=20, min=0, max=1000),
|
||||
io.Combo.Input("process_device", options=["cuda", "cpu"]),
|
||||
io.Boolean.Input("force_clear_cache", default=True),
|
||||
io.Int.Input(
|
||||
"top_weight_differences",
|
||||
default=20,
|
||||
min=0,
|
||||
max=1000,
|
||||
tooltip="Number of largest individual absolute parameter differences retained for the detailed report. Zero disables this list.",
|
||||
),
|
||||
io.Combo.Input(
|
||||
"process_device",
|
||||
options=["cuda", "cpu"],
|
||||
tooltip="Device for per-work-unit floating-point analysis. A CUDA OOM retries only the affected unit on CPU.",
|
||||
),
|
||||
io.Boolean.Input(
|
||||
"force_clear_cache",
|
||||
default=True,
|
||||
tooltip="Run garbage collection and clear the CUDA allocator cache after every analyzed work unit. Saves retained memory but slows analysis.",
|
||||
),
|
||||
])
|
||||
return inputs
|
||||
|
||||
@@ -1059,6 +1085,7 @@ class _ModelAnalysisNode(io.ComfyNode):
|
||||
node_id=cls.NODE_ID,
|
||||
display_name=cls.DISPLAY_NAME,
|
||||
category="ModelUtils/Analysis",
|
||||
description="Compare two model files without merging them and return separate standard-metric and CWB-diagnostic reports.",
|
||||
inputs=_common_inputs(
|
||||
cls.MODEL_TYPE,
|
||||
alignment_control=cls.EMBEDDING_ALIGNMENT or cls.LORA_MODE,
|
||||
|
||||
+12
-12
@@ -53,8 +53,8 @@ class CheckpointInfoLoader(BaseModelInfoLoader):
|
||||
display_name="Checkpoint Info Loader",
|
||||
category=cls.CATEGORY,
|
||||
inputs=[
|
||||
io.Combo.Input("checkpoint", options=folder_paths.get_filename_list("checkpoints")),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100)
|
||||
io.Combo.Input("checkpoint", options=folder_paths.get_filename_list("checkpoints"), tooltip="Checkpoint whose downloaded information and example workflow will be returned."),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100, tooltip="Zero-based index of the saved example workflow to return when multiple workflows are available.")
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output(display_name="preview"),
|
||||
@@ -76,8 +76,8 @@ class LoRAInfoLoader(BaseModelInfoLoader):
|
||||
display_name="LoRA Info Loader",
|
||||
category=cls.CATEGORY,
|
||||
inputs=[
|
||||
io.Combo.Input("lora", options=folder_paths.get_filename_list("loras")),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100)
|
||||
io.Combo.Input("lora", options=folder_paths.get_filename_list("loras"), tooltip="LoRA whose downloaded information and example workflow will be returned."),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100, tooltip="Zero-based index of the saved example workflow to return when multiple workflows are available.")
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output(display_name="preview"),
|
||||
@@ -99,8 +99,8 @@ class EmbeddingInfoLoader(BaseModelInfoLoader):
|
||||
display_name="Embedding Info Loader",
|
||||
category=cls.CATEGORY,
|
||||
inputs=[
|
||||
io.Combo.Input("embedding", options=folder_paths.get_filename_list("embeddings")),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100)
|
||||
io.Combo.Input("embedding", options=folder_paths.get_filename_list("embeddings"), tooltip="Embedding whose downloaded information and example workflow will be returned."),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100, tooltip="Zero-based index of the saved example workflow to return when multiple workflows are available.")
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output(display_name="preview"),
|
||||
@@ -122,8 +122,8 @@ class VAEInfoLoader(BaseModelInfoLoader):
|
||||
display_name="VAE Info Loader",
|
||||
category=cls.CATEGORY,
|
||||
inputs=[
|
||||
io.Combo.Input("vae", options=folder_paths.get_filename_list("vae")),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100)
|
||||
io.Combo.Input("vae", options=folder_paths.get_filename_list("vae"), tooltip="VAE whose downloaded information and example workflow will be returned."),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100, tooltip="Zero-based index of the saved example workflow to return when multiple workflows are available.")
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output(display_name="preview"),
|
||||
@@ -145,8 +145,8 @@ class ControlNetInfoLoader(BaseModelInfoLoader):
|
||||
display_name="ControlNet Info Loader",
|
||||
category=cls.CATEGORY,
|
||||
inputs=[
|
||||
io.Combo.Input("controlnet", options=folder_paths.get_filename_list("controlnet")),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100)
|
||||
io.Combo.Input("controlnet", options=folder_paths.get_filename_list("controlnet"), tooltip="ControlNet whose downloaded information and example workflow will be returned."),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100, tooltip="Zero-based index of the saved example workflow to return when multiple workflows are available.")
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output(display_name="preview"),
|
||||
@@ -168,8 +168,8 @@ class DiffusionModelInfoLoader(BaseModelInfoLoader):
|
||||
display_name="Diffusion Model Info Loader",
|
||||
category=cls.CATEGORY,
|
||||
inputs=[
|
||||
io.Combo.Input("diffusion_model", options=folder_paths.get_filename_list("diffusion_models")),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100)
|
||||
io.Combo.Input("diffusion_model", options=folder_paths.get_filename_list("diffusion_models"), tooltip="Diffusion model whose downloaded information and example workflow will be returned."),
|
||||
io.Int.Input("workflow_index", default=0, min=0, max=100, tooltip="Zero-based index of the saved example workflow to return when multiple workflows are available.")
|
||||
],
|
||||
outputs=[
|
||||
io.Image.Output(display_name="preview"),
|
||||
|
||||
+21
-16
@@ -83,10 +83,11 @@ class ModelPruneKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"diffusionmodel_name",
|
||||
options=folder_paths.get_filename_list("diffusion_models"),
|
||||
tooltip="Diffusion model from which matching tensor keys will be removed.",
|
||||
),
|
||||
io.String.Input("keys_to_prune", multiline=True, default=""),
|
||||
io.Boolean.Input("use_regex", default=False),
|
||||
io.String.Input("output_filename", default="pruned_model"),
|
||||
io.String.Input("keys_to_prune", multiline=True, default="", tooltip="One tensor-key pattern per line. Blank lines are ignored."),
|
||||
io.Boolean.Input("use_regex", default=False, tooltip="Interpret each line as a regular expression; otherwise match literal key text."),
|
||||
io.String.Input("output_filename", default="pruned_model", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_path"),
|
||||
@@ -113,10 +114,11 @@ class TextEncoderPruneKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"textencoder_name",
|
||||
options=folder_paths.get_filename_list("text_encoders"),
|
||||
tooltip="Text encoder from which matching tensor keys will be removed.",
|
||||
),
|
||||
io.String.Input("keys_to_prune", multiline=True, default=""),
|
||||
io.Boolean.Input("use_regex", default=False),
|
||||
io.String.Input("output_filename", default="pruned_textencoder"),
|
||||
io.String.Input("keys_to_prune", multiline=True, default="", tooltip="One tensor-key pattern per line. Blank lines are ignored."),
|
||||
io.Boolean.Input("use_regex", default=False, tooltip="Interpret each line as a regular expression; otherwise match literal key text."),
|
||||
io.String.Input("output_filename", default="pruned_textencoder", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_path"),
|
||||
@@ -143,10 +145,11 @@ class LoRAPruneKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"lora_name",
|
||||
options=folder_paths.get_filename_list("loras"),
|
||||
tooltip="LoRA from which matching tensor keys will be removed.",
|
||||
),
|
||||
io.String.Input("keys_to_prune", multiline=True, default=""),
|
||||
io.Boolean.Input("use_regex", default=False),
|
||||
io.String.Input("output_filename", default="pruned_lora"),
|
||||
io.String.Input("keys_to_prune", multiline=True, default="", tooltip="One tensor-key pattern per line. Blank lines are ignored."),
|
||||
io.Boolean.Input("use_regex", default=False, tooltip="Interpret each line as a regular expression; otherwise match literal key text."),
|
||||
io.String.Input("output_filename", default="pruned_lora", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_path"),
|
||||
@@ -173,10 +176,11 @@ class CheckpointPruneKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"ckpt_name",
|
||||
options=folder_paths.get_filename_list("checkpoints"),
|
||||
tooltip="Checkpoint from which matching tensor keys will be removed.",
|
||||
),
|
||||
io.String.Input("keys_to_prune", multiline=True, default=""),
|
||||
io.Boolean.Input("use_regex", default=False),
|
||||
io.String.Input("output_filename", default="pruned_checkpoint"),
|
||||
io.String.Input("keys_to_prune", multiline=True, default="", tooltip="One tensor-key pattern per line. Blank lines are ignored."),
|
||||
io.Boolean.Input("use_regex", default=False, tooltip="Interpret each line as a regular expression; otherwise match literal key text."),
|
||||
io.String.Input("output_filename", default="pruned_checkpoint", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_path"),
|
||||
@@ -203,10 +207,11 @@ class EmbeddingPruneKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"embedding",
|
||||
options=folder_paths.get_filename_list("embeddings"),
|
||||
tooltip="Embedding from which matching tensor keys will be removed.",
|
||||
),
|
||||
io.String.Input("keys_to_prune", multiline=True, default=""),
|
||||
io.Boolean.Input("use_regex", default=False),
|
||||
io.String.Input("output_filename", default="pruned_embedding"),
|
||||
io.String.Input("keys_to_prune", multiline=True, default="", tooltip="One tensor-key pattern per line. Blank lines are ignored."),
|
||||
io.Boolean.Input("use_regex", default=False, tooltip="Interpret each line as a regular expression; otherwise match literal key text."),
|
||||
io.String.Input("output_filename", default="pruned_embedding", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_path"),
|
||||
@@ -218,4 +223,4 @@ class EmbeddingPruneKeys(io.ComfyNode):
|
||||
use_regex: bool, output_filename: str) -> io.NodeOutput:
|
||||
path = _prune_keys(embedding, "embeddings",
|
||||
keys_to_prune, use_regex, output_filename)
|
||||
return io.NodeOutput(path)
|
||||
return io.NodeOutput(path)
|
||||
|
||||
+21
-16
@@ -78,10 +78,11 @@ class ModelRenameKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"diffusionmodel_name",
|
||||
options=folder_paths.get_filename_list("diffusion_models"),
|
||||
tooltip="Diffusion model whose tensor keys will be renamed.",
|
||||
),
|
||||
io.String.Input("old_keys", multiline=True, default=""),
|
||||
io.String.Input("new_keys", multiline=True, default=""),
|
||||
io.String.Input("output_filename", default="renamed_model"),
|
||||
io.String.Input("old_keys", multiline=True, default="", tooltip="Existing key text or pattern, one entry per line, paired by line with New Keys."),
|
||||
io.String.Input("new_keys", multiline=True, default="", tooltip="Replacement key text, one entry per line, paired by line with Old Keys."),
|
||||
io.String.Input("output_filename", default="renamed_model", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_path"),
|
||||
@@ -108,10 +109,11 @@ class TextEncoderRenameKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"textencoder_name",
|
||||
options=folder_paths.get_filename_list("text_encoders"),
|
||||
tooltip="Text encoder whose tensor keys will be renamed.",
|
||||
),
|
||||
io.String.Input("old_keys", multiline=True, default=""),
|
||||
io.String.Input("new_keys", multiline=True, default=""),
|
||||
io.String.Input("output_filename", default="renamed_textencoder"),
|
||||
io.String.Input("old_keys", multiline=True, default="", tooltip="Existing key text or pattern, one entry per line, paired by line with New Keys."),
|
||||
io.String.Input("new_keys", multiline=True, default="", tooltip="Replacement key text, one entry per line, paired by line with Old Keys."),
|
||||
io.String.Input("output_filename", default="renamed_textencoder", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_path"),
|
||||
@@ -138,10 +140,11 @@ class LoRARenameKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"lora_name",
|
||||
options=folder_paths.get_filename_list("loras"),
|
||||
tooltip="LoRA whose tensor keys will be renamed.",
|
||||
),
|
||||
io.String.Input("old_keys", multiline=True, default=""),
|
||||
io.String.Input("new_keys", multiline=True, default=""),
|
||||
io.String.Input("output_filename", default="renamed_lora"),
|
||||
io.String.Input("old_keys", multiline=True, default="", tooltip="Existing key text or pattern, one entry per line, paired by line with New Keys."),
|
||||
io.String.Input("new_keys", multiline=True, default="", tooltip="Replacement key text, one entry per line, paired by line with Old Keys."),
|
||||
io.String.Input("output_filename", default="renamed_lora", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_path"),
|
||||
@@ -168,10 +171,11 @@ class CheckpointRenameKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"ckpt_name",
|
||||
options=folder_paths.get_filename_list("checkpoints"),
|
||||
tooltip="Checkpoint whose tensor keys will be renamed.",
|
||||
),
|
||||
io.String.Input("old_keys", multiline=True, default=""),
|
||||
io.String.Input("new_keys", multiline=True, default=""),
|
||||
io.String.Input("output_filename", default="renamed_checkpoint"),
|
||||
io.String.Input("old_keys", multiline=True, default="", tooltip="Existing key text or pattern, one entry per line, paired by line with New Keys."),
|
||||
io.String.Input("new_keys", multiline=True, default="", tooltip="Replacement key text, one entry per line, paired by line with Old Keys."),
|
||||
io.String.Input("output_filename", default="renamed_checkpoint", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_path"),
|
||||
@@ -198,10 +202,11 @@ class EmbeddingRenameKeys(io.ComfyNode):
|
||||
io.Combo.Input(
|
||||
"embedding",
|
||||
options=folder_paths.get_filename_list("embeddings"),
|
||||
tooltip="Embedding whose tensor keys will be renamed.",
|
||||
),
|
||||
io.String.Input("old_keys", multiline=True, default=""),
|
||||
io.String.Input("new_keys", multiline=True, default=""),
|
||||
io.String.Input("output_filename", default="renamed_embedding"),
|
||||
io.String.Input("old_keys", multiline=True, default="", tooltip="Existing key text or pattern, one entry per line, paired by line with New Keys."),
|
||||
io.String.Input("new_keys", multiline=True, default="", tooltip="Replacement key text, one entry per line, paired by line with Old Keys."),
|
||||
io.String.Input("output_filename", default="renamed_embedding", tooltip="Output filename without extension, written under the matching ComfyUI model directory."),
|
||||
],
|
||||
outputs=[
|
||||
io.String.Output(display_name="output_path"),
|
||||
@@ -213,4 +218,4 @@ class EmbeddingRenameKeys(io.ComfyNode):
|
||||
new_keys: str, output_filename: str) -> io.NodeOutput:
|
||||
path = _rename_keys(embedding, "embeddings",
|
||||
old_keys, new_keys, output_filename)
|
||||
return io.NodeOutput(path)
|
||||
return io.NodeOutput(path)
|
||||
|
||||
@@ -305,10 +305,10 @@ def _get_common_inputs():
|
||||
tooltip="Clamp outlier singular values"),
|
||||
io.Float.Input("min_diff", default=0.0, min=0.0, max=1.0, step=0.001,
|
||||
tooltip="Skip layers with max difference below this"),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip"),
|
||||
io.String.Input("output_filename", default="extracted_te_lora"),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16"),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda"),
|
||||
io.Combo.Input("mismatch_mode", options=["skip", "zeros", "error"], default="skip", tooltip="Handle missing or incompatible text-encoder tensors by skipping them, substituting zeros where supported, or aborting."),
|
||||
io.String.Input("output_filename", default="extracted_te_lora", tooltip="Output filename without extension, written under the ComfyUI LoRA directory."),
|
||||
io.Combo.Input("save_dtype", options=["fp16", "bf16", "fp32"], default="fp16", tooltip="Data type used to save extracted text-encoder LoRA factors."),
|
||||
io.Combo.Input("device", options=["cuda", "cpu"], default="cuda", tooltip="Device used for per-layer extraction arithmetic; CUDA out-of-memory retries the affected layer on CPU where supported."),
|
||||
io.String.Input("skip_patterns", default="", multiline=True,
|
||||
tooltip="Patterns for layers to skip (regex or glob depending on glob_skip_patterns)"),
|
||||
io.Boolean.Input("glob_skip_patterns", default=False,
|
||||
@@ -370,10 +370,10 @@ class TextEncoderLoRAExtractRatio(io.ComfyNode):
|
||||
description="Keep singular values > max(S) / ratio.",
|
||||
inputs=[
|
||||
*_get_te_model_inputs(),
|
||||
io.Float.Input("linear_ratio", default=2.0, min=1.0, max=100.0, step=0.1),
|
||||
io.Float.Input("conv_ratio", default=2.0, min=1.0, max=100.0, step=0.1),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Float.Input("linear_ratio", default=2.0, min=1.0, max=100.0, step=0.1, tooltip="Ratio threshold for linear layers; higher values retain more singular values."),
|
||||
io.Float.Input("conv_ratio", default=2.0, min=1.0, max=100.0, step=0.1, tooltip="Ratio threshold for convolution layers; higher values retain more singular values."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
@@ -410,10 +410,10 @@ class TextEncoderLoRAExtractQuantile(io.ComfyNode):
|
||||
description="Keep enough singular values to reach target percentage.",
|
||||
inputs=[
|
||||
*_get_te_model_inputs(),
|
||||
io.Float.Input("linear_quantile", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Float.Input("conv_quantile", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Float.Input("linear_quantile", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target cumulative singular-value fraction for linear layers."),
|
||||
io.Float.Input("conv_quantile", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target cumulative singular-value fraction for convolution layers."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
@@ -450,9 +450,9 @@ class TextEncoderLoRAExtractKnee(io.ComfyNode):
|
||||
description="Automatically find optimal rank using knee detection on singular value curve.",
|
||||
inputs=[
|
||||
*_get_te_model_inputs(),
|
||||
io.Combo.Input("knee_method", options=["sv_knee", "sv_cumulative_knee"], default="sv_knee"),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Combo.Input("knee_method", options=["sv_knee", "sv_cumulative_knee"], default="sv_knee", tooltip="Detect the knee from raw singular values or their cumulative distribution."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
@@ -489,10 +489,10 @@ class TextEncoderLoRAExtractFrobenius(io.ComfyNode):
|
||||
description="Preserve target fraction of Frobenius norm.",
|
||||
inputs=[
|
||||
*_get_te_model_inputs(),
|
||||
io.Float.Input("linear_target", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Float.Input("conv_target", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Float.Input("linear_target", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target Frobenius-norm fraction retained for linear layers."),
|
||||
io.Float.Input("conv_target", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target Frobenius-norm fraction retained for convolution layers."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
@@ -572,10 +572,10 @@ class TextEncoderDoRAExtractRatio(io.ComfyNode):
|
||||
description="Keep singular values > max(S) / ratio.",
|
||||
inputs=[
|
||||
*_get_te_model_inputs(),
|
||||
io.Float.Input("linear_ratio", default=2.0, min=1.0, max=100.0, step=0.1),
|
||||
io.Float.Input("conv_ratio", default=2.0, min=1.0, max=100.0, step=0.1),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Float.Input("linear_ratio", default=2.0, min=1.0, max=100.0, step=0.1, tooltip="Ratio threshold for linear layers; higher values retain more singular values."),
|
||||
io.Float.Input("conv_ratio", default=2.0, min=1.0, max=100.0, step=0.1, tooltip="Ratio threshold for convolution layers; higher values retain more singular values."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
@@ -612,10 +612,10 @@ class TextEncoderDoRAExtractQuantile(io.ComfyNode):
|
||||
description="Keep enough singular values to reach target percentage.",
|
||||
inputs=[
|
||||
*_get_te_model_inputs(),
|
||||
io.Float.Input("linear_quantile", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Float.Input("conv_quantile", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Float.Input("linear_quantile", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target cumulative singular-value fraction for linear layers."),
|
||||
io.Float.Input("conv_quantile", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target cumulative singular-value fraction for convolution layers."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
@@ -652,9 +652,9 @@ class TextEncoderDoRAExtractKnee(io.ComfyNode):
|
||||
description="Automatically find optimal rank using knee detection on singular value curve.",
|
||||
inputs=[
|
||||
*_get_te_model_inputs(),
|
||||
io.Combo.Input("knee_method", options=["sv_knee", "sv_cumulative_knee"], default="sv_knee"),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Combo.Input("knee_method", options=["sv_knee", "sv_cumulative_knee"], default="sv_knee", tooltip="Detect the knee from raw singular values or their cumulative distribution."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
@@ -691,10 +691,10 @@ class TextEncoderDoRAExtractFrobenius(io.ComfyNode):
|
||||
description="Preserve target fraction of Frobenius norm.",
|
||||
inputs=[
|
||||
*_get_te_model_inputs(),
|
||||
io.Float.Input("linear_target", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Float.Input("conv_target", default=0.9, min=0.0, max=1.0, step=0.01),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384),
|
||||
io.Float.Input("linear_target", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target Frobenius-norm fraction retained for linear layers."),
|
||||
io.Float.Input("conv_target", default=0.9, min=0.0, max=1.0, step=0.01, tooltip="Target Frobenius-norm fraction retained for convolution layers."),
|
||||
io.Int.Input("linear_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for linear layers."),
|
||||
io.Int.Input("conv_max_rank", default=128, min=1, max=16384, tooltip="Maximum extracted rank for convolution layers."),
|
||||
*_get_common_inputs(),
|
||||
],
|
||||
outputs=[io.String.Output(display_name="output_path")],
|
||||
|
||||
@@ -332,6 +332,8 @@ def test_all_ten_schemas_and_lora_switch_contract(cwb):
|
||||
for node in cwb.CWB_MERGER_NODES:
|
||||
schema = node.define_schema()
|
||||
ids = [value.id for value in schema.inputs]
|
||||
assert schema.description
|
||||
assert all(value.tooltip for value in schema.inputs)
|
||||
assert ids[:3] == ["execution_mode", "model_a", "model_b"]
|
||||
if node.INPUT_COUNT == 3:
|
||||
assert ids[3] == "model_c"
|
||||
|
||||
@@ -43,6 +43,8 @@ def test_five_node_schema_contract(analysis):
|
||||
for node in analysis.MODEL_ANALYSIS_NODES:
|
||||
schema = node.define_schema()
|
||||
assert schema.category == "ModelUtils/Analysis"
|
||||
assert schema.description
|
||||
assert all(item.tooltip for item in schema.inputs)
|
||||
assert [item.id for item in schema.inputs[:3]] == [
|
||||
"execution_mode", "model_a", "model_b",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user