diff --git a/src/diffusers/loaders/lora_conversion_utils.py b/src/diffusers/loaders/lora_conversion_utils.py index 41948d205c89..510a698e505f 100644 --- a/src/diffusers/loaders/lora_conversion_utils.py +++ b/src/diffusers/loaders/lora_conversion_utils.py @@ -2331,6 +2331,20 @@ def _convert_non_diffusers_flux2_lora_to_diffusers(state_dict): temp_state_dict[new_key] = v original_state_dict = temp_state_dict + # Some Flux2 checkpoints skip the ai-toolkit `single_blocks` / `double_blocks` + # layout and already store expanded diffusers block names. Accept those + # directly, and normalize the legacy `sformer_blocks` alias used by some exports. + possible_expanded_block_prefixes = { + "single_transformer_blocks.": "single_transformer_blocks.", + "transformer_blocks.": "transformer_blocks.", + "sformer_blocks.": "transformer_blocks.", + } + for key in list(original_state_dict.keys()): + for source_prefix, target_prefix in possible_expanded_block_prefixes.items(): + if key.startswith(source_prefix): + converted_state_dict[target_prefix + key[len(source_prefix) :]] = original_state_dict.pop(key) + break + num_double_layers = 0 num_single_layers = 0 for key in original_state_dict.keys(): @@ -2421,6 +2435,8 @@ def _convert_non_diffusers_flux2_lora_to_diffusers(state_dict): "txt_in": "context_embedder", "time_in.in_layer": "time_guidance_embed.timestep_embedder.linear_1", "time_in.out_layer": "time_guidance_embed.timestep_embedder.linear_2", + "guidance_in.in_layer": "time_guidance_embed.guidance_embedder.linear_1", + "guidance_in.out_layer": "time_guidance_embed.guidance_embedder.linear_2", "final_layer.linear": "proj_out", "final_layer.adaLN_modulation.1": "norm_out.linear", "single_stream_modulation.lin": "single_stream_modulation.linear",