From 510bccf330a424cca742ca8084d78f4f577c9336 Mon Sep 17 00:00:00 2001 From: leejet Date: Fri, 25 Sep 2026 16:30:34 +0800 Subject: [PATCH] fix: map Qwen Image 2.1 LoRAs to fused MLP weights (#2057) --- src/model/adapter/lora.hpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/model/adapter/lora.hpp b/src/model/adapter/lora.hpp index cb368fea..e9d20a4e 100644 --- a/src/model/adapter/lora.hpp +++ b/src/model/adapter/lora.hpp @@ -163,6 +163,27 @@ struct LoraModel : public GGMLRunner { lora_tensors = std::move(new_lora_tensors); } + + std::unordered_map new_lora_tensors; + for (const auto& [old_name, tensor] : lora_tensors) { + std::string new_name = old_name; + if (starts_with(old_name, "lora.model.diffusion_model.transformer_blocks.")) { + // Qwen Image 2.1 stores the gate before the projection in fused MLP weights. + for (const auto& suffix : {std::string(".img_mlp.gate_layer.weight."), std::string(".img_mlp.proj.weight.")}) { + size_t pos = old_name.find(suffix); + if (pos == std::string::npos) { + continue; + } + std::string fused_name = old_name.substr(5, pos - 5) + ".img_mlp.gate_up.weight"; + if (model_tensor_names.find(fused_name) != model_tensor_names.end()) { + new_name = "lora." + fused_name + (suffix == ".img_mlp.proj.weight." ? ".1." : ".") + old_name.substr(pos + suffix.size()); + } + break; + } + } + new_lora_tensors[new_name] = tensor; + } + lora_tensors = std::move(new_lora_tensors); } ggml_tensor* get_lora_weight_diff(const std::string& model_tensor_name, ggml_context* ctx, ggml_backend_t backend) {