Skip to content

LoRA and checkpoint conversion util - #1236

Merged
dxqb merged 6 commits into
Nerogar:mergefrom
dxqb:convert_util
Feb 3, 2026
Merged

LoRA and checkpoint conversion util#1236
dxqb merged 6 commits into
Nerogar:mergefrom
dxqb:convert_util

Conversation

@dxqb

@dxqb dxqb commented Dec 30, 2025

Copy link
Copy Markdown
Collaborator

Draft to simplify and extend LoRA and checkpoint conversion

Example use (Flux2 pattern definition):

def diffusers_to_original(qkv_fusion):
    return [
        ("context_embedder", "txt_in"),
        ("x_embedder",       "img_in"),
        ("time_guidance_embed.timestep_embedder", "time_in", [
            ("linear_1", "in_layer"),
            ("linear_2", "out_layer"),
        ]),
        ("time_guidance_embed.guidance_embedder", "guidance_in", [
            ("linear_1", "in_layer"),
            ("linear_2", "out_layer"),
        ]),
        ("double_stream_modulation_img.linear", "double_stream_modulation_img.lin"),
        ("double_stream_modulation_txt.linear", "double_stream_modulation_txt.lin"),
        ("single_stream_modulation.linear",     "single_stream_modulation.lin"),
        ("proj_out",                            "final_layer.linear"),
        ("norm_out.linear", "final_layer.adaLN_modulation.1", swap_chunks, swap_chunks),
        ("transformer_blocks.{i}", "double_blocks.{i}",
            qkv_fusion("attn.to_q", "attn.to_k", "attn.to_v", "img_attn.qkv") + \
            qkv_fusion("attn.add_q_proj", "attn.add_k_proj", "attn.add_v_proj", "txt_attn.qkv") + [
            ("attn.norm_k.weight",       "img_attn.norm.key_norm.scale"),
            ("attn.norm_q.weight",       "img_attn.norm.query_norm.scale"),
            ("attn.to_out.0",            "img_attn.proj"),
            ("ff.linear_in",             "img_mlp.0"),
            ("ff.linear_out",            "img_mlp.2"),
            ("attn.norm_added_k.weight", "txt_attn.norm.key_norm.scale"),
            ("attn.norm_added_q.weight", "txt_attn.norm.query_norm.scale"),
            ("attn.to_add_out",          "txt_attn.proj"),
            ("ff_context.linear_in",     "txt_mlp.0"),
            ("ff_context.linear_out",    "txt_mlp.2"),
        ]),
        ("single_transformer_blocks.{i}", "single_blocks.{i}", [
            ("attn.to_qkv_mlp_proj", "linear1"),
            ("attn.to_out",          "linear2"),
            ("attn.norm_k.weight",   "norm.key_norm.scale"),
            ("attn.norm_q.weight",   "norm.query_norm.scale"),
        ]),
    ]

diffusers_lora_to_original = diffusers_to_original(lora_qkv_fusion)
diffusers_checkpoint_to_original = diffusers_to_original(qkv_fusion)
diffusers_lora_to_comfy = [remove_prefix("transformer"), diffusers_to_original(lora_qkv_fusion), add_prefix("diffusion_model")]


save_state_dict = convert(save_state_dict, diffusers_lora_to_comfy)

@yamatazen

This comment was marked as resolved.

@dxqb

dxqb commented Dec 30, 2025

Copy link
Copy Markdown
Collaborator Author

Can it merge LoRA to checkpoint?

no, not its purpose, and you wouldn't do that on the .safetensors key level.
There are Comfy workflows that can do that. the output can then be loaded into OneTrainer

@dxqb

This comment was marked as resolved.

@dxqb
dxqb changed the base branch from master to merge January 24, 2026 07:12
@dxqb

dxqb commented Feb 3, 2026

Copy link
Copy Markdown
Collaborator Author

merging this because it is required to create Flux2 checkpoints
requires more work to be a generic conversion util

@dxqb
dxqb marked this pull request as ready for review February 3, 2026 13:59
@dxqb
dxqb merged commit af62406 into Nerogar:merge Feb 3, 2026
1 check passed
Calamdor added a commit to Calamdor/OneTrainer that referenced this pull request Mar 15, 2026
Replace hand-rolled QKV grouping and _combine_qkv() with the
lora_qkv_fusion / lora_qkv_mlp_fusion helpers from convert_util
(PR Nerogar#1236). Key routing is now expressed as declarative
ConversionPattern tuples processed by convert_util.convert(),
making the structure consistent with the Flux2 conversion approach.

DoRA scale merging and text-encoder legacy remapping are kept
separate as convert_util doesn't handle those cases.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Calamdor added a commit to Calamdor/OneTrainer that referenced this pull request Mar 15, 2026
…o 0.45

- Rewrite convert_wan2_2_lora.py using declarative convert_util patterns
  (PR Nerogar#1236 framework) instead of manual str.replace chains.
  _BLOCK_LAYER_PATTERNS defines per-block layer name mapping with a
  catch-all for norm/other layers; _WAN_HIGH/LOW_NOISE_PATTERNS define
  the full prefix routing for each expert.  Suffix rename (lora_down →
  lora_A) is a separate post-pass since convert_util passes suffixes
  through unchanged.

- Update Low-Noise Expert preset: min 0.0 → 0.45.  Very-low-noise
  timesteps (near t=0) represent near-clean images where LoRA gradients
  are negligible; raising the floor concentrates training steps on the
  region where the low-noise expert does meaningful work.

- Update Combined Training preset: min 0.0 → 0.45 for the same reason.
  shift=7 (expert boundary bias) is preserved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Calamdor added a commit to Calamdor/OneTrainer that referenced this pull request Mar 20, 2026
…o 0.45

- Rewrite convert_wan2_2_lora.py using declarative convert_util patterns
  (PR Nerogar#1236 framework) instead of manual str.replace chains.
  _BLOCK_LAYER_PATTERNS defines per-block layer name mapping with a
  catch-all for norm/other layers; _WAN_HIGH/LOW_NOISE_PATTERNS define
  the full prefix routing for each expert.  Suffix rename (lora_down →
  lora_A) is a separate post-pass since convert_util passes suffixes
  through unchanged.

- Update Low-Noise Expert preset: min 0.0 → 0.45.  Very-low-noise
  timesteps (near t=0) represent near-clean images where LoRA gradients
  are negligible; raising the floor concentrates training steps on the
  region where the low-noise expert does meaningful work.

- Update Combined Training preset: min 0.0 → 0.45 for the same reason.
  shift=7 (expert boundary bias) is preserved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Calamdor added a commit to Calamdor/OneTrainer that referenced this pull request Mar 28, 2026
…o 0.45

- Rewrite convert_wan2_2_lora.py using declarative convert_util patterns
  (PR Nerogar#1236 framework) instead of manual str.replace chains.
  _BLOCK_LAYER_PATTERNS defines per-block layer name mapping with a
  catch-all for norm/other layers; _WAN_HIGH/LOW_NOISE_PATTERNS define
  the full prefix routing for each expert.  Suffix rename (lora_down →
  lora_A) is a separate post-pass since convert_util passes suffixes
  through unchanged.

- Update Low-Noise Expert preset: min 0.0 → 0.45.  Very-low-noise
  timesteps (near t=0) represent near-clean images where LoRA gradients
  are negligible; raising the floor concentrates training steps on the
  region where the low-noise expert does meaningful work.

- Update Combined Training preset: min 0.0 → 0.45 for the same reason.
  shift=7 (expert boundary bias) is preserved.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BitcrushedHeart pushed a commit to BitcrushedHeart/OneTrainer that referenced this pull request Jun 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants