LoRA Extract (Ratio)
LoRA Extract (Ratio) — extract a LoRA by singular-value ratio threshold
- output_path
The cheapest-to-reason-about of the five LoRA extraction nodes in silveroxides' ComfyUI-ModelUtils. LoRA Extract (Ratio) diffs two checkpoints and, per layer, keeps every singular value bigger than the largest one divided by a ratio you set - S[i] > max(S) / ratio, straight from the node's own description. No target percentage, no norm accounting, no knee-finding - just "keep anything within this factor of the biggest contributor."
The mechanism. Same base setup as every extraction node in this pack: model_a is the fine-tune, model_b the base ("A - B = LoRA," per the tooltip). SVD decomposes each layer's diff into singular values, and Ratio extraction sorts them, finds the largest, and keeps everything above max(S)/ratio. A ratio of 2 (the default) keeps values at least half the size of the biggest one; push the ratio higher and you keep more, smaller values too - the node's own tooltip states this plainly: "higher = more SVs kept." It's a threshold, not a budget, so unlike Quantile or Frobenius extraction the actual rank that results isn't targeting a specific fidelity percentage - it's just "how far down the singular-value spectrum am I willing to go relative to the top."
Inputs that matter. linear_ratio/conv_ratio (both default 2, range 1-100) are the controls that actually shape the output - low ratio means aggressive pruning, only the dominant directions survive; high ratio keeps nearly everything. linear_max_rank/conv_max_rank (128 default) still cap the result, since a high ratio on a layer with a long tail of similarly-sized singular values could otherwise balloon. The rest is the shared extraction toolkit: svd_niter, clamp_quantile (0.99) for outlier clipping, min_diff to skip near-identical layers, skip_patterns/glob_skip_patterns for excluding layers by name, save_dtype (fp16), device (cuda). Output is output_path.
Installing it. ComfyUI Manager, search "Model Utility Toolkit" - or cd ComfyUI/custom_nodes && git clone https://github.com/silveroxides/ComfyUI-ModelUtils, then restart. No extra dependencies in the README; you need your two source checkpoints already downloaded.
Why ratio over the other four. It's the extraction method with the least conceptual overhead if you already have a rough sense of "how aggressive" you want to be, without wanting to think about what percentage of a norm you're preserving. If you tend to reach for a simple gain/threshold slider rather than a target percentage in other tools, Ratio will feel the most familiar. If you'd rather target an explicit fidelity number, Quantile or Frobenius extraction (both in this same pack) are the better fit; if you don't want to pick a number at all, Knee Detection does it automatically.
What extraction is actually for, and what it costs. Extracting a LoRA from a base-and-fine-tune pair is a legitimate, long-standing technique - it's how you turn a full fine-tune into something a fraction of the size that's portable to other checkpoints in the same family, and it's the same idea kohya-ss's training scripts (this pack's acknowledged lineage) have implemented for years. The cost is real: two full checkpoints loaded, SVD run across every layer, which is slow and can OOM a modest GPU if you're not careful. lazy_load and force_clear_cache, both on by default, exist to manage exactly that, and chunk_large_layers (off by default) helps on architectures with big fused transformer blocks. The usual failure mode still applies here too: model_a and model_b need to share an actual architecture lineage, and mismatch_mode defaulting to skip means an unrelated pair won't error, it'll just quietly produce an incomplete LoRA.
Inputs (17)
| Name | Type | Default | Description |
|---|---|---|---|
| model_a | COMBO | Finetuned model (A - B = LoRA) | |
| model_b | COMBO | Base model (A - B = LoRA) | |
| linear_ratio | FLOAT | 2.01–100 | Ratio threshold for linear layers (higher = more SVs kept) |
| conv_ratio | FLOAT | 2.01–100 | Ratio threshold for conv layers (higher = more SVs kept) |
| linear_max_rank | INT | 1281–16384 | Maximum rank for linear layers |
| conv_max_rank | INT | 1281–16384 | Maximum rank for conv layers |
| lazy_load | BOOLEAN | true | Low memory mode: load tensors from disk on demand |
| force_clear_cache | BOOLEAN | true | Clear CUDA cache after each layer |
| 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 | 3 options: skip, zeros, error |
| output_filename | STRING | extracted_lora | — |
| save_dtype | COMBO | fp16 | 3 options: fp16, bf16, fp32 |
| device | COMBO | cuda | 2 options: cuda, cpu |
| 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 | STRING | — |