Nodes/Model Utility Toolkit/DoRA Extract (Fixed Rank)
ComfyUI Node

DoRA Extract (Fixed Rank)

Pull an adapter out of a base/finetune pair at a rank you choose

By silveroxides·Created 2 years ago·Updated 3 days ago· 17
DoRA Extract (Fixed Rank)
  • layer_parameters
  • output_path
◄model_a▾►
◄model_b▾►
◄linear_dim64►
◄conv_dim32►
◄svd_niter2►
◄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►

Full fine-tuning genuinely produces better results than LoRA training, and the community has never really disputed that - the reason people train LoRAs anyway is that fine-tuning a whole checkpoint is expensive and a LoRA is cheap to store and share. This node is the middle path taken after the fact instead of during training: hand it a base checkpoint and a fine-tune of it, and it computes the difference and compresses that difference into a low-rank adapter, at a rank you specify directly. It's the classic "extract a LoRA from a diff" operation this pack's README credits to kohya-ss/sd-scripts' lineage, applied here to produce a DoRA-format adapter specifically rather than a plain LoRA.

How it works

model_a and model_b are your two inputs, and their tooltips spell out the direction unambiguously: model_a is "Finetuned model (A - B = LoRA)", model_b is "Base model (A - B = LoRA)." Get them backwards and you're extracting the negative of what you meant, which the math handles but which will confuse you when you go to apply it.

linear_dim (default 64) and conv_dim (default 32) are the fixed ranks - set separately because attention/linear layers and convolutional layers behave differently under SVD compression, and the pack's own README lists "Fixed" rank as one of five rank-selection strategies it ships (alongside Ratio, Quantile, Knee-detection, and Frobenius-norm - see DoRAExtractFrobenius in this same pack for the adaptive alternative). Higher rank keeps more of the original difference's fidelity at the cost of a bigger output file; lower rank is more compact and lossier. svd_niter (default 2) controls SVD power iterations - the tooltip is direct: higher is "more accurate but slower."

A handful of settings tune the extraction quality and memory footprint: clamp_quantile (default 0.99) clips outlier singular values so a few extreme weights don't dominate the compressed result; min_diff (default 0) skips layers where the base and fine-tune barely differ, which is a legitimate speed and size win - those layers weren't meaningfully touched by the fine-tune anyway. chunk_large_layers (off by default) splits big fused layers (QKV, MLP blocks) into chunks, useful on tighter VRAM budgets. lazy_load and force_clear_cache (both default on) manage memory the same way they do throughout this pack. mismatch_mode (default skip) handles tensors that exist in one model but not the other. skip_patterns (regex, or glob with glob_skip_patterns) lets you exclude specific layers from extraction entirely. save_dtype (default fp16) and device (default cuda) round it out. Output is a single output_path string (output_filename default extracted_lora), and it's a save node - this writes the file when it runs.

Installing it

ComfyUI Manager: search Model Utility Toolkit, install, restart. Or:

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

Restart ComfyUI. No downloads needed beyond the two model files you're extracting from.

Where people get burned, and the honest take on DoRA

Get model_a/model_b swapped and the extraction still runs - SVD doesn't care which direction you fed it - but the resulting adapter applies the inverse of the change you wanted. If applying the extracted DoRA makes your output look less like your fine-tune, not more, that's the first thing to check.

The bigger thing to know before you commit time to this: DoRA had a real moment of enthusiasm - "LoRAs and fine tunes are dead to me, all hail DoRA" was a genuine sentiment in 2024 - and it never converted into mainstream adoption. The community's honest, repeated experience is that DoRA adapters don't stack well with each other, and that likeness reproduction is dataset-dependent rather than reliably better than a plain LoRA extracted the same way. If you're extracting this to combine with other adapters later, know going in that stacking is the documented weak point, not a hypothetical one.

CategoryModelUtils/DoRA

Inputs (18)

NameTypeDefaultDescription
model_aCOMBOFinetuned model (A - B = LoRA)
model_bCOMBOBase model (A - B = LoRA)
linear_dimINT641–16384Rank for linear/attention layers
conv_dimINT321–16384Rank for conv layers
svd_niterINT20–10SVD power iterations (higher = more accurate but slower)
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_dim; b=conv_dim; c=clamp_quantile; d=min_diff Full names are also accepted. Unassigned values use this node's settings; existing filters still apply.

Outputs (1)

NameTypeDescription
output_path*—