feat: add Qwen Image 2.1 support (#1994)

This commit is contained in:
leejet authored and GitHub committed 2026-09-20 22:51:21 +08:00
1 parent 1330cebae8
commit 137f7409bb
16 files changed
+637 -37

No files matched your search

+7 -2
View File
@@ -80,6 +80,7 @@ const char* model_version_to_str[] = {
"LingBot Video",
"Qwen Image",
"Qwen Image Layered",
"Qwen Image 2.1",
"Hunyuan Video",
"Anima",
"Flux.2",
@@ -2375,6 +2376,8 @@ sd::Tensor<float> StableDiffusionGGML::sample(const std::shared_ptr<DiffusionMod
} else if (sd_version_is_flux(version) || sd_version_is_flux2(version) || sd_version_is_longcat(version) || sd_version_is_sefi_image(version)) {
diffusion_params.extra = FluxDiffusionExtra{&guidance_tensor,
local_skip_layers};
} else if (version == VERSION_QWEN_IMAGE_2_1) {
diffusion_params.extra = QwenImage21DiffusionExtra{&condition.c_token_types};
} else if (sd_version_is_anima(version)) {
diffusion_params.extra = AnimaDiffusionExtra{condition.c_t5_ids.empty() ? nullptr : &condition.c_t5_ids,
condition.c_t5_weights.empty() ? nullptr : &condition.c_t5_weights};
@@ -2575,7 +2578,7 @@ int StableDiffusionGGML::get_diffusion_model_down_factor() {
if (sd_version_is_dit(version)) {
if (sd_version_is_sensenova_u1(version)) {
down_factor = 32;
} else if (sd_version_is_wan(version) || sd_version_is_lingbot_video(version) || sd_version_is_minimax_h3(version)) {
} else if (version == VERSION_QWEN_IMAGE_2_1 || sd_version_is_wan(version) || sd_version_is_lingbot_video(version) || sd_version_is_minimax_h3(version)) {
down_factor = 2;
} else {
down_factor = 1;
@@ -2591,6 +2594,8 @@ int StableDiffusionGGML::get_latent_channel() {
latent_channel = 128;
} else if (sd_version_is_minimax_h3(version)) {
latent_channel = 24;
} else if (version == VERSION_QWEN_IMAGE_2_1) {
latent_channel = 64;
} else if (version == VERSION_WAN2_2_TI2V) {
latent_channel = 48;
} else if (sd_version_is_hunyuan_video(version)) {
@@ -2619,7 +2624,7 @@ int StableDiffusionGGML::get_latent_channel() {
}
int StableDiffusionGGML::get_image_channels() const {
return version == VERSION_QWEN_IMAGE_LAYERED ? 4 : 3;
return version == VERSION_QWEN_IMAGE_LAYERED || version == VERSION_QWEN_IMAGE_2_1 ? 4 : 3;
}
int StableDiffusionGGML::get_image_seq_len(int h, int w) {
+1 -1
View File
@@ -37,7 +37,7 @@ extern const char* model_version_to_str[];
static inline bool sd_version_supports_ref_latent_img_cfg(SDVersion version) {
return version == VERSION_FLUX ||
sd_version_is_flux2(version) ||
sd_version_is_qwen_image(version) ||
(sd_version_is_qwen_image(version) && version != VERSION_QWEN_IMAGE_2_1) ||
sd_version_is_mage_flow(version) ||
sd_version_is_longcat(version) ||
sd_version_is_z_image(version) ||
+5 -1
View File
@@ -285,7 +285,8 @@ namespace sd::pipeline {
vae_width = request->width;
vae_height = request->height;
} else {
int target_pixels = ref_image_params.vae_input_max_pixels > 0 ? ref_image_params.vae_input_max_pixels : 1024 * 1024;
int default_pixels = sd->version == VERSION_QWEN_IMAGE_2_1 ? request->width * request->height : 1024 * 1024;
int target_pixels = ref_image_params.vae_input_max_pixels > 0 ? ref_image_params.vae_input_max_pixels : default_pixels;
int vae_image_size = std::min(target_pixels, request->width * request->height);
vae_width = sqrt(vae_image_size * ref_images[i].shape()[0] / ref_images[i].shape()[1]);
vae_height = vae_width * ref_images[i].shape()[1] / ref_images[i].shape()[0];
@@ -309,6 +310,9 @@ namespace sd::pipeline {
resized_ref_img.shape()[0]);
ref_latent = sd->encode_first_stage(resized_ref_img);
if (sd->version == VERSION_QWEN_IMAGE_2_1) {
ref_images[i] = std::move(resized_ref_img);
}
} else {
ref_latent = sd->encode_first_stage(ref_images[i]);
}
+14 -6
View File
@@ -28,6 +28,7 @@
#include "model/diffusion/model.hpp"
#include "model/diffusion/pid.hpp"
#include "model/diffusion/qwen_image.hpp"
#include "model/diffusion/qwen_image_2_1.hpp"
#include "model/diffusion/sensenova_u1.h"
#include "model/diffusion/unet.hpp"
#include "model/diffusion/wan.hpp"
@@ -285,12 +286,19 @@ namespace sd::model_builders {
enable_vision,
weight_manager,
tokenizers);
result.diffusion = std::make_shared<Qwen::QwenImageRunner>(ctx.backends.runtime_backend(SDBackendModule::DIFFUSION),
tensor_storage_map,
"model.diffusion_model",
version,
weight_manager,
sd_ctx_params->model_args);
if (version == VERSION_QWEN_IMAGE_2_1) {
result.diffusion = std::make_shared<Qwen::QwenImage21Runner>(ctx.backends.runtime_backend(SDBackendModule::DIFFUSION),
tensor_storage_map,
"model.diffusion_model",
weight_manager);
} else {
result.diffusion = std::make_shared<Qwen::QwenImageRunner>(ctx.backends.runtime_backend(SDBackendModule::DIFFUSION),
tensor_storage_map,
"model.diffusion_model",
version,
weight_manager,
sd_ctx_params->model_args);
}
} else if (sd_version_is_mage_flow(version)) {
result.conditioner = std::make_shared<LLMEmbedder>(ctx.backends.runtime_backend(SDBackendModule::TE),
tensor_storage_map,
+1 -1
View File
@@ -65,7 +65,7 @@ namespace sd::pipeline {
return LCM_SCHEDULER;
} else if (sample_method == DDIM_TRAILING_SAMPLE_METHOD) {
return SIMPLE_SCHEDULER;
} else if (sd != nullptr && sd_version_is_flux(sd->version)) {
} else if (sd != nullptr && (sd_version_is_flux(sd->version) || sd->version == VERSION_QWEN_IMAGE_2_1)) {
return FLUX_SCHEDULER;
} else if (sd != nullptr && sd_version_is_flux2(sd->version)) {
return FLUX2_SCHEDULER;