Diffusers documentation
Démarrage rapide
Démarrage rapide
Modular Diffusers est un framework permettant de construire rapidement des pipelines flexibles et personnalisables. Ces pipelines peuvent aller au-delà de ce que les DiffusionPipeline standard peuvent faire. Au cœur de Modular Diffusers se trouvent des ModularPipelineBlocks qui peuvent être combinés avec d'autres blocs pour s'adapter à de nouveaux flux de travail. Les blocs sont convertis en ModularPipeline, une interface conviviale destinée aux utilisateurs pour exécuter des tâches de génération.
Ce guide vous montre comment exécuter un pipeline modulaire, comprendre sa structure et le personnaliser en modifiant les blocs qui le composent. Si vous êtes familier avec DiffusionPipeline, lisez d'abord Coming from DiffusionPipeline pour savoir ce qui fonctionne différemment.
Exécuter un pipeline
ModularPipeline est l’interface principale pour charger, exécuter et gérer les pipelines modulaires.
import torch
from diffusers import ModularPipeline, ComponentsManager
# Use ComponentsManager to enable auto CPU offloading for memory efficiency
manager = ComponentsManager()
manager.enable_auto_cpu_offload(device="cuda:0")
pipe = ModularPipeline.from_pretrained("Qwen/Qwen-Image", components_manager=manager)
pipe.load_components(dtype=torch.bfloat16)
image = pipe(
prompt="cat wizard with red hat, gandalf, lord of the rings, detailed, fantasy, cute, adorable, Pixar, Disney",
).images[0]
imagefrom_pretrained() utilise un chargement paresseux : il lit la configuration pour savoir où charger chaque composant, mais ne charge réellement les poids du modèle que lorsque vous appelez load_components(). Cela vous donne le contrôle sur le moment et la manière dont les composants sont chargés.
ComponentsManageravecenable_auto_cpu_offloaddéplace automatiquement les modèles entre le CPU et le GPU selon les besoins, réduisant ainsi l’utilisation de la mémoire pour les grands modèles comme Qwen-Image. En savoir plus dans le guide ComponentsManager.Si vous n’avez pas besoin de déchargement, supprimez l’argument
components_manageret déplacez le pipeline manuellement sur votre appareil avecto("cuda").
En savoir plus sur la création et le chargement de pipelines dans les guides Créer un pipeline et Charger des composants.
Comprendre la structure
Un ModularPipeline comporte deux parties : une définition (les blocs) et un état (les composants et configurations chargés).
Affichez le pipeline pour voir son état — les composants et leur statut de chargement et leur configuration.
print(pipe)QwenImageModularPipeline {
"_blocks_class_name": "QwenImageAutoBlocks",
"_class_name": "QwenImageModularPipeline",
"_diffusers_version": "0.37.0.dev0",
"transformer": [
"diffusers",
"QwenImageTransformer2DModel",
{
"pretrained_model_name_or_path": "Qwen/Qwen-Image",
"revision": null,
"subfolder": "transformer",
"type_hint": [
"diffusers",
"QwenImageTransformer2DModel"
],
"variant": null
}
],
...
}Accédez à la définition via pipe.blocks — il s’agit du ModularPipelineBlocks qui définit les flux de travail, les entrées, les sorties et la logique de calcul du pipeline.
print(pipe.blocks)QwenImageAutoBlocks(
Class: SequentialPipelineBlocks
Description: Auto Modular pipeline for text-to-image, image-to-image, inpainting, and controlnet tasks using QwenImage.
Supported workflows:
- `text2image`: requires `prompt`
- `image2image`: requires `prompt`, `image`
- `inpainting`: requires `prompt`, `mask_image`, `image`
- `controlnet_text2image`: requires `prompt`, `control_image`
...
Components:
text_encoder (`Qwen2_5_VLForConditionalGeneration`)
vae (`AutoencoderKLQwenImage`)
transformer (`QwenImageTransformer2DModel`)
...
Sub-Blocks:
[0] text_encoder (QwenImageAutoTextEncoderStep)
[1] vae_encoder (QwenImageAutoVaeEncoderStep)
[2] controlnet_vae_encoder (QwenImageOptionalControlNetVaeEncoderStep)
[3] denoise (QwenImageAutoCoreDenoiseStep)
[4] decode (QwenImageAutoDecodeStep)
)La sortie renvoie :
- Les flux de travail pris en charge (text2image, image2image, inpainting, etc.)
- Les sous-blocs dont il est composé (text_encoder, vae_encoder, denoise, decode)
Flux de travail
Ce pipeline prend en charge plusieurs flux de travail et adapte son comportement en fonction des entrées que vous fournissez. Par exemple, si vous passez image au pipeline, il exécute un flux de travail image-vers-image au lieu de texte-vers-image. En savoir plus sur le fonctionnement interne dans le guide AutoPipelineBlocks.
from diffusers.utils import load_image
input_image = load_image("https://github.com/Trgtuan10/Image_storage/blob/main/cute_cat.png?raw=true")
image = pipe(
prompt="cat wizard with red hat, gandalf, lord of the rings, detailed, fantasy, cute, adorable, Pixar, Disney",
image=input_image,
).images[0]Utilisez get_workflow() pour extraire les blocs d'un workflow spécifique. Transmettez le nom du workflow (par exemple, "image2image", "inpainting", "controlnet_text2image") pour n'obtenir que les blocs pertinents pour ce workflow. Cela est utile lorsque vous souhaitez personnaliser ou déboguer un workflow spécifique. Vous pouvez consulter pipe.blocks.available_workflows pour voir tous les workflows disponibles.
img2img_blocks = pipe.blocks.get_workflow("image2image")Sous-blocs
Les blocs peuvent contenir d'autres blocs. pipe.blocks vous donne la définition du bloc de premier niveau (ici, QwenImageAutoBlocks), tandis que sub_blocks vous permet d'accéder aux plus petits blocs à l'intérieur.
QwenImageAutoBlocks est composé de : text_encoder, vae_encoder, controlnet_vae_encoder, denoise et decode.
Ces sous-blocs s’exécutent les uns après les autres et les données circulent linéairement d’un bloc à l’autre — les intermediate_outputs de chaque bloc deviennent disponibles en tant que inputs du bloc suivant. C’est ainsi que SequentialPipelineBlocks fonctionne.
Vous pouvez y accéder via la propriété sub_blocks. La propriété doc est utile pour consulter la documentation complète de n’importe quel bloc, y compris ses entrées, ses sorties et ses composants.
vae_encoder_block = pipe.blocks.sub_blocks["vae_encoder"]
print(vae_encoder_block.doc)Ce bloc peut être converti en pipeline afin qu'il puisse s'exécuter de manière autonome avec init_pipeline().
vae_encoder_pipe = vae_encoder_block.init_pipeline()
# Reuse the VAE we already loaded, we can reuse it with update_components() method
vae_encoder_pipe.update_components(vae=pipe.vae)
# Run just this block
image_latents = vae_encoder_pipe(image=input_image).image_latents
print(image_latents.shape)Il réutilise le VAE de notre pipeline d’origine au lieu de le recharger, ce qui permet de maintenir une utilisation de la mémoire efficace. En savoir plus dans le guide Chargement des composants.
Les blocs étant composables, vous pouvez modifier la définition du pipeline en ajoutant, supprimant ou échangeant des blocs pour créer de nouveaux flux de travail. Dans la section suivante, nous ajouterons un bloc de détection de contours canny à un pipeline ControlNet, afin que vous puissiez passer une image ordinaire plutôt qu’une carte de contours canny prétraitée.
Composer de nouveaux flux de travail
Ajoutons un bloc de détection de contours canny à un pipeline ControlNet. Chargez d’abord un bloc canny préconstruit depuis le Hub (voir Building Custom Blocks pour en créer un vous-même).
from diffusers.modular_pipelines import ModularPipelineBlocks
# Load a canny block from the Hub
canny_block = ModularPipelineBlocks.from_pretrained(
"diffusers-internal-dev/canny-filtering",
trust_remote_code=True,
)
print(canny_block.doc)class CannyBlock
Inputs:
image (`Union[Image, ndarray]`):
Image to compute canny filter on
low_threshold (`int`, *optional*, defaults to 50):
Low threshold for the canny filter.
high_threshold (`int`, *optional*, defaults to 200):
High threshold for the canny filter.
...
Outputs:
control_image (`PIL.Image`):
Canny map for input imageUtilisez get_workflow pour extraire le workflow ControlNet de QwenImageAutoBlocks.
# Get the controlnet workflow that we want to work with
blocks = pipe.blocks.get_workflow("controlnet_text2image")
print(blocks.doc)class SequentialPipelineBlocks
Inputs:
prompt (`str`):
The prompt or prompts to guide image generation.
control_image (`Image`):
Control image for ControlNet conditioning.
...Le workflow extrait est un SequentialPipelineBlocks et il nécessite actuellement control_image en entrée. Insérez le bloc canny au début afin que le pipeline accepte une image ordinaire à la place.
# Insert canny at the beginning
blocks.sub_blocks.insert("canny", canny_block, 0)
# Check the updated structure: CannyBlock is now listed as first sub-block
print(blocks)
# Check the updated doc
print(blocks.doc)class SequentialPipelineBlocks
Inputs:
image (`Union[Image, ndarray]`):
Image to compute canny filter on
low_threshold (`int`, *optional*, defaults to 50):
Low threshold for the canny filter.
high_threshold (`int`, *optional*, defaults to 200):
High threshold for the canny filter.
prompt (`str`):
The prompt or prompts to guide image generation.
...Le pipeline prend désormais image en entrée au lieu de control_image. Comme les blocs d’une séquence partagent automatiquement les données, la sortie du bloc canny (control_image) est transmise au bloc de débruitage qui en a besoin, et l’entrée du bloc canny (image) devient une entrée du pipeline, aucun bloc antérieur ne la fournissant.
Créez un pipeline à partir des blocs modifiés et chargez un modèle ControlNet. Le ControlNet ne fait pas partie du dépôt de modèle d’origine, il faut donc le charger séparément et l’ajouter avec update_components().
pipeline = blocks.init_pipeline("Qwen/Qwen-Image", components_manager=manager)
pipeline.load_components(dtype=torch.bfloat16)
# Load the ControlNet model
controlnet_spec = pipeline.get_component_spec("controlnet")
controlnet_spec.pretrained_model_name_or_path = "InstantX/Qwen-Image-ControlNet-Union"
controlnet = controlnet_spec.load(dtype=torch.bfloat16)
pipeline.update_components(controlnet=controlnet)Exécutez maintenant le pipeline - le bloc canny prétraite l'image pour ControlNet.
from diffusers.utils import load_image
prompt = "cat wizard with red hat, gandalf, lord of the rings, detailed, fantasy, cute, adorable, Pixar, Disney"
image = load_image("https://github.com/Trgtuan10/Image_storage/blob/main/cute_cat.png?raw=true")
output = pipeline(
prompt=prompt,
image=image,
).images[0]
outputÉtapes suivantes
Comprendre les briques de base de Modular Diffusers :
- ModularPipelineBlocks : l'unité de base pour définir une étape dans un pipeline.
- SequentialPipelineBlocks : Enchaîne des blocs pour les exécuter séquentiellement.
- AutoPipelineBlocks : créez des pipelines qui prennent en charge plusieurs flux de travail.
- États : Comment les données sont partagées entre les blocs.
Apprenez à créer vos propres blocs avec une logique personnalisée dans le guide Building Custom Blocks.
Utilisez ComponentsManager pour partager des modèles entre plusieurs pipelines et gérer la mémoire efficacement.
Connectez les pipelines modulaires à Mellon, une interface visuelle basée sur des nœuds pour construire des workflows. Les blocs personnalisés créés avec Modular Diffusers fonctionnent immédiatement avec Mellon - aucun code d'interface utilisateur n'est requis. En savoir plus dans le guide Mellon.