TE LoRA Extract (Frobenius)
Keep X% of the Frobenius norm
- output_path
Think of a LoRA's job as "reproduce this finetune delta as faithfully as possible for the file size." The Frobenius variant of ModelUtils' TE extractors is the one that's most honest about that trade, because it measures the delta in the way that actually predicts reconstruction error: energy. Tell it to preserve 90% of the Frobenius norm and it picks whatever rank each layer needs to get there.
In practice this works like the pack's other extract nodes - A - B per .weight tensor, SVD, write lora_A/lora_B factors to your loras folder - with one twist in the rank math. SVD orders a matrix's "energy" in its singular values: the squared singular values sum to the squared Frobenius norm, so if you keep the top k singular values, you know exactly what fraction of the layer's total energy you've preserved. The node keeps adding singular values until the retained energy crosses your target. No guessing, no curve-reading - just "I want this much of the signal, figure out the rank."
One subtlety worth knowing: the target is computed relative to what's achievable within linear_max_rank/conv_max_rank, not the layer's full theoretical spectrum. So the knob reads as "retain X% of what a rank-128 LoRA could hold," which is a sensible contract - it means the cap and the target compose instead of fighting.
The inputs that matter
- model_a / model_b - fine-tuned and base encoders from
models/text_encoders. - linear_target / conv_target - the retained-energy fraction for linear/attention vs convolution layers (default 0.9). 0.9 is a solid starting point; nudge toward 0.99 for high-fidelity extraction, or down toward 0.7 for maximum compression.
- linear_max_rank / conv_max_rank - the caps (default 128) that the energy target is measured against.
- probe_offset - extra singular values sampled beyond the cap so the energy calculation sees a full-enough spectrum.
- output_filename / save_dtype / device / lazy_load / force_clear_cache - the family standard: output name (in
loras), save precision (fp16 default), compute device with per-layer CPU fallback on OOM, and streaming memory behavior.
It's an output node; output_path reports where the file was written.
Install
ComfyUI Manager → search "Model Utility Toolkit", or:
cd ComfyUI/custom_nodes
git clone https://github.com/silveroxides/ComfyUI-ModelUtils
cd ComfyUI-ModelUtils
pip install -r requirements.txt
Restart; the node lives under ModelUtils/LoRA Extract (TE). The important runtime dependency is unifiedefficientloader, which streams both encoders so memory stays flat during the run.
Gotchas
Same family traps: mismatch_mode: skip is the default, so comparing against the wrong base produces a small, silent, useless file instead of an error. Full SVD per layer means a progress bar and minutes of patience. If the math of "energy" feels like overkill and you just want a rank, use the Fixed node; if you want zero knobs at all, the Knee variant reads the spectrum for you. Frobenius is the one you reach for when you actually care about the fidelity-to-size trade and want it phrased in the quantity that predicts it.
Inputs (18)
| Name | Type | Default | Description |
|---|---|---|---|
| model_a | COMBO | Finetuned Text Encoder model (A - B = LoRA) | |
| model_b | COMBO | Base Text Encoder model (A - B = LoRA) | |
| linear_target | FLOAT | 0.900–1 | Target Frobenius-norm fraction retained for linear layers. |
| conv_target | FLOAT | 0.900–1 | Target Frobenius-norm fraction retained for convolution layers. |
| probe_offset | INT | 321–4096 | Extra singular values sampled beyond Max Rank for a reliable bounded rank decision. |
| 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 | * | — |