TE DoRA Extract (Knee)
Let the singular values pick the rank
- output_path
Of the three DoRA extractors in this pack, this is the one that wants to do all the thinking. Fixed rank makes you choose; Frobenius makes you choose a fraction. Knee detection looks at each layer's singular value curve and finds the elbow - the point where the spectrum stops being meaningful and turns into noise - and uses that as the rank. It's the "extract me a text-encoder DoRA, you figure out the sizes" button.
How it works
Model A is the fine-tuned text encoder, Model B is the base. Per layer, the node computes A − B, SVD-decomposes the delta, and runs knee detection on the singular value curve to pick the cutoff rank. The DoRA structure - low-rank down/up factors plus the dora_scale magnitude vector - is preserved, and the file lands in your LoRA directory.
Two knobs shape the detection. knee_method (default sv_knee) chooses whether to detect the knee on the raw singular values or on their cumulative distribution - the raw spectrum when you trust the values directly, the cumulative version when you want the energy-accumulation viewpoint. knee_probe_offset (default 32) matters more than it looks: it probes extra singular values beyond the max rank so the detector doesn't mistake the hard cut of a truncated spectrum for a real knee. A false knee at the boundary is the classic failure mode of this whole approach, and the probe offset is the guard against it. linear_max_rank / conv_max_rank (defaults 128) cap the result per layer type, so an uncooperative layer can't explode.
Inputs that matter
- model_a / model_b - fine-tuned and base text encoders (
A - B = LoRA), both frommodels/text_encoders. - knee_method -
sv_knee(raw singular values) orcumulative. - knee_probe_offset (default 32) - extra singular values sampled past max rank to avoid a false knee.
- linear_max_rank / conv_max_rank (defaults 128) - caps per layer type.
- output_filename (default
extracted_te_lora) - written to the LoRA directory. - save_dtype (default fp16), clamp_quantile (0.99), min_diff (0), chunk_large_layers (off) - same as the other extractors.
- mismatch_mode, skip_patterns / glob_skip_patterns, lazy_load (on), force_clear_cache (off), device - the usual handling.
Outputs
output_path - a terminal node; the file is the deliverable.
When to pick Knee
When you're extracting from a pair you know nothing about and you don't want to babysit rank settings - this is the recommended first pass for a stranger fine-tune. The honest caveat: knee detection is data-dependent and a little black-boxy, and if a layer's spectrum doesn't have a clean elbow you can get a weird rank. If a particular layer comes out suspicious, that's what min_diff (skip near-identical layers) and the max-rank caps are for. The Frobenius variant is the more controllable fallback.
Install
Part of Model Utility Toolkit (silveroxides/ComfyUI-ModelUtils). ComfyUI Manager → search "Model Utility Toolkit", or:
cd ComfyUI/custom_nodes
git clone https://github.com/silveroxides/ComfyUI-ModelUtils
Restart ComfyUI. Real dependency: unifiedefficientloader (UEL). Keep ComfyUI current - the pack uses the newer extension API. Extraction lineage: kohya-ss/sd-scripts and LyCORIS, per the pack's acknowledgements.
Inputs (17)
| Name | Type | Default | Description |
|---|---|---|---|
| model_a | COMBO | Finetuned Text Encoder model (A - B = LoRA) | |
| model_b | COMBO | Base Text Encoder model (A - B = LoRA) | |
| knee_method | COMBO | sv_knee | Detect the knee from raw singular values or their cumulative distribution. |
| knee_probe_offset | INT | 321–4096 | Extra singular values probed beyond Max Rank to avoid detecting a false knee at the partial-spectrum boundary. |
| linear_max_rank | INT | 1281–16384 | Maximum extracted rank for linear layers. |
| conv_max_rank | INT | 1281–16384 | Maximum extracted rank for convolution layers. |
| lazy_load | BOOLEAN | true | Low memory mode: load tensors from disk on demand |
| force_clear_cache | BOOLEAN | false | Clear CUDA cache after each layer; slower but useful under severe VRAM pressure. |
| chunk_large_layers | BOOLEAN | false | Split large fused layers (QKV, MLP) into chunks |
| clamp_quantile | FLOAT | 0.990.5–1 | Clamp outlier singular values |
| min_diff | FLOAT | 0.0000–1 | Skip layers with max difference below this |
| mismatch_mode | COMBO | skip | Handle missing or incompatible text-encoder tensors by skipping them, substituting zeros where supported, or aborting. |
| output_filename | STRING | extracted_te_lora | Output filename without extension, written under the ComfyUI LoRA directory. |
| save_dtype | COMBO | fp16 | Data type used to save extracted text-encoder LoRA factors. |
| device | COMBO | cuda | Device used for per-layer extraction arithmetic; CUDA out-of-memory retries the affected layer on CPU where supported. |
| skip_patterns | STRING | Patterns for layers to skip (regex or glob depending on glob_skip_patterns) | |
| glob_skip_patterns | BOOLEAN | false | When True, skip_patterns use glob syntax (* = any sequence, ? = any char, dots are literal). When False (default), patterns are Python regex matched as substrings. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| output_path | * | — |