Nodes/Model Utility Toolkit/TE LoRA Extract (Frobenius)
ComfyUI Node

TE LoRA Extract (Frobenius)

Keep X% of the Frobenius norm

By silveroxides·Created about a year ago·Updated about 24 hours ago· 14
TE LoRA Extract (Frobenius)
    • output_path
    model_a
    model_b
    linear_target0.90
    conv_target0.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

    Think of a LoRA's job as "reproduce this finetune delta as faithfully as possible for the file size." The Frobenius variant of ModelUtils' TE extractors is the one that's most honest about that trade, because it measures the delta in the way that actually predicts reconstruction error: energy. Tell it to preserve 90% of the Frobenius norm and it picks whatever rank each layer needs to get there.

    In practice this works like the pack's other extract nodes - A - B per .weight tensor, SVD, write lora_A/lora_B factors to your loras folder - with one twist in the rank math. SVD orders a matrix's "energy" in its singular values: the squared singular values sum to the squared Frobenius norm, so if you keep the top k singular values, you know exactly what fraction of the layer's total energy you've preserved. The node keeps adding singular values until the retained energy crosses your target. No guessing, no curve-reading - just "I want this much of the signal, figure out the rank."

    One subtlety worth knowing: the target is computed relative to what's achievable within linear_max_rank/conv_max_rank, not the layer's full theoretical spectrum. So the knob reads as "retain X% of what a rank-128 LoRA could hold," which is a sensible contract - it means the cap and the target compose instead of fighting.

    The inputs that matter

    • model_a / model_b - fine-tuned and base encoders from models/text_encoders.
    • linear_target / conv_target - the retained-energy fraction for linear/attention vs convolution layers (default 0.9). 0.9 is a solid starting point; nudge toward 0.99 for high-fidelity extraction, or down toward 0.7 for maximum compression.
    • linear_max_rank / conv_max_rank - the caps (default 128) that the energy target is measured against.
    • probe_offset - extra singular values sampled beyond the cap so the energy calculation sees a full-enough spectrum.
    • output_filename / save_dtype / device / lazy_load / force_clear_cache - the family standard: output name (in loras), save precision (fp16 default), compute device with per-layer CPU fallback on OOM, and streaming memory behavior.

    It's an output node; output_path reports where the file was written.

    Install

    ComfyUI Manager → search "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; the node lives under ModelUtils/LoRA Extract (TE). The important runtime dependency is unifiedefficientloader, which streams both encoders so memory stays flat during the run.

    Gotchas

    Same family traps: mismatch_mode: skip is the default, so comparing against the wrong base produces a small, silent, useless file instead of an error. Full SVD per layer means a progress bar and minutes of patience. If the math of "energy" feels like overkill and you just want a rank, use the Fixed node; if you want zero knobs at all, the Knee variant reads the spectrum for you. Frobenius is the one you reach for when you actually care about the fidelity-to-size trade and want it phrased in the quantity that predicts it.

    CategoryModelUtils/LoRA Extract (TE)

    Inputs (18)

    NameTypeDefaultDescription
    model_aCOMBOFinetuned Text Encoder model (A - B = LoRA)
    model_bCOMBOBase Text Encoder model (A - B = LoRA)
    linear_targetFLOAT0.900–1Target Frobenius-norm fraction retained for linear layers.
    conv_targetFLOAT0.900–1Target Frobenius-norm fraction retained 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*