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 mengubah ModularPipelineBlocks menjadi pipeline yang dapat dieksekusi, yang memuat model dan melakukan langkah-langkah komputasi yang didefinisikan dalam blok-blok tersebut. Ini adalah antarmuka utama untuk menjalankan pipeline, dan API-nya sangat mirip dengan DiffusionPipeline tetapi dengan beberapa perbedaan utama.

  • Pemmuatan bersifat lazy. Dengan DiffusionPipeline, from_pretrained() membuat pipeline dan memuat semua model secara bersamaan. Dengan ModularPipeline, pembuatan dan pemmuatan adalah dua langkah terpisah: from_pretrained() membaca konfigurasi dan mengetahui dari mana setiap komponen harus dimuat, tetapi tidak benar-benar memuat bobot model. Anda memuat model kemudian dengan load_components(), di mana Anda meneruskan argumen pemmuatan seperti dtype dan quantization_config.

  • Dua cara membuat pipeline. Anda dapat menggunakan from_pretrained() dengan repositori model diffusers yang sudah ada — ini secara otomatis memetakan ke blok pipeline default dan kemudian mengonversinya menjadi ModularPipeline tanpa perlu pengaturan tambahan. Anda dapat memeriksa modular_pipelines_directory untuk melihat model mana yang saat ini didukung. Anda juga dapat merakit pipeline Anda sendiri dari ModularPipelineBlocks dan mengonversinya dengan metode init_pipeline() (lihat Membuat pipeline untuk detail lebih lanjut).

  • Menjalankan pipeline-nya sama saja. Setelah dimuat, Anda memanggil pipeline dengan argumen yang sama seperti yang biasa Anda gunakan. Satu ModularPipeline dapat mendukung beberapa alur kerja (teks-ke-gambar, gambar-ke-gambar, inpainting, dll.) ketika blok pipeline menggunakan AutoPipelineBlocks untuk secara otomatis memilih alur kerja berdasarkan input Anda.

Berikut adalah contoh lengkap untuk text-to-image, image-to-image, dan inpainting dengan SDXL.

teks-ke-gambar
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")

Panduan ini akan menunjukkan cara membuat ModularPipeline, mengelola komponen-komponennya, dan menjalankan pipeline.

Membuat pipeline

Ada dua cara untuk membuat ModularPipeline. Merakit dan membuat pipeline dari ModularPipelineBlocks dengan init_pipeline(), atau memuat pipeline yang sudah ada dengan from_pretrained().

Anda juga dapat menginisialisasi ComponentsManager untuk menangani penempatan perangkat dan manajemen memori. Jika Anda tidak memerlukan offloading otomatis, Anda dapat melewati langkah ini dan memindahkan pipeline ke perangkat Anda secara manual dengan pipeline.to("cuda").

Lihat dokumentasi ComponentsManager untuk detail lebih lanjut tentang bagaimana komponen dapat dikelola di berbagai alur kerja.

init_pipeline

init_pipeline() mengonversi ModularPipelineBlocks apa pun menjadi ModularPipeline.

Mari kita definisikan blok minimal untuk melihat cara kerjanya:

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

Panggil init_pipeline() untuk mengubahnya menjadi pipeline. Atribut blocks pada pipeline adalah blok yang digunakan untuk membuatnya — atribut ini menentukan input, output, dan logika komputasi yang diharapkan.

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

Blocks bersifat mutable — Anda dapat dengan bebas menambahkan, menghapus, atau mengganti blocks sebelum membuat pipeline. Namun, setelah pipeline dibuat, memodifikasi pipeline.blocks tidak akan memengaruhi pipeline karena hal tersebut mengembalikan salinan. Jika Anda menginginkan struktur block yang berbeda, buat pipeline baru setelah memodifikasi blocks.

Saat Anda memanggil init_pipeline() tanpa repositori, ia menggunakan pretrained_model_name_or_path yang didefinisikan dalam ComponentSpec blok untuk menentukan dari mana setiap komponen dimuat. Mencetak pipeline menampilkan konfigurasi pemuatan komponen.

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
    }
  ]
}

Jika Anda meneruskan repositori ke init_pipeline(), jalur pemuatan akan ditimpa dengan mencocokkan komponen blok Anda terhadap konfigurasi pipeline di repositori tersebut (model_index.json atau modular_model_index.json). Lihat Modular repository untuk cara spesifikasi pemuatan dicatat dan disimpan.

Pada contoh di bawah, pretrained_model_name_or_path akan diperbarui menjadi "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
    }
  ]
}

Jika komponen dalam blok Anda tidak ada di repositori, komponen tersebut tetap null dan dilewati selama load_components().

from_pretrained

from_pretrained() adalah cara yang praktis untuk membuat ModularPipeline tanpa perlu mendefinisikan blok secara manual.

Itu bekerja dengan tiga jenis repositori.

Repositori diffusers reguler. Lemparkan repositori model apa pun yang didukung dan ia akan secara otomatis memetakan ke blok pipeline default. Model yang saat ini didukung termasuk SDXL, Wan, Qwen, Z-Image, Flux, dan Flux2.

from diffusers import ModularPipeline, ComponentsManager

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

Repositori modular. Repositori ini berisi modular_model_index.json yang menentukan kelas dari setiap komponen dan dari mana komponen tersebut dimuat, dengan komponen disimpan berdampingan dengannya. Lihat Repositori modular untuk cara membuatnya.

from diffusers import ModularPipeline, ComponentsManager

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

Repositori modular dengan kode kustom. Beberapa repositori menyertakan blok pipeline kustom di samping konfigurasi pemuatan. Tambahkan trust_remote_code=True untuk memuatnya. Lihat Blok kustom untuk cara membuat blok Anda sendiri.

from diffusers import ModularPipeline, ComponentsManager

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

Ketika blok pipeline mendefinisikan alur kerja (periksa pipeline.blocks.available_workflows), berikan workflow= untuk hanya mempertahankan blok dari alur kerja tersebut — pemangkasan yang sama dengan get_workflow(). Pipeline kemudian hanya mendeklarasikan komponen yang digunakan oleh alur kerja itu, dan docstring-nya menjelaskan input dari alur kerja tersebut secara persis.

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

Memuat komponen

ModularPipeline tidak secara otomatis menginstansiasi dengan komponen. Ia hanya memuat konfigurasi dan spesifikasi komponen. Anda dapat memuat komponen dengan load_components().

Ini akan memuat semua komponen yang memiliki spesifikasi pemuatan yang valid.

import torch

pipeline.load_components(dtype=torch.float16)

Anda juga dapat memuat komponen tertentu berdasarkan nama. Contoh di bawah ini hanya memuat text_encoder.

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

Pada pipeline yang bloknya mendefinisikan alur kerja, workflow= hanya memuat komponen yang digunakan oleh alur kerja tersebut. Pipeline tetap mempertahankan semua bloknya, sehingga ini adalah cara yang praktis untuk menjalankan satu pipeline melintasi berbagai alur kerja: setiap pemanggilan hanya menambahkan apa yang masih kurang dari alur kerja baru.

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

Setelah dimuat, mencetak pipeline menunjukkan komponen mana yang dimuat — dua field pertama berubah dari null menjadi pustaka dan kelas komponen.

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

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

Keyword argument seperti dtype, variant, revision, dan quantization_config diteruskan ke from_pretrained() untuk setiap komponen. Anda dapat meneruskan satu nilai untuk diterapkan ke semua komponen, atau dict untuk mengatur nilai per komponen.

# 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() hanya memuat komponen yang belum dimuat dan memiliki spesifikasi pemuatan yang valid. Artinya, jika Anda sudah mengatur komponen pada pipeline, memanggil load_components() lagi tidak akan memuat ulang komponen tersebut.

Memperbarui komponen

update_components() mengganti komponen pada pipeline dengan yang baru. Ketika sebuah komponen diperbarui, spesifikasi pemuatan juga diperbarui dalam konfigurasi pipeline dan load_components() akan melewatinya pada pemanggilan berikutnya.

Dari AutoModel

Anda dapat meneruskan objek model yang dimuat dengan AutoModel.from_pretrained(). Model yang dimuat dengan cara ini secara otomatis diberi tag dengan informasi pemuatannya.

from diffusers import AutoModel

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

Dari ComponentSpec

Gunakan get_component_spec() untuk mendapatkan salinan spesifikasi komponen saat ini, memodifikasinya, dan memuat komponen baru.

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)

Anda juga dapat membuat ComponentSpec dari awal.

Tidak semua komponen dimuat dari bobot pra-terlatih — beberapa dibuat dari konfigurasi (tercantum di bawah pipeline.config_component_names). Untuk komponen tersebut, gunakan create() alih-alih load().

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

Atau cukup lewati objeknya secara langsung.

from diffusers.guiders import ClassifierFreeGuidance

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

Lihat panduan Guiders untuk detail lebih lanjut tentang guiders yang tersedia dan cara mengonfigurasinya.

Membagi pipeline menjadi beberapa tahap

Karena blok bersifat komposabel, Anda dapat membongkar sebuah pipeline dan menyusunnya kembali menjadi pipeline terpisah untuk setiap tahap. Contoh di bawah ini menunjukkan bagaimana kita dapat memisahkan blok text encoder dari bagian lain pipeline, sehingga Anda dapat meng-encode prompt secara independen dan meneruskan embeddings ke pipeline utama.

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 mengelola memori di antara beberapa pipeline. Berbeda dengan strategi offloading dalam DiffusionPipeline yang mengikuti urutan tetap, ComponentsManager membuat keputusan offloading secara dinamis setiap kali model menjalankan forward pass, berdasarkan situasi memori saat itu. Artinya, komponen ini berfungsi terlepas dari berapa banyak pipeline yang Anda buat atau urutan apa pun yang Anda jalankan. Lihat panduan ComponentsManager untuk detail lebih lanjut.

Jika tahap pipeline berbagi komponen (misalnya, VAE yang sama digunakan untuk encoding dan decoding), Anda dapat menggunakan update_components() untuk meneruskan komponen yang sudah dimuat ke pipeline lain daripada memuatnya lagi.

Repositori modular

Repositori diperlukan jika blok pipeline menggunakan komponen terlatih sebelumnya. Repositori menyediakan spesifikasi pemuatan dan metadata.

ModularPipeline berfungsi dengan repositori diffusers biasa secara bawaan. Namun, Anda juga dapat membuat repositori modular untuk fleksibilitas yang lebih besar. Repositori modular berisi file modular_model_index.json yang memuat 3 elemen berikut.

  • library dan class menunjukkan pustaka tempat komponen dimuat dan kelasnya. Jika null, komponen belum dimuat.
  • loading_specs_dict berisi informasi yang diperlukan untuk memuat komponen, seperti repositori dan subfolder tempat komponen tersebut dimuat.
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)

Secara default, save_pretrained() menulis setiap komponen yang saat ini dimuat dan dapat diserialisasi oleh Diffusers. Komponen yang tidak dimuat, atau tidak dapat diserialisasi, tidak ditulis dan tetap mempertahankan spesifikasi pemuatan yang ada.

Simpan salinan mandiri

Muat semua komponen, lalu simpan. Setiap spesifikasi menunjuk ke hasil tersebut, sehingga semuanya dimuat ulang dari satu tempat, termasuk secara offline.

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

Tujuan yang dicatat dalam modular_model_index.json adalah tempat di mana save_pretrained() menulis: save_directory untuk penyimpanan lokal, atau repo_id ketika Anda meneruskan push_to_hub=True.

Memindahkan file dengan cara lain tidak menulis ulang indeks. Salinan yang diunduh dengan hf download --local-dir tetap berfungsi: ketika pipeline dimuat dari direktori lokal, setiap komponen yang file-nya hadir di direktori tersebut dimuat dari sana, bukan dari repositori yang tercatat. Salinan yang diunggah dengan hf upload tetap menunjuk ke lokasi lama, sehingga dalam kasus tersebut indeks perlu diperbarui secara manual.

Dengan huggingface_hub>=1.32.0, file yang didukung Xet dan identik dapat berbagi satu payload cache di antara repositori Hub mana pun. Ini mencakup file individual dalam checkpoint yang dipartisi: shard dengan hash Xet yang sama dapat digunakan kembali bahkan ketika shard lain berbeda. Kedua unduhan harus menggunakan direktori cache Hub yang sama dengan dukungan symlink. Mengubah dtype, serialisasi, atau batas shard dapat mengubah hash file dan mencegah penggunaan kembali. Ini menghemat lalu lintas unduhan dan ruang disk, bukan memori yang digunakan oleh komponen yang dimuat.

Caching bersama bersifat best-effort. Pengaturan HF_HUB_DISABLE_SHARED_BLOBS=1 tetap mendukung pemuatan, tetapi meng-cache salinan terpisah. Referensi komponen yang ada di modular_model_index.json tetap tidak berubah; pertahankan referensi eksternal untuk komponen yang tidak disimpan dalam repositori modular.

Merujuk komponen di repositori lain

Spesifikasi pemuatan komponen dalam modular_model_index.json dapat menunjuk ke repositori lain. Sebagai contoh, diffusers/flux2-bnb-4bit-modular memuat transformer terkuantisasinya dari diffusers/FLUX.2-dev-bnb-4bit dan komponen lainnya dari black-forest-labs/FLUX.2-dev.

Kami sangat merekomendasikan repositori yang mandiri: dengan menjaga semua komponen tetap bersama, pipeline menjadi lebih mudah diunduh, dibagikan, dan digunakan secara offline tanpa bergantung pada repositori lain. Gunakan referensi lintas repositori hanya jika Anda memang sengaja ingin komponen dihosting di tempat lain.

Lewati overwrite_modular_index=False untuk mempertahankan spesifikasi pemuatan di modular_model_index.json apa adanya. Komponen yang disimpan dengan spesifikasi pemuatan kosong tetap diisi dengan tujuan, karena tidak ada yang perlu dipertahankan.

Dengan huggingface_hub>=1.32.0, file identik yang didukung Xet dapat berbagi satu payload cache di antara repositori melalui symlink, sehingga menghindari unduhan duplikat dan penggunaan disk. Referensi lintas repositori tidak diperlukan untuk ini. Lihat Simpan salinan mandiri untuk persyaratan dan batasan cache bersama.

Perbarui indeks modular yang sudah ada

Referensi yang ada ke repositori asli tetap berfungsi. Jika sebuah referensi hanya digunakan untuk menghindari unduhan duplikat, lebih baik memperbaruinya untuk memuat dari repositori modular setelah file komponen tersedia di sana.

Pertama, periksa bahwa repositori modular berisi konfigurasi komponen yang sama dan semua file bobot yang diperlukan, termasuk indeks bobot dan setiap shard untuk checkpoint yang di-shard. Hash Xet yang cocok menentukan file bobot mana yang dapat menggunakan ulang cache bersama. Simpan referensi ke komponen yang tidak ada atau sengaja dimuat dari checkpoint lain.

Edit hanya spesifikasi pemuatan yang relevan pada salinan lokal dari modular_model_index.json. Misalnya, untuk menggunakan VAE yang disimpan di bawah vae/ di repositori modular dengan varian bobot yang sama:

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

Hal ini juga menghapus field repo lama. Revisi dari repositori asal tidak mengidentifikasi revisi di tujuan: gunakan None untuk cabang default tujuan, atau tetapkan revisi tujuan yang berisi komponen tersebut. Sesuaikan subfolder dan variant jika nama filenya berbeda.

Sebelum menerbitkan indeks yang diperbarui, muat dengan ModularPipeline.from_pretrained("path/to/local-copy"), panggil load_components(names="vae"), dan verifikasi bahwa komponen dimuat dengan parameter yang diharapkan. Unggah hanya indeks yang diedit; menyimpan ulang bobot dapat mengubah hash-nya dan mencegah penggunaan ulang cache.

Kode kustom

Repositori modular juga dapat memuat blok pipeline kustom sebagai kode Python. Hal ini memungkinkan Anda untuk membagikan blok khusus yang bukan bawaan dari Diffusers. Sebagai contoh, diffusers/Florence2-image-Annotator memuat blok kustom di samping konfigurasi pemuatan:

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

File config.json berisi kunci auto_map yang memberi tahu ModularPipeline di mana blok kustom dapat ditemukan:

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

Muat repositori kode kustom dengan trust_remote_code=True seperti yang ditunjukkan dalam from_pretrained. Lihat Blok kustom untuk cara membuat dan membagikan blok Anda sendiri.

Update on GitHub