😺NKD LoRA Control
Half Your LoRA Is Dead Weight — 😺NKD LoRA Control Shows You Which Half
- model
- positive
- negative
- MODEL
- positive
- negative
The problem this solves
A LoRA isn't one blob. It's dozens of small weight patches, one per transformer block, and they aren't equally important. Two might be doing 80% of the character likeness while the rest quietly nudge your style and background. That's why stacking three LoRAs so often turns to mud: every adapter smears itself across blocks that had nothing to do with what you wanted.
😺NKD LoRA Control scores each block by how much of the LoRA it actually carries, then lets you mute, boost or schedule blocks before the sampler sees them. Same job as ShootTheSound's Realtime-Lora node, which the author credits as where per-block analysis as a ComfyUI node started - except this one reads block names out of the file, with no architecture table.
How it works
It opens the .safetensors and derives block identity from the tensor key itself - <group>_<index> - so transformer_blocks.12 and single_transformer_blocks.12 separate for free. Impact per block is the Frobenius norm of the weight delta the LoRA adds, computed with a Gram trick instead of materialising the full product. Scores are relative to the strongest block in the file, which always reads 100. Plain LoRA, LoHa, LoKR and full-diff formats are all recognised.
Muting a block drops its tensors from the weights entirely. Setting one to 0.5 scales one factor of each up/down pair, so the multiplier applies once instead of squaring itself; negative values push against what the LoRA learned there. It's tested across FLUX, Klein, Wan, Qwen, Krea, MiniMax H3, SDXL and SD 1.5 - pick a LoRA and the block list appears without running the graph.
Inputs and outputs
Four you actually set:
- model - your checkpoint or UNET output.
- lora_name - the file to load and analyse.
- strength - overall, −10 to 10. Multiplies the curve when one is connected.
- blocks - a string the block panel writes for you. Leave it alone unless you enjoy editing rule text.
Optional: curve - a float list, one value per sampling step (the floats output of 😺NKD Sigmas Curve, from the author's separate Sigmas Curve pack). positive and negative take your conditioning and only appear once a curve is wired, because ComfyUI hooks hang off the conditioning, not the model; wire a curve without them and the node raises rather than silently ignoring you.
Outputs are MODEL (to your KSampler) plus the positive/negative pair the schedule rides on.
The panel is where the work happens. Drag down the checkbox column to kill a run of blocks, and the Impact ≥ filter mutes everything under a threshold until only the load-bearing blocks are left. Save LoRA bakes the shape into a normal .safetensors any loader can take at 1.0 - muted blocks aren't written, so it gets smaller. The curve can't be baked in: a weights file has nowhere to put something that changes across the sampling run.
One thing worth knowing: no fixed "high impact preset" ships with it, on purpose. On twelve Klein LoRAs, the high-impact block range another pack ships was the strongest range in only two of them. Which blocks carry a LoRA depends on what was trained, not the architecture.
Installing it
ComfyUI Manager → search NKD Basic Tools → install → restart. Or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/Nekodificador/ComfyUI-NKD-Basic-Tools
No model downloads for this node. But the pack declares onnxruntime and huggingface_hub for its Face Rig and crop nodes, so you pull a chunky onnxruntime wheel whether or not you touch a face. Python 3.10+.
Where people get burned
Curve on a quantised model. ComfyUI's hook system walks weights assuming plain nn.Linear, which blows up on GGUF and fp8 layers. The node detects those, applies the LoRA at a flat strength instead, and says so on a line under the panel. Graceful - but if your schedule "isn't doing anything" on a GGUF checkpoint, that's why.
Wrong base model. Muting blocks won't save a LoRA trained for the wrong architecture - an Illustrious LoRA on Flux does nothing, and Pony/Illustrious/SDXL LoRAs stay selectable while often being incompatible. Test with and without, same seed, before blaming the panel.
It's model-only. Per-block shaping patches the diffusion model; the hook path sets CLIP strength to 0.0. If an SDXL-era LoRA needs its text encoder shaped, this won't do it.
blocks is state, not a setting. Hand-edit it past the panel and the impact readout flips to off, because the pattern is no longer a clean threshold. Presets are the portable way to move a setup between LoRAs: a rule naming a block the file doesn't have is skipped, so one saved on a 38-single FLUX LoRA applies cleanly to a 24-single Klein one.
The strongest use case is LoRA bleed on multi-LoRA stacks. Killing the low-impact blocks is how you keep a style LoRA out of your character's face.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| lora_name | COMBO | LoRA file to load and analyse | |
| strength | FLOAT | 1.00-10–10 | Overall LoRA strength. Multiplies the curve when one is connected. |
| blocks | STRING | Per-block rules, written by the panel | |
| curveopt | FLOAT | Strength over sampling steps, as a float list (e.g. the 'floats' output of 😺NKD Sigmas Curve). | |
| positiveopt | CONDITIONING | — | |
| negativeopt | CONDITIONING | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| MODEL | MODEL | — |
| positive | CONDITIONING | — |
| negative | CONDITIONING | — |