Buckets:

mishig's picture
|
download
raw
11.7 kB
# ControlNet
[ControlNet](https://huggingface.co/papers/2302.05543) direciona um modelo de difusão pré-treinado com uma imagem de controle estrutural (bordas, profundidade ou pose) enquanto você mantém um prompt de texto. Ele congela o modelo base e adiciona uma rede paralela cujos resíduos guiam o desruidador, permitindo controle de layout sem ajuste fino.
Carregue um ControlNet para o controle de que você precisa (por exemplo, canny) e, em seguida, passe-o como `controlnet=` para [from_pretrained()](/docs/diffusers/v0.43.0/pt/api/pipelines/overview#diffusers.DiffusionPipeline.from_pretrained). Use `controlnet_conditioning_scale` para definir com que intensidade o controle direciona a geração.
> [!TIP]
> ControlNets estão disponíveis para muitos modelos, como [Flux](../api/pipelines/controlnet_flux), [Hunyuan-DiT](../api/pipelines/controlnet_hunyuandit), [Stable Diffusion 3](../api/pipelines/controlnet_sd3) e outros. Os exemplos neste guia usam Flux e Stable Diffusion XL. Para T2I-Adapter em checkpoints mais antigos da família Stable Diffusion, consulte [Adaptadores legados](./legacy_adapters#t2i-adapter). Prefira ControlNet para novos trabalhos de geração controlável.
As abas abaixo mostram o ControlNet para texto-para-imagem, imagem-para-imagem e inpainting.
Gere uma imagem canny com [opencv-python](https://github.com/opencv/opencv-python).
```py
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)
```
Passe a imagem canny para o pipeline. Use o parâmetro `controlnet_conditioning_scale` para determinar quanto peso atribuir ao controle.
```py
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]
```
imagem original
imagem canny
imagem gerada
Gere um mapa de profundidade com um pipeline de estimativa de profundidade do Transformers.
```py
import torch
import numpy as np
from PIL import Image
from transformers import DPTImageProcessor, DPTForDepthEstimation
from diffusers import ControlNetModel, StableDiffusionXLControlNetImg2ImgPipeline, AutoencoderKL
from diffusers.utils import load_image
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
image = load_image(
"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/non-enhanced-prompt.png"
).resize((1024, 1024))
depth_image = get_depth_map(image)
```
Passe o mapa de profundidade para o pipeline. Use o parâmetro `controlnet_conditioning_scale` para determinar quanto peso atribuir ao controle.
```py
controlnet = 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 = StableDiffusionXLControlNetImg2ImgPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0",
controlnet=controlnet,
vae=vae,
dtype=torch.float16,
).to(device)
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.
"""
controlnet_conditioning_scale = 0.5
pipeline(
prompt,
image=image,
control_image=depth_image,
controlnet_conditioning_scale=controlnet_conditioning_scale,
strength=0.99,
num_inference_steps=100,
).images[0]
```
imagem original
mapa de profundidade
imagem gerada
Gere uma imagem de máscara que marca quais pixels substituir e, em seguida, passe-a como `mask_image` junto com a imagem de controle.
```py
import cv2
import torch
import numpy as np
from PIL import Image
from diffusers.utils import load_image
from diffusers import StableDiffusionXLControlNetInpaintPipeline, ControlNetModel
init_image = load_image(
"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/non-enhanced-prompt.png"
)
init_image = init_image.resize((1024, 1024))
mask_image = load_image(
"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/cat_mask.png"
)
mask_image = mask_image.resize((1024, 1024))
def make_canny_condition(image):
image = np.array(image)
image = cv2.Canny(image, 100, 200)
image = image[:, :, None]
image = np.concatenate([image, image, image], axis=2)
image = Image.fromarray(image)
return image
control_image = make_canny_condition(init_image)
```
Passe a máscara e a imagem de controle para o pipeline. Use o parâmetro `controlnet_conditioning_scale` para determinar quanto peso atribuir ao controle.
```py
controlnet = ControlNetModel.from_pretrained(
"diffusers/controlnet-canny-sdxl-1.0", dtype=torch.float16
)
pipeline = StableDiffusionXLControlNetInpaintPipeline.from_pretrained(
"stabilityai/stable-diffusion-xl-base-1.0", controlnet=controlnet, dtype=torch.float16
).to("cuda") # or "mps", "xpu", "cpu"
pipeline(
"a cute and fluffy bunny rabbit",
num_inference_steps=100,
strength=0.99,
controlnet_conditioning_scale=0.5,
image=init_image,
mask_image=mask_image,
control_image=control_image,
).images[0]
```
imagem original
imagem de máscara
imagem gerada
## Multi-ControlNet
Compose vários ControlNets (por exemplo, canny + depth) passando-os como uma lista. Mescle as regiões sobrepostas quando possível e ajuste cada `controlnet_conditioning_scale`. Construa `canny_image` com OpenCV Canny (como em text-to-image) e `depth_image` com DPT (como em image-to-image). Redimensione todas as imagens de controle para o tamanho do pipeline antes de chamar o pipeline.
```py
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]
```
imagem canny
mapa de profundidade
imagem gerada
## Modo de suposição
[Modo de estimativa](https://github.com/lllyasviel/ControlNet/discussions/188) gera uma imagem a partir de um controle isolado quando você não tem (ou não deseja) um prompt de texto. Ele escala os resíduos do ControlNet pela profundidade do bloco, de aproximadamente `0.1` nos blocos de downblock iniciais até `1.0` no bloco intermediário. Isso impede que as camadas iniciais super-restrinjam a geração, enquanto os blocos mais profundos ainda carregam a estrutura.
```py
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]
```
imagem canny
imagem gerada

Xet Storage Details

Size:
11.7 kB
·
Xet hash:
4a5995fc5ada4d623c06ead36d242e3f5cf6ddd4868b8500f19b4a2489d54a1f

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.