使用 Diffusers 实现 ControlNet 高速推理

2024-03-11 01:40

本文主要是介绍使用 Diffusers 实现 ControlNet 高速推理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

自从 Stable Diffusion 风靡全球以来,人们一直在寻求如何更好地控制生成过程的方法。ControlNet 提供了一个简单的迁移学习方法,能够允许用户在很大程度上自定义生成过程。通过 ControlNet,用户可以轻松地使用多种空间语义条件信息 (例如深度图、分割图、涂鸦图、关键点等) 来控制生成过程。

具体来说,我们可以:

将卡通绘图转化为逼真的照片,同时保持极佳的布局连贯性。

63ed3c6e0075acb0ab9ec516fb3760f3.jpeg
写实版的 Lofi Girl (上: 原图,下: 新图)

进行室内设计。

原图新图
85d46eb2ffb5dabe8a0dc7607f6fe632.png86bd4a608e3338be925fd6f0ccf994d8.jpeg

将涂鸦草图变成艺术作品。

原图新图
bf78d700d76c9c4f87482bcd7746e917.png0e6be5f9eeac9fea2f11c80bef7118c0.jpeg

甚至拟人化著名的 logo 形象。

原图新图
37fd6fcdf2faab25e07a973fd2d7543e.jpeg7566bf180d09df6fd62652dc8b3b4bf8.png

ControlNet,使一切皆有可能 🌠

本文的主要内容:

  1. 介绍 StableDiffusionControlNetPipeline

  2. 展示多种控制条件样例

让我们开启控制之旅!

ControlNet 简述

ControlNet 在 Adding Conditional Control to Text-to-Image Diffusion Models 一文中提被出,作者是 Lvmin Zhang 和 Maneesh Agrawala。它引入了一个框架,支持在扩散模型 (如 Stable Diffusion) 上附加额外的多种空间语义条件来控制生成过程。

训练 ControlNet 包括以下步骤:

  1. 克隆扩散模型的预训练参数 (文中称为 可训练副本, trainable copy。如 Stable Diffusion 的 latent UNet 部分),同时保留原本的预训练参数 (文中称为 锁定副本, locked copy)。这样可以实现: a) 让锁定副本保留从大型数据集中学到的丰富知识;b) 让可训练副本学习特定任务的知识。

  2. 可训练副本和锁定副本的参数通过 “零卷积” 层 (详见 此处) 连接。“零卷积” 层是 ControlNet 框架的一部分,会在特定任务中优化参数。这是一种训练技巧,可以在新任务条件训练时保留已冻结模型已经学到的语义信息。

训练 ControlNet 的过程如图所示:

6a8d1d21ff73ea554ab5b03ef53c0710.png

图片出处:
https://github.com/lllyasviel/ControlNet

ControlNet 训练集中的其中一种样例如下 (额外的控制条件是 Canny 边缘图):

原始图片应用控制条件
ce3f926df402622b65f4ac576bbf4d74.png696f6a7b8fb765f3501b666ac4f620a7.png

同样地,如果我们使用的额外控制条件是语义分割图,那么 ControlNet 训练集的样例就是这样:

原始图片应用控制条件
69c3f03840feaa04e12f505049b7566a.pngdcb6700ed954691d45d7a1df37d0942b.png

每对 ControlNet 施加一种额外的控制条件,都需要训练一份新的可训练副本参数。论文中提出了 8 种不同的控制条件,对应的控制模型在 Diffusers 中均已支持!

模型列表:
https://hf.co/lllyasviel?search=controlnet

推理阶段需要同时使用扩散模型的预训练权重以及训练过的 ControlNet 权重。如要使用 Stable Diffusion v1-5 以及其 ControlNet 权重推理,其参数量要比仅使用 Stable Diffusion v1-5 多大约 7 亿个,因此推理 ControlNet 需要消耗更多的内存。

Stable Diffusion v1-5 链接:
https://hf.co/runwayml/stable-diffusion-v1-5

由于在训练过程中扩散模型预训练参数为锁定副本,因此在使用不同的控制条件训练时,只需要切换 ControlNet 可训练副本的参数即可。这样在一个应用程序中部署多个 ControlNet 权重就非常简单了,本文会在后面详细介绍。

StableDiffusionControlNetPipeline

在开始之前,我们要向社区贡献者 Takuma Mori (@takuma104) 表示巨大的感谢。将 ControlNet 集成到 Diffusers 中,他功不可没 ❤️。

类似 Diffusers 中的 其他 Pipeline,Diffusers 同样为 ControlNet 提供了 StableDiffusionControlNetPipeline 供用户使用。StableDiffusionControlNetPipeline 的核心是 controlnet 参数,它接收用户指定的训练过的 ControlNetModel 实例作为输入,同时保持扩散模型的预训练权重不变。

  • Hugging Face 文档里对各种 Pipeline 的介绍:
    https://hf.co/docs/diffusers/api/pipelines/overview

  • StableDiffusionControlNetPipeline
    https://hf.co/docs/diffusers/main/en/api/pipelines/stable_diffusion/controlnet

  • ControlNetModel
    https://hf.co/docs/diffusers/main/en/api/models

本文将介绍 StableDiffusionControlNetPipeline 的多个不同用例。首先要介绍的第一个 ControlNet 模型是 Canny 模型,这是目前最流行的 ControlNet 模型之一,您可能已经在网上见识过一些它生成的精美图片。在阅读到各个部分的代码时,也欢迎您使用此 Colab 笔记本 运行相关代码片段。

  • Canny 模型链接:
    https://hf.co/runwayml/stable-diffusion-v1-5

  • Colab 链接:
    https://colab.research.google.com/github/huggingface/notebooks/blob/main/diffusers/controlnet.ipynb

运行代码之前,首先确保我们已经安装好所有必要的库:

pip install diffusers==0.14.0 transformers xformers git+https://github.com/huggingface/accelerate.git

为处理不同 ControlNet 对应的多种控制条件,还需要安装一些额外的依赖项:

  • OpenCV
    https://opencv.org/

  • controlnet-aux - ControlNet 预处理模型库
    https://github.com/patrickvonplaten/controlnet_aux

pip install opencv-contrib-python
pip install controlnet_aux

我们将以著名的油画作品《戴珍珠耳环的少女》为例,首先让我们下载这张图像并查看一下:

from diffusers.utils import load_imageimage = load_image("https://hf.co/datasets/huggingface/documentation-images/resolve/main/diffusers/input_image_vermeer.png"
)
image
d6b1a5b5e6ad87177486b4271e0650af.jpeg

然后将图像输入给 Canny 预处理器:

import cv2
from PIL import Image
import numpy as npimage = np.array(image)low_threshold = 100
high_threshold = 200image = 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 本质上是边缘检测器:

01be7f185a85a57ac1109992c163dbcf.jpeg

接下来,我们加载 runwaylml/stable-diffusion-v1-5 和 Canny 边缘 ControlNet 模型。设置参数 torch.dtype=torch.float16 可以指定模型以半精度模式加载,可实现内存高效和快速的推理。

Canny 边缘 ControlNet 链接:
https://hf.co/lllyasviel/sd-controlnet-canny

from diffusers import StableDiffusionControlNetPipeline, ControlNetModel
import torchcontrolnet = ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-canny", torch_dtype=torch.float16)
pipe = StableDiffusionControlNetPipeline.from_pretrained("runwayml/stable-diffusion-v1-5", controlnet=controlnet, torch_dtype=torch.float16
)

这里我们不使用 Stable Diffusion 默认的 PNDMScheduler 调度器,而使用改进的 UniPCMultistepScheduler (目前最快的扩散模型调度器之一),可以极大地加快推理速度。经测试,在保证生成图像质量的同时,我们能将推理阶段的采样步数从 50 降到 20。更多关于调度器的信息可以点击 此处 查看。

  • PNDMScheduler 链接:
    https://hf.co/docs/diffusers/main/en/api/schedulers/pndm

  • UniPCMultistepScheduler 链接:
    https://hf.co/docs/diffusers/main/en/api/schedulers/unipc

  • Diffusers 调度器的文档:
    https://hf.co/docs/diffusers/main/en/using-diffusers/schedulers

from diffusers import UniPCMultistepSchedulerpipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)

我们通过调用 enable_model_cpu_offload 函数来启用智能 CPU 卸载,而不是直接将 pipeline 加载到 GPU 上。

enable_model_cpu_offload 文档:
https://hf.co/docs/diffusers/main/en/api/pipelines/stable_diffusion/controlnet

智能 CPU 卸载是一种降低显存占用的方法。扩散模型 (如 Stable Diffusion) 的推理并不是运行一个单独的模型,而是多个模型组件的串行推理。如在推理 ControlNet Stable Diffusion 时,需要首先运行 CLIP 文本编码器,其次推理扩散模型 UNet 和 ControlNet,然后运行 VAE 解码器,最后运行 safety checker (安全检查器,主要用于审核过滤违规图像)。而在扩散过程中大多数组件仅运行一次,因此不需要一直占用 GPU 内存。通过启用智能模型卸载,可以确保每个组件在不需要参与 GPU 计算时卸载到 CPU 上,从而显著降低显存占用,并且不会显著增加推理时间 (仅增加了模型在 GPU-CPU 之间的转移时间)。

注意: 启用 enable_model_cpu_offload 后,pipeline 会自动进行 GPU 内存管理,因此请不要再使用 .to("cuda") 手动将 pipeline 转移到 GPU。

pipe.enable_model_cpu_offload()

最后,我们要充分利用 FlashAttention/xformers 进行注意力层加速。运行下列代码以实现加速,如果该代码没有起作用,那么您可能没有正确安装 xformers 库,此时您可以跳过该代码。

FlashAttention/xformers 仓库链接:
https://github.com/facebookresearch/xformers

pipe.enable_xformers_memory_efficient_attention()

基本条件准备就绪,现在来运行 ControlNet pipeline!

跟运行 Stable Diffusion image-to-image pipeline 相同的是,我们也使用了文本提示语来引导图像生成过程。不过有一些不同的是,ControlNet 允许施加更多种类的控制条件来控制图像生成过程,比如使用刚才我们创建的 Canny 边缘图就能更精确的控制生成图像的构图。

让我们来看一些有趣的,将 17 世纪的名作《戴珍珠耳环的少女》中的少女一角换为现代的名人会是什么样?使用 ControlNet 就能轻松做到,只需要在提示语中写上他们的名字即可!

首先创建一个非常简单的帮助函数来实现生成图像的网格可视化。

def image_grid(imgs, rows, cols):assert len(imgs) == rows * colsw, h = imgs[0].sizegrid = Image.new("RGB", size=(cols * w, rows * h))grid_w, grid_h = grid.sizefor i, img in enumerate(imgs):grid.paste(img, box=(i % cols * w, i // cols * h))return grid

然后输入名字提示语,并设置随机种子以便复现。

prompt = ", best quality, extremely detailed"
prompt = [t + prompt for t in ["Sandra Oh", "Kim Kardashian", "rihanna", "taylor swift"]] # 分别为: 吴珊卓、金·卡戴珊、蕾哈娜、泰勒·斯威夫特
generator = [torch.Generator(device="cpu").manual_seed(2) for i in range(len(prompt))]

最后运行 pipeline,并可视化生成的图像!

output = pipe(prompt,canny_image,negative_prompt=["monochrome, lowres, bad anatomy, worst quality, low quality"] * 4,num_inference_steps=20,generator=generator,
)image_grid(output.images, 2, 2)
21b87b9b8e34eeb2fb91ca76f9236441.jpeg

我们还能轻松地将 ControlNet 与微调结合使用!例如使用 DreamBooth 对模型进行微调,然后使用 ControlNet 增加控制信息,将其渲染到不同的场景中。

DreamBooth 文档链接:
https://hf.co/docs/diffusers/main/en/training/dreambooth

本文将以我们最爱的土豆先生为例,来介绍怎样结合使用 ControlNet 和 DreamBooth。

相较于上文,pipeline 中使用的 ControlNet 部分保持不变,但是不使用 Stable Diffusion 1.5,而是重新加载一个 土豆先生 模型 (使用 Dreambooth 微调的 Stable Diffusion 模型) 🥔。

“土豆先生”模型地址:
https://hf.co/sd-dreambooth-library/mr-potato-head

虽然 ControlNet 没变,但仍然需要重新加载 pipeline。

model_id = "sd-dreambooth-library/mr-potato-head"
pipe = StableDiffusionControlNetPipeline.from_pretrained(model_id,controlnet=controlnet,torch_dtype=torch.float16,
)
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
pipe.enable_model_cpu_offload()
pipe.enable_xformers_memory_efficient_attention()

现在来让土豆先生摆一个《戴珍珠耳环的少女》的姿势吧!

generator = torch.manual_seed(2)
prompt = "a photo of sks mr potato head, best quality, extremely detailed"
output = pipe(prompt,canny_image,negative_prompt="monochrome, lowres, bad anatomy, worst quality, low quality",num_inference_steps=20,generator=generator,
)
output.images[0]

看得出来土豆先生尽力了,这场景着实不太适合他,不过他仍然抓住了精髓🍟。

9bc436536ad384baf84973c52a840659.jpeg

ControlNet 还有另一个独特应用: 从图像提取人体姿态,用姿态信息控制生成具有相同姿态的新图像。因此在下一个示例中,我们将使用 Open Pose ControlNet 来教超级英雄如何做瑜伽!

Open Pose ControlNet 模型地址:
https://hf.co/lllyasviel/sd-controlnet-openpose

首先,我们需要收集一些瑜伽动作图像集:

urls = "yoga1.jpeg", "yoga2.jpeg", "yoga3.jpeg", "yoga4.jpeg"
imgs = [load_image("https://huggingface.co/datasets/YiYiXu/controlnet-testing/resolve/main/" + url) for url in urls
]image_grid(imgs, 2, 2)
574b3388ea7a13473d8429e51e4577e2.jpeg

通过 controlnet_aux 提供的 OpenPose 预处理器,我们可以很方便地提取瑜伽姿态。

from controlnet_aux import OpenposeDetectormodel = OpenposeDetector.from_pretrained("lllyasviel/ControlNet")poses = [model(img) for img in imgs]
image_grid(poses, 2, 2)
0f209f7aaa5417e05d1003dfaf339066.jpeg

瑜伽姿态提取完成后,我们接着创建一个 Open Pose ControlNet pipeline 来生成一些相同姿态的超级英雄图像。Let's go 🚀

controlnet = ControlNetModel.from_pretrained("fusing/stable-diffusion-v1-5-controlnet-openpose", torch_dtype=torch.float16
)model_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionControlNetPipeline.from_pretrained(model_id,controlnet=controlnet,torch_dtype=torch.float16,
)
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
pipe.enable_model_cpu_offload()

超级英雄的瑜伽时间!

generator = [torch.Generator(device="cpu").manual_seed(2) for i in range(4)]
prompt = "super-hero character, best quality, extremely detailed"
output = pipe([prompt] * 4,poses,negative_prompt=["monochrome, lowres, bad anatomy, worst quality, low quality"] * 4,generator=generator,num_inference_steps=20,
)
image_grid(output.images, 2, 2)
ba0e2d1db052ba2bcb14a135dd4d335a.png

通过以上示例,我们对 StableDiffusionControlNetPipeline 的多种用法有了直观的认识,也学会了如何使用 Diffusers 玩转 ControlNet。不过,还有一些 ControlNet 支持的其他类型的控制条件示例,由于篇幅原因本文不再展开,如想了解更多信息,可以点击以下链接查看相应的模型文档页面:

  • lllyasviel/sd-controlnet-depth
    https://hf.co/lllyasviel/sd-controlnet-depth

  • lllyasviel/sd-controlnet-hed
    https://hf.co/lllyasviel/sd-controlnet-hed

  • lllyasviel/sd-controlnet-normal
    https://hf.co/lllyasviel/sd-controlnet-normal

  • lllyasviel/sd-controlnet-scribble
    https://hf.co/lllyasviel/sd-controlnet-scribble

  • lllyasviel/sd-controlnet-seg
    https://hf.co/lllyasviel/sd-controlnet-scribble

  • lllyasviel/sd-controlnet-openpose
    https://hf.co/lllyasviel/sd-controlnet-openpose

  • lllyasviel/sd-controlnet-mlsd
    https://hf.co/lllyasviel/sd-controlnet-mlsd

  • lllyasviel/sd-controlnet-mlsd
    https://hf.co/lllyasviel/sd-controlnet-canny

我们非常欢迎您尝试组合不同的控制组件来生成精美的图像,并在 Twitter 上与 @diffuserslib 分享您的作品。如果您还没有运行上述代码段,这里再次建议您查看刚才提到的 Colab 笔记本,亲自运行代码体验示例的效果!

在上文中,我们介绍了加速生成过程、减少显存占用的一些技巧,它们包括: 快速调度器、智能模型卸载、xformers。如果结合使用这些技巧,单张图像的生成过程仅需要: V100 GPU 上约 3 秒的推理时间以及约 4 GB 的 VRAM 占用;免费 GPU 服务 (如 Google Colab 的 T4) 上约 5 秒的推理时间。如果没有实现这些技巧,同样的生成过程可达 17 秒!现已集成至 Diffusers 工具箱,来使用 Diffusers 吧,它真的非常强力!💪

结语

本文介绍了 StableDiffusionControlNetPipeline 的多个用例,非常有趣!我们也非常期待看到社区在此 pipeline 的基础上能构建出什么好玩的应用。如果您想了解更多 Diffusers 支持的关于控制模型的其他 pipeline 和技术细节,请查看我们的 官方文档。

  • StableDiffusionControlNetPipeline
    https://hf.co/docs/diffusers/main/en/api/pipelines/stable_diffusion/controlnet

  • Diffusers 控制生成的文档
    https://hf.co/docs/diffusers/main/en/using-diffusers/controlling_generation

如果您想直接尝试 ControlNet 的控制效果,我们也能满足!只需点击以下 HuggingFace Spaces 即可尝试控制生成图像:

  • Canny ControlNet Spaces
    https://hf.co/spaces/diffusers/controlnet-canny

  • OpenPose ControlNet Spaces
    https://hf.co/spaces/diffusers/controlnet-openpose


原文链接: https://huggingface.co/blog/controlnet

作者: Sayak Paul、YiYi Xu、Patrick von Platen

译者: SuSung-boy

审校、排版: zhongdongy (阿东)

这篇关于使用 Diffusers 实现 ControlNet 高速推理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/796193

相关文章

C语言中联合体union的使用

本文编辑整理自: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=179471 一、前言 “联合体”(union)与“结构体”(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和。而在“联合”中,各成员共享一段内存空间, 一个联合变量

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

Lipowerline5.0 雷达电力应用软件下载使用

1.配网数据处理分析 针对配网线路点云数据,优化了分类算法,支持杆塔、导线、交跨线、建筑物、地面点和其他线路的自动分类;一键生成危险点报告和交跨报告;还能生成点云数据采集航线和自主巡检航线。 获取软件安装包联系邮箱:2895356150@qq.com,资源源于网络,本介绍用于学习使用,如有侵权请您联系删除! 2.新增快速版,简洁易上手 支持快速版和专业版切换使用,快速版界面简洁,保留主

如何免费的去使用connectedpapers?

免费使用connectedpapers 1. 打开谷歌浏览器2. 按住ctrl+shift+N,进入无痕模式3. 不需要登录(也就是访客模式)4. 两次用完,关闭无痕模式(继续重复步骤 2 - 4) 1. 打开谷歌浏览器 2. 按住ctrl+shift+N,进入无痕模式 输入网址:https://www.connectedpapers.com/ 3. 不需要登录(也就是

大语言模型(LLMs)能够进行推理和规划吗?

大语言模型(LLMs),基本上是经过强化训练的 n-gram 模型,它们在网络规模的语言语料库(实际上,可以说是我们文明的知识库)上进行了训练,展现出了一种超乎预期的语言行为,引发了我们的广泛关注。从训练和操作的角度来看,LLMs 可以被认为是一种巨大的、非真实的记忆库,相当于为我们所有人提供了一个外部的系统 1(见图 1)。然而,它们表面上的多功能性让许多研究者好奇,这些模型是否也能在通常需要系

通过SSH隧道实现通过远程服务器上外网

搭建隧道 autossh -M 0 -f -D 1080 -C -N user1@remotehost##验证隧道是否生效,查看1080端口是否启动netstat -tuln | grep 1080## 测试ssh 隧道是否生效curl -x socks5h://127.0.0.1:1080 -I http://www.github.com 将autossh 设置为服务,隧道开机启动

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档:https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址:https://github.com/Hufe921/canvas-editor 前提声明: 由于CanvasEditor目前不支持vue、react 等框架开箱即用版,所以需要我们去Git下载源码,拿到其中两个主