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

TE DoRA Extract (Quantile)

DoRA for text encoders, rank by quantile

By silveroxides·Created about a year ago·Updated about 24 hours ago· 14
TE DoRA Extract (Quantile)
    • 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

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

    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.

    Outputs (1)

    NameTypeDescription
    output_path*