#
模块化管道

`ModularPipeline` 将 `ModularPipelineBlocks` 转换为可执行的管道，加载模型并执行块中定义的计算步骤。它是运行管道的主要接口，与 `DiffusionPipeline` API 非常相似。

主要区别在于在管道中包含了一个预期的 `output` 参数。

text-to-image
image-to-image
inpainting

    import torch
    from diffusers.modular_pipelines import SequentialPipelineBlocks
    from diffusers.modular_pipelines.stable_diffusion_xl import TEXT2IMAGE_BLOCKS

    blocks = SequentialPipelineBlocks.from_blocks_dict(TEXT2IMAGE_BLOCKS)

    modular_repo_id = "YiYiXu/modular-loader-t2i-0704"
    pipeline = blocks.init_pipeline(modular_repo_id)

    pipeline.load_components(torch_dtype=torch.float16)
    pipeline.to("cuda")

    image = pipeline(prompt="Astronaut in a jungle, cold color palette, muted colors, detailed, 8k", output="images")[0]
    image.save("modular_t2i_out.png")

本指南将向您展示如何创建一个`ModularPipeline`并管理其中的组件。

##
添加块

块是`InsertableDict`对象，可以在特定位置插入，提供了一种灵活的方式来混合和匹配块。

使用`insert()`在块类或`sub_blocks`属性上添加一个块。

    # BLOCKS是块类的字典，您需要向其中添加类
    BLOCKS.insert("block_name", BlockClass, index)
    # sub_blocks属性包含实例，向该属性添加一个块实例
    t2i_blocks.sub_blocks.insert("block_name", block_instance, index)

使用`pop()`在块类或`sub_blocks`属性上移除一个块。

    # 从预设中移除一个块类
    BLOCKS.pop("text_encoder")
    # 分离出一个块实例
    text_encoder_block = t2i_blocks.sub_blocks.pop("text_encoder")

通过将现有块设置为新块来交换块。

    # 在预设中替换块类
    BLOCKS["prepare_latents"] = CustomPrepareLatents
    # 使用块实例在sub_blocks属性中替换
    t2i_blocks.sub_blocks["prepare_latents"] = CustomPrepareLatents()

##
创建管道

有两种方法可以创建一个`ModularPipeline`。从`ModularPipelineBlocks`组装并创建管道，或使用`from_pretrained()`加载现有管道。

您还应该初始化一个`ComponentsManager`来处理设备放置和内存以及组件管理。

> 有关它如何帮助管理不同工作流中的组件的更多详细信息，请参阅ComponentsManager文档。

ModularPipelineBlocks
from_pretrained

使用`init_pipeline()`方法从组件和配置规范创建一个`ModularPipeline`。此方法从`modular_model_index.json`文件加载规范，但尚未加载模型。

    from diffusers import ComponentsManager
    from diffusers.modular_pipelines import SequentialPipelineBlocks
    from diffusers.modular_pipelines.stable_diffusion_xl import TEXT2IMAGE_BLOCKS

    t2i_blocks = SequentialPipelineBlocks.from_blocks_dict(TEXT2IMAGE_BLOCKS)

    modular_repo_id = "YiYiXu/modular-loader-t2i-0704"
    components = ComponentsManager()
    t2i_pipeline = t2i_blocks.init_pipeline(modular_repo_id, components_manager=components)

##
加载组件

一个`ModularPipeline`不会自动实例化组件。它只加载配置和组件规范。您可以使用`load_components()`加载所有组件，或仅使用`load_components()`加载特定组件。

load_components
load_components

    import torch

    t2i_pipeline.load_components(torch_dtype=torch.float16)
    t2i_pipeline.to("cuda")

下面的例子仅加载UNet和VAE。

    import torch

    t2i_pipeline.load_components(names=["unet", "vae"], torch_dtype=torch.float16)

打印管道以检查加载的预训练组件。

    t2i_pipeline

这应该与管道初始化自的模块化仓库中的`modular_model_index.json`文件匹配。如果管道不需要某个组件，即使它在模块化仓库中存在，也不会被包含。

要修改组件加载的来源，编辑仓库中的`modular_model_index.json`文件，并将其更改为您希望的加载路径。下面的例子从不同的仓库加载UNet。

    # 原始
    "unet": [
      null, null,
      {
        "repo": "stabilityai/stable-diffusion-xl-base-1.0",
        "subfolder": "unet",
        "variant": "fp16"
      }
    ]

    # 修改后
    "unet": [
      null, null,
      {
        "repo": "RunDiffusion/Juggernaut-XL-v9",
        "subfolder": "unet",
        "variant": "fp16"
      }
    ]

###
组件加载状态

下面的管道属性提供了关于哪些组件被加载的更多信息。

使用`component_names`返回所有预期的组件。

    t2i_pipeline.component_names
    ['text_encoder', 'text_encoder_2', 'tokenizer', 'tokenizer_2', 'guider', 'scheduler', 'unet', 'vae', 'image_processor']

使用`null_component_names`返回尚未加载的组件。使用`from_pretrained()`加载这些组件。

    t2i_pipeline.null_component_names
    ['text_encoder', 'text_encoder_2', 'tokenizer', 'tokenizer_2', 'scheduler']

使用`pretrained_component_names`返回将从预训练模型加载的组件。

    t2i_pipeline.pretrained_component_names
    ['text_encoder', 'text_encoder_2', 'tokenizer', 'tokenizer_2', 'scheduler', 'unet', 'vae']

使用 `config_component_names` 返回那些使用默认配置创建的组件（不是从模块化仓库加载的）。来自配置的组件不包括在内，因为它们已经在管道创建期间初始化。这就是为什么它们没有列在 `null_component_names` 中。

    t2i_pipeline.config_component_names
    ['guider', 'image_processor']

##
更新组件

根据组件是预训练组件还是配置组件，组件可能会被更新。

> 在更新组件时，组件可能会从预训练变为配置。组件类型最初是在块的 `expected_components` 字段中定义的。

预训练组件通过 `ComponentSpec` 更新，而配置组件则通过直接传递对象或使用 `ComponentSpec` 更新。

`ComponentSpec` 对于预训练组件显示 `default_creation_method="from_pretrained"`，对于配置组件显示 `default_creation_method="from_config`。

要更新预训练组件，创建一个 `ComponentSpec`，指定组件的名称和从哪里加载它。使用 `load()` 方法来加载组件。

    from diffusers import ComponentSpec, UNet2DConditionModel

    unet_spec = ComponentSpec(name="unet",type_hint=UNet2DConditionModel, repo="stabilityai/stable-diffusion-xl-base-1.0", subfolder="unet", variant="fp16")
    unet = unet_spec.load(torch_dtype=torch.float16)

`update_components()` 方法用一个新的组件替换原来的组件。

    t2i_pipeline.update_components(unet=unet2)

当组件被更新时，加载规范也会在管道配置中更新。

###
组件提取和修改

当你使用 `load()` 时，新组件保持其加载规范。这使得提取规范并重新创建组件成为可能。

    spec = ComponentSpec.from_component("unet", unet2)
    spec
    ComponentSpec(name='unet', type_hint=<class 'diffusers.models.unets.unet_2d_condition.UNet2DConditionModel'>, description=None, config=None, repo='stabilityai/stable-diffusion-xl-base-1.0', subfolder='unet', variant='fp16', revision=None, default_creation_method='from_pretrained')
    unet2_recreated = spec.load(torch_dtype=torch.float16)

`get_component_spec()` 方法获取当前组件规范的副本以进行修改或更新。

    unet_spec = t2i_pipeline.get_component_spec("unet")
    unet_spec
    ComponentSpec(
        name='unet',
        type_hint=<class 'diffusers.models.unets.unet_2d_condition.UNet2DConditionModel'>,
        pretrained_model_name_or_path='RunDiffusion/Juggernaut-XL-v9',
        subfolder='unet',
        variant='fp16',
        default_creation_method='from_pretrained'
    )

    # 修改以从不同的仓库加载
    unet_spec.pretrained_model_name_or_path = "stabilityai/stable-diffusion-xl-base-1.0"

    # 使用修改后的规范加载组件
    unet = unet_spec.load(torch_dtype=torch.float16)

##
模块化仓库

一个仓库 如果管道块使用预训练组件，则需要y。该存储库提供了加载规范和元数据。

`ModularPipeline`特别需要模块化存储库（参见示例存储库），这比典型的存储库更灵活。它包含一个`modular_model_index.json`文件，包含以下3个元素。

- `library`和`class`显示组件是从哪个库加载的及其类。如果是`null`，则表示组件尚未加载。
- `loading_specs_dict`包含加载组件所需的信息，例如从中加载的存储库和子文件夹。

与标准存储库不同，模块化存储库可以根据`loading_specs_dict`从不同的存储库获取组件。组件不需要存在于同一个存储库中。

模块化存储库可能包含用于加载`ModularPipeline`的自定义代码。这允许您使用不是Diffusers原生的专用块。

    modular-diffdiff-0704/
    ├── block.py                    # 自定义管道块实现
    ├── config.json                 # 管道配置和auto_map
    └── modular_model_index.json    # 组件加载规范

config.json文件包含一个`auto_map`键，指向`block.py`中定义自定义块的位置。

    {
      "_class_name": "DiffDiffBlocks",
      "auto_map": {
        "ModularPipelineBlocks": "block.DiffDiffBlocks"
      }
    }

Update on GitHub