Diffusers documentation

Bagikan komponen model di beberapa GPU dengan device_map

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Bagikan komponen model di beberapa GPU dengan device_map

Argumen device_map menempatkan komponen model pada GPU yang terpisah. Gunakan ini ketika model tidak muat di satu GPU dan GPU Anda tidak memiliki interkoneksi yang cepat. Lihat Inferensi terdistribusi untuk membandingkannya dengan strategi lain, dan Penempatan perangkat untuk opsi device_map lainnya.

Contoh di bawah ini memuat setiap komponen hanya untuk tahap yang membutuhkannya, dan menggunakan device_map untuk mendistribusikan komponen besar ke dua GPU.

Enkode prompt

Setel device_map="balanced" untuk menempatkan text encoder di GPU yang terpisah. Gunakan max_memory untuk membatasi jumlah memori yang digunakan oleh masing-masing GPU. Setel transformer dan vae ke None agar hanya text encoder yang dimuat.

from diffusers import FluxPipeline
import torch

prompt = """
cinematic film still of a cat sipping a margarita in a pool in Palm Springs, California
highly detailed, high budget hollywood movie, cinemascope, moody, epic, gorgeous, film grain
"""

pipeline = FluxPipeline.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    transformer=None,
    vae=None,
    device_map="balanced",
    max_memory={0: "16GB", 1: "16GB"},
    dtype=torch.bfloat16
)
with torch.no_grad():
    print("Encoding prompts.")
    prompt_embeds, pooled_prompt_embeds, text_ids = pipeline.encode_prompt(
        prompt=prompt, prompt_2=None, max_sequence_length=512
    )

Setelah Anda memiliki teks embeddings, hapus text encoders dari GPU untuk memberi ruang bagi transformer.

import gc

def flush():
    gc.collect()
    torch.cuda.empty_cache()
    torch.cuda.reset_max_memory_allocated()
    torch.cuda.reset_peak_memory_stats()

del pipeline.text_encoder
del pipeline.text_encoder_2
del pipeline.tokenizer
del pipeline.tokenizer_2
del pipeline

flush()

Denoise dengan transformer yang dipecah

Set device_map="auto" agar Accelerate menempatkan transformer. Proses ini mengisi GPU pertama sebelum berpindah ke GPU berikutnya, dan hanya menggunakan CPU atau disk ketika memori GPU habis. Pada dua GPU berukuran lebih kecil, transformer akan terbagi di kedua GPU tersebut. Bobot yang berada di CPU atau disk akan memperlambat inferensi.

from diffusers import AutoModel
import torch

transformer = AutoModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    subfolder="transformer",
    device_map="auto",
    dtype=torch.bfloat16
)

Periksa transformer.hf_device_map untuk melihat bagaimana transformer didistribusikan di antara perangkat. Pipeline yang dimuat dengan device_map juga memiliki atribut hf_device_map yang menunjukkan di mana setiap komponen ditempatkan.

Muat pipeline hanya dengan transformer, dan setel output_type="latent" agar mengembalikan latents alih-alih gambar.

pipeline = FluxPipeline.from_pretrained(
    "black-forest-labs/FLUX.1-dev",
    text_encoder=None,
    text_encoder_2=None,
    tokenizer=None,
    tokenizer_2=None,
    vae=None,
    transformer=transformer,
    dtype=torch.bfloat16
)

print("Running denoising.")
height, width = 768, 1360
latents = pipeline(
    prompt_embeds=prompt_embeds,
    pooled_prompt_embeds=pooled_prompt_embeds,
    num_inference_steps=50,
    guidance_scale=3.5,
    height=height,
    width=width,
    output_type="latent",
).images

Decode latents

Hapus pipeline dan transformer dari memori, lalu muat VAE untuk mendekode latents. VAE cukup kecil untuk muat di satu GPU.

import torch
from diffusers import AutoencoderKL
from diffusers.image_processor import VaeImageProcessor

del pipeline.transformer
del pipeline
del transformer

flush()

vae = AutoencoderKL.from_pretrained(
    "black-forest-labs/FLUX.1-dev", subfolder="vae", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"
vae_scale_factor = 2 ** (len(vae.config.block_out_channels) - 1)
image_processor = VaeImageProcessor(vae_scale_factor=vae_scale_factor)

with torch.no_grad():
    print("Running decoding.")
    latents = FluxPipeline._unpack_latents(latents, height, width, vae_scale_factor)
    latents = (latents / vae.config.scaling_factor) + vae.config.shift_factor

    image = vae.decode(latents, return_dict=False)[0]
    image = image_processor.postprocess(image, output_type="pil")
    image[0].save("split_transformer.png")

Dengan memuat dan melepas model yang Anda butuhkan pada tahap tertentu secara selektif serta membagi model terbesar ke beberapa GPU, Anda dapat menjalankan inferensi dengan model besar pada GPU konsumen.

Update on GitHub