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

DoRA Extract (Ratio)

DoRA Extract (Ratio) — extract a DoRA by relative singular-value magnitude

By silveroxides·Created about a year ago·Updated 4 days ago· 14
DoRA 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

    Three ways to pick a rank when extracting a DoRA from two checkpoints, and this pack ships all three as separate nodes: knee detection finds the natural elbow in each layer's singular-value curve automatically, quantile keeps enough singular values to hit a target cumulative percentage, and this one - ratio - takes the simplest approach of the three. It keeps any singular value that's still at least a certain fraction of the largest one in that layer, and throws away anything smaller than the threshold. No accumulation, no curve-shape analysis - just a straight relative-magnitude cutoff, layer by layer.

    The distinction from quantile is worth being precise about, because they sound similar and aren't quite the same thing. Quantile asks "how much of the total energy have I captured so far" - a global, cumulative question. Ratio asks "is this singular value still big enough to matter compared to the biggest one in this layer" - a local, per-value question. In practice the two often land on similar ranks for a given layer, but not identically: a layer with one dominant singular value and a long, gently-sloping tail of smaller ones can hit a high quantile target quickly (most of the energy is in that one value) while still failing a strict ratio threshold on many of the tail values, or the reverse, depending on how the two thresholds are set relative to each other.

    How it works. model_a minus model_b gives the per-layer weight delta; SVD decomposes it into singular values; the node keeps every singular value greater than max(S) / ratio, where S is that layer's full set of singular values. A ratio of 2 keeps anything at least half the size of the layer's largest singular value - a fairly tight cut. Push ratio up and you're dividing by a bigger number, which lowers the bar and keeps more (weaker) singular values, meaning higher rank and a more faithful but larger extraction.

    Inputs that matter. model_a (finetune) and model_b (base) - same convention as the pack's other extraction nodes. linear_ratio and conv_ratio (both default 2, range 1–100) are the actual dial, split between linear/attention layers and convolutional ones. linear_max_rank and conv_max_rank (both default 128) are hard ceilings regardless of what the ratio threshold would otherwise allow through.

    Shared plumbing with the rest of this node family: chunk_large_layers (off by default) for splitting fused QKV/MLP blocks before extraction, clamp_quantile (default 0.99) to bound outlier singular values, min_diff (default 0) to skip barely-changed layers, mismatch_mode (default "skip") for layers that don't align between the two checkpoints, skip_patterns (regex, or glob with glob_skip_patterns on) to manually exclude layers, save_dtype (default fp16), device (default cuda), output_filename (default "extracted_lora"), lazy_load (on by default), and force_clear_cache (on by default).

    Output. output_path (STRING), and this is an output node - it runs as a terminal step in the graph whether or not anything downstream reads that path.

    Installing it. ComfyUI Manager, search "Model Utility Toolkit," or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/silveroxides/ComfyUI-ModelUtils
    

    then restart.

    Troubleshooting. If you're getting a much bigger or smaller extraction than expected, check ratio before anything else - because it divides rather than accumulates, small changes near the default of 2 can shift a layer's kept rank more sharply than the equivalent nudge would on the quantile node. If a layer's singular values are all fairly close in magnitude (no single dominant one), ratio-based selection tends to keep either almost all of them or almost none, depending on which side of the threshold that flat spread happens to fall - quantile handles that shape more gracefully, so if a specific layer's output looks off, that's worth trying as an alternative rather than just cranking the ratio further. As always, two full checkpoints in memory at once is the real resource cost here; leave lazy_load and force_clear_cache on unless your hardware can comfortably hold both.

    CategoryModelUtils/DoRA

    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