Skip to content

Commit 3cd940c

Browse files
claudecharchit7
authored andcommitted
Add Chroma modular pipeline (text2image)
Contribution to huggingface#13295. Adds a ModularPipeline for Chroma (t2i only): - T5-only text encoder block with Chroma's padding-token attention masking - guider-based CFG denoise loop (ClassifierFreeGuidance) - reuses Flux-style packed-latent prep, mu-shift timesteps, RoPE ids, decode Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dcg23vUZRMfkX5mkfdKh3Q
1 parent 53e5b00 commit 3cd940c

61 files changed

Lines changed: 2565 additions & 765 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/api/pipelines/chroma.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,11 @@ image.save("chroma-single-file.png")
105105
[[autodoc]] ChromaInpaintPipeline
106106
- all
107107
- __call__
108+
109+
## ChromaModularPipeline
110+
111+
[[autodoc]] ChromaModularPipeline
112+
113+
## ChromaAutoBlocks
114+
115+
[[autodoc]] ChromaAutoBlocks

‎src/diffusers/__init__.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,8 @@
503503
[
504504
"AnimaAutoBlocks",
505505
"AnimaModularPipeline",
506+
"ChromaAutoBlocks",
507+
"ChromaModularPipeline",
506508
"Cosmos3DistilledBlocks",
507509
"Cosmos3DistilledModularPipeline",
508510
"Cosmos3OmniBlocks",
@@ -1329,6 +1331,8 @@
13291331
from .modular_pipelines import (
13301332
AnimaAutoBlocks,
13311333
AnimaModularPipeline,
1334+
ChromaAutoBlocks,
1335+
ChromaModularPipeline,
13321336
Cosmos3DistilledBlocks,
13331337
Cosmos3DistilledModularPipeline,
13341338
Cosmos3OmniBlocks,

‎src/diffusers/loaders/peft.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
logger = logging.get_logger(__name__)
4747

4848
_SET_ADAPTER_SCALE_FN_MAPPING = defaultdict(
49-
lambda: (lambda model_cls, weights: weights),
49+
lambda: lambda model_cls, weights: weights,
5050
{
5151
"UNet2DConditionModel": _maybe_expand_lora_scales,
5252
"UNetMotionModel": _maybe_expand_lora_scales,

‎src/diffusers/modular_pipelines/__init__.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@
103103
"AnimaAutoBlocks",
104104
"AnimaModularPipeline",
105105
]
106+
_import_structure["chroma"] = [
107+
"ChromaAutoBlocks",
108+
"ChromaModularPipeline",
109+
]
106110
_import_structure["cosmos"] = [
107111
"Cosmos3DistilledBlocks",
108112
"Cosmos3DistilledModularPipeline",
@@ -139,6 +143,7 @@
139143
from ..utils.dummy_pt_objects import * # noqa F403
140144
else:
141145
from .anima import AnimaAutoBlocks, AnimaModularPipeline
146+
from .chroma import ChromaAutoBlocks, ChromaModularPipeline
142147
from .components_manager import ComponentsManager
143148
from .cosmos import (
144149
Cosmos3DistilledBlocks,

‎src/diffusers/modular_pipelines/anima/modular_blocks_anima.py‎

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ class AnimaCoreDenoiseStep(SequentialPipelineBlocks):
3434
Denoise block that takes encoded Anima text inputs and runs the denoising process.
3535
3636
Components:
37-
text_conditioner (`AnimaTextConditioner`) transformer (`CosmosTransformer3DModel`) scheduler
38-
(`FlowMatchEulerDiscreteScheduler`) guider (`ClassifierFreeGuidance`)
37+
text_conditioner (`AnimaTextConditioner`)
38+
transformer (`CosmosTransformer3DModel`)
39+
scheduler (`FlowMatchEulerDiscreteScheduler`)
40+
guider (`ClassifierFreeGuidance`)
3941
4042
Inputs:
4143
qwen_prompt_embeds (`Tensor`):
@@ -100,7 +102,8 @@ class AnimaDecodeStep(SequentialPipelineBlocks):
100102
Decode Anima latents into generated images.
101103
102104
Components:
103-
vae (`AutoencoderKLQwenImage`) image_processor (`VaeImageProcessor`)
105+
vae (`AutoencoderKLQwenImage`)
106+
image_processor (`VaeImageProcessor`)
104107
105108
Inputs:
106109
latents (`Tensor`):
@@ -128,12 +131,13 @@ def outputs(self):
128131
# auto_docstring
129132
class AnimaImg2ImgCoreDenoiseStep(SequentialPipelineBlocks):
130133
"""
131-
Denoise block for Anima image-to-image generation. Uses image_latents already in state from
132-
AnimaImg2ImgVaeEncoderStep.
134+
Denoise block for Anima image-to-image generation. Uses image_latents already in state from AnimaImg2ImgVaeEncoderStep.
133135
134136
Components:
135-
text_conditioner (`AnimaTextConditioner`) transformer (`CosmosTransformer3DModel`) scheduler
136-
(`FlowMatchEulerDiscreteScheduler`) guider (`ClassifierFreeGuidance`)
137+
text_conditioner (`AnimaTextConditioner`)
138+
transformer (`CosmosTransformer3DModel`)
139+
scheduler (`FlowMatchEulerDiscreteScheduler`)
140+
guider (`ClassifierFreeGuidance`)
137141
138142
Inputs:
139143
qwen_prompt_embeds (`Tensor`):
@@ -203,13 +207,13 @@ def outputs(self):
203207
# auto_docstring
204208
class AnimaAutoCoreDenoiseStep(AutoPipelineBlocks):
205209
"""
206-
Denoise step that selects between text-to-image and image-to-image denoising based on whether image_latents is
207-
present in state. - `AnimaCoreDenoiseStep` (text2image) is used when no image_latents are present. -
208-
`AnimaImg2ImgCoreDenoiseStep` (img2img) is used when image_latents are present.
210+
Denoise step that selects between text-to-image and image-to-image denoising based on whether image_latents is present in state. - `AnimaCoreDenoiseStep` (text2image) is used when no image_latents are present. - `AnimaImg2ImgCoreDenoiseStep` (img2img) is used when image_latents are present.
209211
210212
Components:
211-
text_conditioner (`AnimaTextConditioner`) transformer (`CosmosTransformer3DModel`) scheduler
212-
(`FlowMatchEulerDiscreteScheduler`) guider (`ClassifierFreeGuidance`)
213+
text_conditioner (`AnimaTextConditioner`)
214+
transformer (`CosmosTransformer3DModel`)
215+
scheduler (`FlowMatchEulerDiscreteScheduler`)
216+
guider (`ClassifierFreeGuidance`)
213217
214218
Inputs:
215219
qwen_prompt_embeds (`Tensor`):
@@ -271,11 +275,11 @@ def description(self) -> str:
271275
# auto_docstring
272276
class AnimaAutoVaeImageEncoderStep(AutoPipelineBlocks):
273277
"""
274-
VAE Image Encoder step that encodes the input image to produce image_latents. Skipped when no image is provided
275-
(text-to-image workflow).
278+
VAE Image Encoder step that encodes the input image to produce image_latents. Skipped when no image is provided (text-to-image workflow).
276279
277280
Components:
278-
vae (`AutoencoderKLQwenImage`) image_processor (`VaeImageProcessor`)
281+
vae (`AutoencoderKLQwenImage`)
282+
image_processor (`VaeImageProcessor`)
279283
280284
Inputs:
281285
image (`Image | list`, *optional*):
@@ -318,10 +322,15 @@ class AnimaAutoBlocks(SequentialPipelineBlocks):
318322
- `img2img`: requires `image`, `prompt`
319323
320324
Components:
321-
text_encoder (`Qwen3Model`) tokenizer (`Qwen2Tokenizer`) t5_tokenizer (`T5Tokenizer`) guider
322-
(`ClassifierFreeGuidance`) vae (`AutoencoderKLQwenImage`) image_processor (`VaeImageProcessor`)
323-
text_conditioner (`AnimaTextConditioner`) transformer (`CosmosTransformer3DModel`) scheduler
324-
(`FlowMatchEulerDiscreteScheduler`)
325+
text_encoder (`Qwen3Model`)
326+
tokenizer (`Qwen2Tokenizer`)
327+
t5_tokenizer (`T5Tokenizer`)
328+
guider (`ClassifierFreeGuidance`)
329+
vae (`AutoencoderKLQwenImage`)
330+
image_processor (`VaeImageProcessor`)
331+
text_conditioner (`AnimaTextConditioner`)
332+
transformer (`CosmosTransformer3DModel`)
333+
scheduler (`FlowMatchEulerDiscreteScheduler`)
325334
326335
Inputs:
327336
prompt (`str`):
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from typing import TYPE_CHECKING
2+
3+
from ...utils import (
4+
DIFFUSERS_SLOW_IMPORT,
5+
OptionalDependencyNotAvailable,
6+
_LazyModule,
7+
get_objects_from_module,
8+
is_torch_available,
9+
is_transformers_available,
10+
)
11+
12+
13+
_dummy_objects = {}
14+
_import_structure = {}
15+
16+
try:
17+
if not (is_transformers_available() and is_torch_available()):
18+
raise OptionalDependencyNotAvailable()
19+
except OptionalDependencyNotAvailable:
20+
from ...utils import dummy_torch_and_transformers_objects # noqa F403
21+
22+
_dummy_objects.update(get_objects_from_module(dummy_torch_and_transformers_objects))
23+
else:
24+
_import_structure["modular_blocks_chroma"] = ["ChromaAutoBlocks"]
25+
_import_structure["modular_pipeline"] = ["ChromaModularPipeline"]
26+
27+
if TYPE_CHECKING or DIFFUSERS_SLOW_IMPORT:
28+
try:
29+
if not (is_transformers_available() and is_torch_available()):
30+
raise OptionalDependencyNotAvailable()
31+
except OptionalDependencyNotAvailable:
32+
from ...utils.dummy_torch_and_transformers_objects import * # noqa F403
33+
else:
34+
from .modular_blocks_chroma import ChromaAutoBlocks
35+
from .modular_pipeline import ChromaModularPipeline
36+
else:
37+
import sys
38+
39+
sys.modules[__name__] = _LazyModule(
40+
__name__,
41+
globals()["__file__"],
42+
_import_structure,
43+
module_spec=__spec__,
44+
)
45+
46+
for name, value in _dummy_objects.items():
47+
setattr(sys.modules[__name__], name, value)

0 commit comments

Comments
 (0)