Multi LoRA Stack Ortho (Model Only)
The LoRA stacker that tries to stop LoRAs fighting each other
- model
- MODEL
Everyone who stacks LoRAs learns the same lesson the hard way: put a character LoRA on top of a style LoRA and the result is muddy. Neither lands right, the character drifts, the style half-appears. The standard advice is to shrug and lower both strengths to 0.6, add them one at a time with a fixed seed, and hope. Multi LoRA Stack Ortho (Model Only) is the one node in the ComfyUi-DuoNodes pack that actually tries to fix the mechanism instead of the workflow around it.
What it actually is
It's a "model only" LoRA stacker - you feed it one MODEL, it applies a stack of LoRAs, you get one patched MODEL back. Nothing exotic there; it's the same job rgthree's Power Lora Loader or a chain of Load LoRA nodes do. What's different is the merge_method widget. Set to sequential and it behaves like the plain stacking node in the same pack. Set to ortho_gs (the default) and it runs Gram-Schmidt orthogonalization over your LoRAs' down matrices before applying them, in an attempt to remove the interference term between them.
It's the only one of the pack's three nodes worth getting excited about. The other two are convenient wrappers; this one is an experiment with a real idea behind it.
How the ortho trick works
When two LoRAs stack additively you're really doing ΔW = s₁(A₁B₁) + s₂(A₂B₂). Each LoRA's low-rank factor pair A·B reads from some set of input directions via the down matrix B. If two B matrices read from overlapping directions, the adapters partially cancel or amplify each other - that's the interference you can feel when stacking two character LoRAs.
The ortho mode fixes this at load time: the first LoRA's down matrix is kept as-is and its row space becomes the committed basis. Each later LoRA's down matrix has its rows projected onto the orthogonal complement of everything committed before it (the source does this with an SVD/QR under the hood). Result: each LoRA reads from input directions the earlier ones ignore, and the interference term disappears. Up matrices, alphas, and your strength settings are untouched.
The two gotchas are in the README and they're honest ones. Order matters - the first LoRA in the stack is unmodified, everyone after gives way, so put your most important LoRA first. And a later LoRA can lose magnitude when its target subspace is already covered by an earlier one. That's the price of removing the fight.
Inputs and outputs
model(MODEL, required) - the checkpoint, straight from a Checkpoint Loader. Model-only means no CLIP, which is fine for Flux and for SDXL LoRAs that only touch the UNet.lora_stack(STRING) - the JSON config widget. You normally never touch this; the UI's ➕ Add LoRA button and per-slot enable toggles, dropdown, and strength slider manage it for you. Structure is[{ "on": true, "lora": "name.safetensors", "strength": 1.0 }, ...].merge_method-ortho_gsorsequential. Set it tosequentialto A/B the two modes on the exact same stack in place; the README says it reproduces the plain node exactly.strength_1…strength_10(optional FLOAT, -2.0 to 2.0) - wire a FLOAT in from a scheduler or primitive and it overrides that slot's slider. Skip them and the sliders rule.- Output: a single
MODEL, wired into your sampler's model input.
One more honest note: ortho mode only does anything when your LoRAs actually share model keys. Check the console for the ortho keys: N, pass-through: M line - if everything is passing through, there's nothing to orthogonalize and you'll see no difference.
Installing it
No dependencies, no model files, pure Python plus a bit of JS. Via ComfyUI Manager, search ComfyUi-DuoNodes; or by hand:
cd ComfyUI/custom_nodes/
git clone https://github.com/UndefinedUo/ComfyUi-DuoNodes.git
Restart ComfyUI fully. The nodes appear under loaders. If the UI looks wrong after an update, hard-refresh with Ctrl+F5 to clear the cached JS. If the node doesn't appear at all, check the ComfyUI console for import errors - this is a small pack, so a missing node means the import failed, not that you forgot a dependency.
The verdict
This is a niche, genuinely under-the-radar node - you won't find it discussed anywhere, and the OrthoLoRA idea it ports comes from training-side code (anima_lora) with almost no community footprint. Treat it as an experiment for the specific case that drives you nuts: two LoRAs with similar subjects or styles that keep clobbering each other. For everyday "load three LoRAs" work, the boring Power Lora Loader is still the default. But if you've ever stacked two character LoRAs and watched both fall apart, this is the first node that does something smarter than telling you to turn the dial down.
Inputs (13)
| Name | Type | Default | Description |
|---|---|---|---|
| model | MODEL | — | |
| lora_stack | STRING | [] | — |
| merge_method | COMBO | ortho_gs | 2 options: ortho_gs, sequential |
| strength_1opt | FLOAT | 1.00-2–2 | — |
| strength_2opt | FLOAT | 1.00-2–2 | — |
| strength_3opt | FLOAT | 1.00-2–2 | — |
| strength_4opt | FLOAT | 1.00-2–2 | — |
| strength_5opt | FLOAT | 1.00-2–2 | — |
| strength_6opt | FLOAT | 1.00-2–2 | — |
| strength_7opt | FLOAT | 1.00-2–2 | — |
| strength_8opt | FLOAT | 1.00-2–2 | — |
| strength_9opt | FLOAT | 1.00-2–2 | — |
| strength_10opt | FLOAT | 1.00-2–2 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| MODEL | MODEL | — |