Nodes/Model Utility Toolkit/LoRA Extract (Ratio)
ComfyUI Node

LoRA Extract (Ratio)

LoRA Extract (Ratio) — extract a LoRA by singular-value ratio threshold

By silveroxides·Created about a year ago·Updated 4 days ago· 14
LoRA Extract (Ratio)
    • output_path
    model_a
    model_b
    linear_ratio2.0
    conv_ratio2.0
    linear_max_rank128
    conv_max_rank128
    lazy_loadtrue
    force_clear_cachetrue
    chunk_large_layersfalse
    clamp_quantile0.99
    min_diff0.000
    mismatch_modeskip
    output_filenameextracted_lora
    save_dtypefp16
    devicecuda
    skip_patterns
    glob_skip_patternsfalse

    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.

    CategoryModelUtils/LoRA

    Inputs (17)

    NameTypeDefaultDescription
    model_aCOMBOFinetuned model (A - B = LoRA)
    model_bCOMBOBase model (A - B = LoRA)
    linear_ratioFLOAT2.01–100Ratio threshold for linear layers (higher = more SVs kept)
    conv_ratioFLOAT2.01–100Ratio threshold for conv layers (higher = more SVs kept)
    linear_max_rankINT1281–16384Maximum rank for linear layers
    conv_max_rankINT1281–16384Maximum rank for conv layers
    lazy_loadBOOLEANtrueLow memory mode: load tensors from disk on demand
    force_clear_cacheBOOLEANtrueClear CUDA cache after each layer
    chunk_large_layersBOOLEANfalseSplit large fused layers (QKV, MLP) into chunks
    clamp_quantileFLOAT0.990.5–1Clamp outlier singular values
    min_diffFLOAT0.0000–1Skip layers with max difference below this
    mismatch_modeCOMBOskip3 options: skip, zeros, error
    output_filenameSTRINGextracted_lora
    save_dtypeCOMBOfp163 options: fp16, bf16, fp32
    deviceCOMBOcuda2 options: cuda, cpu
    skip_patternsSTRINGPatterns for layers to skip (regex or glob depending on glob_skip_patterns)
    glob_skip_patternsBOOLEANfalseWhen 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)

    NameTypeDescription
    output_pathSTRING