使用 diffusers 训练你自己的 ControlNet 🧨
简介
ControlNet 这个神经网络模型使得用户可以通过施加额外条件,细粒度地控制扩散模型的生成过程。这一技术最初由 Adding Conditional Control to Text-to-Image Diffusion Models 这篇论文提出,并很快地风靡了扩散模型的开源社区。作者开源了 8 个不同的模型,使得用户可以用 8 种条件去控制 Stable Diffusion 模型(包括版本 1 到 5 )。这 8 种条件包括姿态估计、深度图、边缘图、素描图 等等。

在这篇博客中,我们首先介绍训练 Uncanny Faces model 的步骤。这是一个基于 3D 合成人脸的人脸姿态模型(这里的 uncanny faces 只是一个无意得到的结果,后面我们会讲到)。
开始着手用 Stable Diffusion 训练你的 ControlNet
训练你自己的 ControlNet 需要 3 个步骤:
设计你想要的生成条件: 使用 ControlNet 可以灵活地“驯服” Stable Diffusion,使它朝着你想的方向生成。预训练的模型已经展示出了大量可用的生成条件,此外开源社区也已经开发出了很多其它条件,比如这里 像素化的色彩板。
构建你自己的数据集: 当生成条件确定好后,就该构建数据集了。你既可以从头构建一个数据集,也可以使用现有数据集中的数据。为了训练模型,这个数据集需要有三个维度的信息: 图片、作为条件的图片,以及语言提示。
训练模型: 一旦数据集建好了,就可以训练模型了。如果你使用 这个基于 diffusers 的训练脚本,训练其实是最简单的。这里你需要一个至少 8G 显存的 GPU。
1. 设计你想要的生成条件
在设计你自己的生成条件前,有必要考虑一下两个问题:
- 哪种生成条件是我想要的?
- 是否已有现存的模型可以把正常图片转换成我的条件图片?
举个例子,假如我们想要使用人脸特征点作为生成条件。我们的思考过程应该是这样: 1. 一般基于特征点的 ControlNet 效果都还挺好。2. 人脸特征点检测也是一个很常见的任务,也有很多模型可以在普通图片上检测人脸特征点。3. 让 Stable Diffusion 去根据特征点生成人脸图片也挺有意思,还能让生成的人脸模仿别人的表情。

2. 构建你自己的数据集
好!那我们现在已经决定用人脸特征点作为生成条件了。接下来我们需要这样构建数据集:
- 准备 ground truth 图片 (
image): 这里指的就是真实人脸图片 - 准备 条件图片 (
conditioning_image): 这里指的就是画出来的特征点 - 准备 说明文字 (
caption): 描述图片的文字
针对这个项目,我们使用微软的 FaceSynthetics 数据集: 这是一个包含了 10 万合成人脸的数据集。你可能会想到其它一些人脸数据集,比如 Celeb-A HQ 和 FFHQ,但这个项目我们决定还是采用合成人脸。

这里的 FaceSynthetics 数据集看起来是个不错的选择: 它包含了真实的人脸图片,同时也包含了被标注过的人脸特征点(按照 iBUG 68 特征点的格式),同时还有人脸的分割图。

然而,这个数据集也不是完美的。我们前面说过,我们应该有模型可以将真实图片转换到条件图片。但这里似乎没有这样的模型,把人脸图片转换成我们特征点标注形式(无法把特征点转换为分割图)。

所以我们需要用另一种方法:
- 使用
FaceSynthetics中的真实图片 (image) - 使用一个现有的模型把人脸图片转换为 68 个特征点的形式。这里我们使用 SPIGA 这个模型
- 使用自己的代码把人脸特征点转换为人脸分割图,以此作为“条件图片” (
conditioning_image) - 把这些数据保存为 Hugging Face Dataset
这里 是将真实图片转换到分割图的代码,以及将数据保存为 Hugging Face Dataset 的代码。
现在我们准备好了 ground truth 图片和“条件图片”,我们还缺少说明文字。我们强烈推荐你把说明文字加进去,但你也可以试试使用空的说明文字来看看效果。因为 FaceSynthetics 数据集并没有自带说明文字,我们使用 BLIP captioning 去给图片加上文字(代码在这里)。
至此,我们就完成了数据集的构建。这个 Face Synthetics SPIGA with captions 数据集包含了 ground truth 图片、条件图片,以及对应的说明文字,总计有 10 万条数据。一切就绪,我们现在可以开始训练模型了。

3. 模型训练
有了 数据,下一步就是训练模型。即使这部分很难,但有了 下面的脚本,这个过程却变成了最简单的部分。我们用了一个 A100 GPU去训练(在 LambdaLabs 每小时 1.1 美元租的)。
我们的训练经验
我们以 batch size 为 4 训练了 3 个 epoch。结果表明此策略有些太激进,导致结果出现过拟合现象。模型有点忘记人脸的概念了,即使提示语中包含“怪物史莱克”或“一只猫”,模型也只会生成人脸而不是“史莱克”或猫;同时模型也对各种风格变得不敏感。
如果我们只训练 1 个 epoch (即模型仅学习了 10 万张照片),模型倒是能遵循输入的姿态,同时也没什么过拟合。看起来还行,但由于我们用的是合成数据,模型最终生成的都是些看起来很 3D 的人脸,而不是真实人脸。当然,基于我们用的数据集,生成这样的效果也正常。这里是训练好的模型: uncannyfaces_25K。

在这张可交互表格 (请访问下面的链接) 中,你可以看看不同步数下模型训练进度如何。在训练了大约 15k 步后,模型就已经开始学习姿态了。最终模型在 25k 步后成熟。
训练具体怎么做
首先我们安装各种依赖:
pip install git+https://github.com/huggingface/diffusers.git transformers accelerate xformers==0.0.16 wandb
huggingface-cli login
wandb login
然后运行这个脚本 train_controlnet.py
!accelerate launch train_controlnet.py \
--pretrained_model_name_or_path="stabilityai/stable-diffusion-2-1-base" \
--output_dir="model_out" \
--dataset_name=multimodalart/facesyntheticsspigacaptioned \
--conditioning_image_column=spiga_seg \
--image_column=image \
--caption_column=image_caption \
--resolution=512 \
--learning_rate=1e-5 \
--validation_image "./face_landmarks1.jpeg" "./face_landmarks2.jpeg" "./face_landmarks3.jpeg" \
--validation_prompt "High-quality close-up dslr photo of man wearing a hat with trees in the background" "Girl smiling, professional dslr photograph, dark background, studio lights, high quality" "Portrait of a clown face, oil on canvas, bittersweet expression" \
--train_batch_size=4 \
--num_train_epochs=3 \
--tracker_project_name="controlnet" \
--enable_xformers_memory_efficient_attention \
--checkpointing_steps=5000 \
--validation_steps=5000 \
--report_to wandb \
--push_to_hub
我们详细看看这些设置参数,同时也看看有哪些优化方法可以用于 8GB 以下显存的 GPU 训练。
pretrained_model_name_or_path: 基础的 Stable Diffusion 模型,这里我们使用 v2-1 版本,因为这一版生成人脸效果更好output_dir: 保存模型的目录文件夹dataset_name: 用于训练的数据集,这里我们使用 Face Synthetics SPIGA with captionsconditioning_image_column: 数据集中包含条件图片的这一栏的名称,这里我们用spiga_segimage_column: 数据集中包含 ground truth 图片的这一栏的名称,这里我们用imagecaption_column: 数据集中包含文字说明的这一栏的名称,这里我们用image_captionresolution: ground truth 图片和条件图片的分辨率,这里我们用512x512learning_rate: 学习率。我们发现设成1e-5效果很好,但你也可以试试介于1e-4和2e-6之间的其它值validation_image: 这里是让你在训练过程中偷窥一下效果的。每隔validation_steps步训练,这些验证图片都会跑一下,让你看看当前的训练效果。请在这里插入一个指向一系列条件图片的本地路径validation_prompt: 这里是一句文本提示,用于和你的验证图片一起验证当前模型。你可以根据你的需要设置train_batch_size: 这是训练时使用的 batch size。因为我们用的是 V100,所以我们还有能力把它设成 4。但如果你的 GPU 显存比较小,我们推荐直接设成 1。num_train_epochs: 训练模型使用的轮数。每一轮模型都会看一遍整个数据集。我们实验用的是 3 轮,但似乎最好的结果应该是出现在一轮多一点的地方。当训练了 3 轮时,我们的模型过拟合了。checkpointing_steps: 每隔这么多步,我们都会保存一下模型的中间结果检查点。这里我们设置成 5000,也就是每训练 5000 步就保存一下检查点。validation_steps: 每隔这么多步,validation_image和validation_prompt就会跑一下,来验证训练过程。report_to: 向哪里报告训练情况。这里我们使用 Weights and Biases 这个平台,它可以给出美观的训练报告。push_to_hub: 将最终结果推到 Hugging Face Hub.
但是将 train_batch_size 从 4 减小到 1 可能还不足以使模型能够在低配置 GPU 上运行,这里针对不同 GPU 的 VRAM 提供一些其它配置信息:
适配 16GB 显存的 GPU
pip install bitsandbytes
--train_batch_size=1 \
--gradient_accumulation_steps=4 \
--gradient_checkpointing \
--use_8bit_adam
这里 batch size 设为 1,同时使用 4 步的梯度累计等同于你使用原始的 batch size 为 4 的情况。除此之外,我们开启了对梯度保存检查点,以及 8 bit 的 Adam 优化器训练,以此更多地节省显存。
适配 12GB 显存的 GPU
--gradient_accumulation_steps=4 \
--gradient_checkpointing \
--use_8bit_adam
--set_grads_to_none
适配 8GB 显存的 GPU
请参考 我们的教程
4. 总结
训练 ControlNet 的过程非常有趣。我们已经成功地训练了一个可以模仿真实人脸姿态的模型。然而这个模型更多是生成 3D 风格的人脸图片而不是真实人脸图片,这是由于我们使用了合成人脸的数据执行训练。当然这也让生成的模型有了独特的魅力。
试试我们的 Hugging Face Space

下一步,为了生成真实的人脸图片,同时还不使用真实人脸数据集,我们可以用 Stable Diffusion Image2Image 跑一遍所有的 FaceSynthetics 图片,把看起来很 3D 的人脸转换成真实人脸图片,然后再训练 ControlNet。
请继续关注我们,接下来我们将举办 ControlNet 训练赛事。请在 Twitter 关注 Hugging Face,或者加入我们的 Discord 以便接收最新消息!
如果您此前曾被 ControlNet 将 Lofi Girl 的动画形象改成写实版类真人画面的能力折服,却又担心自己难以承担高昂的训练成本,不妨报名参加我们近期的提供免费 TPU 的 ControlNet 微调活动。试试看充满创造力的你能有什么样的大作!
英文原文: https://hf.co/blog/train-your-controlnet
作者: Apolinário from multimodal AI art, Pedro Cuenca
译者: HoiM Y, 阿东
使用 diffusers 训练你自己的 ControlNet 🧨的更多相关文章
- SSD框架训练自己的数据集
SSD demo中详细介绍了如何在VOC数据集上使用SSD进行物体检测的训练和验证.本文介绍如何使用SSD实现对自己数据集的训练和验证过程,内容包括: 1 数据集的标注2 数据集的转换3 使用SSD如 ...
- 基于英特尔® 至强 E5 系列处理器的单节点 Caffe 评分和训练
原文链接 在互联网搜索引擎和医疗成像等诸多领域,深度神经网络 (DNN) 应用的重要性正在不断提升. Pradeep Dubey 在其博文中概述了英特尔® 架构机器学习愿景. 英特尔正在实现 Prad ...
- 记一周cdqz训练
#include <cstdio> using namespace std; int main(){ puts("转载请注明出处:http://www.cnblogs.com/w ...
- 语言模型kenlm的训练及使用
一.背景 近期研究了一下语言模型,同事推荐了一个比较好用的工具包kenlm,记录下使用过程. 二.使用kenlm训练 n-gram 1.工具介绍:http://kheafield.com/code/k ...
- LUA中将未分类数据分为测试集和训练集
require 'torch' require 'image' local setting = {parent_root = '/home/pxu/image'} function list_chil ...
- HDU-SupportOrNot训练实录
菜鸡队训练实录. 现场赛记录: 2016:[名称:奖项/排名] ZJPSC:Gold/1 CCPC中南邀请赛:Gold/1 ICPC Dalian:Gold/24 ICPC Beijing:Gold/ ...
- [转]Tesseract 3.02中文字库训练
下载chi_sim.traindata字库下载tesseract-ocr-setup-3.02.02.exe 下载地址:http://code.google.com/p/tesseract-ocr/d ...
- codefordream 关于js中级训练
中级训练接着就紧锣密鼓的开始了. 首先是关于变量,变量的作用是给一个数据值标注名称. 注:JavaScript中变量名,函数名,参数名的命名规范:至少由字母,下划线,美元符号,数字其中的一种组成,但不 ...
- codefordream 关于js初级训练
这里的初级训练相对简单,差不多都是以前知识温习. 比如输出“hello world”,直接使用console.log()就行.注释符号,“//”可以注释单行,快捷键 alt+/,"/* ...
- svm训练显示信息说明
现简单对屏幕回显信息进行说明: #iter 为迭代次数, nu 与前面的操作参数 -n nu 相同, obj 为 SVM 文件转换为的二次规划求解得到的最小值, rho 为判决函数的常数项 b ...
随机推荐
- hdu1710 二叉树(C/C++)
hdu1710 题目地址:https://acm.dingbacode.com/showproblem.php?pid=1710 (最近几天杭电原网址开不进去了,之后应该可以通..吧) Binary ...
- Vue+Element+Table表格动态跨列文章
https://my.oschina.net/u/4772459/blog/4699602 如图所示: 1 <template class="SysRole"> 2 & ...
- 4组-Beta冲刺-5/5
一.基本情况 队名:摸鲨鱼小队 组长博客:https://www.cnblogs.com/smallgrape/p/15608986.html github链接:https://github.com/ ...
- numpy.ndarray类型方法
numpy.ndarray 类numpy.ndarray(shape,dtype = float,buffer = None,offset = 0,strides = None,order = Non ...
- AntD为Form的List设置默认值 (antd form.list 设置默认值 )
import React from "react"; function demo() { const FormConfig = { labelCol: { span: 8 }, w ...
- Python笔记(4)——元组(Python编程:从入门到实践)
元组 1. 元组:不可变的列表.元组一经创建不能被修改. 2. 表示:用圆括号()来表示,并用逗号来分隔其中的元素.可通过索引访问其元素. 3. 访问:访问列表元素,指出元组的名称,再指出元素的索引, ...
- [C++] epoll server实例
// IO多路复用,事件驱动+非阻塞,实现一个线程完成对多个fd的监控和响应,提升CPU利用率 // epoll优点: // 1.select需要每次调用select时拷贝fd,epoll_ctl拷贝 ...
- 转发:前端组件化之Monorepo方案实战
前言 在上一篇的前端组件化方案探究中,我们研究了什么是组件化以及我们为什么需要组件化.也调研和测试了一些开源项目,并且在使用.学习.研究.对比之后最终确定了以 pnpm + workspace + c ...
- 关于一维数组传入函数的使用 //西电oj214题字符统计
#include<stdio.h> void count(char str[],int num[]){//形参用[],传递数组首地址后可以直接正常用数组str[i] int i; for( ...
- 事与愿违( backfire effect ) 的故事
例如:我作为一个需求者,我想要买世界上最便宜的苹果手机,但是当我进入市场去寻找世界上最便宜苹果手机的时候,这一行为本身就使得苹果手机的价格上升. 作为供应者,我本来要去卖最贵的房子,但是当我作为开发商 ...