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

TE LoRA Extract (Knee)

The LoRA node that picks its own rank

By silveroxides·Created about a year ago·Updated about 24 hours ago· 14
TE LoRA Extract (Knee)
    • output_path
    model_a
    model_b
    knee_methodsv_knee
    knee_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

    Every LoRA extractor in this pack makes you answer one question: what rank? This one answers it for you. Feed it a fine-tuned text encoder and its base, and it looks at each layer's singular value curve, finds where the curve elbows over - the "knee" - and cuts the rank there. The full rank-selection menu in ModelUtils' TE extractors is the single most useful default to reach for when you don't want to think about rank at all.

    Here's the idea. When you decompose the A - B weight delta with SVD, you get a descending list of singular values. Early ones carry real signal; the tail is numeric dust. Plot that curve and there's usually a visible bend where "meaningful" turns into "noise." Knee detection finds that bend automatically and keeps everything above it. The node computes the full picture per layer, so each layer gets its own natural rank - attention layers that need more capacity get more, layers with nothing going on get almost nothing.

    You get two flavors via knee_method:

    • sv_knee (default) - finds the elbow on the raw singular value curve, the classic "bend in the spectrum."
    • sv_cumulative_knee - finds the elbow on the cumulative curve instead, which behaves differently when a few big singular values dominate the rest.

    The inputs that matter

    • model_a / model_b - fine-tuned and base encoders from models/text_encoders.
    • knee_method - above.
    • linear_max_rank / conv_max_rank - caps (default 128) that keep the automatic rank from ever running away on a weird layer. The knee detector can't exceed these.
    • knee_probe_offset - extra singular values probed beyond the cap so the detector doesn't mistake the edge of the truncated spectrum for a knee. If your ranks keep landing suspiciously exactly at the cap, bump this.
    • output_filename / save_dtype / device / lazy_load / force_clear_cache - the shared family knobs: where the LoRA lands (your loras folder), save precision (fp16 default), compute device with per-layer CPU OOM fallback, and memory streaming.

    The result is a normal PEFT-style LoRA (lora_A/lora_B keys) you load with a regular LoraLoader. It's an output node - output_path just tells you where the file went.

    Install

    ComfyUI Manager, search "Model Utility Toolkit". Or manually:

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

    Restart and it appears under ModelUtils/LoRA Extract (TE). Runtime dependency that matters here: unifiedefficientloader, which streams the two safetensors so memory stays flat.

    Gotchas

    Same family traps apply. mismatch_mode: skip is the default, so a wrong base quietly skips everything and hands you a useless little file. And because this mode runs the full SVD (it needs the whole spectrum to find the knee), it's among the slower extractors - give it a few minutes and a progress bar. If the automatic rank ever underdelivers, the honest fix isn't more knobs, it's falling back to the Fixed node with a rank you chose. But for the common case - "just extract it, I don't want to tune" - Knee is the one.

    CategoryModelUtils/LoRA Extract (TE)

    Inputs (17)

    NameTypeDefaultDescription
    model_aCOMBOFinetuned Text Encoder model (A - B = LoRA)
    model_bCOMBOBase Text Encoder model (A - B = LoRA)
    knee_methodCOMBOsv_kneeDetect the knee from raw singular values or their cumulative distribution.
    knee_probe_offsetINT321–4096Extra singular values probed beyond Max Rank to avoid detecting a false knee at the partial-spectrum boundary.
    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*