You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/source/en/modular_diffusers/guiders.md
+1-15Lines changed: 1 addition & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -89,29 +89,15 @@ t2i_pipeline.guider
89
89
90
90
## Changing guider parameters
91
91
92
-
The guider parameters can be adjusted with either the [`~ComponentSpec.create`] method or with[`~ModularPipeline.update_components`]. The example below changes the `guidance_scale` value.
92
+
The guider parameters can be adjusted with the [`~ComponentSpec.create`] method and[`~ModularPipeline.update_components`]. The example below changes the `guidance_scale` value.
Copy file name to clipboardExpand all lines: docs/source/en/modular_diffusers/modular_diffusers_states.md
+1-3Lines changed: 1 addition & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,9 +25,7 @@ This guide explains how states work and how they connect blocks.
25
25
26
26
The [`~modular_pipelines.PipelineState`] is a global state container for all blocks. It maintains the complete runtime state of the pipeline and provides a structured way for blocks to read from and write to shared data.
27
27
28
-
There are two dict's in [`~modular_pipelines.PipelineState`] for structuring data.
29
-
30
-
- The `values` dict is a **mutable** state containing a copy of user provided input values and intermediate output values generated by blocks. If a block modifies an `input`, it will be reflected in the `values` dict after calling `set_block_state`.
28
+
[`~modular_pipelines.PipelineState`] stores all data in a `values` dict, which is a **mutable** state containing user provided input values and intermediate output values generated by blocks. If a block modifies an `input`, it will be reflected in the `values` dict after calling `set_block_state`.
@@ -25,81 +25,151 @@ This guide will show you how to create a [`~modular_pipelines.ModularPipelineBlo
25
25
26
26
A [`~modular_pipelines.ModularPipelineBlocks`] requires `inputs`, and `intermediate_outputs`.
27
27
28
-
-`inputs` are values provided by a user and retrieved from the [`~modular_pipelines.PipelineState`]. This is useful because some workflows resize an image, but the original image is still required. The [`~modular_pipelines.PipelineState`] maintains the original image.
28
+
-`inputs` are values a block reads from the [`~modular_pipelines.PipelineState`] to perform its computation. These can be values provided by a user (like a prompt or image) or values produced by a previous block (like encoded `image_latents`).
29
29
30
30
Use `InputParam` to define `inputs`.
31
31
32
-
```py
33
-
from diffusers.modular_pipelines import InputParam
34
-
35
-
user_inputs = [
36
-
InputParam(name="image", type_hint="PIL.Image", description="raw input image to process")
37
-
]
38
-
```
32
+
```py
33
+
classImageEncodeStep(ModularPipelineBlocks):
34
+
...
35
+
36
+
@property
37
+
definputs(self):
38
+
return [
39
+
InputParam(name="image", type_hint="PIL.Image", required=True, description="raw input image to process"),
40
+
]
41
+
...
42
+
```
39
43
40
44
-`intermediate_outputs` are new values created by a block and added to the [`~modular_pipelines.PipelineState`]. The `intermediate_outputs` are available as `inputs` for subsequent blocks or available as the final output from running the pipeline.
41
45
42
46
Use `OutputParam` to define `intermediate_outputs`.
43
47
44
-
```py
45
-
from diffusers.modular_pipelines import OutputParam
48
+
```py
49
+
classImageEncodeStep(ModularPipelineBlocks):
50
+
...
46
51
47
-
user_intermediate_outputs = [
48
-
OutputParam(name="image_latents", description="latents representing the image")
49
-
]
50
-
```
52
+
@property
53
+
defintermediate_outputs(self):
54
+
return [
55
+
OutputParam(name="image_latents", description="latents representing the image"),
56
+
]
57
+
58
+
...
59
+
```
51
60
52
61
The intermediate inputs and outputs share data to connect blocks. They are accessible at any point, allowing you to track the workflow's progress.
53
62
63
+
## Components and configs
64
+
65
+
The components and pipeline-level configs a block needs are specified in [`ComponentSpec`] and [`~modular_pipelines.ConfigSpec`].
66
+
67
+
-[`ComponentSpec`] contains the expected components used by a block. You need the `name` of the component and ideally a `type_hint` that specifies exactly what the component is.
68
+
-[`~modular_pipelines.ConfigSpec`] contains pipeline-level settings that control behavior across all blocks.
When the blocks are converted into a pipeline, the components become available to the block as the first argument in `__call__`.
90
+
54
91
## Computation logic
55
92
56
93
The computation a block performs is defined in the `__call__` method and it follows a specific structure.
57
94
58
-
1. Retrieve the [`~modular_pipelines.BlockState`] to get a local view of the `inputs`
95
+
1. Retrieve the [`~modular_pipelines.BlockState`] to get a local view of the `inputs`.
59
96
2. Implement the computation logic on the `inputs`.
60
97
3. Update [`~modular_pipelines.PipelineState`] to push changes from the local [`~modular_pipelines.BlockState`] back to the global [`~modular_pipelines.PipelineState`].
61
98
4. Return the components and state which becomes available to the next block.
62
99
63
100
```py
64
-
def__call__(self, components, state):
65
-
# Get a local view of the state variables this block needs
66
-
block_state =self.get_block_state(state)
101
+
classImageEncodeStep(ModularPipelineBlocks):
102
+
103
+
def__call__(self, components, state):
104
+
# Get a local view of the state variables this block needs
105
+
block_state =self.get_block_state(state)
67
106
68
-
# Your computation logic here
69
-
# block_state contains all your inputs
70
-
# Access them like: block_state.image, block_state.processed_image
107
+
# Your computation logic here
108
+
# block_state contains all your inputs
109
+
# Access them like: block_state.image, block_state.processed_image
71
110
72
-
# Update the pipeline state with your updated block_states
73
-
self.set_block_state(state, block_state)
74
-
return components, state
111
+
# Update the pipeline state with your updated block_states
112
+
self.set_block_state(state, block_state)
113
+
return components, state
75
114
```
76
115
77
-
### Components and configs
116
+
##Putting it all together
78
117
79
-
The components and pipeline-level configs a block needs are specified in [`ComponentSpec`] and [`~modular_pipelines.ConfigSpec`].
118
+
Here is the complete block with all the pieces connected.
80
119
81
-
-[`ComponentSpec`] contains the expected components used by a block. You need the `name` of the component and ideally a `type_hint` that specifies exactly what the component is.
82
-
-[`~modular_pipelines.ConfigSpec`] contains pipeline-level settings that control behavior across all blocks.
120
+
```py
121
+
from diffusers import ComponentSpec, AutoencoderKL
122
+
from diffusers.modular_pipelines import InputParam, ModularPipelineBlocks, OutputParam
Every block has a `doc` property that is automatically generated from the properties you defined above. It provides a summary of the block's description, components, inputs, and outputs.
Copy file name to clipboardExpand all lines: docs/source/en/modular_diffusers/quickstart.md
+52-14Lines changed: 52 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -39,17 +39,44 @@ image
39
39
[`~ModularPipeline.from_pretrained`] uses lazy loading - it reads the configuration to learn where to load each component from, but doesn't actually load the model weights until you call [`~ModularPipeline.load_components`]. This gives you control over when and how components are loaded.
40
40
41
41
> [!TIP]
42
-
> [`ComponentsManager`] with `enable_auto_cpu_offload` automatically moves models between CPU and GPU as needed, reducing memory usage for large models like Qwen-Image. Learn more in the [ComponentsManager](./components_manager) guide.
42
+
> `ComponentsManager` with `enable_auto_cpu_offload` automatically moves models between CPU and GPU as needed, reducing memory usage for large models like Qwen-Image. Learn more in the [ComponentsManager](./components_manager) guide.
43
+
>
44
+
> If you don't need offloading, remove the `components_manager` argument and move the pipeline to your device manually with `to("cuda")`.
43
45
44
46
Learn more about creating and loading pipelines in the [Creating a pipeline](https://huggingface.co/docs/diffusers/modular_diffusers/modular_pipeline#creating-a-pipeline) and [Loading components](https://huggingface.co/docs/diffusers/modular_diffusers/modular_pipeline#loading-components) guides.
45
47
46
48
## Understand the structure
47
49
48
-
A [`ModularPipeline`] has two parts:
49
-
-**State**: the loaded components (models, schedulers, processors) and configuration
50
-
-**Definition**: the [`ModularPipelineBlocks`] that specify inputs, outputs, expected components and computation logic
50
+
A [`ModularPipeline`] has two parts: a **definition** (the blocks) and a **state** (the loaded components and configs).
51
51
52
-
The blocks define *what* the pipeline does. Access them through `pipe.blocks`.
52
+
Print the pipeline to see its state — the components and their loading status and configuration.
Access the definition through `pipe.blocks` — this is the [`~modular_pipelines.ModularPipelineBlocks`] that defines the pipeline's workflows, inputs, outputs, and computation logic.
53
80
```py
54
81
print(pipe.blocks)
55
82
```
@@ -87,7 +114,8 @@ The output returns:
87
114
88
115
### Workflows
89
116
90
-
`QwenImageAutoBlocks` is a [`ConditionalPipelineBlocks`], so this pipeline supports multiple workflows and adapts its behavior based on the inputs you provide. For example, if you pass `image` to the pipeline, it runs an image-to-image workflow instead of text-to-image. Let's see this in action with an example.
117
+
This pipeline supports multiple workflows and adapts its behavior based on the inputs you provide. For example, if you pass `image` to the pipeline, it runs an image-to-image workflow instead of text-to-image. Learn more about how this works under the hood in the [AutoPipelineBlocks](https://huggingface.co/docs/diffusers/modular_diffusers/auto_pipeline_blocks) guide.
118
+
91
119
```py
92
120
from diffusers.utils import load_image
93
121
@@ -99,20 +127,21 @@ image = pipe(
99
127
).images[0]
100
128
```
101
129
102
-
Use `get_workflow()` to extract the blocks for a specific workflow. Pass the workflow name (e.g., `"image2image"`, `"inpainting"`, `"controlnet_text2image"`) to get only the blocks relevant to that workflow.
130
+
Use `get_workflow()` to extract the blocks for a specific workflow. Pass the workflow name (e.g., `"image2image"`, `"inpainting"`, `"controlnet_text2image"`) to get only the blocks relevant to that workflow. This is useful when you want to customize or debug a specific workflow. You can check `pipe.blocks.available_workflows` to see all available workflows.
Conditional blocks are convenient for users, but their conditional logic adds complexity when customizing or debugging. Extracting a workflow gives you the specific blocks relevant to your workflow, making it easier to work with. Learn more in the [AutoPipelineBlocks](https://huggingface.co/docs/diffusers/modular_diffusers/auto_pipeline_blocks) guide.
108
135
109
136
### Sub-blocks
110
137
111
138
Blocks can contain other blocks. `pipe.blocks` gives you the top-level block definition (here, `QwenImageAutoBlocks`), while `sub_blocks` lets you access the smaller blocks inside it.
112
139
113
-
`QwenImageAutoBlocks` is composed of: `text_encoder`, `vae_encoder`, `controlnet_vae_encoder`, `denoise`, and `decode`. Access them through the `sub_blocks` property.
140
+
`QwenImageAutoBlocks` is composed of: `text_encoder`, `vae_encoder`, `controlnet_vae_encoder`, `denoise`, and `decode`.
114
141
115
-
The `doc` property is useful for seeing the full documentation of any block, including its inputs, outputs, and components.
142
+
These sub-blocks run one after another and data flows linearly from one block to the next — each block's `intermediate_outputs` become available as `inputs` to the next block. This is how [`SequentialPipelineBlocks`](./sequential_pipeline_blocks) work.
143
+
144
+
You can access them through the `sub_blocks` property. The `doc` property is useful for seeing the full documentation of any block, including its inputs, outputs, and components.
@@ -182,9 +211,8 @@ class SequentialPipelineBlocks
182
211
...
183
212
```
184
213
185
-
The extracted workflow is a [`SequentialPipelineBlocks`](./sequential_pipeline_blocks) - a multi-block type where blocks run one after another and data flows linearly from one block to the next. Each block's `intermediate_outputs` become available as `inputs` to subsequent blocks.
186
214
187
-
Currently this workflow requires `control_image` as input. Let's insert the canny block at the beginning so the pipeline accepts a regular image instead.
215
+
The extracted workflow is a [`SequentialPipelineBlocks`](./sequential_pipeline_blocks) and it currently requires `control_image` as input. Insert the canny block at the beginning so the pipeline accepts a regular image instead.
188
216
```py
189
217
# Insert canny at the beginning
190
218
blocks.sub_blocks.insert("canny", canny_block, 0)
@@ -211,7 +239,7 @@ class SequentialPipelineBlocks
211
239
212
240
Now the pipeline takes `image` as input instead of `control_image`. Because blocks in a sequence share data automatically, the canny block's output (`control_image`) flows to the denoise block that needs it, and the canny block's input (`image`) becomes a pipeline input since no earlier block provides it.
213
241
214
-
Create a pipeline from the modified blocks and load a ControlNet model.
242
+
Create a pipeline from the modified blocks and load a ControlNet model. The ControlNet isn't part of the original model repository, so load it separately and add it with [`~ModularPipeline.update_components`].
0 commit comments