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, сначала прочитайте Coming from 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").

Подробнее о создании и загрузке конвейеров см. в руководствах Создание конвейера и Загрузка компонентов.

Понимание структуры

ModularPipeline состоит из двух частей: определения (блоки) и состояния (загруженные компоненты и конфигурации).

Выведите конвейер, чтобы увидеть его состояние — компоненты, их статус загрузки и конфигурацию.

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 из нашего исходного конвейера, а не загружает его заново, что позволяет эффективно использовать память. Подробнее в руководстве Загрузка компонентов.

Поскольку блоки комбинируемы, вы можете изменять определение конвейера, добавляя, удаляя или заменяя блоки для создания новых рабочих процессов. В следующем разделе мы добавим блок обнаружения границ Canny в конвейер ControlNet, чтобы вы могли передавать обычное изображение вместо предварительно обработанной карты границ Canny.

Создавайте новые рабочие процессы

Добавим блок canny edge detection в пайплайн ControlNet. Сначала загрузим готовый блок canny с Hub (см. Building Custom Blocks, чтобы создать собственный).

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, чтобы извлечь рабочий процесс ControlNet из 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.
      ...

Извлечённый workflow представляет собой 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.
      ...

Теперь конвейер принимает image в качестве входных данных вместо control_image. Поскольку блоки в последовательности автоматически разделяют данные, выход блока canny (control_image) поступает в блок denoise, которому он необходим, а вход блока canny (image) становится входом конвейера, так как ни один предыдущий блок его не предоставляет.

Создайте конвейер из модифицированных блоков и загрузите модель 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:

  • ModularPipelineBlocks: базовая единица для определения шага в конвейере.
  • SequentialPipelineBlocks: объединяет блоки для последовательного выполнения.
  • AutoPipelineBlocks: создание конвейеров, поддерживающих несколько рабочих процессов.
  • Состояния: как данные разделяются между блоками.
Update on GitHub