LC LoRA Extract
Finetune minus base, compressed into a LoRA
- finetuned
- base
- report
What it does
Takes a finetune and the base model it was built on, subtracts one from the other, and compresses the difference into a LoRA. That's it. You wire in finetuned and base, hit queue, and get a file in models/loras.
Why bother? Because a 25 GB finetune is a terrible thing to distribute or stack, and its actual change from the base is a small fraction of that. This is the standard trick - diff the checkpoints, SVD the difference - the same thing people describe in forum answers as "merge the lora with the model it's intended for, then produce a lora from the difference", except it's one node instead of a night of Kohya scripts. The author used it to produce the Krealism Turbo and Raw LoRAs.
How it works
For each layer in both models it computes finetuned - base, compresses that with SVD down to at most rank, and writes the result in the same key layout ComfyUI's own LoRA saver uses: diffusion_model.<layer>.lora_up / lora_down, with .diff_b for biases. Any LoRA loader reads it, no special node required.
Layers that didn't meaningfully change are left out entirely, so the file contains only what the finetune actually altered. Both models can be in any precision - bf16, fp8, int8, nvfp4, GGUF - because the weights are decoded to full precision before the subtraction.
The settings
parts picks what goes in. all layers is the whole difference. blocks only keeps just the numbered blocks - on Krea 2 that drops text fusion and the embedding layers, which is the version that works when the LoRA is meant for Krea 2 Raw. custom blocks uses the blocks string, which takes ranges and singles like 14-27 or 4-9, 16, 20-22.
rank (default 256) is the ceiling, not a promise: no layer uses more than that, and layers needing less stay smaller. keep (default 0.90) is how much of each layer's change survives - higher is closer to the finetune and a bigger file. The author's own figure for Krealism is 256 at 0.90, which matched the full model on Turbo. min_change (default 0.001) is the floor below which a layer counts as untouched; 0.001 skips bf16 rounding noise without eating real changes.
Then filename (saved under models/loras, and it never overwrites - a number gets appended), save_dtype (bf16 or fp16), plus enabled and embed_workflow and the optional metadata switch. Output is a single report telling you what got written.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/lonecatone23/ComfyUI_LC_ModelBuilder_nodes
Restart. Nothing extra to install - this node uses safetensors, torch and ComfyUI core, which you already have.
Where people get burned
Extract from bf16 versions of both models. If either side is quantized it gets decoded first, but that rounding stacks on top of your new one, so the report ends up with a bigger file holding noise. The node warns you, which is better than most tools manage.
Second, this is an approximation. SVD throws away the small directions, and keep below 1.0 throws away more deliberately, so a LoRA extracted at rank 64 will not reproduce the finetune exactly - it will reproduce the parts you kept. Sanity-check with a fixed seed against the full model before you delete the finetune.
Third, embed_workflow defaults on. Turn it off (or set metadata to necessary only) before you share the file, unless you want your exact node graph riding along inside it.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| finetuned | MODEL | The finetune or merge (e.g. Krealism). Any precision. | |
| base | MODEL | The model it was built on (e.g. Krea 2 Turbo). Any precision. | |
| parts | COMBO | all layers | all layers = the whole difference. blocks only = just the numbered blocks (on Krea 2 this leaves out text fusion and the embedding layers; use it for a LoRA meant for Krea 2 Raw). custom blocks = the list below. |
| blocks | STRING | 14-27 | Used with custom blocks: ranges and single numbers, e.g. 14-27 or 4-9, 16, 20-22. |
| rank | INT | 2561–4096 | Highest rank any layer may use. Layers that need less stay smaller. |
| keep | FLOAT | 0.900.5–1 | How much of each layer's change to keep (0.90 = 90%). Higher = closer to the finetune, bigger file. Krealism: 0.90 at rank 256 matched the full model. |
| min_change | FLOAT | 0.00100–0.1 | Layers that changed less than this (relative to the layer) count as unchanged and are left out. 0.001 skips bf16 rounding noise. |
| filename | STRING | Krea 2/Your Loras/extracted_lora | Saved under models/loras. A number is added instead of overwriting. |
| save_dtype | COMBO | bf16 | 2 options: bf16, fp16 |
| enabled | BOOLEAN | true | Off = skip the save entirely (no file written), without physically bypassing the node. Convert to an input to gate saving from a switch elsewhere in the graph. |
| embed_workflow | BOOLEAN | true | Include the prompt and workflow JSON in the saved file's metadata. Turn off before sharing/publishing a checkpoint if you don't want your exact node graph attached. |
| metadataopt | COMBO | keep all | keep all = everything this save normally writes (with embed_workflow on, your whole node graph). necessary only = just what loading needs (quant settings, if any) plus the architecture and trigger words: no workflow, no training details, no titles or edit notes. Use it before sharing a file. |
| applied_lorasopt | BOOLEAN | false | included = read each layer as it really runs, with the LoRAs, merges and patches on the MODEL wire applied (LC LoRA Loader, LoRA Editor...). Extract 'Krealism + 3 LoRAs' as one LoRA. file weights only = the model files' own weights (the old behaviour). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| report | STRING | — |