-
Notifications
You must be signed in to change notification settings - Fork 2
Add Qwen Image Edit 2509 pipeline support #465
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
justinchuby
wants to merge
3
commits into
main
Choose a base branch
from
justinchuby-add-qwen-image-edit-2509
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,6 +46,7 @@ def _init_diffusers_class_map() -> None: | |
| CLIPTextConfig, | ||
| CogVideoXConfig, | ||
| QwenImageConfig, | ||
| QwenImageTextEncoderConfig, | ||
| QwenImageVAEConfig, | ||
| UNet2DConfig, | ||
| VAEConfig, | ||
|
|
@@ -64,6 +65,7 @@ def _init_diffusers_class_map() -> None: | |
| from mobius.models.hunyuan_dit import HunyuanDiT2DModel, HunyuanDiTConfig | ||
| from mobius.models.qwen_image import QwenImageTransformer2DModel | ||
| from mobius.models.qwen_image_vae import AutoencoderKLQwenImageModel | ||
| from mobius.models.qwen_vl import Qwen25VLCausalLMModel | ||
| from mobius.models.unet import UNet2DConditionModel | ||
| from mobius.models.vae import AutoencoderKLModel | ||
| from mobius.models.video_vae import VideoAutoencoderModel, VideoVAEConfig | ||
|
|
@@ -86,7 +88,12 @@ def _init_diffusers_class_map() -> None: | |
| "QwenImageTransformer2DModel": ( | ||
| QwenImageTransformer2DModel, | ||
| QwenImageConfig, | ||
| "denoising", | ||
| "qwen-image-denoising", | ||
| ), | ||
| "Qwen2_5_VLForConditionalGeneration": ( | ||
| Qwen25VLCausalLMModel, | ||
| QwenImageTextEncoderConfig, | ||
| "qwen-image-text-encoding", | ||
| ), | ||
| "AutoencoderKL": (AutoencoderKLModel, VAEConfig, "vae"), | ||
| "AutoencoderKLQwenImage": ( | ||
|
|
@@ -203,6 +210,19 @@ def _load_diffusers_component_config(model_id: str, component_name: str) -> dict | |
| return json.load(f) | ||
|
|
||
|
|
||
| def _load_optional_diffusers_json(model_id: str, filename: str) -> dict: | ||
| """Load optional non-neural pipeline metadata without failing the build.""" | ||
| from huggingface_hub import hf_hub_download | ||
| from huggingface_hub.utils import EntryNotFoundError | ||
|
|
||
| try: | ||
| path = hf_hub_download(repo_id=model_id, filename=filename) | ||
| except EntryNotFoundError: | ||
| return {} | ||
| with open(path) as f: | ||
| return json.load(f) | ||
|
|
||
|
|
||
| def _prepare_unet_loras(unet_loras: dict) -> tuple[tuple, dict]: | ||
| """Load each UNet LoRA ``.safetensors``; return baked-adapter specs + merged weights. | ||
|
|
||
|
|
@@ -236,6 +256,8 @@ def build_diffusers_pipeline( | |
| dtype: str | ir.DataType | None = None, | ||
| load_weights: bool = True, | ||
| unet_loras: dict | None = None, | ||
| components: set[str] | None = None, | ||
| execution_provider: str = "default", | ||
| ) -> ModelPackage: | ||
| """Build ONNX models for all supported components in a diffusers pipeline. | ||
|
|
||
|
|
@@ -255,6 +277,9 @@ def build_diffusers_pipeline( | |
| inferred from the file); at inference a ``lora_gate.{name}`` scalar | ||
| input switches/blends it. Requires ``load_weights=True`` to apply the | ||
| adapter weights. | ||
| components: Optional component-name allowlist. Non-neural pipeline metadata | ||
| is still retained so a single-component export preserves its contract. | ||
| execution_provider: Target execution provider for EP-aware graph optimization. | ||
|
|
||
| Returns: | ||
| A :class:`ModelPackage` containing the built component model(s). | ||
|
|
@@ -275,10 +300,14 @@ def build_diffusers_pipeline( | |
| dtype = resolve_dtype(dtype) | ||
|
|
||
| package = ModelPackage({}) | ||
| component_configs: dict[str, dict] = {} | ||
| pipeline_class = str(pipeline_index.get("_class_name", "DiffusionPipeline")) | ||
|
|
||
| for component_name, component_info in pipeline_index.items(): | ||
| if component_name.startswith("_"): | ||
| continue | ||
| if components is not None and component_name not in components: | ||
| continue | ||
| if not isinstance(component_info, list) or len(component_info) != 2: | ||
| continue | ||
|
|
||
|
|
@@ -300,6 +329,7 @@ def build_diffusers_pipeline( | |
| ) | ||
|
|
||
| component_config_dict = _load_diffusers_component_config(model_id, component_name) | ||
| component_configs[component_name] = component_config_dict | ||
| config = config_class.from_diffusers(component_config_dict) | ||
|
|
||
| if dtype is not None and hasattr(config, "dtype"): | ||
|
|
@@ -318,16 +348,29 @@ def build_diffusers_pipeline( | |
|
|
||
| model_module = module_class(config) | ||
|
|
||
| sub_pkg = build_from_module(model_module, config, task_name) | ||
| if ( | ||
| pipeline_class == "QwenImageEditPlusPipeline" | ||
| and class_name == "AutoencoderKLQwenImage" | ||
| ): | ||
| task_name = "qwen-image-edit-vae" | ||
| sub_pkg = build_from_module( | ||
| model_module, | ||
| config, | ||
| task_name, | ||
| execution_provider=execution_provider, | ||
| ) | ||
|
|
||
| # Flatten sub-package into the top-level package | ||
| if len(sub_pkg) == 1 and "model" in sub_pkg: | ||
| sub_pkg["model"].graph.name = f"{model_id}/{component_name}" | ||
| package[component_name] = sub_pkg["model"] | ||
| else: | ||
| for sub_name, sub_model in sub_pkg.items(): | ||
| sub_model.graph.name = f"{model_id}/{component_name}_{sub_name}" | ||
| package[f"{component_name}_{sub_name}"] = sub_model | ||
| package_name = ( | ||
| component_name if sub_name == "model" else f"{component_name}_{sub_name}" | ||
| ) | ||
| sub_model.graph.name = f"{model_id}/{package_name}" | ||
| package[package_name] = sub_model | ||
|
|
||
| if load_weights: | ||
| state_dict = _download_diffusers_component_weights(model_id, component_name) | ||
|
|
@@ -344,4 +387,24 @@ def build_diffusers_pipeline( | |
| f"Supported diffusers classes: {sorted(_DIFFUSERS_CLASS_MAP)}." | ||
| ) | ||
|
|
||
| from mobius._diffusers_configs import DiffusersPipelineConfig | ||
|
|
||
| package.config = DiffusersPipelineConfig( | ||
| source_model_id=model_id, | ||
| pipeline_class=pipeline_class, | ||
| component_configs=component_configs, | ||
| scheduler_config=( | ||
| _load_optional_diffusers_json(model_id, "scheduler/scheduler_config.json") | ||
| if "scheduler" in pipeline_index | ||
| else {} | ||
| ), | ||
| processor_config=( | ||
| _load_optional_diffusers_json(model_id, "processor/preprocessor_config.json") | ||
| if "processor" in pipeline_index | ||
| else {} | ||
| ), | ||
| model_type=( | ||
| "qwen_image_edit" if pipeline_class == "QwenImageEditPlusPipeline" else "diffusers" | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also this |
||
| ), | ||
| ) | ||
| return package | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't look general enough