Nodes/Model Utility Toolkit/DoRA Learned Extract (Quantile) (WIP)
ComfyUI Node

DoRA Learned Extract (Quantile) (WIP)

DoRA Learned Extract (Quantile) — percentage-targeted extraction, gradient-refined

By silveroxides·Created about a year ago·Updated 4 days ago· 14
DoRA Learned Extract (Quantile) (WIP)
    • output_path
    model_a
    model_b
    linear_quantile0.90
    conv_quantile0.90
    linear_max_rank128
    conv_max_rank128
    optimize_iters500
    learning_rate1.000
    optimizerprodigy
    lr_scheduleplateau
    lr_patience2
    lr_factor0.90
    lr_cooldown2
    early_stop_loss0
    early_stop_stall2000
    early_stop_lr0
    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

    Same idea as DoRAExtractQuantile - pick a target percentage of cumulative singular-value energy to keep per layer instead of a fixed rank - with a gradient-descent refinement stage added on top. And like the rest of this sub-family, it ships labeled "(WIP)" in its own display name, which is the pack author being upfront that this is the least-proven corner of the extraction tools rather than a finished feature you should trust without checking.

    The refinement idea across all five "Learned" nodes here is the same: SVD gives you the provably optimal low-rank approximation of a weight matrix in isolation, but that's a narrower guarantee than it sounds - it says nothing about how the result behaves once it's reassembled into DoRA's magnitude-and-direction format and actually loaded, and it treats every layer as an independent problem rather than accounting for how they interact. So this node uses the quantile-targeted SVD result as an initialization, then runs an optimizer to directly minimize the reconstruction error against the real weight delta, on the bet that direct loss minimization can close some of that gap. It's a reasonable bet. It's also explicitly unverified, per the label.

    Inputs that matter. model_a (finetune) and model_b (base) - the pair being diffed. linear_quantile and conv_quantile (both default 0.9) are your actual target: keep adding singular values, largest first, until you've captured 90% of that layer's cumulative singular-value sum, split separately for linear/attention and convolutional layers since they often need different amounts of rank to hit the same target. linear_max_rank and conv_max_rank (both default 128) cap the rank regardless of what the quantile target would otherwise demand.

    The optimization stage: optimize_iters (default 500, set to 0 to skip refinement and fall back to plain quantile-based SVD, which is functionally what DoRAExtractQuantile already gives you for less compute), optimizer (default "prodigy," an adaptive optimizer whose whole selling point is not needing you to tune a learning rate by hand), learning_rate (default 1 - appropriate for Prodigy; the tooltip specifically warns AdamW wants closer to 0.01, so don't leave this at 1 if you switch optimizers), lr_schedule (default "plateau") shaped by lr_patience (default 2), lr_factor (default 0.9), and lr_cooldown (default 2), plus early stopping via early_stop_loss (1e-6), early_stop_stall (2000 iterations without improvement), and early_stop_lr (9.01e-9).

    Shared plumbing: chunk_large_layers for fused QKV/MLP blocks, clamp_quantile (default 0.99) to bound outlier singular values, min_diff (default 0) to skip near-untouched layers, mismatch_mode (default "skip"), skip_patterns/glob_skip_patterns for manual layer exclusion, output_filename (default "extracted_lora"), save_dtype (default fp16), device (default cuda), lazy_load (on by default), force_clear_cache (on by default).

    Output. output_path (STRING). Output node - it runs as a terminal step in the graph regardless of downstream wiring.

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

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

    then restart.

    Troubleshooting. Given the WIP status, the most useful check is a direct comparison: run this and the plain DoRAExtractQuantile on the same model pair at the same quantile targets, then actually load both results and see whether the refined version behaves noticeably better - don't assume the extra compute automatically buys you something. If optimize_iters consistently exhausts its full budget without triggering an early stop, that's almost always a learning-rate mismatch with your chosen optimizer rather than evidence the model pair is unusually resistant to fitting. And as with every node in this extraction family, two full checkpoints have to be resident at once for the diff - leave lazy_load and force_clear_cache on unless you know you have the VRAM to spare.

    CategoryModelUtils/DoRA

    Inputs (27)

    NameTypeDefaultDescription
    model_aCOMBOFinetuned model (A - B = LoRA)
    model_bCOMBOBase model (A - B = LoRA)
    linear_quantileFLOAT0.900–1
    conv_quantileFLOAT0.900–1
    linear_max_rankINT1281–16384
    conv_max_rankINT1281–16384
    optimize_itersINT5000–10000Number of gradient descent iterations (0 = skip optimization)
    learning_rateFLOAT1.0000.0001–100Base learning rate. AdamW prefers ~0.01, Prodigy prefers ~1.0
    optimizerCOMBOprodigyOptimization algorithm
    lr_scheduleCOMBOplateauLearning rate scheduling strategy
    lr_patienceINT20–1000Steps to wait before decaying LR (Plateau)
    lr_factorFLOAT0.900.01–1Factor to decay LR by (Plateau)
    lr_cooldownINT20–1000Steps to wait after decay before checking again (Plateau)
    early_stop_lossFLOAT00–1Stop early if MSE loss drops below this value
    early_stop_stallINT20000–10000Stop early if loss doesn't improve for this many iterations
    early_stop_lrFLOAT00–1Stop early if learning rate drops below this value
    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