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 2 years ago·Updated 3 days ago· 17
DoRA Learned Extract (Quantile) (WIP)
  • layer_parameters
  • output_path
◄model_a▾►
◄model_b▾►
◄linear_quantile0.90►
◄conv_quantile0.90►
◄probe_offset32►
◄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_cachefalse►
◄chunk_large_layersfalse►
◄clamp_quantile0.99►
◄min_diff0.000►
◄mismatch_modeskip►
◄output_filenameextracted_lora►
◄save_dtypefp16►
◄devicecuda►
◄skip_patterns►
◄glob_skip_patternsfalse►
◄include_modefalse►

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 (30)

NameTypeDefaultDescription
model_aCOMBOFinetuned model (A - B = LoRA)
model_bCOMBOBase model (A - B = LoRA)
linear_quantileFLOAT0.900–1Target cumulative singular-value fraction for linear layers.
conv_quantileFLOAT0.900–1Target cumulative singular-value fraction for convolution layers.
probe_offsetINT321–4096Extra singular values sampled beyond Max Rank for a reliable bounded rank decision.
linear_max_rankINT1281–16384Maximum extracted rank for linear layers.
conv_max_rankINT1281–16384Maximum extracted rank for convolution layers.
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_cacheBOOLEANfalseClear CUDA cache after each layer; slower but useful under severe VRAM pressure.
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_modeCOMBOskipHandle missing or incompatible model tensors by skipping them, substituting zeros where supported, or aborting.
output_filenameSTRINGextracted_loraOutput filename without extension, written under ComfyUI's LoRA directory.
save_dtypeCOMBOfp16Data type used to save the extracted DoRA tensors.
deviceCOMBOcudaDevice used for extraction arithmetic; CUDA out-of-memory processing falls back per affected layer where supported.
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.
include_modeBOOLEANfalseUse Skip Patterns as a whitelist instead. Only matching layers are extracted; an empty whitelist extracts nothing.
layer_parametersoptMODELUTILS_LAYER_PARAMETERSOptional Layer Parameter Configuration. a=linear_quantile; b=conv_quantile; c=clamp_quantile; d=min_diff; e=linear_max_rank; f=conv_max_rank Full names are also accepted. Unassigned values use this node's settings; existing filters still apply.

Outputs (1)

NameTypeDescription
output_path*—