TE LoRA Extract (Ratio)
Keep the singular values that actually matter
- output_path
Picking a LoRA rank is usually a guess: 16, 32, 64, whatever fits. This node replaces the guess with a rule. Extract a LoRA from a fine-tuned text encoder minus its base, but instead of forcing a fixed rank, keep every singular value that's at least max(S) / ratio - the ratio variant of silveroxides/ComfyUI-ModelUtils' TE extractors.
It's the same family as the pack's other extract nodes: A - B per weight tensor, SVD, write lora_A/lora_B factors to your loras folder. The only real difference is how the rank is decided per layer. Where the Fixed node sets one rank for everything, Ratio lets the singular value spectrum of each layer speak - a layer whose signal decays fast gets a low rank automatically, a layer with lots of meaningful structure keeps more. That per-layer adaptation is the entire selling point, and it's why you'd reach for this over Fixed if you want efficiency without hand-tuning ranks.
The inputs that matter
- model_a / model_b - fine-tuned encoder and base encoder, both from
models/text_encoders. A minus B is the delta. - linear_ratio / conv_ratio - the threshold for linear/attention vs convolution layers, default 2. Higher values retain more singular values: a ratio of 4 keeps everything above max/4, which is a lower cutoff than max/2, so more of the spectrum survives. Lower it to force a tighter rank. This is the kohya convention, so if you've used "extract LoRA" in sd-scripts, you've met this knob before.
- linear_max_rank / conv_max_rank - hard caps (default 128) so a single noisy layer can't blow the rank up.
- probe_offset - extra singular values sampled past the max rank so the rank decision is made against a full-enough spectrum rather than a truncated one.
- output_filename / save_dtype / device / lazy_load - shared across the whole extractor family: where it's written, what dtype it's saved in (fp16 default), where the arithmetic runs, and whether tensors stream from disk.
One output, output_path - the path of the written file. It's an output node; nothing needs to follow it.
Install
From 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, and the node appears under ModelUtils/LoRA Extract (TE). The key runtime dependency is unifiedefficientloader, which streams the two safetensors so you don't need to hold both encoders in RAM.
Where it bites
The silent-skip trap applies here as much as anywhere in this pack: with mismatch_mode: skip (the default), missing or shape-incompatible tensors just vanish. Compare an encoder against the wrong base and you'll get a small, useless file with no error. And remember this is SVD over a whole encoder - it runs for minutes with a progress bar, not seconds. If you'd rather the spectrum pick the rank for you in one shot, the Knee variant automates exactly that; use Ratio when you want the explicit, tunable threshold.
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_ratio | FLOAT | 2.01–100 | Ratio threshold for linear layers; higher values retain more singular values. |
| conv_ratio | FLOAT | 2.01–100 | Ratio threshold for convolution layers; higher values retain more singular values. |
| 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 | * | — |