Diffusers documentation
Início rápido
Início rápido
Modular Diffusers é um framework para construir rapidamente pipelines flexíveis e personalizáveis. Esses pipelines podem ir além do que os DiffusionPipeline padrão conseguem fazer. No núcleo do Modular Diffusers estão os ModularPipelineBlocks, que podem ser combinados com outros blocos para se adaptar a novos fluxos de trabalho. Os blocos são convertidos em um ModularPipeline, uma interface amigável voltada para o usuário para executar tarefas de geração.
Este guia mostra como executar um pipeline modular, entender sua estrutura e personalizá-lo modificando os blocos que o compõem. Se você está familiarizado com DiffusionPipeline, leia Vindo do DiffusionPipeline primeiro para saber o que funciona de forma diferente.
Executar um pipeline
ModularPipeline é a interface principal para carregar, executar e gerenciar pipelines modulares.
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() usa carregamento preguiçoso - ele lê a configuração para saber de onde carregar cada componente, mas não carrega os pesos do modelo de fato até você chamar load_components(). Isso dá a você controle sobre quando e como os componentes são carregados.
ComponentsManagercomenable_auto_cpu_offloadmove automaticamente os modelos entre a CPU e a GPU conforme necessário, reduzindo o uso de memória para modelos grandes como Qwen-Image. Saiba mais no guia ComponentsManager.Se você não precisar de offloading, remova o argumento
components_managere mova o pipeline para o seu dispositivo manualmente comto("cuda").
Saiba mais sobre a criação e o carregamento de pipelines nos guias Criando um pipeline e Carregando componentes.
Entender a estrutura
A ModularPipeline tem duas partes: uma definição (os blocos) e um estado (os componentes e configurações carregados).
Imprima o pipeline para ver seu estado — os componentes e seu status de carregamento e configuração.
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
}
],
...
}Acesse a definição por meio de pipe.blocks — este é o ModularPipelineBlocks que define os fluxos de trabalho, entradas, saídas e a lógica de computação do 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)
)A saída retorna:
- Os fluxos de trabalho suportados (text2image, image2image, inpainting, etc.)
- Os Sub-Blocks dos quais é composto (text_encoder, vae_encoder, denoise, decode)
Fluxos de trabalho
Este pipeline suporta vários fluxos de trabalho e adapta seu comportamento com base nas entradas que você fornece. Por exemplo, se você passar image para o pipeline, ele executa um fluxo de trabalho de imagem para imagem em vez de texto para imagem. Saiba mais sobre como isso funciona por baixo dos panos no guia 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]Use get_workflow() para extrair os blocos de um workflow específico. Passe o nome do workflow (por exemplo, "image2image", "inpainting", "controlnet_text2image") para obter apenas os blocos relevantes para aquele workflow. Isso é útil quando você deseja personalizar ou depurar um workflow específico. Você pode verificar pipe.blocks.available_workflows para ver todos os workflows disponíveis.
img2img_blocks = pipe.blocks.get_workflow("image2image")Sub-blocos
Blocos podem conter outros blocos. pipe.blocks fornece a definição do bloco de nível superior (aqui, QwenImageAutoBlocks), enquanto sub_blocks permite acessar os blocos menores dentro dele.
QwenImageAutoBlocks é composto por: text_encoder, vae_encoder, controlnet_vae_encoder, denoise e decode.
Esses sub-blocos são executados um após o outro e os dados fluem linearmente de um bloco para o próximo — os intermediate_outputs de cada bloco ficam disponíveis como inputs para o bloco seguinte. É assim que o SequentialPipelineBlocks funciona.
Você pode acessá-los por meio da propriedade sub_blocks. A propriedade doc é útil para ver a documentação completa de qualquer bloco, incluindo suas entradas, saídas e componentes.
vae_encoder_block = pipe.blocks.sub_blocks["vae_encoder"]
print(vae_encoder_block.doc)Este bloco pode ser convertido em um pipeline para que ele possa ser executado de forma independente com 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)Ele reutiliza o VAE do nosso pipeline original em vez de recarregá-lo, mantendo o uso de memória eficiente. Saiba mais no guia Carregando componentes.
Como os blocos são composíveis, você pode modificar a definição do pipeline adicionando, removendo ou substituindo blocos para criar novos fluxos de trabalho. Na próxima seção, adicionaremos um bloco de detecção de bordas canny a um pipeline ControlNet, para que você possa passar uma imagem comum em vez de um mapa de bordas canny pré-processado.
Crie novos fluxos de trabalho
Vamos adicionar um bloco de detecção de bordas canny a um pipeline do ControlNet. Primeiro, carregue um bloco canny pré-construído do Hub (veja Building Custom Blocks para criar o seu próprio).
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 imageUse get_workflow para extrair o workflow do 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.
...O workflow extraído é um SequentialPipelineBlocks e atualmente requer control_image como entrada. Insira o bloco canny no início para que o pipeline aceite uma imagem comum.
# 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.
...Agora o pipeline recebe image como entrada em vez de control_image. Como os blocos em uma sequência compartilham dados automaticamente, a saída do bloco canny (control_image) flui para o bloco denoise que precisa dela, e a entrada do bloco canny (image) se torna uma entrada do pipeline, já que nenhum bloco anterior a fornece.
Crie um pipeline a partir dos blocos modificados e carregue um modelo ControlNet. O ControlNet não faz parte do repositório original do modelo, portanto, carregue-o separadamente e adicione-o com 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)Agora execute o pipeline - o bloco canny pré-processa a imagem para o 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]
outputPróximas etapas
Entenda os blocos de construção fundamentais do Modular Diffusers:
- ModularPipelineBlocks: a unidade básica para definir uma etapa em um pipeline.
- SequentialPipelineBlocks: Encadeia blocos para executá-los em sequência.
- AutoPipelineBlocks: Crie pipelines que suportam múltiplos fluxos de trabalho.
- Estados: Como os dados são compartilhados entre blocos.
Aprenda a criar seus próprios blocos com lógica personalizada no guia Building Custom Blocks.
Use ComponentsManager para compartilhar modelos entre vários pipelines e gerenciar a memória de forma eficiente.
Conecte pipelines modulares ao Mellon, uma interface visual baseada em nós para a criação de fluxos de trabalho. Blocos personalizados criados com Modular Diffusers funcionam imediatamente com o Mellon - sem necessidade de código de interface. Leia mais no guia do Mellon.