diff --git a/src/model/diffusion/control.hpp b/src/model/diffusion/control.hpp index eeb8f5109..bf3c7e435 100644 --- a/src/model/diffusion/control.hpp +++ b/src/model/diffusion/control.hpp @@ -5,7 +5,8 @@ #include "model_loader.h" #include "model_manager.h" -#define CONTROL_NET_GRAPH_SIZE 1536 +// Match main UNet's MAX_GRAPH_SIZE so SDXL ControlNet (transformer_depth={1,2,10}) fits. +#define CONTROL_NET_GRAPH_SIZE MAX_GRAPH_SIZE /* =================================== ControlNet =================================== diff --git a/src/name_conversion.cpp b/src/name_conversion.cpp index 64b7c681d..2f9a4d184 100644 --- a/src/name_conversion.cpp +++ b/src/name_conversion.cpp @@ -736,6 +736,62 @@ std::string convert_diffusers_dit_to_original_krea2(std::string name) { return name; } +// Convert a diffusers-format ControlNet tensor name to the original (LDM/lllyasviel) layout +// declared by ControlNetBlock. Reuses the UNet down/mid conversion for the shared encoder +// (down_blocks, mid_block, time_embedding, add_embedding, conv_in) and adds the ControlNet-only +// mappings: input_hint_block, zero_convs, middle_block_out. +std::string convert_diffusers_controlnet_to_original_sdxl(std::string name) { + name = convert_diffusers_unet_to_original_sdxl(std::move(name)); + + static const std::vector> prefix_map = { + {"controlnet_cond_embedding.conv_in.", "input_hint_block.0."}, + {"controlnet_cond_embedding.blocks.0.", "input_hint_block.2."}, + {"controlnet_cond_embedding.blocks.1.", "input_hint_block.4."}, + {"controlnet_cond_embedding.blocks.2.", "input_hint_block.6."}, + {"controlnet_cond_embedding.blocks.3.", "input_hint_block.8."}, + {"controlnet_cond_embedding.blocks.4.", "input_hint_block.10."}, + {"controlnet_cond_embedding.blocks.5.", "input_hint_block.12."}, + {"controlnet_cond_embedding.conv_out.", "input_hint_block.14."}, + {"controlnet_mid_block.", "middle_block_out.0."}, + }; + for (const auto& p : prefix_map) { + if (starts_with(name, p.first)) { + return p.second + name.substr(p.first.size()); + } + } + + static const std::string controlnet_down_prefix = "controlnet_down_blocks."; + if (starts_with(name, controlnet_down_prefix)) { + size_t rest_start = controlnet_down_prefix.size(); + size_t dot = name.find('.', rest_start); + if (dot != std::string::npos) { + std::string idx = name.substr(rest_start, dot - rest_start); + return "zero_convs." + idx + ".0" + name.substr(dot); + } + } + + return name; +} + +static bool is_diffusers_controlnet_name(const std::string& name) { + static const std::vector heads = { + "controlnet_cond_embedding.", + "controlnet_down_blocks.", + "controlnet_mid_block.", + "down_blocks.", + "mid_block.", + "time_embedding.", + "add_embedding.", + "conv_in.", + }; + for (const auto& h : heads) { + if (starts_with(name, h)) { + return true; + } + } + return false; +} + std::string convert_diffusion_model_name(std::string name, std::string prefix, SDVersion version) { if (sd_version_is_sd1(version) || sd_version_is_sd2(version)) { name = convert_diffusers_unet_to_original_sd1(name); @@ -1338,6 +1394,9 @@ std::string convert_tensor_name(std::string name, SDVersion version) { name = name.substr(pos + 1); } } + if (sd_version_is_sdxl(version) && is_diffusers_controlnet_name(name)) { + name = convert_diffusers_controlnet_to_original_sdxl(name); + } } if (is_lora) {