Diffusers documentation

快速入门

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

快速入门

Modular Diffusers 是一个用于快速构建灵活且可定制流水线的框架。这些流水线能够超越标准 DiffusionPipeline 的功能。Modular Diffusers 的核心是 ModularPipelineBlocks,它们可以与其他块组合,以适应新的工作流。这些块会被转换为 ModularPipeline,这是一个面向用户的友好接口,用于运行生成任务。

本指南将向您展示如何运行模块化流水线、理解其结构,并通过修改组成流水线的各个模块来进行自定义。如果您熟悉 DiffusionPipeline,请先阅读 来自 DiffusionPipeline,以了解其中的差异。

运行流水线

ModularPipeline 是用于加载、运行和管理模块化流水线的主要接口。

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]
image

from_pretrained() 采用延迟加载机制——它会读取配置以了解各组件的加载来源,但直到你调用 load_components() 时才会实际加载模型权重。这让你能够控制组件的加载时机和方式。

ComponentsManager 配合 enable_auto_cpu_offload 可自动在 CPU 和 GPU 之间移动模型,从而降低 Qwen-Image 等大型模型的内存占用。详情请参阅 ComponentsManager 指南。

如果不需要 offloading,请移除 components_manager 参数,并使用 to("cuda") 手动将 pipeline 移动到目标设备上。

有关创建和加载管道的更多信息,请参阅创建管道和加载组件指南。

理解结构

ModularPipeline 由两部分组成:定义(即各个 block)和 状态(即已加载的组件和配置)。

打印 pipeline 以查看其状态——包括各组件及其加载状态和配置。

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
    }
  ],
  ...
}

通过 pipe.blocks 访问定义 — 这是 ModularPipelineBlocks,用于定义流水线的工作流、输入、输出和计算逻辑。

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)
)

输出返回:

  • 支持的工作流(text2image、image2image、inpainting 等)
  • 它由以下子模块组成(text_encoder、vae_encoder、denoise、decode)

工作流程

此流水线支持多种工作流,并根据您提供的输入调整其行为。例如,如果您向流水线传入 image,它将执行图像到图像的工作流,而不是文本到图像的工作流。有关其底层工作原理的更多信息,请参阅 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]

使用 get_workflow() 可提取特定工作流的块。传入工作流名称(例如 "image2image"、"inpainting"、"controlnet_text2image")即可仅获取与该工作流相关的块。当您想要自定义或调试特定工作流时,此方法非常有用。您可以查看 pipe.blocks.available_workflows 以查看所有可用的工作流。

img2img_blocks = pipe.blocks.get_workflow("image2image")

子块

块可以包含其他块。pipe.blocks 提供顶层块定义(此处为 QwenImageAutoBlocks),而 sub_blocks 则用于访问其中的较小块。

QwenImageAutoBlocks 由以下部分组成:text_encoder、vae_encoder、controlnet_vae_encoder、denoise 和 decode。

这些子块按顺序依次执行,数据从一个块线性流向下一个块——每个块的 intermediate_outputs 都会作为 inputs 提供给下一个块。SequentialPipelineBlocks 就是这样工作的。

您可以通过 sub_blocks 属性访问它们。doc 属性可用于查看任何块的完整文档,包括其输入、输出和组件。

vae_encoder_block = pipe.blocks.sub_blocks["vae_encoder"]
print(vae_encoder_block.doc)

此代码块可以转换为流水线,从而能够通过 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)

它复用了原始流水线中的 VAE,而不是重新加载,从而保持内存使用效率。有关详细信息,请参阅 加载组件 指南。

由于块是可组合的,你可以通过添加、删除或替换块来修改流水线的定义,从而创建新的工作流。在下一节中,我们将向 ControlNet 流水线添加一个 canny 边缘检测块,这样你就可以传入一张普通图像,而不是一张预先处理好的 canny 边缘图。

组合新的工作流

让我们向 ControlNet 流水线中添加一个 canny 边缘检测块。首先,从 Hub 加载一个预构建的 canny 块(参见 构建自定义块 以创建您自己的块)。

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 image

使用 get_workflow 从 QwenImageAutoBlocks 中提取 ControlNet 工作流。

# 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.
      ...

提取出的工作流是一个 SequentialPipelineBlocks,目前它需要 control_image 作为输入。请在开头插入 canny 块,以便该流水线能够接受普通图像作为输入。

# 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.
      ...

现在,pipeline 以 image 作为输入,而不是 control_image。由于序列中的各个 block 会自动共享数据,canny block 的输出(control_image)会流向需要它的 denoise block,而 canny block 的输入(image)则成为 pipeline 的输入,因为没有更早的 block 提供该数据。

使用修改后的模块创建 pipeline,并加载 ControlNet 模型。ControlNet 不属于原始模型仓库,因此需要单独加载,并通过 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)

现在运行流水线 - canny 块会为 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

后续步骤

学习基础知识
构建自定义块
共享组件
可视化界面

了解 Modular Diffusers 的核心构建模块:

Update on GitHub