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 điều hướng một mô hình khuếch tán được huấn luyện trước bằng một hình ảnh kiểm soát cấu trúc (đường viền, độ sâu hoặc tư thế) trong khi bạn vẫn giữ nguyên câu lệnh văn bản. Nó đóng băng mô hình cơ sở và thêm một mạng song song, trong đó các phần dư (residuals) của mạng này dẫn dắt bộ khử nhiễu (denoiser), nhờ đó bạn có được khả năng kiểm soát bố cục mà không cần tinh chỉnh (fine-tuning).

Tải một ControlNet cho loại điều khiển bạn cần (ví dụ canny), sau đó truyền nó dưới dạng controlnet= vào from_pretrained(). Sử dụng controlnet_conditioning_scale để thiết lập mức độ mạnh mà điều khiển định hướng quá trình tạo.

ControlNet có sẵn cho nhiều mô hình như Flux, Hunyuan-DiT, Stable Diffusion 3 và nhiều hơn nữa. Các ví dụ trong hướng dẫn này sử dụng Flux và Stable Diffusion XL. Đối với T2I-Adapter trên các checkpoint thuộc họ Stable Diffusion cũ hơn, hãy xem Legacy adapters. Ưu tiên sử dụng ControlNet cho các công việc tạo ảnh có kiểm soát mới.

Các tab bên dưới hiển thị ControlNet cho text-to-image, image-to-image và inpainting.

text-to-image
image-to-image
inpainting

Tạo ảnh canny bằng 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)

Truyền ảnh canny vào pipeline. Sử dụng tham số controlnet_conditioning_scale để xác định mức độ ưu tiên gán cho điều khiển.

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)
ảnh gốc
Control image (Canny edges)
ảnh canny
Generated image (ControlNet + prompt)
hình ảnh được tạo

Multi-ControlNet

Kết hợp nhiều ControlNet (ví dụ canny + depth) bằng cách truyền chúng dưới dạng một danh sách. Che mờ các vùng chồng lấn khi có thể và tinh chỉnh từng controlnet_conditioning_scale. Tạo canny_image bằng OpenCV Canny (như trong text-to-image) và depth_image bằng DPT (như trong image-to-image). Thay đổi kích thước mọi ảnh điều khiển về kích thước của pipeline trước khi gọi 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
ảnh canny
Depth map
bản đồ độ sâu
Generated image (ControlNet + prompt)
hình ảnh được tạo

Chế độ đoán

Chế độ Guess tạo ra hình ảnh từ một tín hiệu điều khiển đơn lẻ khi bạn không có (hoặc không muốn dùng) prompt văn bản. Chế độ này nhân các phần dư của ControlNet theo độ sâu của khối, từ khoảng 0.1 ở các khối xuống sớm lên đến 1.0 ở khối giữa. Điều này giúp các lớp sớm không bị ràng buộc quá mức trong khi các khối sâu hơn vẫn duy trì cấu trúc.

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
ảnh canny
Generated image (Guess mode)
hình ảnh được tạo
Update on GitHub