Skip to content

Commit a9d736e

Browse files
authored
Merge branch 'main' into feat/mag-cache
2 parents 6a69fcf + 7f43cb1 commit a9d736e

63 files changed

Lines changed: 4361 additions & 556 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/source/en/_toctree.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@
346346
title: Flux2Transformer2DModel
347347
- local: api/models/flux_transformer
348348
title: FluxTransformer2DModel
349+
- local: api/models/glm_image_transformer2d
350+
title: GlmImageTransformer2DModel
349351
- local: api/models/hidream_image_transformer
350352
title: HiDreamImageTransformer2DModel
351353
- local: api/models/hunyuan_transformer2d
@@ -540,6 +542,8 @@
540542
title: Flux2
541543
- local: api/pipelines/control_flux_inpaint
542544
title: FluxControlInpaint
545+
- local: api/pipelines/glm_image
546+
title: GLM-Image
543547
- local: api/pipelines/hidream
544548
title: HiDream-I1
545549
- local: api/pipelines/hunyuandit
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
2+
3+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
4+
the License. You may obtain a copy of the License at
5+
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
8+
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
9+
an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
10+
specific language governing permissions and limitations under the License. -->
11+
12+
# GlmImageTransformer2DModel
13+
14+
A Diffusion Transformer model for 2D data from [GlmImageTransformer2DModel] (TODO).
15+
16+
## GlmImageTransformer2DModel
17+
18+
[[autodoc]] GlmImageTransformer2DModel

docs/source/en/api/pipelines/chroma.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,9 @@ image.save("chroma-single-file.png")
9999
[[autodoc]] ChromaImg2ImgPipeline
100100
- all
101101
- __call__
102+
103+
## ChromaInpaintPipeline
104+
105+
[[autodoc]] ChromaInpaintPipeline
106+
- all
107+
- __call__
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<!--Copyright 2025 The HuggingFace Team. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
-->
15+
16+
# GLM-Image
17+
18+
## Overview
19+
20+
GLM-Image is an image generation model adopts a hybrid autoregressive + diffusion decoder architecture, effectively pushing the upper bound of visual fidelity and fine-grained details. In general image generation quality, it aligns with industry-standard LDM-based approaches, while demonstrating significant advantages in knowledge-intensive image generation scenarios.
21+
22+
Model architecture: a hybrid autoregressive + diffusion decoder design、
23+
24+
+ Autoregressive generator: a 9B-parameter model initialized from [GLM-4-9B-0414](https://huggingface.co/zai-org/GLM-4-9B-0414), with an expanded vocabulary to incorporate visual tokens. The model first generates a compact encoding of approximately 256 tokens, then expands to 1K–4K tokens, corresponding to 1K–2K high-resolution image outputs. You can check AR model in class `GlmImageForConditionalGeneration` of `transformers` library.
25+
+ Diffusion Decoder: a 7B-parameter decoder based on a single-stream DiT architecture for latent-space image decoding. It is equipped with a Glyph Encoder text module, significantly improving accurate text rendering within images.
26+
27+
Post-training with decoupled reinforcement learning: the model introduces a fine-grained, modular feedback strategy using the GRPO algorithm, substantially enhancing both semantic understanding and visual detail quality.
28+
29+
+ Autoregressive module: provides low-frequency feedback signals focused on aesthetics and semantic alignment, improving instruction following and artistic expressiveness.
30+
+ Decoder module: delivers high-frequency feedback targeting detail fidelity and text accuracy, resulting in highly realistic textures, lighting, and color reproduction, as well as more precise text rendering.
31+
32+
GLM-Image supports both text-to-image and image-to-image generation within a single model
33+
34+
+ Text-to-image: generates high-detail images from textual descriptions, with particularly strong performance in information-dense scenarios.
35+
+ Image-to-image: supports a wide range of tasks, including image editing, style transfer, multi-subject consistency, and identity-preserving generation for people and objects.
36+
37+
This pipeline was contributed by [zRzRzRzRzRzRzR](https://github.com/zRzRzRzRzRzRzR). The codebase can be found [here](https://huggingface.co/zai-org/GLM-Image).
38+
39+
## Usage examples
40+
41+
### Text to Image Generation
42+
43+
```python
44+
import torch
45+
from diffusers.pipelines.glm_image import GlmImagePipeline
46+
47+
pipe = GlmImagePipeline.from_pretrained("zai-org/GLM-Image",torch_dtype=torch.bfloat16,device_map="cuda")
48+
prompt = "A beautifully designed modern food magazine style dessert recipe illustration, themed around a raspberry mousse cake. The overall layout is clean and bright, divided into four main areas: the top left features a bold black title 'Raspberry Mousse Cake Recipe Guide', with a soft-lit close-up photo of the finished cake on the right, showcasing a light pink cake adorned with fresh raspberries and mint leaves; the bottom left contains an ingredient list section, titled 'Ingredients' in a simple font, listing 'Flour 150g', 'Eggs 3', 'Sugar 120g', 'Raspberry puree 200g', 'Gelatin sheets 10g', 'Whipping cream 300ml', and 'Fresh raspberries', each accompanied by minimalist line icons (like a flour bag, eggs, sugar jar, etc.); the bottom right displays four equally sized step boxes, each containing high-definition macro photos and corresponding instructions, arranged from top to bottom as follows: Step 1 shows a whisk whipping white foam (with the instruction 'Whip egg whites to stiff peaks'), Step 2 shows a red-and-white mixture being folded with a spatula (with the instruction 'Gently fold in the puree and batter'), Step 3 shows pink liquid being poured into a round mold (with the instruction 'Pour into mold and chill for 4 hours'), Step 4 shows the finished cake decorated with raspberries and mint leaves (with the instruction 'Decorate with raspberries and mint'); a light brown information bar runs along the bottom edge, with icons on the left representing 'Preparation time: 30 minutes', 'Cooking time: 20 minutes', and 'Servings: 8'. The overall color scheme is dominated by creamy white and light pink, with a subtle paper texture in the background, featuring compact and orderly text and image layout with clear information hierarchy."
49+
image = pipe(
50+
prompt=prompt,
51+
height=32 * 32,
52+
width=36 * 32,
53+
num_inference_steps=30,
54+
guidance_scale=1.5,
55+
generator=torch.Generator(device="cuda").manual_seed(42),
56+
).images[0]
57+
58+
image.save("output_t2i.png")
59+
```
60+
61+
### Image to Image Generation
62+
63+
```python
64+
import torch
65+
from diffusers.pipelines.glm_image import GlmImagePipeline
66+
from PIL import Image
67+
68+
pipe = GlmImagePipeline.from_pretrained("zai-org/GLM-Image",torch_dtype=torch.bfloat16,device_map="cuda")
69+
image_path = "cond.jpg"
70+
prompt = "Replace the background of the snow forest with an underground station featuring an automatic escalator."
71+
image = Image.open(image_path).convert("RGB")
72+
image = pipe(
73+
prompt=prompt,
74+
image=[image], # can input multiple images for multi-image-to-image generation such as [image, image1]
75+
height=33 * 32,
76+
width=32 * 32,
77+
num_inference_steps=30,
78+
guidance_scale=1.5,
79+
generator=torch.Generator(device="cuda").manual_seed(42),
80+
).images[0]
81+
82+
image.save("output_i2i.png")
83+
```
84+
85+
+ Since the AR model used in GLM-Image is configured with `do_sample=True` and a temperature of `0.95` by default, the generated images can vary significantly across runs. We do not recommend setting do_sample=False, as this may lead to incorrect or degenerate outputs from the AR model.
86+
87+
## GlmImagePipeline
88+
89+
[[autodoc]] pipelines.glm_image.pipeline_glm_image.GlmImagePipeline
90+
- all
91+
- __call__
92+
93+
## GlmImagePipelineOutput
94+
95+
[[autodoc]] pipelines.glm_image.pipeline_output.GlmImagePipelineOutput

docs/source/en/api/pipelines/qwenimage.md

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,12 +108,46 @@ pipe = QwenImageEditPlusPipeline.from_pretrained(
108108
image_1 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/grumpy.jpg")
109109
image_2 = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/peng.png")
110110
image = pipe(
111-
image=[image_1, image_2],
112-
prompt='''put the penguin and the cat at a game show called "Qwen Edit Plus Games"''',
111+
image=[image_1, image_2],
112+
prompt='''put the penguin and the cat at a game show called "Qwen Edit Plus Games"''',
113113
num_inference_steps=50
114114
).images[0]
115115
```
116116

117+
## Performance
118+
119+
### torch.compile
120+
121+
Using `torch.compile` on the transformer provides ~2.4x speedup (A100 80GB: 4.70s → 1.93s):
122+
123+
```python
124+
import torch
125+
from diffusers import QwenImagePipeline
126+
127+
pipe = QwenImagePipeline.from_pretrained("Qwen/Qwen-Image", torch_dtype=torch.bfloat16).to("cuda")
128+
pipe.transformer = torch.compile(pipe.transformer)
129+
130+
# First call triggers compilation (~7s overhead)
131+
# Subsequent calls run at ~2.4x faster
132+
image = pipe("a cat", num_inference_steps=50).images[0]
133+
```
134+
135+
### Batched Inference with Variable-Length Prompts
136+
137+
When using classifier-free guidance (CFG) with prompts of different lengths, the pipeline properly handles padding through attention masking. This ensures padding tokens do not influence the generated output.
138+
139+
```python
140+
# CFG with different prompt lengths works correctly
141+
image = pipe(
142+
prompt="A cat",
143+
negative_prompt="blurry, low quality, distorted",
144+
true_cfg_scale=3.5,
145+
num_inference_steps=50,
146+
).images[0]
147+
```
148+
149+
For detailed benchmark scripts and results, see [this gist](https://gist.github.com/cdutr/bea337e4680268168550292d7819dc2f).
150+
117151
## QwenImagePipeline
118152

119153
[[autodoc]] QwenImagePipeline

docs/source/en/training/distributed_inference.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,35 @@ Pass the [`ContextParallelConfig`] to [`~ModelMixin.enable_parallelism`].
314314
pipeline.transformer.enable_parallelism(config=ContextParallelConfig(ulysses_degree=2))
315315
```
316316

317+
### Unified Attention
318+
319+
[Unified Sequence Parallelism](https://huggingface.co/papers/2405.07719) combines Ring Attention and Ulysses Attention into a single approach for efficient long-sequence processing. It applies Ulysses's *all-to-all* communication first to redistribute heads and sequence tokens, then uses Ring Attention to process the redistributed data, and finally reverses the *all-to-all* to restore the original layout.
320+
321+
This hybrid approach leverages the strengths of both methods:
322+
- **Ulysses Attention** efficiently parallelizes across attention heads
323+
- **Ring Attention** handles very long sequences with minimal memory overhead
324+
- Together, they enable 2D parallelization across both heads and sequence dimensions
325+
326+
[`ContextParallelConfig`] supports Unified Attention by specifying both `ulysses_degree` and `ring_degree`. The total number of devices used is `ulysses_degree * ring_degree`, arranged in a 2D grid where Ulysses and Ring groups are orthogonal (non-overlapping).
327+
Pass the [`ContextParallelConfig`] with both `ulysses_degree` and `ring_degree` set to bigger than 1 to [`~ModelMixin.enable_parallelism`].
328+
329+
```py
330+
pipeline.transformer.enable_parallelism(config=ContextParallelConfig(ulysses_degree=2, ring_degree=2))
331+
```
332+
333+
> [!TIP]
334+
> Unified Attention is to be used when there are enough devices to arrange in a 2D grid (at least 4 devices).
335+
336+
We ran a benchmark with Ulysess, Ring, and Unified Attention with [this script](https://github.com/huggingface/diffusers/pull/12693#issuecomment-3694727532) on a node of 4 H100 GPUs. The results are summarized as follows:
337+
338+
| CP Backend | Time / Iter (ms) | Steps / Sec | Peak Memory (GB) |
339+
|--------------------|------------------|-------------|------------------|
340+
| ulysses | 6670.789 | 7.50 | 33.85 |
341+
| ring | 13076.492 | 3.82 | 56.02 |
342+
| unified_balanced | 11068.705 | 4.52 | 33.85 |
343+
344+
From the above table, it's clear that Ulysses provides better throughput, but the number of devices it can use remains limited to the number of attention heads, a limitation that is solved by unified attention.
345+
317346
### parallel_config
318347

319348
Pass `parallel_config` during model initialization to enable context parallelism.

examples/dreambooth/train_dreambooth_lora_flux2_img2img.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,9 +1695,13 @@ def get_sigmas(timesteps, n_dim=4, dtype=torch.float32):
16951695
cond_model_input = (cond_model_input - latents_bn_mean) / latents_bn_std
16961696

16971697
model_input_ids = Flux2Pipeline._prepare_latent_ids(model_input).to(device=model_input.device)
1698-
cond_model_input_ids = Flux2Pipeline._prepare_image_ids(cond_model_input).to(
1698+
cond_model_input_list = [cond_model_input[i].unsqueeze(0) for i in range(cond_model_input.shape[0])]
1699+
cond_model_input_ids = Flux2Pipeline._prepare_image_ids(cond_model_input_list).to(
16991700
device=cond_model_input.device
17001701
)
1702+
cond_model_input_ids = cond_model_input_ids.view(
1703+
cond_model_input.shape[0], -1, model_input_ids.shape[-1]
1704+
)
17011705

17021706
# Sample noise that we'll add to the latents
17031707
noise = torch.randn_like(model_input)
@@ -1724,6 +1728,9 @@ def get_sigmas(timesteps, n_dim=4, dtype=torch.float32):
17241728
packed_noisy_model_input = Flux2Pipeline._pack_latents(noisy_model_input)
17251729
packed_cond_model_input = Flux2Pipeline._pack_latents(cond_model_input)
17261730

1731+
orig_input_shape = packed_noisy_model_input.shape
1732+
orig_input_ids_shape = model_input_ids.shape
1733+
17271734
# concatenate the model inputs with the cond inputs
17281735
packed_noisy_model_input = torch.cat([packed_noisy_model_input, packed_cond_model_input], dim=1)
17291736
model_input_ids = torch.cat([model_input_ids, cond_model_input_ids], dim=1)
@@ -1742,7 +1749,8 @@ def get_sigmas(timesteps, n_dim=4, dtype=torch.float32):
17421749
img_ids=model_input_ids, # B, image_seq_len, 4
17431750
return_dict=False,
17441751
)[0]
1745-
model_pred = model_pred[:, : packed_noisy_model_input.size(1) :]
1752+
model_pred = model_pred[:, : orig_input_shape[1], :]
1753+
model_input_ids = model_input_ids[:, : orig_input_ids_shape[1], :]
17461754

17471755
model_pred = Flux2Pipeline._unpack_latents_with_ids(model_pred, model_input_ids)
17481756

examples/dreambooth/train_dreambooth_lora_qwen_image.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,14 +1513,12 @@ def get_sigmas(timesteps, n_dim=4, dtype=torch.float32):
15131513
height=model_input.shape[3],
15141514
width=model_input.shape[4],
15151515
)
1516-
print(f"{prompt_embeds_mask.sum(dim=1).tolist()=}")
15171516
model_pred = transformer(
15181517
hidden_states=packed_noisy_model_input,
15191518
encoder_hidden_states=prompt_embeds,
15201519
encoder_hidden_states_mask=prompt_embeds_mask,
15211520
timestep=timesteps / 1000,
15221521
img_shapes=img_shapes,
1523-
txt_seq_lens=prompt_embeds_mask.sum(dim=1).tolist(),
15241522
return_dict=False,
15251523
)[0]
15261524
model_pred = QwenImagePipeline._unpack_latents(

src/diffusers/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
is_torchao_available,
2424
is_torchsde_available,
2525
is_transformers_available,
26+
is_transformers_version,
2627
)
2728

2829

@@ -227,6 +228,7 @@
227228
"FluxControlNetModel",
228229
"FluxMultiControlNetModel",
229230
"FluxTransformer2DModel",
231+
"GlmImageTransformer2DModel",
230232
"HiDreamImageTransformer2DModel",
231233
"HunyuanDiT2DControlNetModel",
232234
"HunyuanDiT2DModel",
@@ -460,6 +462,7 @@
460462
"BriaFiboPipeline",
461463
"BriaPipeline",
462464
"ChromaImg2ImgPipeline",
465+
"ChromaInpaintPipeline",
463466
"ChromaPipeline",
464467
"ChronoEditPipeline",
465468
"CLIPImageProjection",
@@ -494,6 +497,7 @@
494497
"FluxKontextPipeline",
495498
"FluxPipeline",
496499
"FluxPriorReduxPipeline",
500+
"GlmImagePipeline",
497501
"HiDreamImagePipeline",
498502
"HunyuanDiTControlNetPipeline",
499503
"HunyuanDiTPAGPipeline",
@@ -983,6 +987,7 @@
983987
FluxControlNetModel,
984988
FluxMultiControlNetModel,
985989
FluxTransformer2DModel,
990+
GlmImageTransformer2DModel,
986991
HiDreamImageTransformer2DModel,
987992
HunyuanDiT2DControlNetModel,
988993
HunyuanDiT2DModel,
@@ -1186,6 +1191,7 @@
11861191
BriaFiboPipeline,
11871192
BriaPipeline,
11881193
ChromaImg2ImgPipeline,
1194+
ChromaInpaintPipeline,
11891195
ChromaPipeline,
11901196
ChronoEditPipeline,
11911197
CLIPImageProjection,
@@ -1220,6 +1226,7 @@
12201226
FluxKontextPipeline,
12211227
FluxPipeline,
12221228
FluxPriorReduxPipeline,
1229+
GlmImagePipeline,
12231230
HiDreamImagePipeline,
12241231
HunyuanDiTControlNetPipeline,
12251232
HunyuanDiTPAGPipeline,

0 commit comments

Comments
 (0)