From fcc6e5cc4a6d0232eedeaab4cc0103b13078a6c7 Mon Sep 17 00:00:00 2001 From: silveroxides Date: Fri, 2 Oct 2026 21:08:16 +0200 Subject: [PATCH] Support lora.down and lora.up factor suffixes --- nodes/minimax_h3_lora_convert.py | 6 ++++-- tests/test_minimax_h3_lora_convert.py | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/nodes/minimax_h3_lora_convert.py b/nodes/minimax_h3_lora_convert.py index 4930cf5..8609ecb 100644 --- a/nodes/minimax_h3_lora_convert.py +++ b/nodes/minimax_h3_lora_convert.py @@ -15,7 +15,7 @@ from .quantization_guard import inspect_low_bit_input from .uel_io import atomic_uel_writer _FACTOR_RE = re.compile( - r"^(?P.+)\.lora_(?P[AB])(?:\.default)?\.weight$" + r"^(?P.+)\.(?:lora_(?P[AB])|lora\.(?Pdown|up))(?:\.default)?\.weight$" ) _BLOCK_RE = re.compile(r"^transformer_blocks\.(?P\d+)\.(?P.+)$") _REFINER_RE = re.compile(r"^token_refiner\.refiner_blocks\.(?P\d+)\.(?P.+)$") @@ -93,7 +93,9 @@ def _build_plan(keys: list[str]) -> list[_ConversionUnit]: f"Input is not a compatible MiniMax H3 Diffusers PEFT LoRA; unsupported key: {key}" ) mod = match.group("module") - factor = match.group("factor") + factor = match.group("factor_ab") or ( + "A" if match.group("factor_word") == "down" else "B" + ) pair = factors.setdefault(mod, {}) if factor in pair: raise ValueError(f"Duplicate LoRA factor for: {mod}") diff --git a/tests/test_minimax_h3_lora_convert.py b/tests/test_minimax_h3_lora_convert.py index 22655ab..e9c36b8 100644 --- a/tests/test_minimax_h3_lora_convert.py +++ b/tests/test_minimax_h3_lora_convert.py @@ -176,3 +176,29 @@ def test_node_schema_and_execution_contract(converter, monkeypatch, tmp_path): assert result.args[0] == "sub/converted_h3.safetensors" assert "MiniMax H3 Diffusers LoRA conversion complete" in result.args[1] assert (loras_dir / "sub" / "converted_h3.safetensors").is_file() + + +def test_lora_down_up_suffixes_supported(converter, tmp_path): + source = tmp_path / "source_down_up.safetensors" + output = tmp_path / "output_down_up.safetensors" + + original = _make_source_tensors("transformer_blocks.0") + # Replace .lora_A/.lora_B with .lora.down/.lora.up on attention layers (DMAD format) + modified = {} + for k, v in original.items(): + if ".attn." in k: + k = k.replace(".lora_A.default.weight", ".lora.down.weight") + k = k.replace(".lora_B.default.weight", ".lora.up.weight") + else: + k = k.replace(".default.weight", ".weight") + modified[k] = v + + save_file(modified, str(source)) + report = converter.convert_minimax_h3_diffusers_lora(str(source), str(output)) + assert "MiniMax H3 Diffusers LoRA conversion complete" in report + converted = load_file(str(output)) + + assert "diffusion_model.blocks.0.attn.qkv_proj.lora_A.weight" in converted + assert "diffusion_model.blocks.0.attn.qkv_proj.lora_B.weight" in converted + assert "diffusion_model.blocks.0.mlp.fc1.lora_A.weight" in converted + assert "diffusion_model.blocks.0.mlp.fc1.lora_B.weight" in converted