Diffusers documentation

ControlNet

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

ControlNet

ControlNet mengarahkan model difusi yang telah dilatih sebelumnya menggunakan gambar kontrol struktural (garis tepi, kedalaman, atau pose) sambil Anda tetap menggunakan prompt teks. Model dasar dibekukan dan jaringan paralel ditambahkan, di mana residual-nya memandu denoiser, sehingga Anda mendapatkan kontrol tata letak tanpa perlu fine-tuning.

Muat ControlNet untuk kontrol yang Anda butuhkan (misalnya canny), lalu lewati sebagai controlnet= ke from_pretrained(). Gunakan controlnet_conditioning_scale untuk mengatur seberapa kuat kontrol mengarahkan generasi.

ControlNet tersedia untuk banyak model seperti Flux, Hunyuan-DiT, Stable Diffusion 3, dan lainnya. Contoh dalam panduan ini menggunakan Flux dan Stable Diffusion XL. Untuk T2I-Adapter pada checkpoint keluarga Stable Diffusion yang lebih lama, lihat Legacy adapters. Gunakan ControlNet untuk pekerjaan generasi yang dapat dikendalikan yang baru.

Tab di bawah ini menampilkan ControlNet untuk teks-ke-gambar, gambar-ke-gambar, dan inpainting.

teks-ke-gambar
image-to-image
inpainting

Buat gambar canny dengan opencv-python.

import cv2
import numpy as np
from PIL import Image
from diffusers.utils import load_image

original_image = load_image(
    "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/non-enhanced-prompt.png"
)

image = np.array(original_image)

low_threshold = 100
high_threshold = 200

image = cv2.Canny(image, low_threshold, high_threshold)
image = image[:, :, None]
image = np.concatenate([image, image, image], axis=2)
canny_image = Image.fromarray(image)

Lewatkan gambar canny ke pipeline. Gunakan parameter controlnet_conditioning_scale untuk menentukan seberapa besar bobot yang diberikan pada kontrol.

import torch
from diffusers.utils import load_image
from diffusers import FluxControlNetPipeline, FluxControlNetModel

controlnet = FluxControlNetModel.from_pretrained(
    "InstantX/FLUX.1-dev-Controlnet-Canny", dtype=torch.bfloat16
)
pipeline = FluxControlNetPipeline.from_pretrained(
    "black-forest-labs/FLUX.1-dev", controlnet=controlnet, dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = """
A photorealistic overhead image of a cat reclining sideways in a flamingo pool floatie holding a margarita. 
The cat is floating leisurely in the pool and completely relaxed and happy.
"""

pipeline(
    prompt, 
    control_image=canny_image,
    controlnet_conditioning_scale=0.5,
    num_inference_steps=50, 
    guidance_scale=3.5,
).images[0]
Generated image (prompt only)
gambar asli
Control image (Canny edges)
canny image
Generated image (ControlNet + prompt)
gambar yang dihasilkan

Multi-ControlNet

Komposisikan beberapa ControlNet (misalnya canny + depth) dengan meneruskannya sebagai daftar. Topang (mask) wilayah yang tumpang tindih jika memungkinkan, dan atur setiap controlnet_conditioning_scale. Bangun canny_image dengan OpenCV Canny (seperti pada text-to-image) dan depth_image dengan DPT (seperti pada image-to-image). Ubah ukuran setiap gambar kontrol ke ukuran pipeline sebelum Anda memanggil pipeline.

import cv2
import torch
import numpy as np
from PIL import Image
from transformers import DPTImageProcessor, DPTForDepthEstimation
from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel, AutoencoderKL
from diffusers.utils import load_image

original_image = load_image(
    "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/non-enhanced-prompt.png"
)
image = np.array(original_image)
canny_image = Image.fromarray(
    np.concatenate([cv2.Canny(image, 100, 200)[:, :, None]] * 3, axis=2)
)

device = "cuda"  # or "mps", "xpu", "cpu"
depth_estimator = DPTForDepthEstimation.from_pretrained("Intel/dpt-hybrid-midas").to(device)
feature_extractor = DPTImageProcessor.from_pretrained("Intel/dpt-hybrid-midas")

def get_depth_map(image):
    image = feature_extractor(images=image, return_tensors="pt").pixel_values.to(device)
    with torch.no_grad(), torch.autocast(device):
        depth_map = depth_estimator(image).predicted_depth

    depth_map = torch.nn.functional.interpolate(
        depth_map.unsqueeze(1),
        size=(1024, 1024),
        mode="bicubic",
        align_corners=False,
    )
    depth_min = torch.amin(depth_map, dim=[1, 2, 3], keepdim=True)
    depth_max = torch.amax(depth_map, dim=[1, 2, 3], keepdim=True)
    depth_map = (depth_map - depth_min) / (depth_max - depth_min)
    image = torch.cat([depth_map] * 3, dim=1)
    image = image.permute(0, 2, 3, 1).cpu().numpy()[0]
    image = Image.fromarray((image * 255.0).clip(0, 255).astype(np.uint8))
    return image

depth_image = get_depth_map(original_image.resize((1024, 1024)))

controlnets = [
    ControlNetModel.from_pretrained(
        "diffusers/controlnet-canny-sdxl-1.0", dtype=torch.float16
    ),
    ControlNetModel.from_pretrained(
        "diffusers/controlnet-depth-sdxl-1.0-small", dtype=torch.float16
    ),
]

vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", dtype=torch.float16)
pipeline = StableDiffusionXLControlNetPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", controlnet=controlnets, vae=vae, dtype=torch.float16
).to(device)

prompt = """
a relaxed rabbit sitting on a striped towel next to a pool with a tropical drink nearby, 
bright sunny day, vacation scene, 35mm photograph, film, professional, 4k, highly detailed
"""
negative_prompt = "lowres, bad anatomy, worst quality, low quality, deformed, ugly"

images = [canny_image.resize((1024, 1024)), depth_image.resize((1024, 1024))]

pipeline(
    prompt,
    negative_prompt=negative_prompt,
    image=images,
    num_inference_steps=100,
    controlnet_conditioning_scale=[0.5, 0.5],
).images[0]
Canny image
canny image
Depth map
peta kedalaman
Generated image (ControlNet + prompt)
gambar yang dihasilkan

Mode tebak

Guess mode menghasilkan gambar dari kontrol saja ketika Anda tidak memiliki (atau tidak ingin menggunakan) prompt teks. Mode ini menskalakan residual ControlNet berdasarkan kedalaman blok, dari sekitar 0.1 di down block awal hingga 1.0 di mid block. Hal ini mencegah lapisan awal terlalu membatasi, sementara blok yang lebih dalam tetap membawa struktur.

import torch
from diffusers.utils import load_image
from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel

controlnet = ControlNetModel.from_pretrained(
  "diffusers/controlnet-canny-sdxl-1.0", dtype=torch.float16
)
pipeline = StableDiffusionXLControlNetPipeline.from_pretrained(
  "stabilityai/stable-diffusion-xl-base-1.0",
  controlnet=controlnet,
  dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"

canny_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/canny-cat.png")
pipeline(
  "",
  image=canny_image,
  guess_mode=True
).images[0]
Canny image
canny image
Generated image (Guess mode)
gambar yang dihasilkan
Update on GitHub