Diffusers documentation

ModularPipeline

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

ModularPipeline

ModularPipeline は、ModularPipelineBlocks を実行可能なパイプラインに変換し、モデルの読み込みとブロックで定義された計算ステップの実行を行います。パイプラインの実行における主要なインターフェースであり、API は DiffusionPipeline と非常に似ていますが、いくつか重要な違いがあります。

  • Loading is lazy. With DiffusionPipeline, from_pretrained() creates the pipeline and loads all models at the same time. With ModularPipeline, creating and loading are two separate steps: from_pretrained() reads the configuration and knows where to load each component from, but doesn’t actually load the model weights. You load the models later with load_components(), which is where you pass loading arguments like dtype and quantization_config.

  • パイプラインを作成する2つの方法。既存の diffusers モデルリポジトリに対して from_pretrained() を使用すると、デフォルトのパイプラインブロックに自動的にマッピングされ、追加の設定なしで ModularPipeline に変換されます。現在サポートされているモデルを確認するには、modular_pipelines_directory を参照してください。また、ModularPipelineBlocks から独自のパイプラインを組み立て、init_pipeline() メソッドで変換することもできます(詳細は パイプラインの作成 を参照)。

  • パイプラインの実行方法は同じです。 読み込みが完了すると、これまで通り同じ引数でパイプラインを呼び出せます。パイプラインのブロックがAutoPipelineBlocksを使用して入力の種類に基づいてワークフローを自動的に選択する場合、単一のModularPipelineで複数のワークフロー(テキストから画像へ、画像から画像へ、インペインティングなど)をサポートできます。

以下は、SDXLによるテキストから画像への変換、画像から画像への変換、インペインティングの完全な例です。

テキストから画像
image-to-image
inpainting
import torch
from diffusers import ModularPipeline

pipeline = ModularPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0")
pipeline.load_components(dtype=torch.float16)
pipeline.to("cuda")  # or "mps", "xpu", "cpu"

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

このガイドでは、ModularPipelineの作成方法、そのコンポーネントの管理方法、およびパイプラインの実行方法について説明します。

パイプラインの作成

There are two ways to create a ModularPipeline. Assemble and create a pipeline from ModularPipelineBlocks with init_pipeline(), or load an existing pipeline with from_pretrained().

ComponentsManager を初期化して、デバイスの配置とメモリ管理を処理することもできます。自動オフロードが不要な場合は、この手順を省略し、pipeline.to("cuda") を使用してパイプラインを手動でデバイスに移動できます。

異なるワークフロー間でコンポーネントの管理をどのように支援できるかについては、ComponentsManagerのドキュメントを参照してください。

init_pipeline

init_pipeline() は、任意の ModularPipelineBlocks を ModularPipeline に変換します。

仕組みを確認するために、最小限のブロックを定義してみましょう。

from transformers import CLIPTextModel
from diffusers.modular_pipelines import (
    ComponentSpec,
    ModularPipelineBlocks,
    PipelineState,
)

class MyBlock(ModularPipelineBlocks):
    @property
    def expected_components(self):
        return [
            ComponentSpec(
                name="text_encoder",
                type_hint=CLIPTextModel,
                pretrained_model_name_or_path="openai/clip-vit-large-patch14",
            ),
        ]

    def __call__(self, components, state: PipelineState) -> PipelineState:
        return components, state

init_pipeline()を呼び出して、パイプラインに変換します。パイプラインのblocks属性は、パイプラインが作成されたブロックであり、期待される入力、出力、および計算ロジックを決定します。

block = MyBlock()
pipe = block.init_pipeline()
pipe.blocks
MyBlock {
  "_class_name": "MyBlock",
  "_diffusers_version": "0.37.0.dev0"
}

ブロックは変更可能であり、パイプラインを作成する前に、ブロックの追加、削除、交換を自由に実行できます。ただし、パイプラインが作成された後でpipeline.blocksを変更しても、pipeline.blocksはコピーを返すため、パイプラインには影響しません。異なるブロック構造を使用したい場合は、ブロックを変更した後に新しいパイプラインを作成してください。

リポジトリを指定せずにinit_pipeline()を呼び出すと、ブロックのComponentSpecで定義されたpretrained_model_name_or_pathを使用して、各コンポーネントの読み込み元が決定されます。パイプラインを出力すると、コンポーネントの読み込み設定が表示されます。

pipe
ModularPipeline {
  "_blocks_class_name": "MyBlock",
  "_class_name": "ModularPipeline",
  "_diffusers_version": "0.37.0.dev0",
  "text_encoder": [
    null,
    null,
    {
      "pretrained_model_name_or_path": "openai/clip-vit-large-patch14",
      "revision": null,
      "subfolder": "",
      "type_hint": [
        "transformers",
        "CLIPTextModel"
      ],
      "variant": null
    }
  ]
}

init_pipeline() にリポジトリを渡すと、そのリポジトリ内のパイプライン設定(model_index.json または modular_model_index.json)とブロックのコンポーネントを照合して、読み込みパスを上書きします。読み込み仕様がどのように記録・保存されるかは、Modular repository を参照してください。

以下の例では、pretrained_model_name_or_path が "stabilityai/stable-diffusion-xl-base-1.0" に更新されます。

pipe = block.init_pipeline("stabilityai/stable-diffusion-xl-base-1.0")
pipe
ModularPipeline {
  "_blocks_class_name": "MyBlock",
  "_class_name": "ModularPipeline",
  "_diffusers_version": "0.37.0.dev0",
  "text_encoder": [
    null,
    null,
    {
      "pretrained_model_name_or_path": "stabilityai/stable-diffusion-xl-base-1.0",
      "revision": null,
      "subfolder": "text_encoder",
      "type_hint": [
        "transformers",
        "CLIPTextModel"
      ],
      "variant": null
    }
  ]
}

ブロック内のコンポーネントがリポジトリに存在しない場合、null のままとなり、load_components() 実行時にスキップされます。

from_pretrained

from_pretrained() は、ブロックを自分で定義せずに ModularPipeline を作成するための便利な方法です。

3種類のリポジトリで動作します。

通常の diffusers リポジトリ。サポートされているモデルリポジトリを渡すと、自動的にデフォルトのパイプラインブロックにマッピングされます。現在サポートされているモデルには、SDXL、Wan、Qwen、Z-Image、Flux、Flux2 が含まれます。

from diffusers import ModularPipeline, ComponentsManager

components = ComponentsManager()
pipeline = ModularPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", components_manager=components
)

モジュール型リポジトリ。これらのリポジトリには、各コンポーネントのクラスと読み込み元を指定するmodular_model_index.jsonが含まれており、コンポーネントはこれと並べて保存されます。作成方法については、モジュール型リポジトリを参照してください。

from diffusers import ModularPipeline, ComponentsManager

components = ComponentsManager()
pipeline = ModularPipeline.from_pretrained(
    "MiniMaxAI/MiniMax-H3", components_manager=components
)

カスタムコードを含むモジュラーリポジトリ。 一部のリポジトリには、読み込み設定に加えてカスタムパイプラインブロックが含まれています。これらをロードするには、trust_remote_code=True を追加してください。独自のブロックを作成する方法については、カスタムブロック を参照してください。

from diffusers import ModularPipeline, ComponentsManager

components = ComponentsManager()
pipeline = ModularPipeline.from_pretrained(
    "diffusers/Florence2-image-Annotator", trust_remote_code=True, components_manager=components
)

パイプラインブロックがワークフローを定義している場合(pipeline.blocks.available_workflows を確認してください)、workflow= を渡すことで、そのワークフローのブロックのみを保持できます。これは get_workflow() と同じプルーニング処理です。これにより、パイプラインは当該ワークフローが使用するコンポーネントのみを宣言し、その docstring には該当するワークフローの入力が正確に記述されます。

pipeline = ModularPipeline.from_pretrained("Qwen/Qwen-Image", workflow="inpainting")

コンポーネントの読み込み

ModularPipeline は、コンポーネントを自動的にインスタンス化しません。設定とコンポーネントの仕様を読み込むだけです。load_components() を使用してコンポーネントを読み込むことができます。

これにより、有効な読み込み仕様を持つすべてのコンポーネントが読み込まれます。

import torch

pipeline.load_components(dtype=torch.float16)

名前を指定して特定のコンポーネントを読み込むこともできます。以下の例では、text_encoderのみを読み込みます。

pipeline.load_components(names=["text_encoder"], dtype=torch.float16)

ブロックがワークフローを定義するパイプラインにおいて、workflow= はそのワークフローが使用するコンポーネントのみを読み込みます。パイプラインはすべてのブロックを保持するため、これは1つのパイプラインを複数のワークフローにわたって実行するための便利な方法です。各呼び出しでは、新しいワークフローがまだ欠いているものだけが追加されます。

pipeline.load_components(workflow="inpainting", dtype=torch.float16)

読み込み後、パイプラインを出力すると、どのコンポーネントが読み込まれたかが表示されます。最初の2つのフィールドは、nullからコンポーネントのライブラリとクラスに変更されます。

pipeline
# text_encoder is loaded - shows library and class
"text_encoder": [
  "transformers",
  "CLIPTextModel",
  { ... }
]

# unet is not loaded yet - still null
"unet": [
  null,
  null,
  { ... }
]

dtype、variant、revision、quantization_config などのキーワード引数は、各コンポーネントに対して from_pretrained() に渡されます。すべてのコンポーネントに適用する単一の値を渡すことも、コンポーネントごとに値を設定するための dict を渡すこともできます。

# apply bfloat16 to all components
pipeline.load_components(dtype=torch.bfloat16)

# different dtypes per component
pipeline.load_components(dtype={"transformer": torch.bfloat16, "default": torch.float32})

load_components() は、まだ読み込まれておらず、有効な読み込み仕様を持つコンポーネントのみを読み込みます。つまり、パイプラインにコンポーネントがすでに設定されている場合、load_components() を再度呼び出しても、そのコンポーネントは再読み込みされません。

コンポーネントの更新

update_components() は、パイプライン内のコンポーネントを新しいものに置き換えます。コンポーネントが更新されると、パイプライン設定内の読み込み仕様も更新され、load_components() は以降の呼び出しでそれをスキップします。

AutoModelから

AutoModel.from_pretrained() で読み込まれたモデルオブジェクトを渡すことができます。この方法で読み込まれたモデルには、読み込み情報が自動的にタグ付けされます。

from diffusers import AutoModel

unet = AutoModel.from_pretrained(
    "RunDiffusion/Juggernaut-XL-v9", subfolder="unet", variant="fp16", dtype=torch.float16
)
pipeline.update_components(unet=unet)

ComponentSpec から

get_component_spec() を使用して、現在のコンポーネント仕様のコピーを取得し、変更を加えたうえで、新しいコンポーネントを読み込みます。

unet_spec = pipeline.get_component_spec("unet")

# modify to load from a different repository
unet_spec.pretrained_model_name_or_path = "RunDiffusion/Juggernaut-XL-v9"

# load and update
unet = unet_spec.load(dtype=torch.float16)
pipeline.update_components(unet=unet)

ComponentSpec をゼロから作成することもできます。

すべてのコンポーネントが事前学習済み重みから読み込まれるわけではありません。一部のコンポーネントはpipeline.config_component_namesに列挙されている設定から作成されます。これらのコンポーネントには、load()ではなくcreate()を使用してください。

guider_spec = pipeline.get_component_spec("guider")
guider_spec.config = {"guidance_scale": 5.0}
guider = guider_spec.create()
pipeline.update_components(guider=guider)

または、オブジェクトを直接渡すこともできます。

from diffusers.guiders import ClassifierFreeGuidance

guider = ClassifierFreeGuidance(guidance_scale=5.0)
pipeline.update_components(guider=guider)

利用可能なGuiderとその設定方法の詳細については、Guiderのガイドを参照してください。

パイプラインをステージに分割する

ブロックは合成可能であるため、パイプラインを分解し、各ステージごとに独立したパイプラインとして再構築できます。以下の例では、テキストエンコーダーブロックをパイプラインの残りの部分から分離する方法を示しています。これにより、プロンプトを独立してエンコードし、その埋め込みベクトルをメインのパイプラインに渡すことができます。

from diffusers import ModularPipeline, ComponentsManager
import torch

device = "cuda"  # or "mps", "xpu", "cpu"
dtype = torch.bfloat16
repo_id = "black-forest-labs/FLUX.2-klein-4B"

# get the blocks and separate out the text encoder
blocks = ModularPipeline.from_pretrained(repo_id).blocks
text_block = blocks.sub_blocks.pop("text_encoder")

# use ComponentsManager to handle offloading across multiple pipelines
manager = ComponentsManager()
manager.enable_auto_cpu_offload(device=device)

# create separate pipelines for each stage
text_encoder_pipeline = text_block.init_pipeline(repo_id, components_manager=manager)
pipeline = blocks.init_pipeline(repo_id, components_manager=manager)

# encode text
text_encoder_pipeline.load_components(dtype=dtype)
text_embeddings = text_encoder_pipeline(prompt="a cat").get_by_kwargs("denoiser_input_fields")

# denoise and decode
pipeline.load_components(dtype=dtype)
output = pipeline(
    **text_embeddings,
    num_inference_steps=4,
).images[0]

ComponentsManagerは、複数のパイプラインにまたがるメモリを管理します。DiffusionPipelineのオフローディング戦略が固定の順序に従うのに対し、ComponentsManagerは、モデルのフォワードパスが実行されるたびに、現在のメモリ状況に基づいて動的にオフローディングの判断を行います。そのため、作成するパイプラインの数がいくつであれ、どの順序で実行しても動作します。詳細については、ComponentsManagerのガイドを参照してください。

パイプラインのステージがコンポーネントを共有する場合(例: エンコードとデコードの両方に同じVAEを使用する場合)、update_components() を使用して、すでに読み込まれたコンポーネントを別のパイプラインに渡すことで、再度読み込む必要をなくすことができます。

モジュール化されたリポジトリ

パイプラインブロックが事前学習済みコンポーネントを使用する場合、リポジトリが必要です。リポジトリは読み込み仕様とメタデータを提供します。

ModularPipelineは、通常のdiffusersリポジトリとそのまま連携できます。ただし、より柔軟性を高めるためにモジュラーリポジトリを作成することも可能です。モジュラーリポジトリには、以下の3つの要素を含むmodular_model_index.jsonファイルが含まれます。

  • library と class は、コンポーネントがどのライブラリから読み込まれたか、およびそのクラスを示します。null の場合、コンポーネントはまだ読み込まれていません。
  • loading_specs_dictには、コンポーネントを読み込むために必要な情報(読み込む対象のリポジトリやサブフォルダなど)が含まれています。
from diffusers import ModularPipeline

# load from a regular repo
pipeline = ModularPipeline.from_pretrained("stabilityai/stable-diffusion-xl-base-1.0")
pipeline.load_components()

# push as a modular repository
pipeline.save_pretrained("local/path", repo_id="my-username/sdxl-modular", push_to_hub=True)

デフォルトでは、save_pretrained()は、Diffusersがシリアライズできる現在ロードされている各コンポーネントを書き出します。ロードされていない、またはシリアライズできないコンポーネントは書き出されず、既存のロード仕様を維持します。

自己完結型のコピーを保存

すべてのコンポーネントを読み込み、保存します。すべての仕様は結果を指しているため、オフラインを含むすべてのコンポーネントが1つの場所から完全に再読み込みされます。

pipe = ModularPipeline.from_pretrained("MiniMaxAI/MiniMax-H3")
pipe.load_components()
pipe.save_pretrained("path/to/local-copy")

modular_model_index.json に記録される保存先は、save_pretrained() が書き込む場所です。ローカル保存の場合は save_directory、push_to_hub=True を渡す場合は repo_id になります。

ファイルを他の方法で移動しても、インデックスは書き換えられません。hf download --local-dirでダウンロードしたコピーは引き続き動作します。ローカルディレクトリからパイプラインを読み込む場合、そのディレクトリにファイルが存在するコンポーネントは、記録されたリポジトリではなく、そこから読み込まれます。hf uploadでアップロードしたコピーは、旧場所を指し続けます。そのため、その場合はインデックスを手動で更新してください。

huggingface_hub>=1.32.0 以降、同一の Xet ベースのファイルは、Hub リポジトリを問わず、1 つのキャッシュ済みペイロードを共有できます。これはシャード化されたチェックポイント内の個別ファイルにも適用されます。他のシャードが異なる場合でも、同じ Xet ハッシュを持つシャードは再利用できます。再利用には、両方のダウンロードがシンボリックリンクをサポートする同じ Hub キャッシュディレクトリを使用する必要があります。dtype、シリアライズ形式、またはシャード境界の変更は、ファイルのハッシュを変更し、再利用を妨げる可能性があります。これにより、ダウンロードトラフィックとディスク容量は節約されますが、読み込まれたコンポーネントが使用するメモリは節約されません。

共有キャッシュはベストエフォートです。HF_HUB_DISABLE_SHARED_BLOBS=1 を設定しても読み込みはサポートされますが、個別のコピーをキャッシュします。modular_model_index.json 内の既存のコンポーネント参照は変更されません。モジュラーリポジトリに保存されていないコンポーネントについては、外部参照を維持してください。

他のリポジトリのコンポーネントを参照する

modular_model_index.json におけるコンポーネントの読み込み仕様は、別のリポジトリを指すことができます。例えば、diffusers/flux2-bnb-4bit-modular は、量子化された transformer を diffusers/FLUX.2-dev-bnb-4bit から、残りのコンポーネントを black-forest-labs/FLUX.2-dev から読み込みます。

自己完結型のリポジトリを強く推奨します。すべてのコンポーネントを1つのリポジトリにまとめることで、他のリポジトリに依存せずに、パイプラインをダウンロード、共有、オフラインで利用しやすくなります。コンポーネントを別の場所にホストすることを意図している場合のみ、リポジトリ間の参照を使用してください。

overwrite_modular_index=False を渡すことで、modular_model_index.json 内の読み込み仕様をそのまま維持できます。保存済みコンポーネントの読み込み仕様が空の場合、保持すべき内容がないため、宛先が自動的に補完されます。

huggingface_hub>=1.32.0 以降、Xet ベースの同一ファイルはシンボリックリンクを介してリポジトリ間で 1 つのキャッシュ済みペイロードを共有でき、重複したダウンロードやディスク使用量を回避できます。この機能にはリポジトリ間の参照は不要です。共有キャッシュの要件と制限については、自己完結型のコピーを保存するを参照してください。

既存のモジュラーインデックスを更新する

元のリポジトリへの既存の参照は引き続き機能します。参照が重複したダウンロードを回避するためにのみ使用されていた場合は、コンポーネントファイルがモジュラーリポジトリで利用可能になった時点で、そこから読み込むよう参照を更新することを推奨します。

まず、モジュラーリポジトリに、コンポーネントの構成と、すべての必須ウェイトファイル(ウェイトインデックスおよびシャード化されたチェックポイントのすべてのシャードを含む)が含まれていることを確認します。一致する Xet ハッシュにより、共有キャッシュを再利用できるウェイトファイルが決定されます。欠落しているコンポーネント、または意図的に別のチェックポイントから読み込まれるコンポーネントへの参照は保持してください。

ローカルのコピーにあるmodular_model_index.jsonの、関連する読み込み仕様のみを編集します。例えば、モジュラーリポジトリ内のvae/に保存されているVAEを、同じ重みバリアントで使用する場合は、以下のようにします。

import json
from pathlib import Path

index_path = Path("path/to/local-copy/modular_model_index.json")
index = json.loads(index_path.read_text())
spec = index["vae"][2]
spec["pretrained_model_name_or_path"] = "my-username/my-modular-repo"
spec.pop("repo", None)
spec["subfolder"] = "vae"
spec["revision"] = None
index_path.write_text(json.dumps(index, indent=2) + "\n")

これにより、レガシーのrepoフィールドも削除されます。元のリポジトリのrevisionは、宛先のrevisionを特定しません。宛先のデフォルトブランチにはNoneを使用するか、コンポーネントを含む宛先のrevisionをピン留めしてください。ファイル名が異なる場合は、subfolderとvariantを調整してください。

更新されたインデックスを公開する前に、ModularPipeline.from_pretrained("path/to/local-copy") で読み込み、load_components(names="vae") を呼び出して、コンポーネントが期待されるパラメータで読み込まれることを確認してください。編集したインデックスのみをアップロードしてください。重みを再保存するとハッシュが変更され、キャッシュの再利用ができなくなる可能性があります。

カスタムコード

モジュール化されたリポジトリには、Python コードとしてカスタムのパイプラインブロックを含めることもできます。これにより、Diffusers にネイティブで存在しない特殊なブロックを共有できます。例えば、diffusers/Florence2-image-Annotator には、読み込み設定とともにカスタムブロックが含まれています:

Florence2-image-Annotator/
├── block.py                    # Custom pipeline blocks implementation
├── config.json                 # Pipeline configuration and auto_map
├── mellon_config.json          # UI configuration for Mellon
└── modular_model_index.json    # Component loading specifications

config.jsonファイルには、ModularPipelineがカスタムブロックの場所を特定するためのauto_mapキーが含まれています。

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

trust_remote_code=True を使用して、from_pretrained に示すようにカスタムコードリポジトリを読み込みます。独自のブロックを作成して共有する方法については、Custom blocks を参照してください。

Update on GitHub