跳转至

控制网

译者:片刻小哥哥

项目地址:https://huggingface.apachecn.org/docs/diffusers/using-diffusers/controlnet

原始地址:https://huggingface.co/docs/diffusers/using-diffusers/controlnet

ControlNet 是一种通过使用附加输入图像调节模型来控制图像扩散模型的模型。您可以使用多种类型的调节输入(精明边缘、用户草图、人体姿势、深度等)来控制扩散模型。这非常有用,因为它使您可以更好地控制图像生成,从而更轻松地生成特定图像,而无需尝试不同的文本提示或去噪值。

请参阅第 3.5 节 ControlNet 有关各种调节输入的 ControlNet 实现列表的论文。您可以在以下位置找到官方稳定扩散 ControlNet 条件模型 lllyasviel 的集线器简介等 社区培训 集线器上的那些。

对于 Stable Diffusion XL (SDXL) ControlNet 模型,您可以在 🤗 上找到它们 扩散器 中心组织,或者您可以浏览 社区培训 集线器上的那些。

ControlNet 模型具有两组通过零卷积层连接的权重(或块):

  • A 锁定副本 保留大型预训练扩散模型学到的所有内容
  • A 可训练副本 接受额外调节输入的训练

由于锁定的副本保留了预训练的模型,因此在新的条件输入上训练和实现 ControlNet 与微调任何其他模型一样快,因为您不是从头开始训练模型。

本指南将向您展示如何使用 ControlNet 进行文本到图像、图像到图像、修复等!有多种类型的 ControlNet 调节输入可供选择,但在本指南中我们将只关注其中的几种。请随意尝试其他调节输入!

在开始之前,请确保已安装以下库:

# uncomment to install the necessary libraries in Colab
#!pip install diffusers transformers accelerate safetensors opencv-python

文本转图像

对于文本到图像,您通常将文本提示传递给模型。但通过 ControlNet,您可以指定额外的调节输入。让我们用精明的图像(黑色背景上的白色轮廓图像)来调节模型。这样,ControlNet就可以使用canny图像作为控制,引导模型生成具有相同轮廓的图像。

加载图像并使用 opencv-python 提取canny图像的库:

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

image = load_image(
    "https://hf.co/datasets/huggingface/documentation-images/resolve/main/diffusers/input\_image\_vermeer.png"
)

image = np.array(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)

原始图像

精明的图像

接下来,加载以 canny 边缘检测为条件的 ControlNet 模型并将其传递给 StableDiffusionControlNetPipeline 。使用速度越快 UniPCMultistepScheduler 并启用模型卸载以加速推理并减少内存使用。

from diffusers import StableDiffusionControlNetPipeline, ControlNetModel, UniPCMultistepScheduler
import torch

controlnet = ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-canny", torch_dtype=torch.float16, use_safetensors=True)
pipe = StableDiffusionControlNetPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5", controlnet=controlnet, torch_dtype=torch.float16, use_safetensors=True
).to("cuda")

pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
pipe.enable_model_cpu_offload()

现在将您的提示和精明的图像传递到管道:

output = pipe(
    "the mona lisa", image=canny_image
).images[0]

图像到图像

对于图像到图像,您通常会将初始图像和提示传递给管道以生成新图像。借助 ControlNet,您可以传递额外的调节输入来指导模型。让我们用深度图(包含空间信息的图像)来调节模型。这样,ControlNet 就可以使用深度图作为控制来指导模型生成保留空间信息的图像。

您将使用 StableDiffusionControlNetImg2ImgPipeline 对于这个任务,它不同于 StableDiffusionControlNetPipeline 因为它允许您传递初始图像作为图像生成过程的起点。

加载图像并使用 深度估计 管道 从🤗 Transformers 中提取图像的深度图:

import torch
import numpy as np

from transformers import pipeline
from diffusers.utils import load_image

image = load_image(
    "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/controlnet-img2img.jpg"
).resize((768, 768))


def get\_depth\_map(image, depth\_estimator):
    image = depth_estimator(image)["depth"]
    image = np.array(image)
    image = image[:, :, None]
    image = np.concatenate([image, image, image], axis=2)
    detected_map = torch.from_numpy(image).float() / 255.0
    depth_map = detected_map.permute(2, 0, 1)
    return depth_map

depth_estimator = pipeline("depth-estimation")
depth_map = get_depth_map(image, depth_estimator).unsqueeze(0).half().to("cuda")

接下来,加载以深度图为条件的 ControlNet 模型并将其传递给 StableDiffusionControlNetImg2ImgPipeline 。使用速度越快 UniPCMultistepScheduler 并启用模型卸载以加速推理并减少内存使用。

from diffusers import StableDiffusionControlNetImg2ImgPipeline, ControlNetModel, UniPCMultistepScheduler
import torch

controlnet = ControlNetModel.from_pretrained("lllyasviel/control\_v11f1p\_sd15\_depth", torch_dtype=torch.float16, use_safetensors=True)
pipe = StableDiffusionControlNetImg2ImgPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5", controlnet=controlnet, torch_dtype=torch.float16, use_safetensors=True
).to("cuda")

pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
pipe.enable_model_cpu_offload()

现在将提示、初始图像和深度图传递到管道:

output = pipe(
    "lego batman and robin", image=image, control_image=depth_map,
).images[0]

原始图像

生成的图像

修复

对于修复,您需要一个初始图像、一个蒙版图像和一个描述用什么替换蒙版的提示。 ControlNet 模型允许您添加另一个控制图像来调节模型。让我们用精明的图像(黑色背景上的白色轮廓图像)来调节模型。这样,ControlNet就可以使用canny图像作为控制,引导模型生成具有相同轮廓的图像。

加载初始图像和掩模图像:

from diffusers import StableDiffusionControlNetInpaintPipeline, ControlNetModel, UniPCMultistepScheduler
from diffusers.utils import load_image
import numpy as np
import torch

init_image = load_image(
    "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/controlnet-inpaint.jpg"
)
init_image = init_image.resize((512, 512))

mask_image = load_image(
    "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/controlnet-inpaint-mask.jpg"
)
mask_image = mask_image.resize((512, 512))

创建一个函数以根据初始图像和掩模图像准备控制图像。这将创建一个张量来标记其中的像素 初始化映像 如果相应的像素在 遮罩图像 超过了一定的阈值。

def make\_inpaint\_condition(image, image\_mask):
    image = np.array(image.convert("RGB")).astype(np.float32) / 255.0
    image_mask = np.array(image_mask.convert("L")).astype(np.float32) / 255.0

    assert image.shape[0:1] == image_mask.shape[0:1]
    image[image_mask > 0.5] = 1.0  # set as masked pixel
    image = np.expand_dims(image, 0).transpose(0, 3, 1, 2)
    image = torch.from_numpy(image)
    return image

control_image = make_inpaint_condition(init_image, mask_image)

原始图像

掩模图像

加载以修复为条件的 ControlNet 模型并将其传递给 StableDiffusionControlNetInpaintPipeline 。使用速度越快 UniPCMultistepScheduler 并启用模型卸载以加速推理并减少内存使用。

from diffusers import StableDiffusionControlNetInpaintPipeline, ControlNetModel, UniPCMultistepScheduler
import torch

controlnet = ControlNetModel.from_pretrained("lllyasviel/control\_v11p\_sd15\_inpaint", torch_dtype=torch.float16, use_safetensors=True)
pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5", controlnet=controlnet, torch_dtype=torch.float16, use_safetensors=True
).to("cuda")

pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
pipe.enable_model_cpu_offload()

现在将提示、初始图像、遮罩图像和控制图像传递到管道:

output = pipe(
    "corgi face with large ears, detailed, pixar, animated, disney",
    num_inference_steps=20,
    eta=1.0,
    image=init_image,
    mask_image=mask_image,
    control_image=control_image,
).images[0]

猜测模式

猜测模式 根本不需要向 ControlNet 提供提示!这迫使 ControlNet 编码器尽力“猜测”输入控制图的内容(深度图、姿态估计、canny 边缘等)。

猜测模式根据块深度以固定比率调整 ControlNet 输出残差的比例。最浅的 下块 对应于0.1,随着块的加深,规模呈指数级增长,使得 中块 输出变为1.0。

猜测模式对提示调节没有任何影响,如果需要,您仍然可以提供提示。

guess_mode=True 在管道中,它是 推荐 设置 指导规模 值介于 3.0 和 5.0 之间。

from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
import torch

controlnet = ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-canny", use_safetensors=True)
pipe = StableDiffusionControlNetPipeline.from_pretrained("runwayml/stable-diffusion-v1-5", controlnet=controlnet, use_safetensors=True).to(
    "cuda"
)
image = pipe("", image=canny_image, guess_mode=True, guidance_scale=3.0).images[0]
image

带提示的常规模式

无提示猜测模式

ControlNet 具有稳定扩散 XL

目前没有太多与 Stable Diffusion XL (SDXL) 兼容的 ControlNet 模型,但我们已经根据精明的边缘检测和深度图训练了两个用于 SDXL 的全尺寸 ControlNet 模型。我们还尝试创建这些兼容 SDXL 的 ControlNet 模型的较小版本,以便更容易在资源受限的硬件上运行。您可以在 🤗 上找到这些检查点 扩散器 中心组织!

让我们使用以 canny 图像为条件的 SDXL ControlNet 来生成图像。首先加载图像并准备 canny 图像:

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

image = load_image(
    "https://huggingface.co/datasets/hf-internal-testing/diffusers-images/resolve/main/sd\_controlnet/hf-logo.png"
)

image = np.array(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)
canny_image

原始图像

精明的图像

加载以 Canny 边缘检测为条件的 SDXL ControlNet 模型,并将其传递给 StableDiffusionXLControlNetPipeline 。您还可以启用模型卸载以减少内存使用。

controlnet = ControlNetModel.from_pretrained(
    "diffusers/controlnet-canny-sdxl-1.0",
    torch_dtype=torch.float16,
    use_safetensors=True
)
vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16, use_safetensors=True)
pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    controlnet=controlnet,
    vae=vae,
    torch_dtype=torch.float16,
    use_safetensors=True
)
pipe.enable_model_cpu_offload()

现在将您的提示(如果您正在使用提示,还可以选择是否定提示)和精明的图像传递到管道:

controlnet_conditioning_scale 参数决定分配给调节输入的权重。为了获得良好的泛化效果,建议使用值 0.5,但请随意尝试这个数字!

prompt = "aerial view, a futuristic research complex in a bright foggy jungle, hard lighting"
negative_prompt = 'low quality, bad quality, sketches'

images = pipe(
    prompt,
    negative_prompt=negative_prompt,
    image=canny_image,
    controlnet_conditioning_scale=0.5,
).images[0]
images

您可以使用 StableDiffusionXLControlNetPipeline 在猜测模式下也可以通过将参数设置为 '真实' :

from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel, AutoencoderKL
from diffusers.utils import load_image
import numpy as np
import torch

import cv2
from PIL import Image

prompt = "aerial view, a futuristic research complex in a bright foggy jungle, hard lighting"
negative_prompt = "low quality, bad quality, sketches"

image = load_image(
    "https://hf.co/datasets/hf-internal-testing/diffusers-images/resolve/main/sd\_controlnet/hf-logo.png"
)

controlnet = ControlNetModel.from_pretrained(
    "diffusers/controlnet-canny-sdxl-1.0", torch_dtype=torch.float16, use_safetensors=True
)
vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16, use_safetensors=True)
pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", controlnet=controlnet, vae=vae, torch_dtype=torch.float16, use_safetensors=True
)
pipe.enable_model_cpu_offload()

image = np.array(image)
image = cv2.Canny(image, 100, 200)
image = image[:, :, None]
image = np.concatenate([image, image, image], axis=2)
canny_image = Image.fromarray(image)

image = pipe(
    prompt, controlnet_conditioning_scale=0.5, image=canny_image, guess_mode=True,
).images[0]

多控制网

将 SDXL 模型替换为类似模型 runwayml/stable-diffusion-v1-5 通过稳定扩散模型使用多个调节输入。

您可以根据不同的图像输入组合多个 ControlNet 条件来创建 多控制网络 。为了获得更好的结果,以下操作通常会有所帮助:

  1. 遮盖条件,使其不重叠(例如,遮盖精明图像中姿势条件所在的区域)
  2. 进行实验 controlnet_conditioning_scale 参数来确定为每个调节输入分配多少权重

在此示例中,您将组合精明图像和人体姿势估计图像来生成新图像。

准备精明的图像调节:

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

canny_image = load_image(
    "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/landscape.png"
)
canny_image = np.array(canny_image)

low_threshold = 100
high_threshold = 200

canny_image = cv2.Canny(canny_image, low_threshold, high_threshold)

# zero out middle columns of image where pose will be overlaid
zero_start = canny_image.shape[1] // 4
zero_end = zero_start + canny_image.shape[1] // 2
canny_image[:, zero_start:zero_end] = 0

canny_image = canny_image[:, :, None]
canny_image = np.concatenate([canny_image, canny_image, canny_image], axis=2)
canny_image = Image.fromarray(canny_image).resize((1024, 1024))

原始图像

精明的图像

准备人体姿势估计条件:

from controlnet_aux import OpenposeDetector
from diffusers.utils import load_image

openpose = OpenposeDetector.from_pretrained("lllyasviel/ControlNet")

openpose_image = load_image(
    "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/person.png"
)
openpose_image = openpose(openpose_image).resize((1024, 1024))

原始图像

人体姿势图像

加载与每个条件对应的 ControlNet 模型列表,并将它们传递给 StableDiffusionXLControlNetPipeline 。使用速度越快 UniPCMultistepScheduler 并启用模型卸载以减少内存使用。

from diffusers import StableDiffusionXLControlNetPipeline, ControlNetModel, AutoencoderKL, UniPCMultistepScheduler
import torch

controlnets = [
    ControlNetModel.from_pretrained(
        "thibaud/controlnet-openpose-sdxl-1.0", torch_dtype=torch.float16, use_safetensors=True
    ),
    ControlNetModel.from_pretrained(
        "diffusers/controlnet-canny-sdxl-1.0", torch_dtype=torch.float16, use_safetensors=True
    ),
]

vae = AutoencoderKL.from_pretrained("madebyollin/sdxl-vae-fp16-fix", torch_dtype=torch.float16, use_safetensors=True)
pipe = StableDiffusionXLControlNetPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", controlnet=controlnets, vae=vae, torch_dtype=torch.float16, use_safetensors=True
)
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
pipe.enable_model_cpu_offload()

现在,您可以将提示(如果您正在使用提示,则可以选择否定提示)、精明图像并将图像摆在管道中:

prompt = "a giant standing in a fantasy landscape, best quality"
negative_prompt = "monochrome, lowres, bad anatomy, worst quality, low quality"

generator = torch.manual_seed(1)

images = [openpose_image, canny_image]

images = pipe(
    prompt,
    image=images,
    num_inference_steps=25,
    generator=generator,
    negative_prompt=negative_prompt,
    num_images_per_prompt=3,
    controlnet_conditioning_scale=[1.0, 0.8],
).images[0]


我们一直在努力

apachecn/AiLearning

【布客】中文翻译组