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

TE DoRA Extract (Quantile)

DoRA for text encoders, rank by quantile

By silveroxides·Created 2 years ago·Updated 3 days ago· 17
TE DoRA Extract (Quantile)
  • layer_parameters
  • output_path
◄model_a▾►
◄model_b▾►
◄linear_quantile0.90►
◄conv_quantile0.90►
◄probe_offset32►
◄linear_max_rank128►
◄conv_max_rank128►
◄lazy_loadtrue►
◄force_clear_cachefalse►
◄chunk_large_layersfalse►
◄clamp_quantile0.99►
◄min_diff0.000►
◄mismatch_modeskip►
◄output_filenameextracted_te_lora►
◄save_dtypefp16►
◄devicecuda►
◄skip_patterns►
◄glob_skip_patternsfalse►
◄include_modefalse►

DoRA's whole idea - from NVIDIA's "Weight-Decomposed Low-Rank Adaptation" paper - is to split a weight update into magnitude and direction, keep the two apart, and low-rank-approximate only the direction. The text-encoder DoRA extractors in ModelUtils do exactly that, and the quantile variant picks each layer's rank by asking "how much of the singular value mass do I want back?" - 90% by default.

So how's the extraction different from the LoRA flavor? Regular LoRA extraction just subtracts: delta = A - B, then SVD. This node's dora_difference step is sneakier. It rescales each row of the fine-tuned encoder A up to the row magnitude of the base B before subtracting, so the low-rank part captures the direction change, and the per-row magnitude is peeled off into a separate dora_scale tensor. The output file carries lora_A, lora_B, and a dora_scale per layer - the magnitude and direction are literally stored as separate things, which is the DoRA signature.

Honest caveat before you get invested: trained DoRA adapters never really hit critical mass in the community - the per-adapter magnitude term is what breaks stacking, which is the property people actually buy from LoRAs. For extraction specifically, that concern is softer: you're distilling an existing delta, not composing fresh adapters. Still, if you're not sure DoRA matters to you, the LoRA equivalents do the same job with fewer concepts in play.

The inputs that matter

  • model_a / model_b - fine-tuned and base encoders from models/text_encoders.
  • linear_quantile / conv_quantile - the cumulative singular-value target for linear/attention vs convolution layers (default 0.9). The rank logic is byte-for-byte the same as the LoRA Quantile node - keep enough singular values of the direction delta to hit the target fraction.
  • linear_max_rank / conv_max_rank - caps (default 128).
  • probe_offset - extra singular values sampled past the cap so the percentile decision is made on a full-enough spectrum.
  • output_filename / save_dtype / device / lazy_load / force_clear_cache - the shared family knobs: output name in your loras folder, save precision (fp16 default), compute device with per-layer CPU fallback on OOM, streaming memory.

The single output output_path reports where the file landed; it's an output node, so nothing follows it.

Install

ComfyUI Manager → "Model Utility Toolkit", or:

cd ComfyUI/custom_nodes
git clone https://github.com/silveroxides/ComfyUI-ModelUtils
cd ComfyUI-ModelUtils
pip install -r requirements.txt

Restart, and it's under ModelUtils/DoRA Extract (TE). unifiedefficientloader is the dependency doing the streaming work.

Gotchas

The usual silent-skip warning applies (mismatch_mode: skip is default - wrong base, empty file, no error), and this is a full SVD per layer, so expect a real runtime. One DoRA-specific quirk: if you compare against a mismatched base, the direction/magnitude split stops being meaningful, so the "silently wrong" failure is easier to miss than on the LoRA side. And dora_scale support depends on your LoraLoader knowing what to do with it - if you load the file and get nothing, check that your loader handles DoRA keys rather than assuming the extraction failed.

CategoryModelUtils/DoRA Extract (TE)

Inputs (20)

NameTypeDefaultDescription
model_aCOMBOFinetuned Text Encoder model (A - B = LoRA)
model_bCOMBOBase Text Encoder 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.
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 text-encoder tensors by skipping them, substituting zeros where supported, or aborting.
output_filenameSTRINGextracted_te_loraOutput filename without extension, written under the ComfyUI LoRA directory.
save_dtypeCOMBOfp16Data type used to save extracted text-encoder LoRA factors.
deviceCOMBOcudaDevice used for per-layer extraction arithmetic; CUDA out-of-memory retries the affected layer on CPU 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*—