Diffusers 模块化管道 ModularPipeline 完全指南:从块组装到组件管理的实战教程
2026/9/10 14:37:33 网站建设 项目流程

Diffusers 模块化管道 ModularPipeline 完全指南:从块组装到组件管理的实战教程

【免费下载链接】diffusers🤗 Diffusers: State-of-the-art diffusion models for image, video, and audio generation in PyTorch.项目地址: https://gitcode.com/GitHub_Trending/di/diffusers

导读

ModularPipeline是 🤗 Diffusers 模块化管道系统的核心执行接口,它将ModularPipelineBlocks(管道块)转换为可运行的扩散管道,负责加载模型并执行块中定义的计算步骤。与传统的DiffusionPipelineAPI 非常相似,它的主要区别在于调用时包含一个预期的output参数。读完本文,你将掌握如何从零组装一个模块化管道、动态增删与替换管道块、按需加载组件、跨仓库混搭预训练权重,以及通过ComponentSpec精确控制每个组件的加载与更新。

[!WARNING] 模块化 Diffusers 正在积极开发中,其 API 可能发生变化(参见 模块化概述)。


一、快速上手:用预设块运行三种 SDXL 工作流

模块化管道系统在src/diffusers/modular_pipelines/下提供了一系列按模型族组织的预设块。以 stable_diffusion_xl 为例,其入口模块公开了TEXT2IMAGE_BLOCKSIMAGE2IMAGE_BLOCKSINPAINT_BLOCKS等块字典(在仓库中,这些字典由StableDiffusionXLAutoBlocks这一SequentialPipelineBlocks子类体系生成,见 modular_blocks_stable_diffusion_xl.py)。

文生图(text-to-image)

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

图生图(image-to-image)

import torch from diffusers.modular_pipelines import SequentialPipelineBlocks from diffusers.modular_pipelines.stable_diffusion_xl import IMAGE2IMAGE_BLOCKS blocks = SequentialPipelineBlocks.from_blocks_dict(IMAGE2IMAGE_BLOCKS) modular_repo_id = "YiYiXu/modular-loader-t2i-0704" pipeline = blocks.init_pipeline(modular_repo_id) pipeline.load_components(dtype=torch.float16) pipeline.to("cuda") url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/sdxl-text2img.png" init_image = load_image(url) prompt = "a dog catching a frisbee in the jungle" image = pipeline(prompt=prompt, image=init_image, strength=0.8, output="images")[0] image.save("modular_i2i_out.png")

局部重绘(inpainting)

import torch from diffusers.modular_pipelines import SequentialPipelineBlocks from diffusers.modular_pipelines.stable_diffusion_xl import INPAINT_BLOCKS from diffusers.utils import load_image blocks = SequentialPipelineBlocks.from_blocks_dict(INPAINT_BLOCKS) modular_repo_id = "YiYiXu/modular-loader-t2i-0704" pipeline = blocks.init_pipeline(modular_repo_id) pipeline.load_components(dtype=torch.float16) pipeline.to("cuda") img_url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/sdxl-text2img.png" mask_url = "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/sdxl-inpaint-mask.png" init_image = load_image(img_url) mask_image = load_image(mask_url) prompt = "A deep sea diver floating" image = pipeline(prompt=prompt, image=init_image, mask_image=mask_image, strength=0.85, output="images")[0] image.save("moduar_inpaint_out.png")

三个示例的核心流程完全一致:用块字典组装块 →init_pipeline解析规范(但不加载权重)→load_components加载组件 →.to("cuda")→ 调用管道并指定outputload_image来自diffusers.utils,用于从 URL 加载参考图与蒙版。

从源码看,SequentialPipelineBlocks.from_blocks_dict会把字典中的每个值(类或实例)统一实例化为块并存入InsertableDict(modular_pipeline.py),而init_pipeline则依据块的model_nameMODULAR_PIPELINE_MAPPING中查表,动态解析出对应的模块化管道类(如StableDiffusionXLModularPipeline)并完成实例化(modular_pipeline.py、MODULAR_PIPELINE_MAPPING)。


二、添加、移除与交换块

块是InsertableDict对象。它继承自OrderedDict,因此可以在特定位置插入、按 key 移除或整体替换,从而以高度灵活的方式混合与匹配块——这正是模块化设计“块可复用、可混搭”的体现(见 overview.md)。

添加块

使用InsertableDict.insert块类字典sub_blocks属性上添加块:

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

InsertableDict.insert的实现会先移除同名 key(避免重复),再在指定index位置插入,最后返回自身以支持链式调用。

移除块

使用InsertableDict.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()

需要注意的是,SequentialPipelineBlocks在初始化时会校验block_namesblock_classes长度一致(modular_pipeline.py),因此替换块时保持 key 不变是最稳妥的做法。此外,ConditionalPipelineBlocks要求block_classesblock_names一一对应,而AutoPipelineBlocks更进一步要求block_trigger_inputs与它们长度一致,且禁止单独设置default_block_name(默认块通过block_trigger_inputs中的None位置指定,见 AutoPipelineBlocks)。


三、创建 ModularPipeline 的两种方式

创建ModularPipeline有两条路径:从块组装init_pipeline)或直接加载仓库from_pretrained)。无论哪种方式,官方都建议初始化一个ComponentsManager来处理设备放置、内存与组件管理。

[!TIP] 关于ComponentsManager如何帮助你在不同工作流中管理组件的更多细节,请参阅 ComponentsManager 文档。

方式一:从 ModularPipelineBlocks 组装

使用ModularPipelineBlocks.init_pipeline从组件与配置规范创建管道。该方法会从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)

方式二:使用 from_pretrained

ModularPipeline.from_pretrained从 Hub 上的模块化仓库直接创建管道。其加载逻辑会优先尝试modular_model_index.json,失败后回退到标准的model_index.json,从而兼容传统非模块化仓库:

from diffusers import ModularPipeline, ComponentsManager components = ComponentsManager() pipeline = ModularPipeline.from_pretrained("YiYiXu/modular-loader-t2i-0704", components_manager=components)

添加trust_remote_code参数以加载自定义的ModularPipeline

from diffusers import ModularPipeline, ComponentsManager components = ComponentsManager() modular_repo_id = "YiYiXu/modular-diffdiff-0704" diffdiff_pipeline = ModularPipeline.from_pretrained(modular_repo_id, trust_remote_code=True, components_manager=components)

from_pretrained内部先通过ModularPipelineBlocks.from_pretrained尝试解析块(块类通过config.json中的auto_map定位),再依据配置内容解析出具体的管道类并构造实例。此外,from_pretrainedinit_pipeline都支持workflow参数:传入后管道块会被裁剪到对应工作流的执行块,load_components()也只会加载该工作流实际用到的组件(modular_pipeline.py)。


四、加载组件:按需实例化,绝不自动

ModularPipeline不会自动实例化组件。创建管道时它只加载配置与组件规范:from_config组件在初始化阶段直接创建(如guiderimage_processor),而from_pretrained组件一律先注册为None,等待后续显式加载(ModularPipeline.init)。

加载全部组件

import torch t2i_pipeline.load_components(dtype=torch.float16) t2i_pipeline.to("cuda")

只加载特定组件

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

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

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

t2i_pipeline

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

load_components在源码层面对 kwargs 做了三类处理(modular_pipeline.py):

  • 传入单个值(如dtype=torch.float16)会应用到所有待加载组件;
  • 传入字典(如dtype={"unet": torch.bfloat16, "default": torch.float32})可对组件分别指定;
  • 传入加载字段(如pretrained_model_name_or_pathvariantrevision)会覆盖ComponentSpec中的对应字段

另外还有一个安全细节:trust_remote_code只会在组件与管道同属一个仓库时被透传。若组件来自外部仓库,load_components会剥离该参数并给出提示,建议你手动AutoModel.from_pretrained(..., trust_remote_code=True)加载后通过update_components注入。

修改组件的加载来源

要修改组件加载的来源,编辑仓库中的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" } ]

这正是模块化仓库的核心价值:不同组件可以来自不同的仓库,只要修改loading_specs_dict中的repo(在ComponentSpec中对应pretrained_model_name_or_path字段)即可。


五、组件加载状态:四个属性看清一切

ModularPipeline提供四组属性用于查询组件的加载状态(实现见 modular_pipeline.py)。

component_names:所有预期组件

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

null_component_names:尚未加载的组件

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

这些组件需要调用ModularPipeline.from_pretrained(实际为load_components)来加载。

pretrained_component_names:将从预训练模型加载的组件

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

config_component_names:用默认配置创建的组件

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

注意:config_component_names返回的是使用默认配置创建的组件(非从模块化仓库加载)。配置类组件在管道创建期间已被初始化,因此它们不会出现在null_component_names。在源码中,这一分类完全由ComponentSpec.default_creation_method决定:"from_pretrained"对应预训练组件,"from_config"对应配置组件。


六、更新组件:ComponentSpec 是核心工具

根据组件是预训练组件还是配置组件,更新方式有所不同。

[!WARNING] 在更新组件时,组件可能会从预训练变为配置。组件类型最初是在块的expected_components字段中定义的。

预训练组件通过ComponentSpec更新,而配置组件既可以直接传递对象,也可以使用ComponentSpec更新。ComponentSpec对预训练组件显示default_creation_method="from_pretrained",对配置组件显示default_creation_method="from_config"

构造 ComponentSpec 并加载

要更新预训练组件,创建一个ComponentSpec,指定组件的名称和加载来源,然后使用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(dtype=torch.float16)

ComponentSpec的完整字段包括:nametype_hint(类型提示,如UNet2DConditionModel)、descriptionconfigpretrained_model_name_or_pathsubfoldervariantrevisiondefault_creation_method。其中repo已废弃的兼容字段,赋值时会自动映射到pretrained_model_name_or_path(见 modular_pipeline_utils.py)。load()会按from_pretrained(或单文件场景下的from_single_file)加载组件,并在组件上写入_diffusers_load_id作为加载痕迹。

用 update_components 替换组件

ModularPipeline.update_components用新组件替换旧组件,同时同步更新内部 spec 与配置:

t2i_pipeline.update_components(unet=unet2)

当组件被更新时,加载规范也会在管道配置中同步更新,从而保证后续save_pretrained写出的modular_model_index.json与当前实际组件一致。

组件提取与修改

当使用ComponentSpec.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(dtype=torch.float16)

ComponentSpec.from_component支持两类组件:通过ComponentSpec.load()创建(带_diffusers_load_id)的组件,以及不带权重的ConfigMixin子类(如 scheduler、guider,走from_config)。其余情况会抛出ValueError

ModularPipeline.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(dtype=torch.float16)

拿到unet后再调用t2i_pipeline.update_components(unet=unet),即可完成"取规范 → 改来源 → 重新加载 → 注入管道"的完整闭环。这条链路在仓库测试 test_modular_pipeline_stable_diffusion_xl.py 中也有覆盖,例如通过pipe.update_components(guider=guider)替换指导器后重新执行推理(见该文件中的test_controlnet_cfg等用例)。


七、模块化仓库:加载规范的载体

如果管道块使用预训练组件,则需要一个模块化仓库来提供加载规范与元数据。ModularPipeline特别需要模块化仓库(它比典型的仓库更灵活),仓库中必须包含一个modular_model_index.json文件,包含以下 3 个元素:

  • libraryclass:显示组件是从哪个库加载的及其类。如果是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" } }

从源码看,ModularPipelineBlocks.from_pretrained正是通过读取config.json中的auto_map来确定远程代码模块与类名,并调用get_class_from_dynamic_module动态加载自定义块类(modular_pipeline.py);而ModularPipeline._load_pipeline_config则按"先modular_model_index.json、后model_index.json"的顺序解析配置(modular_pipeline.py)。保存时,ModularPipeline.save_pretrained会遍历所有from_pretrained组件,逐一调用其save_pretrained并更新modular_model_index.json中的条目,还支持overwrite_modular_index=True将所有组件引用改写为目标仓库(modular_pipeline.py)。


八、底层机制速览:块、状态与执行链

为帮助你更好地理解前文 API,这里梳理模块化管道的底层执行机制(均可在 modular_pipeline.py 与 modular_pipeline_utils.py 中验证):

  • 块层级体系ModularPipelineBlocks(基类,含inputs/outputs/expected_components/expected_configs等规范属性)派生出SequentialPipelineBlocks(顺序执行)、ConditionalPipelineBlocks(按触发输入选择分支)、AutoPipelineBlocks(根据block_trigger_inputs自动选择,首个触发输入非None的分支胜出)与LoopSequentialPipelineBlocks(循环执行)。
  • 数据流动PipelineState是块间传递数据的容器,支持set/get及按kwargs_type分组查询;BlockState则是每个块运行时的输入输出快照,支持属性与下标两种访问方式。
  • 执行入口ModularPipeline.__call__接收stateoutput参数。outputNone时返回完整PipelineState;为字符串时返回对应中间值(如output="images");为列表时返回多个值的字典。它还会将用户 kwargs 与块的inputs声明(含默认值)合并进PipelineState,未知参数会被警告忽略(modular_pipeline.py)。
  • 输入/输出模板InputParam/OutputParam支持从INPUT_PARAM_TEMPLATES/OUTPUT_PARAM_TEMPLATES取模板(如promptstrengthnum_inference_stepsimages等),见 modular_pipeline_utils.py,这也是pipeline(prompt=..., strength=0.8, output="images")这类调用签名能够自动生成的原因。
  • 设备与内存管理ComponentsManager提供组件去重(load_id检测)、collection分组与enable_auto_cpu_offload自动卸载;默认的AutoOffloadStrategy通过组合搜索选出"能释放足够显存的最小模型组合"卸载到 CPU(components_manager.py)。

结语

ModularPipeline把"管道"从一份写死的类拆解为可插拔的块集合 + 组件规范:通过InsertableDict增删替换块,通过modular_model_index.json跨仓库混搭权重,通过ComponentSpec精确控制每个组件的加载与更新,再配合ComponentsManager统一管理内存与设备。理解这套机制后,你就能以极低的成本组合出适合特定工作流的扩散管道,甚至用自定义块扩展 Diffusers 原生能力。若需进一步了解块状态传递、顺序/条件/自动块与组件管理器,可继续阅读 states、pipeline block、sequential pipeline blocks、auto pipeline blocks 与 components manager 等文档。

【免费下载链接】diffusers🤗 Diffusers: State-of-the-art diffusion models for image, video, and audio generation in PyTorch.项目地址: https://gitcode.com/GitHub_Trending/di/diffusers

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询