# Быстрый старт

Modular Diffusers — это фреймворк для быстрого создания гибких и настраиваемых конвейеров. Такие конвейеры могут выполнять задачи, выходящие за рамки возможностей стандартных `DiffusionPipeline`. В основе Modular Diffusers лежат [ModularPipelineBlocks](/docs/diffusers/main/ru/api/modular_diffusers/pipeline_blocks#diffusers.ModularPipelineBlocks), которые можно комбинировать с другими блоками для адаптации к новым рабочим процессам. Блоки преобразуются в [ModularPipeline](/docs/diffusers/main/ru/api/modular_diffusers/pipeline#diffusers.ModularPipeline) — удобный интерфейс для пользователя, предназначенный для выполнения задач генерации.

В этом руководстве показано, как запускать модульный конвейер, понимать его структуру и настраивать его, изменяя блоки, из которых он состоит. Если вы знакомы с [DiffusionPipeline](/docs/diffusers/main/ru/api/pipelines/overview#diffusers.DiffusionPipeline), сначала прочитайте [Coming from DiffusionPipeline](./coming_from_diffusion_pipeline), чтобы узнать, что работает иначе.

## Запуск конвейера

[ModularPipeline](/docs/diffusers/main/ru/api/modular_diffusers/pipeline#diffusers.ModularPipeline) — это основной интерфейс для загрузки, запуска и управления модульными конвейерами.
```py
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()](/docs/diffusers/main/ru/api/modular_diffusers/pipeline#diffusers.ModularPipeline.from_pretrained) использует ленивую загрузку: он читает конфигурацию, чтобы определить, откуда загружать каждый компонент, но не загружает веса модели до тех пор, пока вы не вызовете [load_components()](/docs/diffusers/main/ru/api/modular_diffusers/pipeline#diffusers.ModularPipeline.load_components). Это позволяет вам контролировать, когда и как загружаются компоненты.

> [!TIP]
> `ComponentsManager` с `enable_auto_cpu_offload` автоматически перемещает модели между CPU и GPU по мере необходимости, что снижает потребление памяти для крупных моделей, таких как Qwen-Image. Подробнее в руководстве [ComponentsManager](./components_manager).
>
> Если offloading не требуется, удалите аргумент `components_manager` и вручную переместите пайплайн на ваше устройство с помощью `to("cuda")`.

Подробнее о создании и загрузке конвейеров см. в руководствах [Создание конвейера](https://huggingface.co/docs/diffusers/modular_diffusers/modular_pipeline#creating-a-pipeline) и [Загрузка компонентов](https://huggingface.co/docs/diffusers/modular_diffusers/modular_pipeline#loading-components).

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

[ModularPipeline](/docs/diffusers/main/ru/api/modular_diffusers/pipeline#diffusers.ModularPipeline) состоит из двух частей: **определения** (блоки) и **состояния** (загруженные компоненты и конфигурации).

Выведите конвейер, чтобы увидеть его состояние — компоненты, их статус загрузки и конфигурацию.
```py
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](/docs/diffusers/main/ru/api/modular_diffusers/pipeline_blocks#diffusers.ModularPipelineBlocks), в котором описаны рабочие процессы, входные и выходные данные, а также логика вычислений конвейера.
```py
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](https://huggingface.co/docs/diffusers/modular_diffusers/auto_pipeline_blocks).

```py
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`, чтобы увидеть все доступные рабочие процессы.
```py
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`](./sequential_pipeline_blocks).

К ним можно получить доступ через свойство `sub_blocks`. Свойство `doc` полезно для просмотра полной документации любого блока, включая его входные данные, выходные данные и компоненты.
```py
vae_encoder_block = pipe.blocks.sub_blocks["vae_encoder"]
print(vae_encoder_block.doc)
```

Этот блок можно преобразовать в конвейер, чтобы он мог работать самостоятельно с помощью [init_pipeline()](/docs/diffusers/main/ru/api/modular_diffusers/pipeline_blocks#diffusers.ModularPipelineBlocks.init_pipeline).
```py
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 из нашего исходного конвейера, а не загружает его заново, что позволяет эффективно использовать память. Подробнее в руководстве [Загрузка компонентов](https://huggingface.co/docs/diffusers/modular_diffusers/modular_pipeline#loading-components).

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

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

Добавим блок canny edge detection в пайплайн ControlNet. Сначала загрузим готовый блок canny с Hub (см. [Building Custom Blocks](https://huggingface.co/docs/diffusers/modular_diffusers/custom_blocks), чтобы создать собственный).
```py
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`.
```py
# 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`](./sequential_pipeline_blocks) и в настоящее время требует `control_image` в качестве входных данных. Вставьте блок canny в начало, чтобы пайплайн принимал обычное изображение.
```py
# 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()](/docs/diffusers/main/ru/api/modular_diffusers/pipeline#diffusers.ModularPipeline.update_components).
```py
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.
```py
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](./pipeline_block): базовая единица для определения шага в конвейере.
- [SequentialPipelineBlocks](./sequential_pipeline_blocks): объединяет блоки для последовательного выполнения.
- [AutoPipelineBlocks](./auto_pipeline_blocks): создание конвейеров, поддерживающих несколько рабочих процессов.
- [Состояния](./modular_diffusers_states): как данные разделяются между блоками.

Узнайте, как создавать собственные блоки с собственной логикой в руководстве [Building Custom Blocks](./custom_blocks).

Используйте [`ComponentsManager`](./components_manager) для совместного использования моделей в нескольких конвейерах и эффективного управления памятью.

Подключите модульные конвейеры к [Mellon](https://github.com/cubiq/Mellon) — визуальному интерфейсу на основе узлов для создания рабочих процессов. Пользовательские блоки, созданные с помощью Modular Diffusers, работают с Mellon из коробки — без необходимости писать код для интерфейса. Подробнее в руководстве по Mellon.

