Skip to content

Commit 83955dd

Browse files
authored
Merge branch 'main' into modular-flux-i2i
2 parents 40bc38a + 03c3f69 commit 83955dd

File tree

14 files changed

+1104
-49
lines changed

14 files changed

+1104
-49
lines changed
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
name: Fast PR tests for Modular
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
paths:
7+
- "src/diffusers/modular_pipelines/**.py"
8+
- "src/diffusers/models/modeling_utils.py"
9+
- "src/diffusers/models/model_loading_utils.py"
10+
- "src/diffusers/pipelines/pipeline_utils.py"
11+
- "src/diffusers/pipeline_loading_utils.py"
12+
- "src/diffusers/loaders/lora_base.py"
13+
- "src/diffusers/loaders/lora_pipeline.py"
14+
- "src/diffusers/loaders/peft.py"
15+
- "tests/modular_pipelines/**.py"
16+
- ".github/**.yml"
17+
- "utils/**.py"
18+
- "setup.py"
19+
push:
20+
branches:
21+
- ci-*
22+
23+
concurrency:
24+
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
25+
cancel-in-progress: true
26+
27+
env:
28+
DIFFUSERS_IS_CI: yes
29+
HF_HUB_ENABLE_HF_TRANSFER: 1
30+
OMP_NUM_THREADS: 4
31+
MKL_NUM_THREADS: 4
32+
PYTEST_TIMEOUT: 60
33+
34+
jobs:
35+
check_code_quality:
36+
runs-on: ubuntu-22.04
37+
steps:
38+
- uses: actions/checkout@v3
39+
- name: Set up Python
40+
uses: actions/setup-python@v4
41+
with:
42+
python-version: "3.10"
43+
- name: Install dependencies
44+
run: |
45+
python -m pip install --upgrade pip
46+
pip install .[quality]
47+
- name: Check quality
48+
run: make quality
49+
- name: Check if failure
50+
if: ${{ failure() }}
51+
run: |
52+
echo "Quality check failed. Please ensure the right dependency versions are installed with 'pip install -e .[quality]' and run 'make style && make quality'" >> $GITHUB_STEP_SUMMARY
53+
54+
check_repository_consistency:
55+
needs: check_code_quality
56+
runs-on: ubuntu-22.04
57+
steps:
58+
- uses: actions/checkout@v3
59+
- name: Set up Python
60+
uses: actions/setup-python@v4
61+
with:
62+
python-version: "3.10"
63+
- name: Install dependencies
64+
run: |
65+
python -m pip install --upgrade pip
66+
pip install .[quality]
67+
- name: Check repo consistency
68+
run: |
69+
python utils/check_copies.py
70+
python utils/check_dummies.py
71+
python utils/check_support_list.py
72+
make deps_table_check_updated
73+
- name: Check if failure
74+
if: ${{ failure() }}
75+
run: |
76+
echo "Repo consistency check failed. Please ensure the right dependency versions are installed with 'pip install -e .[quality]' and run 'make fix-copies'" >> $GITHUB_STEP_SUMMARY
77+
78+
run_fast_tests:
79+
needs: [check_code_quality, check_repository_consistency]
80+
strategy:
81+
fail-fast: false
82+
matrix:
83+
config:
84+
- name: Fast PyTorch Modular Pipeline CPU tests
85+
framework: pytorch_pipelines
86+
runner: aws-highmemory-32-plus
87+
image: diffusers/diffusers-pytorch-cpu
88+
report: torch_cpu_modular_pipelines
89+
90+
name: ${{ matrix.config.name }}
91+
92+
runs-on:
93+
group: ${{ matrix.config.runner }}
94+
95+
container:
96+
image: ${{ matrix.config.image }}
97+
options: --shm-size "16gb" --ipc host -v /mnt/hf_cache:/mnt/cache/
98+
99+
defaults:
100+
run:
101+
shell: bash
102+
103+
steps:
104+
- name: Checkout diffusers
105+
uses: actions/checkout@v3
106+
with:
107+
fetch-depth: 2
108+
109+
- name: Install dependencies
110+
run: |
111+
python -m venv /opt/venv && export PATH="/opt/venv/bin:$PATH"
112+
python -m uv pip install -e [quality,test]
113+
pip uninstall transformers -y && python -m uv pip install -U transformers@git+https://github.com/huggingface/transformers.git --no-deps
114+
pip uninstall accelerate -y && python -m uv pip install -U accelerate@git+https://github.com/huggingface/accelerate.git --no-deps
115+
116+
- name: Environment
117+
run: |
118+
python -m venv /opt/venv && export PATH="/opt/venv/bin:$PATH"
119+
python utils/print_env.py
120+
121+
- name: Run fast PyTorch Pipeline CPU tests
122+
if: ${{ matrix.config.framework == 'pytorch_pipelines' }}
123+
run: |
124+
python -m venv /opt/venv && export PATH="/opt/venv/bin:$PATH"
125+
python -m pytest -n 8 --max-worker-restart=0 --dist=loadfile \
126+
-s -v -k "not Flax and not Onnx" \
127+
--make-reports=tests_${{ matrix.config.report }} \
128+
tests/modular_pipelines
129+
130+
- name: Failure short reports
131+
if: ${{ failure() }}
132+
run: cat reports/tests_${{ matrix.config.report }}_failures_short.txt
133+
134+
- name: Test suite reports artifacts
135+
if: ${{ always() }}
136+
uses: actions/upload-artifact@v4
137+
with:
138+
name: pr_${{ matrix.config.framework }}_${{ matrix.config.report }}_test_reports
139+
path: reports
140+
141+

docs/source/en/quantization/gguf.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,44 @@ Once installed, set `DIFFUSERS_GGUF_CUDA_KERNELS=true` to use optimized kernels
7777
- Q5_K
7878
- Q6_K
7979

80+
## Convert to GGUF
81+
82+
Use the Space below to convert a Diffusers checkpoint into the GGUF format for inference.
83+
run conversion:
84+
85+
<iframe
86+
src="https://diffusers-internal-dev-diffusers-to-gguf.hf.space"
87+
frameborder="0"
88+
width="850"
89+
height="450"
90+
></iframe>
91+
92+
93+
```py
94+
import torch
95+
96+
from diffusers import FluxPipeline, FluxTransformer2DModel, GGUFQuantizationConfig
97+
98+
ckpt_path = (
99+
"https://huggingface.co/sayakpaul/different-lora-from-civitai/blob/main/flux_dev_diffusers-q4_0.gguf"
100+
)
101+
transformer = FluxTransformer2DModel.from_single_file(
102+
ckpt_path,
103+
quantization_config=GGUFQuantizationConfig(compute_dtype=torch.bfloat16),
104+
config="black-forest-labs/FLUX.1-dev",
105+
subfolder="transformer",
106+
torch_dtype=torch.bfloat16,
107+
)
108+
pipe = FluxPipeline.from_pretrained(
109+
"black-forest-labs/FLUX.1-dev",
110+
transformer=transformer,
111+
torch_dtype=torch.bfloat16,
112+
)
113+
pipe.enable_model_cpu_offload()
114+
prompt = "A cat holding a sign that says hello world"
115+
image = pipe(prompt, generator=torch.manual_seed(0)).images[0]
116+
image.save("flux-gguf.png")
117+
```
118+
119+
When using Diffusers format GGUF checkpoints, it's a must to provide the model `config` path. If the
120+
model config resides in a `subfolder`, that needs to be specified, too.

src/diffusers/loaders/lora_conversion_utils.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,11 @@ def _convert(original_key, diffusers_key, state_dict, new_state_dict):
817817
# has both `peft` and non-peft state dict.
818818
has_peft_state_dict = any(k.startswith("transformer.") for k in state_dict)
819819
if has_peft_state_dict:
820-
state_dict = {k: v for k, v in state_dict.items() if k.startswith("transformer.")}
820+
state_dict = {
821+
k.replace("lora_down.weight", "lora_A.weight").replace("lora_up.weight", "lora_B.weight"): v
822+
for k, v in state_dict.items()
823+
if k.startswith("transformer.")
824+
}
821825
return state_dict
822826

823827
# Another weird one.

src/diffusers/loaders/single_file_model.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,17 @@
153153
"checkpoint_mapping_fn": convert_cosmos_transformer_checkpoint_to_diffusers,
154154
"default_subfolder": "transformer",
155155
},
156+
"QwenImageTransformer2DModel": {
157+
"checkpoint_mapping_fn": lambda x: x,
158+
"default_subfolder": "transformer",
159+
},
156160
}
157161

158162

163+
def _should_convert_state_dict_to_diffusers(model_state_dict, checkpoint_state_dict):
164+
return not set(model_state_dict.keys()).issubset(set(checkpoint_state_dict.keys()))
165+
166+
159167
def _get_single_file_loadable_mapping_class(cls):
160168
diffusers_module = importlib.import_module(__name__.split(".")[0])
161169
for loadable_class_str in SINGLE_FILE_LOADABLE_CLASSES:
@@ -381,19 +389,23 @@ def from_single_file(cls, pretrained_model_link_or_path_or_dict: Optional[str] =
381389
model_kwargs = {k: kwargs.get(k) for k in kwargs if k in expected_kwargs or k in optional_kwargs}
382390
diffusers_model_config.update(model_kwargs)
383391

392+
ctx = init_empty_weights if is_accelerate_available() else nullcontext
393+
with ctx():
394+
model = cls.from_config(diffusers_model_config)
395+
384396
checkpoint_mapping_kwargs = _get_mapping_function_kwargs(checkpoint_mapping_fn, **kwargs)
385-
diffusers_format_checkpoint = checkpoint_mapping_fn(
386-
config=diffusers_model_config, checkpoint=checkpoint, **checkpoint_mapping_kwargs
387-
)
397+
398+
if _should_convert_state_dict_to_diffusers(model.state_dict(), checkpoint):
399+
diffusers_format_checkpoint = checkpoint_mapping_fn(
400+
config=diffusers_model_config, checkpoint=checkpoint, **checkpoint_mapping_kwargs
401+
)
402+
else:
403+
diffusers_format_checkpoint = checkpoint
404+
388405
if not diffusers_format_checkpoint:
389406
raise SingleFileComponentError(
390407
f"Failed to load {mapping_class_name}. Weights for this component appear to be missing in the checkpoint."
391408
)
392-
393-
ctx = init_empty_weights if is_accelerate_available() else nullcontext
394-
with ctx():
395-
model = cls.from_config(diffusers_model_config)
396-
397409
# Check if `_keep_in_fp32_modules` is not None
398410
use_keep_in_fp32_modules = (cls._keep_in_fp32_modules is not None) and (
399411
(torch_dtype == torch.float16) or hasattr(hf_quantizer, "use_keep_in_fp32_modules")

src/diffusers/loaders/single_file_utils.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
logger = logging.get_logger(__name__) # pylint: disable=invalid-name
6161

6262
CHECKPOINT_KEY_NAMES = {
63+
"v1": "model.diffusion_model.output_blocks.11.0.skip_connection.weight",
6364
"v2": "model.diffusion_model.input_blocks.2.1.transformer_blocks.0.attn2.to_k.weight",
6465
"xl_base": "conditioner.embedders.1.model.transformer.resblocks.9.mlp.c_proj.bias",
6566
"xl_refiner": "conditioner.embedders.0.model.transformer.resblocks.9.mlp.c_proj.bias",

src/diffusers/modular_pipelines/modular_pipeline.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,22 @@ def combine_outputs(*named_output_lists: List[Tuple[str, List[OutputParam]]]) ->
493493

494494
return list(combined_dict.values())
495495

496+
@property
497+
def input_names(self) -> List[str]:
498+
return [input_param.name for input_param in self.inputs]
499+
500+
@property
501+
def intermediate_input_names(self) -> List[str]:
502+
return [input_param.name for input_param in self.intermediate_inputs]
503+
504+
@property
505+
def intermediate_output_names(self) -> List[str]:
506+
return [output_param.name for output_param in self.intermediate_outputs]
507+
508+
@property
509+
def output_names(self) -> List[str]:
510+
return [output_param.name for output_param in self.outputs]
511+
496512

497513
class PipelineBlock(ModularPipelineBlocks):
498514
"""
@@ -2839,3 +2855,8 @@ def _dict_to_component_spec(
28392855
type_hint=type_hint,
28402856
**spec_dict,
28412857
)
2858+
2859+
def set_progress_bar_config(self, **kwargs):
2860+
for sub_block_name, sub_block in self.blocks.sub_blocks.items():
2861+
if hasattr(sub_block, "set_progress_bar_config"):
2862+
sub_block.set_progress_bar_config(**kwargs)

src/diffusers/modular_pipelines/stable_diffusion_xl/before_denoise.py

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -744,8 +744,6 @@ def prepare_latents_inpaint(
744744
timestep=None,
745745
is_strength_max=True,
746746
add_noise=True,
747-
return_noise=False,
748-
return_image_latents=False,
749747
):
750748
shape = (
751749
batch_size,
@@ -768,7 +766,7 @@ def prepare_latents_inpaint(
768766
if image.shape[1] == 4:
769767
image_latents = image.to(device=device, dtype=dtype)
770768
image_latents = image_latents.repeat(batch_size // image_latents.shape[0], 1, 1, 1)
771-
elif return_image_latents or (latents is None and not is_strength_max):
769+
elif latents is None and not is_strength_max:
772770
image = image.to(device=device, dtype=dtype)
773771
image_latents = self._encode_vae_image(components, image=image, generator=generator)
774772
image_latents = image_latents.repeat(batch_size // image_latents.shape[0], 1, 1, 1)
@@ -786,13 +784,7 @@ def prepare_latents_inpaint(
786784
noise = randn_tensor(shape, generator=generator, device=device, dtype=dtype)
787785
latents = image_latents.to(device)
788786

789-
outputs = (latents,)
790-
791-
if return_noise:
792-
outputs += (noise,)
793-
794-
if return_image_latents:
795-
outputs += (image_latents,)
787+
outputs = (latents, noise, image_latents)
796788

797789
return outputs
798790

@@ -864,7 +856,7 @@ def __call__(self, components: StableDiffusionXLModularPipeline, state: Pipeline
864856
block_state.height = block_state.image_latents.shape[-2] * components.vae_scale_factor
865857
block_state.width = block_state.image_latents.shape[-1] * components.vae_scale_factor
866858

867-
block_state.latents, block_state.noise = self.prepare_latents_inpaint(
859+
block_state.latents, block_state.noise, block_state.image_latents = self.prepare_latents_inpaint(
868860
components,
869861
block_state.batch_size * block_state.num_images_per_prompt,
870862
components.num_channels_latents,
@@ -878,8 +870,6 @@ def __call__(self, components: StableDiffusionXLModularPipeline, state: Pipeline
878870
timestep=block_state.latent_timestep,
879871
is_strength_max=block_state.is_strength_max,
880872
add_noise=block_state.add_noise,
881-
return_noise=True,
882-
return_image_latents=False,
883873
)
884874

885875
# 7. Prepare mask latent variables

tests/lora/utils.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2400,7 +2400,6 @@ def _test_group_offloading_inference_denoiser(self, offload_type, use_stream):
24002400

24012401
components, _, _ = self.get_dummy_components(self.scheduler_classes[0])
24022402
pipe = self.pipeline_class(**components)
2403-
pipe = pipe.to(torch_device)
24042403
pipe.set_progress_bar_config(disable=None)
24052404
denoiser = pipe.transformer if self.unet_kwargs is None else pipe.unet
24062405

@@ -2416,6 +2415,10 @@ def _test_group_offloading_inference_denoiser(self, offload_type, use_stream):
24162415
num_blocks_per_group=1,
24172416
use_stream=use_stream,
24182417
)
2418+
# Place other model-level components on `torch_device`.
2419+
for _, component in pipe.components.items():
2420+
if isinstance(component, torch.nn.Module):
2421+
component.to(torch_device)
24192422
group_offload_hook_1 = _get_top_level_group_offload_hook(denoiser)
24202423
self.assertTrue(group_offload_hook_1 is not None)
24212424
output_1 = pipe(**inputs, generator=torch.manual_seed(0))[0]

tests/modular_pipelines/__init__.py

Whitespace-only changes.

tests/modular_pipelines/stable_diffusion_xl/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)