ai-toolkit stores the DoRA magnitude as `<layer>.magnitude`, a suffix the
Krea-2 converter's suffix table did not know. The key fell through to the
generic rsplit fallback, so every magnitude in a block was grouped into a
bogus parent layer and conversion failed with "Unsupported lora format:
dict_keys(['to_gate.magnitude', 'to_k.magnitude', ...])".
Two DoRA magnitude conventions exist and they index different axes of the
(out_features, in_features) weight:
- LyCORIS/kohya `.dora_scale` indexes in_features (norm over the out dim)
- PEFT/diffusers/ai-toolkit `.lora_magnitude_vector.weight` and
`.magnitude` index out_features (norm over the in dim)
DoRALayer only implemented the LyCORIS variant, so the pre-existing
`.lora_magnitude_vector.weight` -> `dora_scale` mapping was mis-oriented:
silently wrong weights on square layers, a broadcast error on the rest.
Carry the orientation explicitly on DoRALayer rather than guessing it from
the tensor shape, map `.magnitude`, and route both PEFT-style keys to the
out-dim path. Verified against ai-toolkit's own forward pass (max deviation
1.4e-6) and end-to-end on Krea-2-Raw.
Closes invoke-ai#9515
Summary
fix: Krea-2 DoRA LoRAs trained with ai-toolkit fail to load with ValueError: Unsupported lora format: dict_keys(['to_gate.magnitude', 'to_k.magnitude', 'to_q.magnitude', 'to_v.magnitude']).
Why. ai-toolkit stores the DoRA magnitude as <layer>.magnitude, a suffix the Krea-2 converter's suffix table didn't know. The key fell through to the generic rsplit fallback, so every magnitude in an attention block got grouped into a bogus parent layer (...attn) whose sub-keys were to_q.magnitude, to_k.magnitude, … — exactly the dict shown in the error.
While fixing that, a second, pre-existing bug surfaced. Two mutually incompatible DoRA magnitude conventions exist, and they index different axes of the (out_features, in_features) weight:
DoRALayer only implemented the LyCORIS math (norm over the output dim). The existing .lora_magnitude_vector.weight -> dora_scale mapping therefore applied a PEFT magnitude with LyCORIS math: silently wrong weights on square layers, and a broadcast error on non-square ones (e.g. Krea-2's ff.down, 6144 × 16384).
How.
The Krea-2 model-config probe already accepted these files, so no identification changes were needed.
Related Issues / Discussions
Closes #9515
Distinct from #9424 (Krea-2 LoKr/LyCORIS support), which is not addressed here.
QA Instructions
Test adapter: https://huggingface.co/khronex/krea2-dora-ehrmantraut-test (ai-toolkit 0.10.17, network.type: dora, native/ComfyUI key layout, 256 modules / 768 tensors)
End-to-end (this is the reproducer from the issue)
Verified on an RTX 4090, Krea-2-Raw (fp8_storage: true), 1024×1024, 28 steps, CFG 4.5, seed 1234, identical prompt with and without the LoRA. The subject identity changes as expected while the composition stays put. Server log for the LoRA run shows krea2_lora_loader executing, and zero Failed to find module for LoRA layer key warnings — all 256 layers patch onto real modules.
Structural check
All 256 converted patch keys were resolved against a meta-device Krea2Transformer2DModel (stock config): 0 missing modules, 0 shape mismatches, including magnitude length == out_features.
Numeric check
The merged weight was compared against ai-toolkit's own forward pass (ToolkitModuleMixin.forward + DoRAModule.apply_dora) for out < in, square, and out > in layers — max absolute deviation 1.4e-6.
Unit tests
New tests/backend/patches/layers/test_dora_layer.py covers both magnitude conventions (the out-dim test asserts equivalence with the ai-toolkit reference formula); test_krea2_lora_conversion_utils.py gains an ai-toolkit .magnitude regression test plus orientation assertions on the existing DoRA tests.
Merge Plan
Normal merge — backend only, no DB or schema changes.
Note the behavior change for adapters that were already loading: Krea-2 LoRAs with .lora_magnitude_vector.weight (PEFT/Diffusers DoRA) previously had their magnitude applied along the wrong axis. Square layers will now produce different — correct — output; non-square ones previously raised a broadcast error.
Checklist