Nodes/OmniNodes/DoRA Loader (Custom) 🎯
ComfyUI Node

DoRA Loader (Custom) 🎯

The DoRA loader that does the real decomposition, not a scaled LoRA β€” with honest limits

By TensorVizionΒ·Created 3 months agoΒ·Updated about 8 hours agoΒ· 0
DoRA Loader (Custom) 🎯
  • model
  • model
  • summary
β—„dora_nameβ–Ύβ–Ί
β—„strength1.00β–Ί

DoRA (weight-Decomposed Low-Rank Adaptation) is LoRA's cleverer cousin: instead of just adding a low-rank delta, it splits the update into a magnitude vector and a normalized direction. That decomposition is the whole point - the trained magnitude only makes sense relative to the normalization. So a DoRA file is not "a LoRA with a bonus scaling vector," and loading it through a plain LoRA loader (or worse, treating dora_scale as an extra strength multiplier) reproduces none of what was actually trained.

This node does the real math. It reads the file's standard LoRA keys plus the dora_scale magnitude vector, computes W' = m Β· (W0 + BA) / β€–W0 + BAβ€–_c - magnitude times the column-normalized base-plus-delta - and hands the resulting delta to ComfyUI's ModelPatcher.add_patches() API. Not a state-dict edit, not a scaled LoRA. It's verified against the defining property of the algorithm: post-merge weight row norms should equal the trained magnitude vector.

The inputs are model, dora_name (a dropdown of files in your loras/ folder - ComfyUI has no separate DoRA folder, the file is just a LoRA-format safetensors with the extra marker), and strength (default 1.0, blends the final delta uniformly toward 0 or past it). Outputs are the patched model and a summary string that reports what got applied and - this is the part to read - what got skipped.

Because the math needs each layer's original weight, there are real constraints you need to respect:

  • Linear/2D layers only. Conv2d (4D) weights - the ResBlock/UNet convs found in many real files - are not implemented and get reported as skipped. The effect on a full file is typically partial. Check summary before assuming the merge fully applied.
  • Apply it early. DoRA's normalization is computed against the model's current weights. If other patches already changed those same layers upstream in your graph, the math silently uses the already-patched weight. Put this node before other model-patching nodes, not after.
  • Confirm the format first. The pack ships a LyCORIS Format Inspector for exactly this: it reads the file's tensor key names and tells you whether it's really DoRA (has the dora_scale marker) or a plain LoRA. If this loader gets a plain LoRA, it'll tell you - it checks for the marker and returns a clear message rather than mis-merging.

Why bother, when ComfyUI's built-in loader sometimes handles these files? Because built-in LyCORIS auto-detection has a documented issue (ComfyUI #8683) where LoHa/LoKr/DoRA files can be silently routed through the plain-LoRA merge path - technically running, mathematically wrong. Loading explicitly through this node avoids betting on that auto-detection. That's the strongest argument for it.

The wider context, honestly: DoRA never reached LoRA's critical mass. The community's verdict was that per-adapter magnitude breaks stacking - you can't pile DoRAs the way you can LoRAs - and likeness gains didn't reliably reproduce, so its corpus presence stayed small. That doesn't make this loader wrong; it makes DoRA a niche you'd only seek out deliberately, and if you do, this is the rare node that executes it faithfully.

Install

Part of OmniNodes:

cd ComfyUI/custom_nodes
git clone https://github.com/TensorVizion/OmniNodes

Restart ComfyUI (or ComfyUI Manager β†’ "OmniNodes"). No extra dependencies.

Troubleshooting

  • "has standard LoRA keys but NO dora_scale marker" - the file is a plain LoRA. Use a normal LoRA loader.
  • summary shows skipped Conv2d layers - expected. Linear layers applied, convs didn't. Decide whether the partial effect is acceptable before building a workflow on it.
  • Unexpected results - check whether another patch node ran on the same model before this one in the graph, and reorder.
CategoryTensorVizion/Model

Inputs (3)

NameTypeDefaultDescription
modelMODELβ€”
dora_nameCOMBO0 options:
strengthFLOAT1.00-5–5β€”

Outputs (2)

NameTypeDescription
modelMODELβ€”
summarySTRINGβ€”