Uh oh!
There was an error while loading. Please reload this page.
Add ZImage LoRA support and integrate into ZImagePipeline - #12750
Conversation
CalamitousFelicitousness
commented
Nov 29, 2025
Tested using a simple script. Testing script#!/usr/bin/env python"""Test script for ZImage LoRA support."""importsyssys.path.insert(0, '/home/ohiom/diffusers/src')
importtorchfromdiffusersimportZImagePipeline# PathsMODEL_PATH="database/models/huggingface/models--Tongyi-MAI--Z-Image-Turbo/snapshots/78771b7e11b922c868dd766476bda1f4fc6bfc96"LORA_PATH="TechnicallyColorZ_V1.safetensors"print("Loading ZImagePipeline...")
pipe=ZImagePipeline.from_pretrained(
MODEL_PATH,
torch_dtype=torch.bfloat16,
local_files_only=True,
)
pipe.to("cuda")
print(f"Pipeline loaded. Has load_lora_weights: {hasattr(pipe, 'load_lora_weights')}")
print(f"\nLoading LoRA from {LORA_PATH}...")
pipe.load_lora_weights(LORA_PATH)
print("LoRA loaded successfully!")
# Generate an imageprompt="t3chnic4lly vibrant 1960s close-up of a woman sitting under a tree in a blue skit and white blouse, she has blonde wavy short hair and a smile with green eyes lake scene by a garden with flowers in the foreground 1960s styl;e film She's holding her hand out there is a small smooth frog in her palm, she's making eye contact with the toad."print(f"\nGenerating image with prompt: {prompt}")
image=pipe(
prompt=prompt,
num_inference_steps=8,
guidance_scale=1.0,
height=1024,
width=1024,
generator=torch.Generator(device="cuda").manual_seed(42),
).images[0]
output_path="test_zimage_lora_output.png"image.save(output_path)
print(f"\nImage saved to {output_path}") |
sayakpaul
commented
Nov 29, 2025
@asomoza cc |
thanks for the contribution, it works ok without scale but we need to add the transformer model here With that:
Also I did a quick run on the tests to check if this was detected but they all fail with: |
sayakpaul
left a comment
There was a problem hiding this comment.
What a clean PR this is! Thanks so much for contributing!
HuggingFaceDocBuilderDev
commented
Nov 30, 2025
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
- Override test_lora_fuse_nan to use ZImage's 'layers' attribute instead of 'transformer_blocks' - Skip block-level LoRA scaling test (not supported in ZImage) - Add required imports: numpy, torch_device, check_if_lora_correctly_set
@sayakpaul You are too kind. As for the remaining failures, as far as I can tell, due to ZImage requiring |
thanks a lot @CalamitousFelicitousness, can you please add the ZImageLoraLoaderMixin to the lora docs here for the tests, I leave it to @sayakpaul to make the decision |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
sayakpaul
commented
Dec 1, 2025
Hmm, the failing tests -- are these because of the numerical instabilities arising from the use of |
ZImage uses 'attention.to_k' naming convention instead of 'attn.to_k', so the base test's module name search loop never finds a match. This override uses the correct naming pattern for ZImage architecture.
Squashed one more naming convention issue with an override. My best somewhat-educated 2AM guess is that it lies somewhere between the Complex64 RoPE and torch.empty, unfortunately here I am beginning to approach the functional limits of my practical knowledge, so if anything comes to mind later on, I will bring it up. |
sayakpaul
commented
Dec 1, 2025
@CalamitousFelicitousness that is understandable. I am facing something similar in #12741 |
sayakpaul
commented
Dec 1, 2025
Let's try to add a |
They are really flaky. I'm doing 10 retries right now, and it whittled down the failures to 6 at the lowest, some tests are failing one run and pass on another. I will just set it to 100 and see if they pass. 100 retriesAnother 100 retriesStatus: We have three remaining tests that haven't passed yet:
|
CalamitousFelicitousness
commented
Dec 1, 2025
@sayakpaul The last three tests fail, even at 250 retries, I tried to initialise the padding tokens to try and get them to pass, but no dice. |
sayakpaul
commented
Dec 1, 2025
Okay, we can rest this case. Let's skip the LoRA testing class entirely ( |
sayakpaul
commented
Dec 1, 2025
@asomoza since I will be off mostly today, could you take care of merging the PR once the test class has been skipped? |
Skip the entire ZImageLoRATests class due to non-deterministic behavior from complex64 RoPE operations and torch.empty padding tokens. LoRA functionality works correctly with real models. Clean up removed: - Individual @unittest.skip decorators - @is_flaky decorator overrides for inherited methods - Custom test method overrides - Global torch deterministic settings - Unused imports (numpy, is_flaky, check_if_lora_correctly_set)
Added the skip and cleaned up the accumulated overrides and workarounds. |
asomoza
commented
Dec 2, 2025
thanks a lot!, the failed test now are unrelated to this PR |
Uh oh!
There was an error while loading. Please reload this page.
@asomoza Hi, Environment
Minimal Reproduction fromdiffusersimportDiffusionPipelinemodel=DiffusionPipeline.from_pretrained("/weights/Z-Image-Turbo")
lora_path="/path/to/lora"model.load_lora_weights(lora_path, adapter_name="xxx")
model.get_list_adapters()
model.set_adapters(adapter_names="xxx")Observed Behavior
Summary of Problems
Overall, the LoRA adapter lifecycle (load → register → activate → unload → reload) appears inconsistent for Z-Image-Turbo in diffusers 0.36.0. Please let me know if I can provide additional debugging information or test patches. In [1]: fromdiffusersimportDiffusionPipelineIn [2]: model=DiffusionPipeline.from_pretrained("/weights/Z-Image-Turbo")
In [3]: lora_path="/path/to/lora"In [4]: model.load_lora_weights(lora_path, adapter_name="xxx")
In [5]: model.get_list_adapters()
Out[5]: {}
In [6]: model.set_adapters(adapter_names="xxx")
---------------------------------------------------------------------------ValueErrorTraceback (mostrecentcalllast)
CellIn[6], line1---->1model.set_adapters(adapter_names="xxx")
File/usr/local/lib/python3.11/site-packages/diffusers/loaders/lora_base.py:736, inLoraBaseMixin.set_adapters(self, adapter_names, adapter_weights)
734missing_adapters=set(adapter_names) -all_adapters735iflen(missing_adapters) >0:
-->736raiseValueError(
737f"Adapter name(s) {missing_adapters} not in the list of present adapters: {all_adapters}."738 )
740# eg {"adapter1": ["unet"], "adapter2": ["unet", "text_encoder"]}741invert_list_adapters= {
742adapter: [partforpart, adaptersinlist_adapters.items() ifadapterinadapters]
743foradapterinall_adapters744 }
ValueError: Adaptername(s) {'xxx'} notinthelistofpresentadapters: set().
In [7]: model.unload_lora_weights()
In [8]: model.load_lora_weights(lora_path, adapter_name="xxx")
---------------------------------------------------------------------------ValueErrorTraceback (mostrecentcalllast)
CellIn[8], line1---->1model.load_lora_weights(lora_path, adapter_name="xxx")
File/usr/local/lib/python3.11/site-packages/diffusers/loaders/lora_pipeline.py:5190, inZImageLoraLoaderMixin.load_lora_weights(self, pretrained_model_name_or_path_or_dict, adapter_name, hotswap, **kwargs)
5187ifnotis_correct_format:
5188raiseValueError("Invalid LoRA checkpoint.")
->5190self.load_lora_into_transformer(
5191state_dict,
5192transformer=getattr(self, self.transformer_name) ifnothasattr(self, "transformer") elseself.transformer,
5193adapter_name=adapter_name,
5194metadata=metadata,
5195_pipeline=self,
5196low_cpu_mem_usage=low_cpu_mem_usage,
5197hotswap=hotswap,
5198 )
File/usr/local/lib/python3.11/site-packages/diffusers/loaders/lora_pipeline.py:5222, inZImageLoraLoaderMixin.load_lora_into_transformer(cls, state_dict, transformer, adapter_name, _pipeline, low_cpu_mem_usage, hotswap, metadata)
5220# Load the layers corresponding to transformer.5221logger.info(f"Loading {cls.transformer_name}.")
->5222transformer.load_lora_adapter(
5223state_dict,
5224network_alphas=None,
5225adapter_name=adapter_name,
5226metadata=metadata,
5227_pipeline=_pipeline,
5228low_cpu_mem_usage=low_cpu_mem_usage,
5229hotswap=hotswap,
5230 )
File/usr/local/lib/python3.11/site-packages/diffusers/loaders/peft.py:221, inPeftAdapterMixin.load_lora_adapter(self, pretrained_model_name_or_path_or_dict, prefix, hotswap, **kwargs)
219iflen(state_dict) >0:
220ifadapter_nameingetattr(self, "peft_config", {}) andnothotswap:
-->221raiseValueError(
222f"Adapter name {adapter_name} already in use in the model - please select a new adapter name."223 )
224elifadapter_namenotingetattr(self, "peft_config", {}) andhotswap:
225raiseValueError(
226f"Trying to hotswap LoRA adapter '{adapter_name}' but there is no existing adapter by that name. "227"Please choose an existing adapter name or set `hotswap=False` to prevent hotswapping."228 )
ValueError: Adapternamexxxalreadyinuseinthemodel-pleaseselectanewadaptername.
In [9]: model.load_lora_weights(lora_path)
/usr/local/lib/python3.11/site-packages/peft/tuners/tuners_utils.py:196: UserWarning: Alreadyfounda`peft_config`attributeinthemodel. Thiswillleadtohavingmultipleadaptersinthemodel. Makesuretoknowwhatyouaredoing!
warnings.warn(
In [10]: model.unload_lora_weights()
IIn [11]: model.load_lora_weights(lora_path)
/usr/local/lib/python3.11/site-packages/peft/tuners/tuners_utils.py:196: UserWarning: Alreadyfounda`peft_config`attributeinthemodel. Thiswillleadtohavingmultipleadaptersinthemodel. Makesuretoknowwhatyouaredoing!
warnings.warn(
In [12]: model.unload_lora_weights()
In [13]: model.load_lora_weights(lora_path)
/usr/local/lib/python3.11/site-packages/peft/tuners/tuners_utils.py:196: UserWarning: Alreadyfounda`peft_config`attributeinthemodel. Thiswillleadtohavingmultipleadaptersinthemodel. Makesuretoknowwhatyouaredoing!
warnings.warn( |
asomoza
commented
Dec 17, 2025
Hi @vagitablebirdcode , with that lora it works without any problems:
since you're using an LLM for this issue, I don't really know what you're doing, but if you're using plain python you need to print the return to see the values, ie: pipe.load_lora_weights("tarn59/pixel_art_style_lora_z_image_turbo", adapter_name="pixel_art")
print(pipe.get_list_adapters())output: {'transformer': ['pixel_art']} |





What does this PR do?
Adds support for LoRA for ZImagePipeline and adds a conversion script into Diffusers format. Resolves issue #12745
Before submitting
documentation guidelines, and
here are tips on formatting docstrings.
Who can review?
Anyone in the community is free to review the PR once the tests have passed. Feel free to tag
members/contributors who may be interested in your PR.
@sayakpaul