2022年作为AIGC(Artificial Intelligence Generated Content)时代的元年,各个领域的AIGC模型与技术都有一个迅猛的发展(比如Stable Diffusion 、ChatGPT、Midjourney 等),未来15年的科技新浪潮已然来临,AIGC无疑给工业界、投资界、学术界以及竞赛界都注入了新的“AI活力”与“AI势能”。
其中在AI绘画 领域,Stable Diffusion模型当仁不让地成为了开源社区中持续繁荣的AI绘画核心模型,并且快速破圈让AIGC的ToC可能性比肩移动互联网时代的产品,每个人都能感受到AI带来的力量与影响。
本文中介绍的Stable Diffusion XL系列模型(简称SDXL)是Stable Diffusion的最新优化版本,由Stability AI发布。比起Stable Diffusion,Stable Diffusion XL做了全方位的优化,Rocky相信,Stable Diffusion是AI绘画领域的“YOLO”,而Stable Diffusion XL就是“YOLOv3”。
因此在本文中,Rocky主要对Stable Diffusion XL系列模型(Stable Diffusion XL 1.0、Stable Diffusion XL 0.9、Stable Diffusion XL Turbo等)的全维度各个方面都做一个深入浅出的分析总结 (SDXL模型结构解析、SDXL模型从0到1保姆级训练教程、SDXL模型不同AI绘画框架从0到1推理运行保姆级教程、最新SDXL资源汇总分享、AI绘画模型的性能测评、AI绘画领域未来发展、SDXL相关配套工具使用等),和大家一些探讨学习,让我们在AIGC时代能够更好地融入和从容。
1. Stable Diffusion XL资源分享
2. Stable Diffusion XL核心基础内容
与Stable Diffusion 1.x-2.x相比,Stable Diffusion XL主要进行如下的优化:
对Stable Diffusion 1.x-2.x的U-Net,VAE,CLIP Text Encoder三大核心模型都做了改进。
增加一个独立的基于Latent的Refiner模型,也是一个扩散模型,用来提升生成图像的精细化程度。
设计了很多训练Tricks,包括图像尺寸条件化策略、图像裁剪参数条件化策略以及多尺度训练策略等。
先发布Stable Diffusion XL 0.9测试版本,基于用户的使用体验和图片生成的反馈情况,针对性增加数据集和使用RLHF(Reinforcement Learning from Human Feedback,基于人类反馈的强化学习)技术优化训练后,推出了Stable Diffusion XL 1.0正式版。
2.1 SDXL整体架构初识
Stable Diffusion XL是一个二阶段的级联扩散模型(Latent Diffusion Model) ,包括Base模型和Refiner模型。其中Base模型的主要工作和Stable Diffusion 1.x-2.x一致 ,具备文生图(txt2img)、图生图(img2img)、图像inpai nting等能力。在Base模型之后,级联了Refiner模型,对Base模型生成的图像Latent特征进行精细化提升,其本质上是在做图生图的工作 。
SDXL Base模型由U-Net、VAE以及CLIP Text Encoder(两个)三个模块组成 ,在FP16精度下Base模型大小6.94G(FP32:13.88G),其中U-Net占5.14G、VAE模型占167M以及两个CLIP Text Encoder一大一小(OpenCLIP ViT-bigG和OpenAI CLIP ViT-L)分别是1.39G和246M。
SDXL Refiner模型同样由U-Net、VAE和CLIP Text Encoder(一个)三个模块组成 ,在FP16精度下Refiner模型大小6.08G,其中U-Net占4.52G、VAE模型占167M(与Base模型共用)以及CLIP Text Encoder模型(OpenCLIP ViT-bigG)大小1.39G(与Base模型共用)。
从下图可以看到,Stable Diffusion XL无论是对模型的整体工作流还是对不同子模块(U-Net、VAE、CLIP Text Encoder)都做了大幅的改进,能够生成1024×1024分辨率及以上的高质量图片。同时这些改进思想无论是对AIGC时代的模型还是传统深度学习时代的模型,都有非常大的迁移应用价值 。
比起Stable Diffusion 1.x-2.x,Stable Diffusion XL的参数量增加到了66亿(Base模型35亿+Refiner模型31亿),并且先后发布了模型结构完全相同的0.9和1.0两个版本 。Stable Diffusion XL 1.0在0.9版本上使用更多训练集+RLHF来优化生成图像的色彩、对比度、光线以及阴影方面,使得生成图像的构图比0.9版本更加鲜明准确。
Rocky相信,以Stable Diffusion XL 1.0版本为核心的AI绘画和AI视频生态将会持续繁荣。
Stable Diffusion XL Base模型参数:SDXL-Base
Stable Diffusion XL Refiner模型参数:SDXL-Refiner
下图中展示了Stability AI用户对SDXL 1.0、SDXL 0.9、SD 1.5以及SD 2.1的性能评估结果。可以看到单独的SDXL 1.0 Base模型的表现明显优于之前的所有SD版本,而完整的SDXL 1.0模型(Base模型 + Refiner模型)则实现了最佳的图像生成整体性能。
2.2 VAE模型(包含详细图解)
VAE模型(变分自编码器,Variational Auto-Encoder)是一个经典的生成式模型,其基本原理就不过多介绍了。在传统深度学习时代,GAN的风头完全盖过了VAE,但VAE简洁稳定的Encoder-Decoder架构,以及能够高效提取数据Latent特征和Latent特征像素级重建的关键能力 ,让其跨过了周期,在AIGC时代重新繁荣。
Stable Diffusion XL依旧是基于Latent 的扩散模型,所以VAE的Encoder和Decoder结构依旧是Stable Diffusion XL提取图像Latent特征和图像像素级重建的关键一招 。
当输入是图片时,Stable Diffusion XL和Stable Diffusion一样,首先会使用VAE的Encoder结构将输入图像转换为Latent特征 ,然后U-Net不断对Latent特征进行优化,最后使用VAE的Decoder结构将Latent特征重建出像素级图像 。除了提取Latent特征和图像的像素级重建外,VAE还可以改进生成图像中的高频细节,小物体特征和整体图像色彩 。
当Stable Diffusion XL的输入是文字时,这时我们不需要VAE的Encoder结构,只需要Decoder进行图像重建。VAE的灵活运用,让Stable Diffusion系列增添了几分优雅。
Stable Diffusion XL使用了和之前Stable Diffusion系列一样的VAE结构(KL-f8) ,但在训练中选择了更大的Batch-Size(256 vs 9) ,并且对模型进行指数滑动平均操作(EMA ,exponential moving average),EMA对模型的参数做平均,从而提高性能并增加模型鲁棒性。
下面是Rocky梳理的Stable Diffusion XL的VAE完整结构图 ,希望能让大家对这个在Stable DIffusion系列中未曾改变架构的模型有一个更直观的认识,在学习时也更加的得心应手: SDXL VAE模型中有三个基础组件:
GSC组件:GroupNorm+SiLU+Conv
Downsample组件:Padding+Conv
Ups ample组件:Interpolate+Conv
同时SDXL VAE模型还有两个核心组件:ResNetBlock模块和SelfAttention模型,两个模块的结构如上图所示。
SDXL VAE Encoder部分包含了三个DownBlock模块、一个ResNetBlock模块以及一个MidBlock模块,将输入图像压缩到Latent空间,转换成为Gaussian Distribution。
而VAE Decoder部分正好相反,其输入Latent空间特征,并重建成为像素级图像作为输出。其包含了三个UpBlock模块、一个ResNetBlock模块以及一个MidBlock模块。
在损失函数方面,使用了久经考验的生成领域“交叉熵”—感知损失(perceptual loss)以及L1回归损失 来约束VAE的训练过程。
下表是Stable Diffusion XL的VAE在COCO2017 验证集上,图像大小为256×256像素的情况下的性能。
(注:Stable Diffusion XL的VAE是从头开始训练的 )
上面的表中的三个VAE模型结构是一样的,不同点在于SD 2.x VAE是基于SD 1.x VAE微调训练了Decoder部分,同时保持Encoder部分权重不变,使他们有相同的Latent特征分布,所以SD 1.x和SD 2.x的VAE模型是互相兼容的 。而SDXL VAE是重新从头开始训练的,所以其Latent特征分布与之前的两者不同。
由于Latent特征分布产生了变化,SDXL VAE的缩放系数 也产生了变化。VAE在将Latent特征送入U-Net之前,需要对Latent特征进行缩放让其标准差尽量为1,之前的Stable Diffusion系列采用的缩放系数为0.18215 ,由于Stable Diffusion XL的VAE进行了全面的重训练,所以缩放系数重新设置为0.13025 。
注意:由于缩放系数的改变,Stable Diffusion XL VAE模型与之前的Stable Diffusion系列并不兼容。如果在SDXL上使用之前系列的VAE,会生成充满噪声的图片。
与此同时,与Stable Diffusion一样,VAE模型在Stable Diffusion XL中除了能进行图像压缩和图像重建的工作外,通过切换不同微调训练版本的VAE模型,能够改变生成图片的细节与整体颜色(更改生成图像的颜色表现,类似于色彩滤镜) 。
目前在开源社区常用的SDXL VAE模型有 :sdxl_vae.safetensors、lastpiecexlVAE_baseonA0897.safetensors、fixFP16ErrorsSDXLLowerMemoryUse_v10.safetensors、xlVAEC_f1.safetensors、flatpiecexlVAE_baseonA1579.safetensors等。
这里Rocky使用了6种不同的SDXL VAE模型,在其他参数保持不变的情况下,对比了SDXL模型的出图效果,如下所示: 可以看到,我们在SDXL中切换VAE模型进行出图时,均不会对构图进行大幅改变,只对生成图像的细节与颜色表现进行调整 。
Rocky目前也在整理汇总高价值的SDXL VAE模型(持续更新),方便大家获取使用。大家可以关注Rocky的公众号WeThinkIn ,后台回复:SDXLVAE ,即可获得资源链接,包含上述的全部SDXL VAE模型权重和更多高价值SDXL VAE模型权重 。
官方的Stable Diffusion XL VAE的权重已经开源:sdxl-vae
需要注意的是,原生Stable Diffusion XL VAE采用FP16精度时会出现数值溢出成NaNs的情况,导致重建的图像是一个黑图,所以必须使用FP32精度进行推理重建。如果大家想要FP16精度进行推理,可以使用sdxl-vae-fp16-fix 版本的SDXL VAE模型,其对FP16出现的NANs的情况进行了修复。
在官网如果遇到网络问题或者下载速度很慢的问题,可以关注Rocky的公众号WeThinkIn ,后台回复:SDXL模型 ,即可获得Stable Diffusion XL VAE模型权重(包含原生SDXL VAE与FP16修复版本)资源链接 。
接下来Rocky将用diffusers库来快速加载Stable Diffusion XL中的VAE模型,并通过可视化的效果直观展示SDXL VAE的压缩与重建效果,完整代码如下所示:
import cv2
import torch
import numpy as np
from diffusers import AutoencoderKL
# 加载SDXL VAE模型: SDXL VAE模型可以通过指定subfolder文件来单独加载。
# SDXL VAE模型权重百度 云网盘:关注Rocky的公众号WeThinkIn,后台回复:SDXL模型,即可获得资源链接
VAE = AutoencoderKL.from_pretrained("/本地路径/sdxl-vae")
VAE.to("cuda")
# 用OpenCV读取和调整图像大小
raw_image = cv2.imread("test_vae.png")
raw_image = cv2.cvtColor(raw_image, cv2.COLOR_BGR2RGB)
raw_image = cv2.resize(raw_image, (1024, 1024))
# 将图像数据转换为浮点数并归一化
image = raw_image.astype(np.float32) / 127.5 - 1.0
# 调整数组维度以匹配PyTorch的格式 (N, C, H, W)
image = image.transpose(2, 0, 1)
image = image[None, :, :, :]
# 转换为PyTorch张量
image = torch.from_numpy(image).to("cuda")
# 压缩图像为Latent特征并重建
with torch.inference_mode():
# 使用SDXL VAE进行压缩和重建
latent = VAE.encode(image).latent_dist.sample()
rec_image = VAE.decode(latent).sample
# 后处理
rec_image = (rec_image / 2 + 0.5).clamp(0, 1)
rec_image = rec_image.cpu().permute(0, 2, 3, 1).numpy()
# 反归一化
rec_image = (rec_image * 255).round().astype("uint8")
rec_image = rec_image[0]
# 保存重建后图像
cv2.imwrite("reconstructed_sdxl.png", cv2.cvtColor(rec_image, cv2.COLOR_RGB2BGR))
接下来,我们分别使用1024×1024分辨率的真实场景图片和二次元图片,使用SDXL VAE模型进行四种尺寸下的压缩与重建,重建效果如下所示: 从对比结果中可以看到,SDXL VAE在对图像进行压缩和重建时,虽然依然存在一定的精度损失,但只在256×256分辨率下会明显出现,比如说人脸特征丢失的情况 。同时比起SD 1.5 VAE模型,SDXL VAE模型在图像压缩与重建时的精度损失大幅降低 。并且不管是二次元图片还是真实场景图片,在不同尺寸下重建时,图片的主要特征都能保留下来,局部特征畸变的情况较少,损失程度较低 。
2.3 U-Net模型(Base部分,包含详细图解)
上表是Stable Diffusion XL与之前的Stable Diffusion系列的对比,从中可以看出,Stable Diffusion 1.x的U-Net参数量只有860M,就算是Stable Diffusion 2.x,其参数量也不过865M。但等到Stable Diffusion XL,U-Net模型(Base部分)参数量就增加到2.6B,参数量增加幅度达到了3倍左右 。
下图是Rocky梳理的Stable Diffusion XL Base U-Net的完整结构图 ,大家可以感受一下其魅力,看着这个完整结构图学习Stable Diffusion XL Base U-Net部分,相信大家脑海中的思路也会更加清晰:
上图中包含Stable Diffusion XL Base U-Net的十四个基本模块:
GSC模块 :Stable Diffusion Base XL U-Net中的最小组件之一,由GroupNorm+SiLU+Conv三者组成。
DownSample模块 :Stable Diffusion Base XL U-Net中的下采样组件,使用了Conv(kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))进行采下采样 。
UpSample模块 :Stable Diffusion Base XL U-Net中的上采样组件,由插值算法(nearest) +Conv组成。
ResNetBlock模块 :借鉴ResNet模型的“残差结构”,让网络能够构建的更深的同时,将Time Embedding信息嵌入模型 。
CrossAttention模块 :将文本的语义信息与图像的语义信息进行Attention机制,增强输入文本Prompt对生成图像的控制。
SelfAttention模块 :SelfAttention模块的整体结构与CrossAttention模块相同,这是输入全部都是图像信息,不再输入文本信息。
FeedForward模块 :Attention机制中的经典模块,由GeGlU+Dropout+Linear组成。
BasicTransformer Block模块 :由LayerNorm+SelfAttention+CrossAttention+FeedForward组成,是多重Attention机制的级联,并且每个Attention机制都是一个“残差结构”。通过加深网络和多Attention机制,大幅增强模型的学习能力与图文的匹配能力 。
SDXL_Spatial Transformer_X模块 :由GroupNorm+Linear+X个BasicTransformer Block +Linear构成,同时ResNet模型的“残差结构”依旧没有缺席。
SDXL_DownBlock模块 :由两个ResNetBlock+一个DownSample组成。
SDXL_UpBlock_X模块 :由X个ResNetBlock模块组成。
CrossAttnDownBlock_X_K模块 :是Stable Diffusion XL Base U-Net中Encoder部分的主要模块,由K个(ResNetBlock模块+SDXL_Spatial Transformer_X模块 )+一个DownSample模块组成。
CrossAttnUpBlock_X_K模块 :是Stable Diffusion XL Base U-Net中Decoder部分的主要模块,由K个(ResNetBlock模块+SDXL_Spatial Transformer_X模块 )+一个UpSample模块组成。
CrossAttnMidBlock模块 :是Stable Diffusion XL Base U-Net中Encoder和ecoder连接的部分,由ResNetBlock+SDXL_Spatial Transformer_10 +ResNetBlock组成。
可以看到,其中增加的SDXL_Spatial Transformer_X模块(主要包含Self Attention + Cross Attention + FeedForward)数量占新增参数量的主要部分 ,Rocky在上表中已经用红色框圈出。U-Net的Encoder和Decoder结构也从之前系列的4stage改成3stage([1,1,1,1] -> [0,2,10]),同时SDXL只使用两次下采样和上采样,而之前的SD系列模型都是三次下采样和上采样。并且比起Stable Diffusion 1.x-2.x,Stable Diffusion XL在第一个stage中不再使用Spatial Transformer Blocks,而在第二和第三个stage中大量增加了Spatial Transformer Blocks(分别是2和10),那么这样设计有什么好处呢?
首先,在第一个stage中不使用SDXL_Spatial Transformer_X模块,可以明显减少显存占用和计算量 。然后在第二和第三个stage这两个维度较小的feature map上使用数量较多的SDXL_Spatial Transformer_X模块,能在大幅提升模型整体性能(学习能力和表达能力)的同时,优化了计算成本 。整个新的SDXL Base U-Net设计思想也让SDXL的Base出图分辨率提升至1024×1024。在出图参数保持一致的情况下,Stable Diffusion XL生成图片的耗时只比Stable Diffusion多了20%-30%之间,这个拥有2.6B参数量的模型已经足够伟大 。
在SDXL U-Net的Encoder结构中,包含了两个CrossAttnDownBlock结构和一个SDXL_DownBlock结构;在Decoder结构中,包含了两个CrossAttnUpBlock结构和一个SDXL_UpBlock结构;与此同时,Encoder和Decoder中间存在Skip Connection,进行信息的传递与融合。
从上面讲到的十四个基本模块中可以看到,BasicTransformer Block模块是整个框架的基石,由SelfAttention,CrossAttention和FeedForward三个组件构成,并且使用了循环残差模式,让SDXL Base U-Net不仅可以设计的更深,同时也具备更强的文本特征和图像体征的学习能力 。
接下来,Rocky再给大家讲解CrossAttention模块的一些细节内容,让大家能更好地理解这个关键模块。
Stable Diffusion XL中的Text Condition信息由两个Text Encoder提供(OpenCLIP ViT-bigG和OpenAI CLIP ViT-L) ,通过Cross Attention组件嵌入,作为K Matrix和V Matrix。与此同时,图片的Latent Feature作为Q Matrix。
但是大家知道Text Condition是三维的,而Latent Feature是四维的,那它们是怎么进行Attention机制的呢?
其实在每次进行Attention机制前,我们需要将Latent Feature从[batch_size,channels,height,width]转换到[batch_size,height*width,channels] ,这样就变成了三维特征,就能够和Text Condition做CrossAttention操作。
在完成CrossAttention操作后,我们再将Latent Feature从[batch_size,height*width,channels]转换到[batch_size,channels,height,width] ,这样就又重新回到原来的维度。
还有一点是Text Condition如何跟latent Feature大小保持一致呢?因为latent embedding不同位置的H和W是不一样的,但是Text Condition是从文本中提取的,其H和W是固定的。这里在CorssAttention模块中有一个非常巧妙的点,那就是在不同特征做Attention操作前,使用Linear层将不同的特征的尺寸大小对齐 。
2.4 Text Encoder模型(包含详细图解)
Stable Diffusion XL模型采用的Text Encoder依然是基于CLIP架构的 。我们知道,CLIP模型主要包含Text Encoder和Image Encoder两个模块 ,Stable Diffusion 1.x系列使用的是OpenAI CLIP ViT-L/14(123.65M)中的Text Encoder模型,而Stable Diffusion 2.x系列则使用OpenCLIP ViT-H/14(354.03M)中的Text Encoder模型。
Stable Diffusion XL和Stable Diffusion 1.x-2.x系列一样,只使用Text Encoder模块从文本信息中提取Text Embeddings 。
不同的是,Stable Diffusion XL与之前的系列相比使用了两个CLIP Text Encoder,分别是OpenCLIP ViT-bigG(694M)和OpenAI CLIP ViT-L/14(123.65M),从而大大增强了Stable Diffusion XL对文本的提取和理解能力,同时提高了输入文本和生成图片的一致性。
其中OpenCLIP ViT-bigG是一个只由Transformer模块组成的模型,一共有32个CLIPEncoder模块,是一个强力的特征提取模型。其单个CLIPEncoder模块结构如下所示:
# OpenCLIP ViT-bigG中CLIPEncoder模块结构
CLIPEncoderLayer(
(self_attention): CLIPAttention(
(k_Matric): Linear(in_features=1280, out_features=1280, bias=True)
(v_Matric): Linear(in_features=1280, out_features=1280, bias=True)
(q_Matric): Linear(in_features=1280, out_features=1280, bias=True)
(out_proj): Linear(in_features=1280, out_features=1280, bias=True)
)
(layer_norm1): LayerNorm((1280,), eps=1e-05, elementwise_affine=True)
(mlp ): CLIPMLP(
(activation_fn): GELUActivation()
(fc1): Linear(in_features=1280, out_features=5120, bias=True)
(fc2): Linear(in_features=5120, out_features=1280, bias=True)
)
(layer_norm2): LayerNorm((1280,), eps=1e-05, elementwise_affine=True)
)
下图是Rocky梳理的SDXL OpenCLIP ViT-bigG的完整结构图 ,大家可以感受一下其魅力,看着这个完整结构图学习Stable Diffusion XL OpenCLIP ViT-bigG部分,相信大家脑海中的思路也会更加清晰: OpenAI CLIP ViT-L/14同样是一个只由Transformer模块组成的模型,一共有12个CLIPEncoder模块,其单个CLIPEncoder模块结构如下所示:
# OpenAI CLIP ViT-L中CLIPEncoder模块结构
CLIPEncoderLayer(
(self_attention): CLIPAttention(
(k_Matric): Linear(in_features=768, out_features=768, bias=True)
(v_Matric): Linear(in_features=768, out_features=768, bias=True)
(q_Matric): Linear(in_features=768, out_features=768, bias=True)
(out_proj): Linear(in_features=768, out_features=768, bias=True)
)
(layer_norm1): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
(mlp): CLIPMLP(
(activation_fn): QuickGELUActivation()
(fc1): Linear(in_features=768, out_features=3072, bias=True)
(fc2): Linear(in_features=3072, out_features=768, bias=True)
)
(layer_norm2): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
)
下图是Rocky梳理的SDXL OpenAI CLIP ViT-L/14的完整结构图 ,大家可以感受一下其魅力,看着这个完整结构图学习Stable Diffusion XL OpenAI CLIP ViT-L/14部分,相信大家脑海中的思路也会更加清晰: 由上面两个结构对比可知,OpenCLIP ViT-bigG的优势在于模型结构更深,特征维度更大,特征提取能力更强,但是其两者的基本CLIPEncoder模块是一样的。
下面Rocky将使用transofmers库演示调用SDXL OpenAI CLIP ViT-L/14 和OpenCLIP ViT-bigG,给大家一个更加直观的SDXL模型的文本编码全过程。
首先是SDXL OpenAI CLIP ViT-L/14的文本编码过程:
from transformers import CLIPTextModel, CLIPTokenizer
# 加载 OpenAI CLIP ViT-L/14 Text Encoder模型和Tokenizer
# SDXL模型权重百度云网盘:关注Rocky的公众号WeThinkIn,后台回复:SDXL模型,即可获得资源链接
text_encoder = CLIPTextModel.from_pretrained("/本地路径/stable-diffusion-xl-base-1.0", subfolder="text_encoder").to("cuda")
text_tokenizer = CLIPTokenizer.from_pretrained("/本地路径/stable-diffusion-xl-base-1.0", subfolder="tokenizer")
# 将输入SDXL模型的prompt进行tokenize,得到对应的token ids特征
prompt = "1girl,beautiful"
text_token_ids = text_tokenizer(
prompt,
padding="max_length",
max_length=text_tokenizer.model_max_length,
truncation=True,
return_tensors="pt"
).input_ids
print("text_token_ids' shape:",text_token_ids.shape)
print("text_token_ids:",text_token_ids)
# 将token ids特征输入OpenAI CLIP ViT-L/14 Text Encoder模型中输出77x768的Text Embeddings特征
text_embeddings = text_encoder(text_token_ids.to("cuda"))[0] # 由于Text Encoder模型输出的是一个元组,所以需要[0]对77x768的Text Embeddings特征进行提取
print("text_embeddings' shape:",text_embeddings.shape)
print(text_embeddings)
---------------- 运行结果 ----------------
text_token_ids' shape: torch.Size([1, 77])
text_token_ids: tensor([[49406, 272, 1611, 267, 1215, 49407, 49407, 49407, 49407, 49407,
49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,
49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,
49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,
49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,
49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,
49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407, 49407,
49407, 49407, 49407, 49407, 49407, 49407, 49407]])
text_embeddings' shape: torch.Size([1, 77, 768])
tensor([[[-0.3885, 0.0230, -0.0521, ..., -0.4901, -0.3065, 0.0674],
[-0.8424, -1.1387, 1.2767, ..., -0.2598, 1.6289, -0.7855],
[ 0.1751, -0.9847, 0.1881, ..., 0.0657, -1.4940, -1.2612],
...,
[ 0.2039, -0.7298, -0.3206, ..., 0.6751, -0.5814, -0.7320],
[ 0.1921, -0.7345, -0.3039, ..., 0.6806, -0.5852, -0.7228],
[ 0.2112, -0.6438, -0.3042, ..., 0.6628, -0.5576, -0.7583]]],
device='cuda:0', grad_fn=)
接着是SDXL OpenCLIP ViT-bigG的文本编码过程:
from transformers import CLIPTextModel, CLIPTokenizer
# 加载 OpenCLIP ViT-bigG Text Encoder模型和Tokenizer
# SDXL模型权重百度云网盘:关注Rocky的公众号WeThinkIn,后台回复:SDXL模型,即可获得资源链接
text_encoder = CLIPTextModel.from_pretrained("/本地路径/stable-diffusion-xl-base-1.0", subfolder="text_encoder_2").to("cuda")
text_tokenizer = CLIPTokenizer.from_pretrained("/本地路径/stable-diffusion-xl-base-1.0", subfolder="tokenizer_2")
# 将输入SDXL模型的prompt进行tokenize,得到对应的token ids特征
prompt = "1girl,beautiful"
text_token_ids = text_tokenizer(
prompt,
padding="max_length",
max_length=text_tokenizer.model_max_length,
truncation=True,
return_tensors="pt"
).input_ids
print("text_token_ids' shape:",text_token_ids.shape)
print("text_token_ids:",text_token_ids)
# 将token ids特征输入OpenCLIP ViT-bigG Text Encoder模型中输出77x1280的Text Embeddings特征
text_embeddings = text_encoder(text_token_ids.to("cuda"))[0] # 由于Text Encoder模型输出的是一个元组,所以需要[0]对77x1280的Text Embeddings特征进行提取
print("text_embeddings' shape:",text_embeddings.shape)
print(text_embeddings)
---------------- 运行结果 ----------------
text_token_ids' shape: torch.Size([1, 77])
text_token_ids: tensor([[49406, 272, 1611, 267, 1215, 49407, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0]])
text_embeddings' shape: torch.Size([1, 77, 1280])
tensor([[[-0.1025, -0.3104, 0.1660, ..., -0.1596, -0.0680, -0.0180],
[ 0.7724, 0.3004, 0.5225, ..., 0.4482, 0.8743, -1.0429],
[-0.3963, 0.0041, -0.3626, ..., 0.1841, 0.2224, -1.9317],
...,
[-0.8887, -0.2579, 1.3508, ..., -0.4421, 0.2193, 1.2736],
[-0.9659, -0.0447, 1.4424, ..., -0.4350, -0.1186, 1.2042],
[-0.5213, -0.0255, 1.8161, ..., -0.7231, -0.3752, 1.0876]]],
device='cuda:0', grad_fn=)
与传统深度学习中的模型融合类似 ,Stable Diffusion XL分别提取两个Text Encoder的倒数第二层特征 ,并进行concat操作作为文本条件(Text Conditioning)。其中OpenCLIP ViT-bigG的特征维度为77×1280,而OpenAI CLIP ViT-L/14的特征维度是77×768,所以输入总的特征维度是77×2048(77是最大的token数,2048是SDXL的context dim),再通过Cross Attention模块将文本信息传入Stable Diffusion XL的训练过程与推理过程中。
从上图可以看到,OpenCLIP ViT-bigG和OpenAI CLIP ViT-L/14在ImageNet上zero-shot性能分别为80.1%和75.4%,Rocky有点疑惑的是,为什么不用CoCa或者将OpenAI CLIP ViT-L/14替换成penAI CLIP ViT-H呢。
和Stable Diffusion 1.x-2.x一致的是,Stable Diffusion XL输入的最大Token数依旧是77,当输入文本的Token数量超过77后,将通过Clip操作拉回77×2048;如果Token数不足77则会通过padding操作得到77×2048。
与此同时,Stable Diffusion XL还提取了OpenCLIP ViT-bigG的pooled text embedding,将其嵌入到Time Embeddings中(add操作),作为辅助约束条件(强化文本的整体语义信息),但是这种辅助条件的强度是较为微弱的。
和之前的系列一样,SDXL Text Encoder在官方训练时是冻结的 ,我们在对SDXL模型进行微调训练时,可以同步开启Text Encoder的微调训练,能够使得Text Encoder对生成图片的控制力增强,使其生成内容更加贴近训练集的分布。
2.5 Refiner模型(包含详细图解)
Rocky看到Stable Diffusion XL的Refiner部分时,脑海里马上联想到了DeepFloyd和StabilityAI联合开发的DeepFloyd IF模型。
DeepFloyd IF是一种基于像素的文本到图像三重级联扩散模型 ,大大提升了扩散模型的图像生成能力。
这次,Stable Diffusion XL终于也开始使用级联策略,在U-Net(Base)之后,级联Refiner模型,进一步提升生成图像的细节特征与整体质量 。
通过级联模型提升生成图片的质量,这可以说这是AIGC时代里的模型融合(ensemble)。和传统深度学习时代的多模型融合策略一样,不管是在学术界、工业界还是竞赛界,都是“行业核武”般的存在。
由于已经有U-Net(Base)模型生成了图像的Latent特征,所以Refiner模型的主要工作是在Latent特征进行小噪声去除和细节质量提升 。
Refiner模型和Base模型一样是基于Latent的扩散模型 ,也采用了Encoder-Decoder结构,和U-Net兼容同一个VAE模型。不过在Text Encoder部分,Refiner模型只使用了OpenCLIP ViT-bigG的Text Encoder,同样提取了倒数第二层特征以及进行了pooled text embedding的嵌入。
下图是Rocky梳理的Stable Diffusion XL Refiner模型的完整结构图 ,大家可以先感受一下其魅力,在学习Refiner模型时可以与Base模型中的U-Net进行对比,会有更多直观的认识:
接下来Rocky给大家分析一下SDXL Refiner模型和SDXL Base模型在结构上的异同:
SDXL Base的Encoder和Decoder结构都采用4个stage,而SDXL Base设计的是3个stage。
SDXL Refiner和SDXL Base一样,在第一个stage中没有使用Attention模块。
在经过第一个卷积后,SDXL Refiner设置初始网络特征维度为384,而SDXL Base 采用的是320。
SDXL Refiner的Attention模块中SDXL_Spatial Transformer结构数量均设置为4。
SDXL Refiner的参数量为2.3B,比起SDXL Base的2.6B参数量略小一些。
SDXL Refiner模型的训练逻辑与SDXL Base一样,不过Refiner模型只在前200个Timesteps上训练(设置的noise level较低)。
在Stable Diffusion XL推理阶段,输入一个prompt,通过VAE和U-Net(Base)模型生成Latent特征,接着给这个Latent特征进行扩散过程加上一定的噪音。在此基础上,再使用Refiner模型进行去噪,以提升图像的整体质量与局部细节。
从下图中可以看到,在使用Refiner模型后,生成图片的背景和人脸部分效果有了一定的提升:
可以看到,Refiner模型主要做了图像生成图像(img2img)的工作 ,其具备很强的迁移兼容能力 ,可以作为Stable Diffusion、Midjourney、DALL-E、GAN、VAE等生成式模型的级联组件,成为AI绘画领域的一个强力后处理工具 ,这不管是对学术界、工业界还是竞赛界,都是一个巨大的利好。
由上表可以看出,Stable Diffusion XL Base模型的效果已经大幅超过SD 1.5和SD 2.1,当增加Refiner模型之后,完整的Stable Diffusion XL模型达到了更加优秀的图像生成效果。
2.6 SDXL官方训练技巧&细节
Stable Diffusion XL在训练阶段提出了很多优化方法,包括图像尺寸条件化策略,图像裁剪参数条件化策略以及多尺度训练策略。这些优化方法对整个AIGC领域都有很好的参考与借鉴意义,其通用性和迁移性能普惠其他的生成式模型的训练与优化 。
2.6.1 图像尺寸条件化
之前在Stable Diffusion的训练过程中,主要分成两个阶段,一个是在256×256的图像尺寸上进行预训练,然后在512×512的图像尺寸上继续训练。
而这两个阶段的训练过程都要对最小图像尺寸进行约束。第一阶段中,会将尺寸小于256×256的图像舍弃;同样的,在第二阶段,会将尺寸小于512×512的图像筛除。这样的约束会导致训练数据中的大量数据被丢弃,从而很可能导致模型性能和泛化性的降低 。
下图展示了如果将尺寸小于256×256的图像筛除,整个数据集将减少39%的数据 。如果加上尺寸小于512×512的图像,未利用数据占整个数据集的百分比将更大 。
针对上述数据集利用率的问题,常规思路可以借助超分模型将尺寸过小的图像放大。但是面对对于图像尺寸过小的场景,目前的超分模型可能会在对图像超分的同时会引入一些噪声伪影,影响模型的训练,导致生成一些模糊的图像 。
Stable Diffusion XL为了在解决数据集利用率问题的同时不引入噪声伪影,将U-Net(Base)模型与原始图像分辨率相关联,核心思想 是将输入图像的原始高度和宽度作为额外的条件嵌入U-Net模型中,表示为 C s i z e = ( h e i g h t , w i d t h ) C_{size} = (height, width) Csize=(height,width)。height和width都使用傅里叶特征编码进行独立嵌入,然后将特征concat后加在Time Embedding上,将图像尺寸作为条件引入训练过程 。这样一来,模型在训练过程中能够学习到图像的原始分辨率信息,从而在推理生成阶段更好地适应不同尺寸的图像生成,而不会产生噪声伪影的问题。
如下图所示,在使用了图像尺寸条件化策略后,Base模型已经对不同图像分辨率有了“自己的判断 ”。当输入低分辨率条件时,生成的图像较模糊;在不断增大分辨率条件时,生成的图像质量不断提升。
2.6.2 图像裁剪参数条件化
之前的Stable Diffusion系列模型,由于需要输入固定的图像尺寸用作训练,很多数据在预处理阶段会被裁剪。生成式模型中典型的预处理方式是先调整图像尺寸,使得最短边与目标尺寸匹配,然后再沿较长边对图像进行随机裁剪或者中心裁剪 。虽然裁剪是一种数据增强方法,但是训练中对图像裁剪导致的图像特征丢失,可能会导致AI绘画模型在图像生成过程中出现不符合训练数据分布的特征 。
如下图所示,对一个骑士的图片做了裁剪操作后,丢失了头部和脚部特征,再将裁剪后的数据放入模型中训练,就会影响模型对骑士这个概念的学习和认识 。
下图中展示了SD 1.4和SD 1.5的经典失败案例,生成图像中的猫出现了头部缺失的问题,龙也出现了体征不完整的情况:
其实之前NovelAI就发现了这个问题,并提出了基于分桶(Ratio Bucketing)的多尺度训练策略,其主要思想是先将训练数据集按照不同的长宽比(aspect ratio)进行分组(groups)或者分桶(buckets)。在训练过程中,每次在buckets中随机选择一个bucket并从中采样Batch个数据进行训练 。将数据集进行分桶可以大量减少裁剪图像的操作,并且能让模型学习多尺度的生成能力;但相对应的,预处理成本大大增加,特别是数据量级较大的情况下。
并且尽管数据分桶成功解决了数据裁剪导致的负面影响,但如果能确保数据裁剪不把负面影响引入生成过程中,裁剪这种数据增强方法依旧能给模型增强泛化性能。所以Stable Diffusion XL使用了一种简单而有效的条件化方法,即图像裁剪参数条件化策略。其主要思想是在加载数据时,将左上角的裁剪坐标通过傅里叶编码后加在Time Embedding上,并嵌入U-Net(Base)模型中,并与原始图像尺寸一起作为额外的条件嵌入U-Net模型,从而在训练过程中让模型学习到对“图像裁剪”的认识 。
从下图中可以看到,将不同的 c c r o p = ( 0 , 0 ) c_{crop} = (0,0) ccrop=(0,0)坐标条件的生成图像进行了对比,当我们设置 时可以生成主要物体居中并且无特征缺失的图像,而采用其它的坐标条件则会出现有裁剪效应的图像:
图像尺寸条件化策略和图像裁剪参数条件化策略都能在SDXL训练过程中使用(在线方式应用),同时也可以很好的迁移到其他AIGC生成式模型的训练中 。下图详细给出了两种策略的通用使用流程:
可以看到,SDXL在训练过程中的数据处理流程和之前的系列是一样的,只是需要再将图像原始长宽(width和height)以及图像进行crop操作时的左上角的裁剪坐标top和left作为条件输入 。
2.6.3 多尺度训练
Stable Diffusion XL采用了多尺度训练策略,这个是在传统深度学习时代的王牌模型YOLO系列中常用的增强模型鲁棒性与泛化性的策略,终于在AIGC领域应用并常规化了,并且Stable Diffusion XL在多尺度训练的基础上,增加了分桶策略。
SDXL的论文中说训练时采用的是内部数据集作为训练集,Rocky推测大概率是基于LAION数据集为基础构建的。Stable Diffusion XL首先采用图像尺寸条件化和图像裁剪参数条件化这两种策略在256×256和512×512的图像尺寸上分别预训练600000步和200000步(batch size = 2048),总的数据量约等于 (600000 + 200000) x 2048 = 16.384亿 。
接着Stable Diffusion XL在1024×1024的图像尺寸上采用多尺度方案来进行微调,并将数据分成不同纵横比的桶(bucket),并且尽可能保持每个桶的像素数接近1024×1024 ,同时相邻的bucket之间height或者width一般相差64像素左右,Stable Diffusion XL的具体分桶情况如下图所示: 其中Aspect Ratio = Height / Width ,表示高宽比。
在训练过程中,一个Batch从一个桶里的图像采样,并且我们在每个训练步骤(step)中可以在不同的桶之间交替切换。除此之外,Aspect Ratio也会作为条件嵌入到U-Net(Base)模型中,嵌入方式和上面提到的其他条件嵌入方式一致,让模型能够更好地学习到“多尺度特征” 。
与此同时,SDXL在多尺度微调阶段依然使用图像裁剪参数条件化策略,进一步增强SDXL对图像裁剪的敏感性。
在完成了多尺度微调后,SDXL就可以进行不同Aspect Ratio的图像生成了,不过官方推荐生成尺寸默认为1024×1024 。
2.6.4 使用Offset Noise
在SDXL进行微调时,使用了Offset Noise操作,能够让SDXL生成的图像有更高的色彩自由度(纯黑或者纯白背景的图像) 。SD 1.x和SD 2.x一般只能生成中等亮度的图片,即生成平均值相对接近 0.5 的图像(全黑图像为 0,全白图像为 1),之所以会出现这个问题,是因为SD系列模型训练和推理过程的不一致造成的。
SD模型在训练中进行noise scheduler流程并不能将图像完全变成随机高斯噪声,但是推理过程中,SD模型是从一个随机高斯噪声开始生成的,因此就会存在训练与推理的噪声处理过程不一致 。
Offset Noise操作是解决这个问题的一种直观并且有效的方法 ,我们只需要在SD模型的微调训练时,把额外从高斯分布中采样的偏置噪声引入图片添加噪声的过程中,这样就对图像的色彩均值造成了破坏,从而提高了SDXL生成图像的“泛化性能” 。 具体的Offset Noise代码如下所示:
def apply_noise_offset(latents, noise, noise_offset, adaptive_noise_scale):
if noise_offset is None:
return noise
if adaptive_noise_scale is not None:
# latent shape: (batch_size, channels, height, width)
# abs mean value for each channel
latent_mean = torch.abs(latents.mean(dim=(2, 3), keepdim=True))
# multiply adaptive noise scale to the mean value and add it to the noise offset
noise_offset = noise_offset + adaptive_noise_scale * latent_mean
noise_offset = torch.clamp(noise_offset, 0.0, None) # in case of adaptive noise scale is negative
noise = noise + noise_offset * torch.randn((latents.shape[0], latents.shape[1], 1, 1), device=latents.device)
return noise
上述代码中的noise_offset默认是采用0.1,SDXL在官方的训练中采用的是0.05 。在后面的SDXL训练教程章节中,我们采用的是0.0357,大家可按照实际训练效果调整noise_offset值。
2.6.5 SDXL的条件注入与训练细节
上面我们已经详细讲解了SDXL的四个额外的条件信息注入(pooled text embedding,图像尺寸条件,图像裁剪参数条件和图像多尺寸条件),其中三个图像条件可以像Timestep一样采用傅立叶编码得到Embedding特征,然后再和pooled text embedding特征concat,得到维度为2816的embeddings特征。
接着再将这个embeddings特征通过两个Linear层映射到和Time Embedding一样的维度空间,然后加(add)到Time Embedding上即可作为SDXL U-Net的条件输入,上述流程的具体代码实现如下所示:
import math
from einops import rearrange
import torch
batch_size = 64
# channel dimension of pooled output of text encoder (s)
pooled_dim = 1280
adm_in_channels = 2816
time_embed_dim = 1280
# 生成Timestep Embeddings
def fourier_embedding(timesteps, outdim=256, max_period=10000):
"""
Classical sinusoidal timestep embedding
as commonly used in diffusion models
: param inputs : batch of integer scalars shape [b ,]
: param outdim : embedding dimension
: param max_period : max freq added
: return : batch of embeddings of shape [b, outdim ]
"""
half = outdim // 2
freqs = torch.exp(-math.log(max_period) * torch.arange(start=0, end=half, dtype=torch.float32) / half).to(device=timesteps.device)
args = timesteps[:, None].float() * freqs[None]
embedding = torch.cat([torch.cos(args), torch.sin(args)], dim=-1)
return embedding
def cat_along_channel_dim(x: torch.Tensor,) -> torch.Tensor:
if x.ndim == 1:
x = x[... , None]
assert x.ndim == 2
b, d_in = x.shape
x = rearrange(x, "b din -> (b din)")
# fourier fn adds additional dimension
emb = fourier_embedding(x)
d_f = emb.shape[-1]
emb = rearrange(emb, "(b din) df -> b (din df)", b=b, din=d_in, df=d_f)
return emb
# 将SDXL的四个额外条件注入进行concat操作
def concat_embeddings(
# batch of size and crop conditioning cf. Sec. 3.2
c_size: torch.Tensor,
c_crop: torch.Tensor,
# batch of target size conditioning cf. Sec. 3.3
c_tgt_size: torch.Tensor ,
# final output of text encoders after pooling cf. Sec . 3.1
c_pooled_txt: torch.Tensor,) -> torch.Tensor:
# fourier feature for size conditioning
c_size_emb = cat_along_channel_dim(c_size)
# fourier feature for size conditioning
c_crop_emb = cat_along_channel_dim(c_crop)
# fourier feature for size conditioning
c_tgt_size_emb = cat_along_channel_dim(c_tgt_size)
return torch.cat([c_pooled_txt, c_size_emb, c_crop_emb, c_tgt_size_emb], dim=1)
# the concatenated output is mapped to the same
# channel dimension than the noise level conditioning
# and added to that conditioning before being fed to the unet
adm_proj = torch.nn.Sequential(
torch.nn.Linear(adm_in_channels, time_embed_dim),
torch.nn.SiLU(),
torch.nn.Linear(time_embed_dim, time_embed_dim)
)
# simulating c_size and c_crop as in Sec. 3.2
c_size = torch.zeros((batch_size, 2)).long()
c_crop = torch.zeros((batch_size, 2)).long ()
# simulating c_tgt_size and pooled text encoder output as in Sec. 3.3
c_tgt_size = torch.zeros((batch_size, 2)).long()
c_pooled = torch.zeros((batch_size, pooled_dim)).long()
# get concatenated embedding
c_concat = concat_embeddings(c_size, c_crop, c_tgt_size, c_pooled)
# mapped to the same channel dimension with time_emb
adm_emb = adm_proj(c_concat)
print("c_size:",c_size.shape)
print("c_crop:",c_crop.shape)
print("c_tgt_size:",c_tgt_size.shape)
print("c_pooled:",c_pooled.shape)
print("c_concat:",c_concat.shape)
print("adm_emb:",adm_emb.shape)
---------------- 运行结果 ----------------
c_size: torch.Size([64, 2])
c_crop: torch.Size([64, 2])
c_tgt_size: torch.Size([64, 2])
c_pooled: torch.Size([64, 1280])
c_concat: torch.Size([64, 2816])
adm_emb: torch.Size([64, 1280])
可以看到,上面的代码流程已经清晰的展示了SDXL进行额外条件注入的全部流程。
讲到这里,SDXL在架构上的优化和训练技巧上的优化都已经介绍好了,最后我们在介绍一下SDXL在训练中的配置。和SD 1.x系列一样,SDXL在训练时采用了1000步的DDPM和相同的noise scheduler,同时依旧采用基于预测noise的损失函数,和SD 1.x系列一致: L S D X L = E x 0 , ϵ ∼ N ( 0 , I ) , t [ ∥ ϵ − ϵ θ ( α ˉ t x 0 + 1 − α ˉ t ϵ , t , c ) ∥ 2 ] L_{SDXL}=mathbb{E}_{mathbf{x}_{0},mathbf{epsilon}sim mathcal{N}(mathbf{0}, mathbf{I}), t}Big[ | mathbf{epsilon}- mathbf{epsilon}_thetabig(sqrt{bar{alpha}_t}mathbf{x}_0 + sqrt{1 – bar{alpha}_t}mathbf{epsilon}, t, mathbf{c}big)|^2Big] LSDXL=Ex0,ϵ∼N(0,I),t[∥ϵ−ϵθ(αˉt x0+1−αˉt ϵ,t,c)∥2] 这里的 c mathbf{c} c为Text Embeddings。
3. 从0到1搭建使用Stable Diffusion XL进行AI绘画(全网最详细讲解)
目前能够加载Stable Diffusion XL模型并进行图像生成的主流AI绘画框架有四种:
diffusers框架
Stable Diffusion WebUI框架
ComfyUI框架
SD.Next框架
为了方便大家使用主流AI绘画框架,Rocky这里也总结汇总了相关的资源,方便大家直接部署使用:
Stable Diffusion WebUI资源包可以关注公众号WeThinkIn ,后台回复“WebUI资源 ”获取。
ComfyUI的500+高质量工作流资源包可以关注公众号WeThinkIn ,并回复“ComfyUI ”获取。
SD.Next资源包可以关注公众号WeThinkIn ,后台回复“SD.Next资源 ”获取。
接下来,为了让大家能够从0到1搭建使用Stable Diffusion XL这个当前性能优异的AI绘画大模型,Rocky将详细的讲解如何用这四个框架构建Stable Diffusion XL推理流程 。那么,跟随着Rocky的脚步,让我们开始吧。
3.1 零基础使用diffusers搭建Stable Diffusion XL推理流程
每次SDXL系列技术在更新迭代时,diffusers库一般都是最先原生支持其功能的,所以在diffusers中能够非常高效的构建Stable Diffusion XL推理流程 。但是由于diffusers目前没有现成的可视化界面,Rocky将在Jupyter Notebook中搭建完整的Stable Diffusion XL推理工作流,让大家能够快速的掌握。
首先,我们需要安装diffusers库,并确保diffusers的版本 >= 0.18.0 ,我们只需要在命令行中输入以下命令进行安装即可:
# 命令中加入:-i https://pypi.tuna.tsinghua.edu.cn/simple some-package 表示使用清华源下载依赖包,速度非常快!
pip install diffusers --upgrade -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
显示如下log表示安装成功:
Successfully installed diffusers-0.18.2 huggingface-hub-0.16.4
接着,我们继续安装其他的依赖库:
pip install transformers==4.27.0 accelerate==0.12.0 safetensors==0.2.7 invisible_watermark -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
显示如下log表示安装成功:
Successfully installed transformers-4.27.0 accelerate==0.12.0 safetensors==0.2.7 invisible_watermark-0.2.0
(注意:想要在diffusers中以fp16的精度加载Stable Diffusion XL模型,必须满足transformers库的版本>=4.27.0)
完成了上述依赖库的安装,我们就可以搭建Stable Diffusion XL模型的完整工作流了。
我们先单独使用Stable Diffusion XL中的Base模型来生成图像:
# 加载diffusers和torch依赖库
from diffusers import DiffusionPipeline
import torch
# 加载Stable Diffusion XL Base模型(stable-diffusion-xl-base-1.0或stable-diffusion-xl-base-0.9)
pipe = DiffusionPipeline.from_pretrained("/本地路径/stable-diffusion-xl-base-1.0",torch_dtype=torch.float16, variant="fp16")
# "/本地路径/stable-diffusion-xl-base-1.0"表示我们需要加载的Stable Diffusion XL Base模型路径
# 大家可以关注Rocky的公众号WeThinkIn,后台回复:SDXL模型,即可获得SDXL模型权重资源链接
# "fp16"代表启动fp16精度。比起fp32,fp16可以使模型显存占用减半
# 使用GPU进行Pipeline的推理
pipe.to("cuda")
# 输入提示词
prompt = "Watercolor painting of a desert landscape, with sand dunes, mountains, and a blazing sun, soft and delicate brushstrokes, warm and vibrant colors"
# 输入负向提示词,表示我们不想要生成的特征
negative_prompt = "(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)"
# 设置seed,可以固定生成图像中的构图
seed = torch.Generator("cuda").manual_seed(42)
# SDXL Base Pipeline进行推理
image = pipe(prompt, negative_prompt=negative_prompt,generator=seed).images[0]
# Pipeline生成的images包含在一个list中:[]
#所以需要使用images[0]来获取list中的PIL图像
# 保存生成图像
image.save("SDXL-Base.png")
完成上面的整个代码流程,我们可以生成一张水彩风格 的沙漠风景画,如果大家按照Rocky的参数进行操作,应该能确保生成下面的图片 :
接着,我们将SDXL Base模型和SDXL Refiner模型级联来生成图像:
from diffusers import DiffusionPipeline
import torch
# 下面的五行代码不变
pipe = DiffusionPipeline.from_pretrained("/本地路径/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16")
pipe.to("cuda")
prompt = "Watercolor painting of a desert landscape, with sand dunes, mountains, and a blazing sun, soft and delicate brushstrokes, warm and vibrant colors"
negative_prompt = "(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)"
seed = torch.Generator("cuda").manual_seed(42)
# 运行SDXL Base模型的Pipeline,设置输出格式为output_type="latent"
image = pipe(prompt=prompt, negative_prompt=negative_prompt, generator=seed, output_type="latent").images
# 加载Stable Diffusion XL Refiner模型(stable-diffusion-xl-refiner-1.0或stable-diffusion-xl-refiner-0.9)
pipe = DiffusionPipeline.from_pretrained("/本地路径/stable-diffusion-xl-refiner-1.0", torch_dtype=torch.float16, variant="fp16")
# "本地路径/stable-diffusion-xl-refiner-1.0"表示我们需要加载的Stable Diffusion XL Refiner模型,
# 大家可以关注Rocky的公众号WeThinkIn,后台回复:SDXL模型,即可获得SDXL模型权重资源链接
pipe.to("cuda")
# SDXL Refiner Pipeline进行推理
images = pipe(prompt=prompt, negative_prompt=negative_prompt, generator=seed, image=image).images
# 保存生成图像
images[0].save("SDXL-Base-Refiner.png")
完成了上述的代码流程,我们再来看看这次Base模型和Refiner模型级联生成的图片:
为了更加直观的对比,我们将刚才生成的两张图片放在一起对比: 我们可以清楚的看到,使用了Refiner模型之后,生成图片的整体质量和细节有比较大的增强改善,构图色彩更加柔和 。
当然的,我们也可以单独使用SDXL Refiner模型对图片的质量进行优化提升(img2img任务):
import torch
from diffusers import StableDiffusionXLImg2ImgPipeline
from diffusers.utils import load_image
pipe = StableDiffusionXLImg2ImgPipeline.from_pretrained("/本地路径/stable-diffusion-xl-base-1.0", torch_dtype=torch.float16, variant="fp16")
pipe = pipe.to("cuda")
image_path = "/本地路径/test.png"
init_image = load_image(image_path).convert("RGB")
prompt = "Watercolor painting of a desert landscape, with sand dunes, mountains, and a blazing sun, soft and delicate brushstrokes, warm and vibrant colors"
negative_prompt = "(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)"
seed = torch.Generator("cuda").manual_seed(42)
image = pipe(prompt, negative_prompt=negative_prompt, generator=seed, image=init_image).images[0]
image.save("SDXL-refiner.png")
Rocky这里是使用了未来机甲风格的图片进行测试对比,可以从下图看到,Refiner模型优化图像质量的效果还是非常明显的,图像毛刺明显消除,整体画面更加自然柔和,细节特征也有较好的补充和重建 。 虽然diffusers库是原生支持SDXL模型的,但是在开源社区中流行使用safetensors格式的SDXL模型,所以我们想用diffusers库运行开源社区的很多SDXL模型时,需要首先将其转成diffusers格式 。Rocky在这里也总结了一套SDXL模型的格式转换教程,方便大家快速转换格式,使用diffusers库运行模型。主要流程如下所示:
pip install diffusers==0.26.3 transformers==4.38.1 accelerate==0.27.2
git clone https://github .com/huggingface/diffusers.git
cd diffusers/scripts
python convert_original_stable_diffusion_to_diffusers.py --checkpoint_path /本地路径/safetensors格式模型 --dump_path /本地路径/转换后diffusers格式模型的保存路径 --from_safetensors
成功运行上述代码后,我们可以看到一个包含scheduler、vae、unet、text_encoder、tokenizer、text_encoder_2、tokenizer_2文件夹以及model_index.json文件的diffusers格式的SDXL模型。
3.2 零基础使用Stable Diffusion WebUI搭建Stable Diffusion XL推理流程
目前Stable Diffusion WebUI已经全面支持Stable Diffusion XL中的Base模型和Refiner模型。
Stable Diffusion WebUI 是AI绘画领域最为流行的框架 ,其生态极其繁荣,非常多的上下游插件能够与Stable Diffusion WebUI一起完成诸如AI视频生成,AI证件照生成等工作流,可玩性非常强。
接下来,咱们就使用这个流行框架搭建Stable Diffusion XL推理流程吧。
首先,我们需要下载安装Stable Diffusion WebUI框架,我们只需要在命令行输入如下代码即可:
git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
安装好后,我们可以看到本地的stable-diffusion-webui文件夹。
下面我们需要安装其依赖库,我们进入Stable Diffusion WebUI文件夹,并进行以下操作:
cd stable-diffusion-webui #进入下载好的automatic文件夹中
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
和SD.Next的配置流程类似,我们还需要配置Stable Diffusion WebUI的repositories插件,我们需要运行下面的代码:
sh webui.sh
#主要依赖包括:BLIP CodeFormer generative-models k-diffusion stable-diffusion-stability-ai taming-transformers
如果发现repositories插件下载速度较慢,出现很多报错,don’t worry,大家可以直接使用Rocky已经配置好的资源包,可以快速启动与Stable Diffusion XL兼容的Stable Diffusion WebUI框架。Stable Diffusion WebUI资源包可以关注公众号WeThinkIn ,后台回复“WebUI资源 ”获取。
在完成了依赖库和repositories插件的安装后,我们就可以配置模型了,我们将Stable Diffusion XL模型放到/stable-diffusion-webui/models/Stable-diffusion/路径下 。这样一来,等我们开启可视化界面后,就可以选择Stable Diffusion XL模型用于推理生成图片了。
完成上述的步骤后,我们可以启动Stable Diffusion WebUI了!我们到/stable-diffusion-webui/路径下,运行launch.py 即可:
python launch.py --listen --port 8888
运行完成后,可以看到命令行中出现的log:
To see the GUI go to: http://0.0.0.0:8888
我们将http://0.0.0.0:8888输入到我们本地的网页中,即可打开如下图所示的Stable Diffusion WebUI可视化界面,愉快的使用Stable Diffusion XL模型进行AI绘画了。 进入Stable Diffusion WebUI可视化界面后,我们可以在红色框中选择SDXL模型,然后在黄色框中输入我们的Prompt和负向提示词,同时在绿色框中设置我们想要生成的图像分辨率(推荐设置成1024×1024 ),然后我们就可以点击Generate按钮,进行AI绘画了。
等待片刻后,图像就生成好了,并展示在界面的右下角,同时也会保存到/stable-diffusion-webui/outputs/txt2img-images/路径下 ,大家可以到对应路径下查看。
3.3 零基础使用ComfyUI搭建Stable Diffusion XL推理流程
ComfyUI 是一个基于节点式 的Stable Diffusion AI绘画工具。和Stable Diffusion WebUI相比,ComfyUI通过将Stable Diffusion模型生成推理的pipeline拆分成独立的节点,实现了更加精准的工作流定制和清晰的可复现性 。
同时其完善的模型加载和图片生成机制,让其能够在2080Ti显卡上构建Stable Diffusion XL的工作流,并能生成1024×1024分辨率的图片 ,如此算力友好,可谓是初学者的福音。
目前ComfyUI已经能够兼容Stable Diffusion XL的Base模型和Refiner模型,下面两张图分别是Rocky使用ComfyUI来加载Stable Diffusion XL Base模型和Stable Diffusion XL Base + Refiner模型并生成图片的完整Pipeline:大家如果看了感觉复杂,不用担心,Rocky已经为大家保存了这两个工作流 ,大家只需关注Rocky的公众号WeThinkIn ,并回复“ComfyUI ”,就能获取这两个工作流以及文生图,图生图,图像Inpainting,ControlNet以及图像超分在内的所有Stable Diffusion经典工作流json文件,大家只需在ComfyUI界面右侧点击Load按钮 选择对应的json文件,即可加载对应的工作流,开始愉快的AI绘画之旅。
话说回来,下面Rocky将带着大家一步一步使用ComfyUI搭建Stable Diffusion XL推理流程,从而实现上面两张图的生成过程。
首先,我们需要安装ComfyUI框架,这一步非常简单,在命令行 输入如下代码即可:
git clone https://github.com/comfyanonymous/ComfyUI.git
安装好后,我们可以看到本地的ComfyUI文件夹。
ComfyUI框架安装到本地后,我们需要安装其依赖库,我们只需以下操作:
cd ComfyUI #进入下载好的ComfyUI文件夹中
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
完成这些配置工作后,我们就可以配置模型了,我们将Stable Diffusion XL模型放到ComfyUI/models/checkpoints/路径下 。这样一来,等我们开启可视化界面后,就可以选择Stable Diffusion XL模型进行AI绘画了。
接下来,我们就可以启动ComfyUI了!我们到ComfyUI/路径下,运行main.py 即可:
python main.py --listen --port 8888
运行完成后,可以看到命令行中出现的log:
To see the GUI go to: http://0.0.0.0:8888
我们将http://0.0.0.0:8888输入到我们本地的网页中,即可打开如上图所示的ComfyUI可视化界面,愉快的使用Stable Diffusion XL模型生成我们想要的图片了。
接下来就是ComfyUI的节点式模块讲解了,首先是只加载Base模型的情况: Rocky已经进行了比较详细的注释,首先大家可以在红框中选择我们的模型(Stable Diffusion XL Base),接着填入Prompt和负向Prompt,并且配置生成推理过程的参数(迭代次数,CFG,Seed等),然后在绿色框中设置好生成图片的分辨率,然后在紫色框中点击Queue Prompt按钮 ,整个推理过程就开始了。等整个推理过程完成之后,生成的图片会在图中黄色箭头所指的地方进行展示,并且会同步将生成图片保存到本地的ComfyUI/output/路径下 。
完成了Stable Diffusion Base模型的推理流程,我们再来看看Base+Refiner模型的推理流程如何搭建: 和Base模型的构建十分相似,首先大家可以在红框中选择我们的Refiner模型(Stable Diffusion XL Refiner),Refiner模型使用的Prompt和负向Prompt与Base模型一致,并且配置生成推理过程的参数(迭代次数,CFG,Seed等),绿色箭头表示将Base模型输出的Latent特征作为Refiner模型的输入 ,然后在蓝色框中点击Queue Prompt按钮 ,整个Refiner精修过程就开始了。等整个推理过程完成之后,生成的图片会在图中紫色箭头所指的地方进行展示,并且会同步将生成图片保存到本地的ComfyUI/output/路径下 。
到此为止,Rocky已经详细讲解了如何使用ComfyUI来搭建Stable Diffusion XL模型进行AI绘画,大家可以按照Rocky的步骤进行尝试。
3.4 零基础使用SD.Next搭建Stable Diffusion XL推理流程
SD.Next 原本是Stable Diffusion WebUI的一个分支,再经过不断的迭代优化后,最终成为了一个独立版本。
SD.Next与Stable Diffusion WebUI相比,包含了更多的高级功能,也兼容Stable Diffusion, Stable Diffusion XL, Kandinsky, DeepFloyd IF等模型结构 ,是一个功能十分强大的AI绘画框架。
那么我们马上开始SD.Next的搭建与使用吧。
首先,我们需要安装SD.Next框架,这一步非常简单,在命令行 输入如下代码即可:
git clone https://github.com/vladmandic/automatic
安装好后,我们可以看到本地的automatic文件夹。
SD.Next框架安装到本地后,我们需要安装其依赖库,我们只需以下操作:
cd automatic #进入下载好的automatic文件夹中
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
除了安装依赖库之外,还需要配置SD.Next所需的repositories插件,我们需要运行以下代码:
cd automatic #进入下载好的automatic文件夹中
python installer.py
如果发现extensions插件下载速度较慢,出现很多报错,大家可以直接使用Rocky已经配置好的资源包,可以快速启动SD.Next框架。SD.Next资源包可以关注公众号WeThinkIn ,后台回复“SD.Next资源 ”获取。
在完成了依赖库和repositories插件的安装后,我们就可以配置模型了,我们将Stable Diffusion XL模型放到/automatic/models/Stable-diffusion/路径下 。这样一来,等我们开启可视化界面后,就可以选择Stable Diffusion XL模型用于推理生成图片了。
完成上述的步骤后,我们可以启动SD.Next了!我们到/automatic/路径下,运行launch.py 即可:
python launch.py --listen --port 8888
运行完成后,可以看到命令行中出现的log:
To see the GUI go to: http://0.0.0.0:8888
我们将http://0.0.0.0:8888输入到我们本地的网页中,即可打开如下图所示的SD.Next可视化界面,愉快的使用Stable Diffusion XL模型进行AI绘画了。 进入SD.Next可视化界面后,我们可以在红色框中选择模型,然后需要修改Settings中的配置,来让SD.Next能够加载Stable Diffusion XL模型。
我们点击上图蓝色框中的Settings,进入Settings配置界面: 从上面图示中可以看到,我们需要做的修改是将Settings -> Stable Diffusion -> Stable Diffusion backend设置为diffusers,并在Stable Diffusion refiner栏中选择Refiner模型 。
然后我们需要将Settings -> Diffusers Settings-> Select diffuser pipeline when loading from safetensors栏设置为Stable Diffusion XL 。
完成了上述的配置修改后,我们就可以使用SD.Next加载Stable Diffusion XL进行AI绘画了!
3.5 SDXL生成图像示例
示例一:未来主义的城市风格
Prompt:Stunning sunset over a futuristic city, with towering skyscrapers and flying vehicles, golden hour lighting and dramatic clouds, high detail, moody atmosphere
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion XL Base+Refiner生成结果: 示例二:天堂海滩风格
Prompt:Serene beach scene with crystal clear water and white sand, tropical palm trees swaying in the breeze, perfect paradise, seascape
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion XL Base+Refiner生成结果:
示例三:未来机甲风格
Prompt:Giant robots fighting in a futuristic city, with buildings falling and explosions all around, intense, fast-paced, dramatic, stylized, futuristic
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion XL Base+Refiner生成结果: 示例四:马斯克风格
Prompt:Elon Musk standing in a workroom, in the style of industrial machinery aesthetics, deutscher werkbund, uniformly staged images, soviet, light indigo and dark bronze, new american color photography, detailed facial features
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion XL Base+Refiner生成结果:
4. 从0到1上手使用Stable Diffusion XL训练自己的AI绘画模型(全网最详细讲解)
4.0 SDXL训练资源分享
SDXL训练脚本:Rocky整理优化过的SDXL完整训练资源SDXL-Train项目,大家只用在SDXL-Train中就可以完成SDXL的模型训练工作,方便大家上手实操 。SDXL-Train项目资源包可以通过关注公众号WeThinkIn ,后台回复“SDXL-Train ”获取。
本文中的SDXL微调训练数据集:二次元人物数据集 ,大家可以关注公众号WeThinkIn ,后台回复“二次元人物数据集 ”获取。
本文中的SDXL微调训练底模型:WeThinkIn_SDXL_二次元模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SDXL_二次元模型 ”获取模型资源链接。
本文中的SDXL LoRA训练数据集:猫女数据集 ,大家可以关注公众号WeThinkIn ,后台回复“猫女数据集 ”获取。
本文中的SDXL LoRA训练底模型:WeThinkIn_SDXL_真人模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SDXL_真人模型 ”获取模型资源链接。
4.1 SDXL训练脉络初识
Stable Diffusion系列模型的训练过程主要分成以下几个步骤,Stable Diffusion XL也不例外:
训练集制作 :数据质量评估,标签梳理,数据清洗,数据标注,标签清洗,数据增强等。
训练文件配置 :预训练模型选择,训练环境配置,训练步数设置,其他超参数设置等。
模型训练 :运行SDXL模型/LoRA模型训练脚本,使用TensorBoard监控模型训练等。
模型测试 :将训练好的自训练SDXL模型/LoRA模型用于效果评估与消融实验。
讲完SDXL训练的方法论,Rocky再向大家推荐一些SDXL训练资源:
https://github.com/qaneel/kohya-trainer(本文中主要的训练工程)
https://github.com/Linaqruf/kohya-trainer(此项目中的kohya-trainer-XL.ipynb和kohya-LoRA-trainer-XL.ipynb可以用于制作数据集和配置训练参数)
https://github.com/bmaltais/kohya_ss(此项目可以GUI可视化训练)
Rocky整理优化过的SDXL完整训练资源SDXL-Train项目,大家只用在SDXL-Train中就可以完成SDXL的模型训练工作,方便大家上手实操 。SDXL-Train项目资源包可以通过关注公众号WeThinkIn ,后台回复“SDXL-Train ”获取。
目前我们对SDXL的训练流程与所需资源有了初步的了解,接下来,就让我们跟随着Rocky的脚步,从0到1使用SDXL模型和训练资源一起训练自己的SDXL绘画模型与LoRA绘画模型吧!
4.2 配置训练环境与训练文件
首先,我们需要下载两个训练资源,只需在命令行输入下面的代码即可:
git clone https://github.com/qaneel/kohya-trainer.git
git clone https://github.com/Linaqruf/kohya-trainer.git
qaneel/kohya-trainer项目包含了Stable Diffusion XL的核心训练脚本 ,而我们需要用Linaqruf/kohya-trainer项目中的kohya-trainer-XL.ipynb和kohya-LoRA-trainer-XL.ipynb文件来生成数据集制作脚本和训练参数配置脚本 。
我们打开Linaqruf/kohya-trainer项目可以看到,里面包含了两个SDXL的.ipynb文件:
接着我们再打开qaneel/kohya-trainer项目,里面包含的两个python文件就是我们后续的训练主脚本: 正常情况下,我们需要运行Linaqruf/kohya-trainer项目中两个SDXL的.ipynb文件的内容,生成训练数据处理脚本(数据标注,数据预处理,数据Latent特征提取,数据分桶(make buckets)等)和训练参数配置文件。
我们使用数据处理脚本完成训练集的制作,然后再运行qaneel/kohya-trainer项目的训练脚本,同时读取训练参数配置文件,为SDXL模型的训练过程配置超参数。
完成上面一整套流程,SDXL模型的训练流程就算跑通了。但是由于Linaqruf/kohya-trainer项目中的两个.ipynb文件内容较为复杂,整个流程比较繁琐,对新手非常不友好,并且想要完成一整套训练流程,需要我们一直在两个项目之前切换,非常不方便 。
所以Rocky这边帮大家对两个项目进行了整合归纳,总结了简单易上手的SDXL模型以及相应LoRA模型的训练流程,制作成SDXL完整训练资源SDXL-Train项目,大家只用在SDXL-Train中就可以完成SDXL的模型训练工作,方便大家上手实操。
SDXL-Train项目资源包可以通过关注公众号WeThinkIn ,后台回复“SDXL-Train ”获取。
下面是SDXL-Train项目中的主要内容,大家可以看到SDXL的数据处理脚本与训练脚本都已包含在内: 我们首先进入SDXL-Train项目中,安装SDXL训练所需的依赖库,我们只需在命令行输入以下命令即可:
cd SDXL-Train
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
# accelerate库的版本需要重新检查一遍,需要安装accelerate==0.16.0版本才能兼容SDXL的训练
pip install accelerate==0.16.0 -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
# Rocky在这里推荐大家安装2.0.1版本的Pytorch,能够兼容SDXL训练的全部流程
pip install torch==2.0.1 -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
在完成上述的依赖库安装后,我们需要确认一下目前的Python、PyTroch、CUDA以及cuDNN的版本是否兼容 ,我们只需要在命令行输入以下命令即可:
# Python版本推荐3.8或者3.9,两个版本皆可
>>> python
Python 3.9
# 加载PyTroch
>>> import torch
# 查看PyTorch版本
>>> print(torch.__version__)
2.0.1+cu117
# 查看CUDA版本
>>> print(torch.version.cuda)
11.7
# 查看cuDNN版本
>>> print(torch.backends.cudnn.version())
8500
# 查看PyTroch、CUDA以及cuDNN的版本是否兼容,True代表兼容
>>> print(torch.cuda.is_available())
True
如果大家在本地自己验证的时候和Rocky上述的版本一致,说明训练环境已经全部兼容!
安装和验证好所有SDXL训练所需的依赖库后,我们还需要设置一下SDXL的训练环境,我们主要使用accelerate库的能力,accelerate库能让PyTorch的训练和推理变得更加高效简洁 。我们只需在命令行输入以下命令,并对每个设置逐一进行填写即可:
# 输入以下命令,开始对每个设置进行填写
accelerate config
# 开始进行训练环境参数的配置
In which compute environment are you running? # 选择This machine,即本机
This machine
# 选择单卡或是多卡训练,如果是多卡,则选择multi-GPU,若是单卡,则选择No distributed training
Which type of machine are you using?
multi-GPU
# 几台机器用于训练,一般选择1台。注意这里是指几台机器,不是几张GPU卡
How many different machines will you use (use more than 1 for multi-node training)? [1]: 1
# torch dynamo,DeepSpeed,FullyShardedDataParallel,Megatron-LM等环境参数,不需要配置
Do you wish to optimize your script with torch dynamo?[yes/NO]: # 输入回车即可
Do you want to use DeepSpeed? [yes/NO]: # 输入回车即可
Do you want to use FullyShardedDataParallel? [yes/NO]: # 输入回车即可
Do you want to use Megatron-LM ? [yes/NO]: # 输入回车即可
# 选择多少张卡投入训练
How many GPU(s) should be used for distributed training? [1]:2
# 设置投入训练的GPU卡id,如果是全部的GPU都投入训练,则输入all即可。
What GPU(s) (by id) should be used for training on this machine as a comma-seperated list? [all]:all
# 训练精度,可以选择fp16
Do you wish to use FP16 or BF16 (mixed precision)?
fp16
# 完成配置后,配置文件default_config.yaml会保存在/root/.cache/huggingface/accelerate下
accelerate configuration saved at /root/.cache/huggingface/accelerate/default_config.yaml完成上述的流程后,接下来我们就可以进行SDXL训练数据的制作和训练脚本的配置流程了!
后续进行SDXL与SDXL LoRA模型训练的时候,只需要加载对应的default_config.yaml配置文件即可,具体的调用方法,本文后续的章节会进行详细讲解。
还有一点需要注意的是,我们进行SDXL模型的训练时,SDXL的CLIP Text Encoder会调用CLIP-ViT-bigG-14-laion2B-39B-b160k和clip-vit-large-patch14两个配置文件 。一般情况下SDXL模型会从huggingface上将配置文件下载到~/.cache/huggingface/目录中,但是由于网络原因很可能会下载失败,从而导致训练的失败。
所以为了让大家能更方便的训练SDXL模型,Rocky已经将CLIP-ViT-bigG-14-laion2B-39B-b160k和clip-vit-large-patch14这两个配置文件放入SDXL-Train项目的utils_json文件夹中,并且已经为大家配置好依赖路径,大家只要使用SDXL-Train项目便无需做任何修改 。如果大家想要修改CLIP-ViT-bigG-14-laion2B-39B-b160k和clip-vit-large-patch14这两个依赖文件夹的调用路径,大家可以找到SDXL-Train/library/sdxl_train_util.py脚本中的第122行,将”utils_json/”部分修改成自己的本地自定义路径比如“/本地路径/utils_json/”即可。
完成上述的流程后,接下来我们就可以进行SDXL训练数据的制作和训练脚本的配置流程了!
4.3 SDXL训练数据集制作
首先,我们需要对数据集进行清洗,和传统深度学习时代一样,数据清洗工作依然占据了AIGC时代模型训练70%-80%左右的时间。
并且这个过程必不可少,因为数据质量决定了机器学习性能的上限,而算法和模型只是在不断逼近这个上限而已 。
我们需要筛除分辨率较低、质量较差(比如说768*768分辨率的图片)、存在破损以及和任务目标无关的数据,接着再去除数据里面可能包含的水印,干扰文字等污染特征 。
同时,我们需要优先保证数据集的质量,在有质量的基础上再去增加数据集的数量与丰富度 。
为了满足AI绘画生成图片时的尺寸适应度,我们可以对数据进行多尺度的增强 ,比如进行1:1,1:2,2:1,1:3,3:4,4:3,9:16,16:9等等尺寸的裁剪与缩放操作。但是切记不能在多尺度增强的时候将图片的主体特征裁剪掉(比如人脸,建筑等)。
完成上述的数据筛选与清洗工作后,我们就可以开始进行数据标注了。
数据标注可以分为自动标注 和手动标注 。自动标注主要依赖像BLIP(img2caption)和Waifu Diffusion 1.4(img2tag)等能够进行图片生成标签的模型,手动标注则依赖标注人员。
4.3.1 使用BLIP自动标注caption
我们先用BLIP对数据进行自动标注,BLIP输出的是自然语言标签 ,我们进入到SDXL-Train/finetune/路径下,运行以下代码即可获得自然语言标签(caption标签):
cd SDXL-Train/finetune/
python make_captions.py "/数据路径" --caption_weights “/本地BLIP模型路径” --batch_size=8 --beam_search --min_length=5 --max_length=75 --debug --caption_extension=".caption" --max_data_loader_n_workers=2
注意:在使用BLIP进行数据标注时需要依赖bert-base-uncased模型,Rocky这边已经帮大家配置好了,大家只要使用SDXL-Train项目便无需做任何修改 。同时,如果大家想要修改bert-base-uncased模型的调用路径,可以找到SDXL-Train/finetune/blip/blip.py脚本的第189行,将“…/bert-base-uncased”部分修改成自己的本地自定义路径比如“/本地路径/bert-base-uncased”即可。
从上面的代码可以看到,我们第一个传入的参数是训练集的路径 。下面Rocky再一一向大家介绍一下其余参数的意义:
–caption_weights:表示加载的本地BLIP模型,如果不传入本地模型路径,则默认从云端下载BLIP模型。
–batch_size:表示每次传入BLIP模型进行前向处理的数据数量。
–beam_search:设置为波束搜索,默认Nucleus采样。
–min_length:设置caption标签的最短长度。
–max_length:设置caption标签的最长长度。
–debug:如果设置,将会在BLIP前向处理过程中,打印所有的图片路径与caption标签内容,以供检查。
–caption_extension:设置caption标签的扩展名,一般为”.caption”。
–max_data_loader_n_workers:设置大于等于2,加速数据处理。
讲完了上述的运行代码以及相关参数,下面Rocky再举一个例子, 让大家能够更加直观的感受到BLIP处理数据生成caption标签的过程:
上图是单个图像的标注示例,整个数据集的标注流程也是同理的。等整个数据集的标注后,Stable Diffusion XL训练所需的caption标注就完成了 。
4.3.2 使用Waifu Diffusion 1.4自动标注tag
接下来我们可以使用Waifu Diffusion 1.4进行自动标注,Waifu Diffusion 1.4输出的是tag关键词 ,这里需要注意的是,调用Waifu Diffusion 1.4模型需要安装Tensorflow库,并且需要下载特定的版本(2.10.1) ,不然运行时会报“DNN library is not found“错误。我们只需要在命令行输入以下命令即可:
pip install tensorflow==2.10.1
完成上述的环境配置后,我们依然进入到SDXL-Trian/finetune/路径下,运行以下代码即可获得tag自动标注:
cd SDXL-Train/finetune/
python tag_images_by_wd14_tagger.py "/数据路径" --batch_size=8 --model_dir="/本地路径/wd-v1-4-moat-tagger-v2" --remove_underscore --general_threshold=0.35 --character_threshold=0.35 --caption_extension=".txt" --max_data_loader_n_workers=2 --debug --undesired_tags=""
从上面的代码可以看到,我们第一个传入的参数是训练集的路径 。
–batch_size:表示每次传入Waifu Diffusion 1.4模型进行前向处理的数据数量。
–model_dir:表示加载的本地Waifu Diffusion 1.4模型路径。
–remove_underscore:如果开启,会将输出tag关键词中的下划线替换为空格。
–general_threshold:设置常规tag关键词的筛选置信度。
–character_threshold:设置人物特征tag关键词的筛选置信度。
–caption_extension:设置tag关键词标签的扩展名,一般为”.txt”。
-max_data_loader_n_workers:设置大于等于2,加速数据处理。
–debug:如果设置,将会在Waifu Diffusion 1.4模型前向处理过程中,打印所有的图片路径与tag关键词标签内容,以供检查。
–undesired_tags:设置不需要输出的tag关键词。
下面Rocky依然用美女图片作为例子, 让大家能够更加直观的感受到Waifu Diffusion 1.4模型处理数据生成tag关键词标签的过程: 上图是单个图像的标注示例,整个数据集的标注流程也是同理的。等整个数据集的标注后,Stable Diffusion XL训练所需的tag关键词标注就完成了 。
上面Rocky是使用了Waifu Diffusion v1.4系列模型中的wd-v1-4-moat-tagger-v2模型,目前Waifu Diffusion v1.4系列模型一共有5个版本,除了刚才介绍到的wd-v1-4-moat-tagger-v2模型,还包括wd-v1-4-swinv2-tagger-v2模型、wd-v1-4-convnext-tagger-v2模型、wd-v1-4-convnextv2-tagger-v2模型以及wd-v1-4-vit-tagger-v2模型。
Rocky也分别对他们的自动标注效果进行了对比,在这里Rocky使用了一张生成的“猫女”图片,分别输入到这五个自动标注模型中,一起来看看不同版本的Waifu Diffusion v1.4模型的效果: 从上图可以看到,在将general_threshold和character_threshold同时设置为0.5时,wd-v1-4-moat-tagger-v2模型的标注效果整体上是最好的,内容丰富且最能反映图片中的语义信息。所以在这里,Rocky也推荐大家使用wd-v1-4-moat-tagger-v2模型 。
大家也可以在SDXL-Train项目的tag_models文件夹下调用这些模型,进行对比测试,感受不同系列Waifu Diffusion v1.4模型的标注效果。
4.3.3 补充标注特殊tag
完成了caption和tag的自动标注之后,如果我们需要训练一些特殊标注 的话,还可以进行手动的补充标注。
SDXL-Trian项目中也提供了对数据进行补充标注的代码,Rocky在这里将其进行提炼总结,方便大家直接使用。
大家可以直接拷贝以下的代码,并按照Rocky在代码中提供的注释进行参数修改,然后运行代码即可对数据集进行补充标注:
import os
# 设置为本地的数据集路径
train_data_dir = "/本地数据集路径"
# 设置要补充的标注类型,包括[".txt", ".caption"]
extension = ".txt"
# 设置要补充的特殊标注
custom_tag = "WeThinkIn"
# 若设置sub_folder = "--all"时,将遍历所有子文件夹中的数据;默认为""。
sub_folder = ""
# 若append设为True,则特殊标注添加到标注文件的末尾
append = False
# 若设置remove_tag为True,则会删除数据集中所有的已存在的特殊标注
remove_tag = False
recursive = False
if sub_folder == "":
image_dir = train_data_dir
elif sub_folder == "--all":
image_dir = train_data_dir
recursive = True
elif sub_folder.startswith("/content"):
image_dir = sub_folder
else:
image_dir = os.path.join(train_data_dir, sub_folder)
os.makedirs(image_dir, exist_ok=True)
# 读取标注文件的函数,不需要改动
def read_file(filename):
with open(filename, "r") as f:
contents = f.read()
return contents
# 将特殊标注写入标注文件的函数,不需要改动
def write_file(filename, contents):
with open(filename, "w") as f:
f.write(contents)
# 将特殊标注批量添加到标注文件的主函数,不需要改动
def process_tags(filename, custom_tag, append, remove_tag):
contents = read_file(filename)
tags = [tag.strip() for tag in contents.split(',')]
custom_tags = [tag.strip() for tag in custom_tag.split(',')]
for custom_tag in custom_tags:
custom_tag = custom_tag.replace("_", " ")
if remove_tag:
while custom_tag in tags:
tags.remove(custom_tag)
else:
if custom_tag not in tags:
if append:
tags.append(custom_tag)
else:
tags.insert(0, custom_tag)
contents = ', '.join(tags)
write_file(filename, contents)
def process_directory(image_dir, tag, append, remove_tag, recursive):
for filename in os.listdir(image_dir):
file_path = os.path.join(image_dir, filename)
if os.path.isdir(file_path) and recursive:
process_directory(file_path, tag, append, remove_tag, recursive)
elif filename.endswith(extension):
process_tags(file_path, tag, append, remove_tag)
tag = custom_tag
if not any(
[filename.endswith(extension) for filename in os.listdir(image_dir)]
):
for filename in os.listdir(image_dir):
if filename.endswith((".png", ".jpg", ".jpeg", ".webp", ".bmp")):
open(
os.path.join(image_dir, filename.split(".")[0] + extension),
"w",
).close()
# 但我们设置好要添加的custom_tag后,开始整个代码流程
if custom_tag:
process_directory(image_dir, tag, append, remove_tag, recursive)
看完了上面的完整代码流程,如果大家觉得代码太复杂,don‘t worry,大家只需要复制 上面的全部代码,并将train_data_dir =”/本地数据集路径”和custom_tag =”WeThinkIn”设置成自己数据集的本地路径和想要添加的特殊标注,然后运行代码即可,非常简单实用 。
还是以之前的美女图片为例子,当运行完上面的代码后,可以看到txt文件中,最开头的tag为“WeThinkIn”: 大家注意,一般我们会将手动补充的特殊tag放在第一位,因为和caption标签不同,tags标签是有顺序的,最开始的tag权重最大,越靠后的tag权重越小 。
到这里,Rocky已经详细讲解了在Stable Diffusion XL训练前,如何对数据集进行caption标注,tag标注以及补充一些关键标注的完整步骤与流程 ,在数据标注完毕后,接下来我们就要进入数据预处理的阶段了。
4.3.4 训练数据预处理
首先,我们需要对刚才生成的后缀为.caption和.txt的标注文件进行整合,存储成一个json格式的文件,方便后续SDXL模型训练时调取训练数据与标注。
我们需要进入SDXL-Train项目的finetune文件夹中,运行merge_all_to_metadata.py脚本即可:
cd SDXL-Train
python ./finetune/merge_all_to_metadata.py "/本地数据路径" "/本地数据路径/meta_clean.json"
如下图所示,我们依旧使用之前的美图女片作为例子,运行完merge_all_to_metadata.py脚本后,我们在数据集路径中得到一个meta_clean.json文件,打开可以看到图片名称对应的tag和caption标注都封装在了文件中,让人一目了然,非常清晰。 在整理好标注文件的基础上,接下来我们需要对数据进行分桶与保存Latent特征,并在meta_clean.json的基础上,将图片的分辨率信息也存储成json格式,并保存一个新的meta_lat.json文件。
我们需要进入SDXL-Train项目的finetune文件夹中,运行prepare_buckets_latents.py脚本即可:
cd SDXL-Train
python ./finetune/prepare_buckets_latents.py "/本地数据路径" "/本地数据路径/meta_clean.json" "/本地数据路径/meta_lat.json" "调用的SDXL模型路径" --batch_size 4 --max_resolution "1024,1024"
运行完脚本,我们即可在数据集路径中获得meta_lat.json文件,其在meta_clean.json基础上封装了图片的分辨率信息,用于SDXL训练时快速进行数据分桶。 同时我们可以看到,美女图片的Latent特征保存为了.npz文件,用于SDXL模型训练时,快速读取数据的Latent特征,加速训练过程。
好的,到目前为止,我们已经完整的进行了SDXL训练所需的数据集制作与预处理流程。总结一下,我们在一张美女图片的基础上,一共获得了以下5个不同的训练配置文件 :
meta_clean.json
meta_lat.json
自然语言标注(.caption)
关键词tag标注(.txt)
数据的Latent特征信息(.npz)
在完成以上所有数据处理过程后,接下来我们就可以进入SDXL训练的阶段了,我们可以对SDXL进行全参微调(finetune),也可以基于SDXL训练对应的LoRA模型。
4.4 SDXL微调(finetune)训练
微调(finetune)训练是让SDXL全参数重新训练的一种方法,理想的状态是让SDXL模型在原有能力的基础上,再学习到一个或几个细分领域的数据特征与分布 ,从而能在工业界,学术界以及竞赛界满足不同的应用需求。
Rocky为大家举一个形象的例子,让大家能够能好理解SDXL全参微调的意义。比如我们要训练一个真人写真SDXL模型,应用于写真领域。那么我们首先需要寻找合适的基于SDXL的预训练底模型,比如一个能生成真人图片的SDXL A模型。然后我们用A模型作为预训练底模型,并收集写真行业优质数据作为训练集,有了模型和数据,再加上Rocky为大家撰写的SDXL微调训练全流程攻略,我们就能训练获得一个能生成真人写真的SDXL行业模型,并作为真人写真相关产品的核心大模型 。
那么话不多说,下面Rocky将告诉大家从0到1使用SDXL模型进行微调训练的全流程攻略 ,让我们一起来训练属于自己的SDXL模型吧!
4.4.1 SDXL 微调(finetune)数据集制作
在SDXL全参数微调中,SDXL能够学习到大量的主题,人物,画风或者抽象概念等信息特征 ,所以我们需要对一个细分领域的数据进行广泛的收集,并进行准确的标注。
Rocky这边收集整理了838张二次元人物数据,包含多样的人物,多样的画风,涵盖了大量的二次元专属信息特征,组成二次元人物数据集 ,作为本次SDXL微调训练的训练集。
Rocky一开始收集了5000张数据,经过筛选只剩838张作为最后的模型训练集,数据集质量决定生成效果的上限 ,所以前期对数据集的清洗工作是非常重要的,Rocky总结了以下的用于SDXL全参微调的数据集筛选要求 :
数据尺寸需要在512×512像素以上。
数据的大小最好大于300K。
数据种类尽量丰富,不同主题,不同画风,不同概念都要充分采集。
一个特殊tag对应的图像特征在数据集中需要一致,不然在推理过程触发这个tag时可能会生成多个特征的平均。
每个数据都要符合我们的审美和评判标准!每个数据都要符合我们的审美和评判标准!每个数据都要符合我们的审美和评判标准!
接下来,我们就可以按照本文4.3 Stable Diffusion XL数据集制作章节里的步骤 ,进行数据的清洗,自动标注,以及添加特殊tag。
Rocky认为对SDXL模型进行微调训练主要有两个目的:增强SDXL模型的图像生成能力与增加SDXL对新prompt的触发能力 。
我们应该怎么理解这两个目的呢。我们拿二次元人物数据集为例,我们想要让SDXL模型学习二次元人物的各种特征,包括脸部特征,服装特征,姿势特征,二次元背景特征,以及二次元画风特征等。通过训练不断让SDXL模型“学习”这些数据的内容,从而增强SDXL模型生成二次元人物图片的能力 。与此同时,我们通过自动标注与特殊tag,将图片的特征与标注信息进行对应,让SDXL在学习图片数据特征的同时,学习到对应的标注信息,能够在前向推理的过程中,通过二次元的专属标签生成对应的二次元人物图像 。
理解了上面的内容,咱们的数据处理部分就告一段落了。为了方便大家使用二次元人物数据集进行后续的SDXL模型微调训练,Rocky这边已经将处理好的二次元人物数据集开源(包含原数据,标注文件,读取数据的json文件等) ,大家可以关注公众号WeThinkIn ,后台回复“二次元人物数据集 ”获取。
4.4.2SDXL 微调训练参数配置
本节中,Rocky主要介绍Stable Diffusion XL全参微调(finetune)训练 的参数配置和训练脚本。
Rocky已经帮大家整理好了SDXL全参微调训练的全部参数与训练脚本,大家可以在SDXL-Trian项目的train_config文件夹中找到相应的训练参数配置(XL_config文件夹),并且可以在SDXL-Trian项目中运行SDXL_finetune.sh脚本,进行SDXL的全参微调训练。
接下来,Rocky将带着大家从头到尾走通SDXL全参微调训练过程,并讲解训练参数的意义。首先,我们可以看到XL_config文件夹中有两个配置文件config_file.toml和sample_prompt.toml,他们分别存储着SDXL的训练超参数与训练中的验证prompt。
其中config_file.toml文件中的配置信息包含了sdxl_arguments,model_arguments,dataset_arguments,training_arguments,logging_arguments,sample_prompt_arguments,saving_arguments,optimizer_arguments八个维度的参数信息,下面Rocky为大家依次讲解各个超参数的作用:
[sdxl_arguments]
cache_text_encoder_outputs = true
no_half_vae = true
min_timestep = 0
max_timestep = 1000
shuffle_caption = false
cache_text_encoder_outputs:Stable Diffusion XL训练时需要打开,用于两个Text Encoder输出结果的缓存与融合。注:当cache_text_encoder_outputs设为true时,shuffle_caption将不起作用。
no_half_vae:当此参数为true时,VAE在训练中使用float32精度;当此为false时,VAE在训练中使用fp16精度。
min_timestep:Stable Diffusion XL Base U-Net在训练时的最小时间步长(默认为0)。
max_timestep:Stable Diffusion XL Base U-Net在训练时的最大时间步长(默认为1000)。
shuffle_caption:当设置为true时,对训练标签进行打乱,能一定程度提高模型的泛化性。
[model_arguments]
pretrained_model_name_or_path = "/本地路径/SDXL模型文件"
vae = "/本地路径/VAE模型文件"
pretrained_model_name_or_path:读取本地Stable Diffusion XL预训练模型用于微调。
vae:读取本地VAE模型,如果不传入本参数,在训练中则会读取Stable Diffusion XL自带的VAE模型。
[dataset_arguments]
debug_dataset = false
in_json = "/本地路径/data_meta_lat.json"
train_data_dir = "/本地路径/训练集"
dataset_repeats = 10
keep_tokens = 0
resolution = "1024,1024"
caption_dropout_rate = 0
caption_tag_dropout_rate = 0
caption_dropout_every_n_epochs = 0
color_aug = false
token_warmup_min = 1
token_warmup_step = 0
debug_dataset:训练时对数据进行debug处理,不让破损数据中断训练进程。
in_json:读取数据集json文件,json文件中包含了数据名称,数据标签,数据分桶等信息。
train_data_dir:读取本地数据集存放路径。
dataset_repeats:整个数据集重复训练的次数。(经验分享:如果数据量级小于一千,可以设置为10;如果数据量级在一千与一万之间,可以设置为5;如果数据量级大于一万,可以设置为2 )
keep_tokens:在训练过程中,会将txt中的tag进行随机打乱。如果将keep tokens设置为n,那前n个token的顺序在训练过程中将不会被打乱。
resolution:设置训练时的数据输入分辨率,分别是width和height。
caption_dropout_rate:针对一个数据丢弃全部标签的概率,默认为0。
caption_tag_dropout_rate:针对一个数据丢弃部分标签的概率,默认为0。(类似于传统深度学习的Dropout逻辑 )
caption_dropout_every_n_epochs:每训练n个epoch,将数据标签全部丢弃。
color_aug:数据颜色增强,建议不启用,其与caching latents不兼容,若启用会导致训练时间大大增加 。
token_warmup_min:在训练一开始学习每个数据的前n个tag(标签用逗号分隔后的前n个tag,比如girl,boy,good)
token_warmup_step:训练中学习标签数达到最大值所需的步数,默认为0,即一开始就能学习全部的标签。
[training_arguments]
output_dir = "/本地路径/模型权重保存地址"
output_name = "sdxl_finetune_WeThinkIn"
save_precision = "fp16"
save_every_n_steps = 1000
train_batch_size = 4
max_token_length = 225
mem_eff_attn = false
xformers = true
max_train_steps = 100000
max_data_loader_n_workers = 8
persistent_data_loader_workers = true
gradient_checkpointing = true
gradient_accumulation_steps = 1
mixed_precision = "fp16"
output_dir:模型保存的路径。
output_name:模型名称。
save_precision:模型保存的精度,一共有[“None”, “float”, “fp16”, “bf16”]四种选择,默认为“None”,即FP32精度。
save_every_n_steps:每n个steps保存一次模型权重。
train_batch_size:训练Batch-Size,与传统深度学习一致。
max_token_length:设置Text Encoder最大的Token数,有[None, 150, 225]三种选择,默认为“None”,即75。
mem_eff_attn:对CrossAttention模块进行轻量化,能够一定程度上加速模型训练并降低显存占用,开启mem_eff_attn后xformers失效。
xformers:xformers插件可以使SDXL模型在训练时显存减少一半左右。
max_train_steps:训练的总步数。
max_data_loader_n_workers:数据加载的DataLoader worker数量,默认为8。
persistent_data_loader_workers:能够让DataLoader worker持续挂载,减少训练中每个epoch之间的数据读取时间,但是会增加内存消耗。
gradient_checkpointing:设为true时开启梯度检查,通过以更长的计算时间为代价,换取更少的显存占用。相比于原本需要存储所有中间变量以供反向传播使用,使用了checkpoint的部分不存储中间变量而是在反向传播过程中重新计算这些中间变量。模型中的任何部分都可以使用gradient checkpoint。
gradient_accumulation_steps:如果显存不足,我们可以使用梯度累积步数,默认为1。
mixed_precision:训练中是否使用混合精度,一共有[“no”, “fp16”, “bf16”]三种选择,默认为“no”。
[logging_arguments]
log_with = "tensorboard"
logging_dir = "/本地路径/logs"
log_prefix = "sdxl_finetune_WeThinkIn"
log_with:选择训练log保存的格式,可以从[“tensorboard”, “wandb”, “all”]三者中选择,也可以不设置。
logging_dir:设置训练log保存的路径。
log_prefix:增加log文件的文件名前缀,比如sdxl_finetune_WeThinkIn1234567890。
[sample_prompt_arguments]
sample_every_n_steps = 100
sample_sampler = "euler_a"
[saving_arguments]
save_model_as = "safetensors"
sample_every_n_steps:在训练中每n步测试一次模型效果。
sample_sampler:设置训练中测试模型效果时使用的sampler,可以选择[“ddim”,“pndm”,“lms”,“euler”,“euler_a”,“heun”,“dpm_2”,“dpm_2_a”,“dpmsolver”,“dpmsolver++”,“dpmsingle”, “k_lms”,“k_euler”,“k_euler_a”,“k_dpm_2”,“k_dpm_2_a”],默认是“ddim”。
save_model_as:每次模型权重保存时的格式,可以选择[“ckpt”, “safetensors”, “diffusers”, “diffusers_safetensors”],目前SD WebUI兼容”ckpt”和”safetensors”格式模型。
[optimizer_arguments]
optimizer_type = "AdaFactor"
learning_rate = 1e-7
train_text_encoder = false
max_grad_norm = 0
optimizer_args = [ "scale_parameter=False", "relative_step=False", "warmup_init=False",]
lr_scheduler = "constant_with_warmup"
lr_warmup_steps = 100
optimizer_type:AdamW (default),Lion, SGDNesterov,AdaFactor等。
learning_rate:训练学习率,单卡推荐设置2e-6,多卡推荐设置1e-7。
train_text_encoder:是否在SDXL训练时同步微调Text Encoder。如果设置为true,则在SDXL训练时同时开启Text Encoder模型的微调训练,增强Text Encoder模型对数据集中标签的控制力,能够让生成图片的特征更加趋近于训练数据集分布。
max_grad_norm:最大梯度范数,0表示没有clip。
optimizer_args:设置优化器额外的参数,比如”weight_decay=0.01 betas=0.9,0.999 …”。
lr_scheduler:设置学习率调度策略,可以设置成linear, cosine, cosine_with_restarts, polynomial, constant (default), constant_with_warmup, adafactor等。
lr_warmup_steps:在启动学习率调度策略前,先固定学习率训练的步数。
到这里,config_file.toml中八个维度的训练超参数就全部讲好了,大家可以根据自己的实际情况这些超参数进行调整。
除了config_file.toml之外,我们配置的文件还有sample_prompt.toml,其主要作用是在训练中阶段性验证模型的性能,里面包含了模型生成验证图片的相关参数:
[prompt]
width = 1024
height = 1024
scale = 7
sample_steps = 28
[[prompt.subset]]
prompt = "1girl, aqua eyes, baseball cap, blonde hair, closed mouth, earrings, green background, hat, hoop earrings, jewelry, looking at viewer, shirt, short hair, simple background, solo, upper body, yellow shirt"
现在我们已经对SDXL训练的整体参数有了比较充分的了解,下面Rocky再对一些关键参数进行深度的解析,让大家能够更好的理解。
4.4.3 SDXL训练的关键参数详解
【1】pretrained_model_name_or_path对SDXL模型微调训练的影响
pretrained_model_name_or_path参数中我们需要加载本地的SDXL模型作为训练底模型。
在SDXL全参数微调训练中,底模型的选择可以说是最为重要的一环。我们需要挑选一个生成能力分布与训练数据分布近似的SDXL模型作为训练底模型(比如说我们训练二次元人物数据集,可以选择生成二次元图片能力强的SDXL模型)。SDXL在微调训练的过程中,在原有底模型的很多能力与概念上持续扩展优化学习,从而得到底模型与数据集分布的一个综合能力。
【2】xformers加速库对SDXL模型微调训练的影响
当我们将xformers设置为true时,使用xformers加速库能对SDXL训练起到2倍左右的加速 ,因为其能使得训练显存占用降低2倍,这样我们就能增大我们的Batch Size数。
想要启动xformers加速库,需要先安装xformers库源,这也非常简单,我们只需要在命令行 输入如下命令即可:
pip install xformers -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
【3】learning_rate对SDXL模型微调训练的影响
SDXL训练过程对学习率的设置非常敏感,如果我们将学习率设置的过大,很有可能导致SDXL模型训练跑飞,在前向推理时生成非常差的图片;如果我们将学习率设置的过小,可能会导致模型无法跳出极小值点 。
Rocky这里总结了相关的SDXL学习率设置经验,分享给大家。如果我们总的Batch Size(单卡Batch Size x GPU数)小于10,可以设置学习率2e-6;如果我们总的Batch Size大于10小于100,可以设置学习率1e-7 。
【4】使用save_state和resume对SDXL模型训练的中断重启
在AI绘画领域,很多时候我们需要进行大规模数据的训练优化,数据量级在10万甚至100万以上,这时候整个训练周期需要一周甚至一个月,训练中可能会出现一些通讯/NCCL超时等问题,导致训练中断。
经典NCCL超时问题如下所示:
[E ProcessGroupNCCL.cpp:828] [Rank 0] Watchdog caught collective operation timeout: WorkNCCL(SeqNum=213, OpType=ALLREDUCE, Timeout(ms)=1800000) ran for 1809831 milliseconds before timing out.
这些训练中断问题会导致我们的训练成本大大增加,为了解决这个问题,我们可以在config_file.toml中设置save_state = true,这样我们在训练模型时不单单保存模型权重,还会保存相关的optimizer states等训练状态。
接着,我们在config_file.toml中设置resume = “/本地路径/模型权重保存地址”,重新运行SDXL训练脚本,这时会直接调取训练中断前的模型权重与训练状态,接着继续训练。
4.4.4 SDXL模型训练
完成训练参数配置后,我们就可以运行训练脚本进行SDXL模型的全参微调训练了。
我们本次训练用的底模型选择了WeThinkIn_SDXL_二次元模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SDXL_二次元模型 ”获取模型资源链接。
我们打开SDXL_finetune.sh脚本,可以看到以下的代码:
accelerate launch
--config_file accelerate_config.yaml
--num_cpu_threads_per_process=8
/本地路径/SDXL-Train/sdxl_train.py
--sample_prompts="/本地路径/SDXL-Trian/train_config/XL_config/sample_prompt.toml"
--config_file="/本地路径/SDXL-Trian/train_config/XL_config/config_file.toml"
我们把训练脚本封装在accelerate库里,这样就能启动我们一开始配置的训练环境了,同时我们将刚才配置好的config_file.toml和sample_prompt.toml参数传入训练脚本中。
接下来,就到了激动人心的时刻,我们只需在命令行输入以下命令,就能开始SDXL的全参微调训练啦:
# 进入SDXL-Trian项目中
cd SDXL-Trian
# 运行训练脚本!
sh SDXL_finetune.sh
训练脚本启动后,会打印出以下的log,方便我们查看整个训练过程的节奏:
running training / 学習開始
# 表示总的训练数据量,等于训练数据 * dataset_repeats: 1024 * 10 = 10240
num examples / サンプル数: 10240
# 表示每个epoch需要多少step,以8卡为例,需要10240/ (2 * 8) = 640
num batches per epoch / 1epochのバッチ数: 640
# 表示总的训练epoch数,等于total optimization steps / num batches per epoch = 64000 / 640 = 100
num epochs / epoch数: 100
# 表示每个GPU卡上的Batch Size数,最终的Batch Size还需要在此基础上*GPU卡数,以8卡为例:2 * 8 = 16
batch size per device / バッチサイズ: 2
#表示n个step计算一次梯度,一般设置为1
gradient accumulation steps / 勾配を合計するステップ数 = 1
# 表示总的训练step数
total optimization steps / 学習ステップ数: 64000
当我们设置1024分辨率+FP16精度+xformers加速时,SDXL模型进行Batch Size = 1的微调训练需要约24.7G的显存,进行Batch Size=14的微调训练需要约32.3G的显存 ,所以想要微调训练SDXL模型,最好配置一个32G以上的显卡,能让我们更加从容地进行训练。
到此为止,Rocky已经将SDXL全参微调训练的全流程都做了详细的拆解 ,等训练完成后,我们就可以获得属于自己的SDXL模型了!
4.4.5 加载自训练SDXL模型进行AI绘画
SDXL模型微调训练完成后,会将模型权重保存在我们之前设置的output_dir路径下。接下来,我们使用Stable Diffusion WebUI作为框架,加载SDXL二次元人物模型进行AI绘画 。
在本文3.3节零基础使用Stable Diffusion WebUI搭建Stable Diffusion XL推理流程中,Rocky已经详细讲解了如何搭建Stable Diffusion WebUI框架,未使用过的朋友可以按照这个流程快速搭建起Stable Diffusion WebUI。
要想使用SDXL模型进行AI绘画,首先我们需要将训练好的SDXL二次元人物模型放入Stable Diffusion WebUI的/models/Stable-diffusion文件夹下。
然后我们在Stable Diffusion WebUI中分别选用SDXL二次元人物模型即可: 完成上图中的操作后,我们就可以进行二次元人物图片的生成啦!
下面是使用本教程训练出来的SDXL二次元人物模型生成的图片:到这里,关于SDXL微调训练的全流程攻略就全部展示给大家了,大家如果觉得好,欢迎给Rocky的劳动点个赞,支持一下Rocky,谢谢大家!
如果大家对SDXL全参数微调训练还有想要了解的知识或者不懂的地方,欢迎在评论区留言,Rocky也会持续优化本文内容,能让大家都能快速了解SDXL训练知识,并训练自己的专属SDXL绘画模型!
4.5 基于SDXL训练LoRA模型
目前Stable Diffusion XL全参微调的训练成本是Stable Diffusion之前系列的2-3倍左右 ,而基于Stable Diffusion XL训练LoRA的成本与之前的系列相比并没有太多增加,故训练LoRA依旧是持续繁荣SDXL生态的高效选择 。
如果大家想要了解LoRA模型的核心基础知识,LoRA的优势,热门LoRA模型推荐等内容,可以阅读Rocky之前写的文章:
深入浅出完整解析LoRA(Low-Rank Adaptation)模型核心基础知识
在本节,Rocky将告诉大家从0到1使用SDXL模型训练对应的LoRA的全流程攻略 ,让我们一起来训练属于自己的SDXL LoRA模型吧!
4.5.1 SDXL LoRA数据集制作
首先,我们需要确定数据集主题,比如说人物,画风或者某个抽象概念等。本次我们选择用Rocky自己搜集的人物主题数据集——猫女数据集来进行SDXL LoRA模型的训练。
确定好数据集主题后,我们需要保证数据集的质量,Rocky总结了以下的SDXL LoRA训练数据集筛选要求 :
当我们训练人物主题 时,一般需要10-20张高质量数据;当我们训练画风主题 时,需要100-200张高质量数据;当我们训练抽象概念 时,则至少需要200张以上的数据。
不管是人物主题,画风主题还是抽象概念,一定要保证数据集中数据的多样性 (比如说猫女姿态,角度,全身半身的多样性)。
每个数据都要符合我们的审美和评判标准!每个数据都要符合我们的审美和评判标准!每个数据都要符合我们的审美和评判标准!
所以Rocky这次挑选的猫女数据集一共有22张图片,包含了猫女的不同姿态数据,并且每张图也符合Rocky的审美哈哈。
接下来,我们就可以按照本文4.3 Stable Diffusion XL数据集制作章节里的步骤 ,进行数据的清洗,自动标注,以及添加特殊tag——即触发词。在这里,我们要在标注文件的开头添加“catwomen”作为猫女的触发词 。
除了对数据进行标注,我们还需要对数据的标注进行清洗,删除一些概念与触发词重合的标签。为什么我们要进行数据标注的清洗呢?因为如果不对标注进行清洗,会导致训练时的tag污染 。
我们拿猫女数据集为例,我们想要让SDXL LoRA模型学习猫女的主要特征,包括脸部特征,服装特征(最具猫女特点的黑色皮衣和黑色眼罩 )等,我们想让“catwomen”学习到这些特征。但是自动标注会给数据打上一些描述脸部特征和服装特征的tag,导致猫女的主要特征被这些tag分走,从而导致tag污染。这样就会导致很多精细化的特征丢失在自动标注的tag中,使得SDXL LoRA在生成猫女图片时缺失黑色皮衣或者黑色眼罩等。
所以我们需要删除自动标注的脸部,服装等tag,从而使得保留下来的触发词等标签是SDXL LoRA模型着重需要学习的。
一张一张手动删除标签费时费力,Rocky这里推荐大家使用Stable Diffusion WebUI的一个数据标注处理插件:stable-diffusion-webui-dataset-tag-editor ,可以对标签进行批量处理,非常方便。
完成上述步骤,咱们的数据处理部分就告一段落了。为了方便大家使用猫女数据集进行后续的LoRA训练,Rocky这边已经将处理好的猫女数据集开源(包含原数据,标注文件,读取数据的json文件等) ,大家可以关注公众号WeThinkIn ,后台回复“猫女数据集 ”获取。
4.5.2 SDXL LoRA训练参数配置
大家可以在SDXL-Trian项目中train_config/XL_LoRA_config路径下找到SDXL LoRA的训练参数配置文件config_file.toml和sample_prompt.toml ,他们分别存储着SDXL_LoRA的训练超参数与训练中的验证prompt信息。
其中config_file.toml文件中的配置文件包含了sdxl_arguments,model_arguments,dataset_arguments,training_arguments,logging_arguments,sample_prompt_arguments,saving_arguments,optimizer_arguments以及additional_network_arguments九个个维度的参数信息。
训练SDXL_LoRA的参数配置与SDXL全参微调的训练配置有相同的部分(上述的前八个维度),也有LoRA的特定参数需要配置(additional_network_arguments)。
下面我们首先看看这些共同的维度中,有哪些需要注意的事项吧:
[sdxl_arguments] # 与SDXL全参微调训练一致
cache_text_encoder_outputs = true
no_half_vae = true
min_timestep = 0
max_timestep = 1000
shuffle_caption = false
[model_arguments] # 与SDXL全参微调训练一致
pretrained_model_name_or_path = "/本地路径/SDXL模型文件"
vae = "/本地路径/VAE模型文件" # 如果只使用模型自带的VAE,不读取额外的VAE模型,则需要将本行直接删除
[dataset_arguments] # 与SDXL全参微调训练不一致
#LoRA训练过程中取消了caption_dropout_rate = 0,caption_tag_dropout_rate = 0,
#caption_dropout_every_n_epochs = 0这三个参数,因为本身LoRA的模型容量较小,不需要再进行类标签Dropout的操作了。
debug_dataset = false
in_json = "/本地路径/data_meta_lat.json"
train_data_dir = "/本地路径/训练集"
dataset_repeats = 1
keep_tokens = 0
resolution = "1024,1024"
color_aug = false
token_warmup_min = 1
token_warmup_step = 0
[training_arguments] # 与SDXL全参微调训练不一致
# SDXL_LoRA增加了sdpa参数,当其设置为true时,训练中启动scaled dot-product attention优化,这时候就不需要再开启xformers了
output_dir = "/本地路径/模型权重保存地址"
output_name = "sdxl_lora_WeThinkIn"
save_precision = "fp16"
save_every_n_epochs = 1
train_batch_size = 4
max_token_length = 225
mem_eff_attn = false
sdpa = true
xformers = false
max_train_epochs = 100 #max_train_epochs设置后,会覆盖掉max_train_steps,即两者同时存在时,以max_train_epochs为准
max_data_loader_n_workers = 8
persistent_data_loader_workers = true
gradient_checkpointing = true
gradient_accumulation_steps = 1
mixed_precision = "fp16"
[logging_arguments] # 与SDXL全参微调训练一致
log_with = "tensorboard"
logging_dir = "/本地路径/logs"
log_prefix = "sdxl_lora_WeThinkIn"
[sample_prompt_arguments] # 与SDXL全参微调训练一致
sample_every_n_epochs = 1
sample_sampler = "euler_a"
[saving_arguments] # 与SDXL全参微调训练一致
save_model_as = "safetensors"
[optimizer_arguments] # 与SDXL全参微调训练不一致
optimizer_type = "AdaFactor"
learning_rate = 1e-5 # 训练SDXL_LoRA时,学习率可以调的大一些,一般比SDXL全参微调的学习率大10倍左右,比如learning_rate = 1e-5
max_grad_norm = 0
optimizer_args = [ "scale_parameter=False", "relative_step=False", "warmup_init=False",]
lr_scheduler = "constant_with_warmup"
lr_warmup_steps = 100
除了上面的参数,训练SDXL_LoRA时还需要设置一些专属参数,这些参数非常关键,下面Rocky将给大家一一讲解:
[additional_network_arguments]
no_metadata = false
network_module = "networks.lora"
network_dim = 32
network_alpha = 16
network_args = [ "conv_dim=32", "conv_alpha=16",]
network_train_unet_only = true
no_metadata:保存模型权重时不附带Metadata数据,建议关闭,能够减少保存下来的LoRA大小。
network_module:选择训练的LoRA模型结构,可以从[“networks.lora”, “networks.dylora”, “lycoris.kohya”]中选择,最常用的LoRA结构默认选择”networks.lora” 。
network_dim:设置LoRA的RANK,设置的数值越大表示表现力越强,但同时需要更多的显存和时间来训练。
network_alpha:设置缩放权重,用于防止下溢并稳定训练的alpha值。
network_args:设置卷积的Rank与缩放权重。
下面表格中Rocky给出一些默认配置,大家可以作为参考:
network_category
network_dim
network_alpha
conv_dim
conv_alpha
LoRA
32
1
–
–
LoCon
16
8
8
1
LoHa
8
4
4
1
如果我们想要训练LoRA ,我们需要设置network_module = “networks.lora”,同时设置network_dim和network_alpha,和上面的配置一致。
如果我们想要训练LoCon ,我们需要设置network_module = “lycoris.kohya”和algo=“locon”,同时设置network_dim和network_alpha:
network_module = "lycoris.kohya"
algo = "locon"
network_dim = 32
network_alpha = 16
network_args = [ "conv_dim=32", "conv_alpha=16",]
如果我们想要训练LoHa ,我们需要设置network_module = “lycoris.kohya”和algo=“loha”,同时设置network_dim和network_alpha:
network_module = "lycoris.kohya"
algo = "loha"
network_dim = 32
network_alpha = 16
network_args = [ "conv_dim=32", "conv_alpha=16",]
network_train_unet_only:如果设置为true,那么只训练U-Net部分。
4.5.3 SDXL LoRA关键参数详解
【1】train_batch_size对SDXL LoRA模型训练的影响
和传统深度学习一样,train_batch_size即为训练时的batch size,表示一次性送入SDXL LoRA模型进行训练的图片数量。
一般来说,较大的batch size 往往每个epoch训练时间更短,但是显存占用会更大,并且收敛得慢 (需要更多epoch数)。较小的batch size 每个epoch训练时间长,但是显存占用会更小,并且收敛得快 (需要更少epoch数)。
但是有研究表明这个结论会在batch size大于8000的时候才会体现 ,所以在实际的训练时,如果GPU数不大于8卡的话,还是需要尽可能占满GPU显存为宜,比如64-96之间(理论上batch size = 时计算效率较高),训练一般都能取得不错效果。
上面的结论在训练SDXL大模型时是非常适用的,不过我们在训练SDXL LoRA模型时,一般来说数据量级是比较小的(10-300为主),所以在这种情况下,我们可以设置batch size为2-6即可。
【2】pretrained_model_name_or_path对SDXL LoRA模型训练的影响
pretrained_model_name_or_path参数中我们需要加载本地的SDXL模型作为训练底模型。
底模型的选择至关重要,SDXL LoRA的很多底层能力与基础概念的学习都来自于底模型的能力 。并且底模型的优秀能力需要与我们训练的主题,比如说人物,画风或者某个抽象概念相适配。如果我们要训练二次元LoRA,则需要选择二次元底模型,如果我们要训练三次元LoRA,则需要选择三次元底模型,以此类推。
【3】network_dim对SDXL LoRA模型训练的影响
network_dim即特征维度,越高表示模型的参数量越大,设置高维度有助于LoRA学习到更多细节特征,但模型收敛速度变慢,同时也更容易过拟合,需要的训练时间更长 。所以network_dim的设置需要根据任务主题去调整。
一般来说,在SDXL的1024*1024分辨率训练基础上,可以设置network_dimension = 128,此时SDXL LoRA大小约为686MB。
【4】network_alpha对SDXL LoRA模型训练的影响
network_alpha是一个缩放因子,用于缩放模型的训练权重 W W W, W = W i n × a l p h a / d i m W = W_{in} times alpha / dim W=Win×alpha/dim。network_alpha设置的越高,LoRA模型能够学习更多的细节信息,同时学习速率也越快 ,推荐将其设置为network_dimension的一半。
4.5.4 SDXL LoRA模型训练
完成训练参数配置后,我们就可以运行训练脚本进行SDXL_LoRA模型的训练了。
我们本次训练用的底模型选择了WeThinkIn_SDXL_真人模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SDXL_真人模型 ”获取模型资源链接。
我们打开SDXL_fintune_LoRA.sh脚本,可以看到以下的代码:
accelerate launch
--config_file accelerate_config.yaml
--num_cpu_threads_per_process=8
/本地路径/SDXL-Train/sdxl_train_network.py
--sample_prompts="/本地路径/SDXL-Train/train_config/XL_LoRA_config/sample_prompt.toml"
--config_file="/本地路径/SDXL-Train/train_config/XL_LoRA_config/config_file.toml"
我们把训练脚本封装在accelerate库里,这样就能启动我们一开始配置的训练环境了,同时我们将刚才配置好的config_file.toml和sample_prompt.toml参数传入训练脚本中。
接下来,就到了激动人心的时刻,我们只需在命令行输入以下命令,就能开始SDXL_LoRA训练啦:
# 进入SDXL-Trian项目中
cd SDXL-Trian
# 运行训练脚本!
sh SDXL_fintune_LoRA.sh
当我们基于SDXL训练SDXL LoRA模型时,我们设置分辨率为1024+FP16精度+xformers加速时,进行Batch Size = 1的微调训练需要约13.3G的显存,进行Batch Size=8的微调训练需要约18.4G的显存 ,所以想要微调训练SDXL LoRA模型,最好配置一个16G以上的显卡,能让我们更加从容地进行训练。
4.5.5 加载SDXL LoRA模型进行AI绘画
SDXL LoRA模型训练完成后,会将模型权重保存在我们之前设置的output_dir路径下。接下来,我们使用Stable Diffusion WebUI作为框架,加载SDXL LoRA模型进行AI绘画。
在本文3.3节零基础使用Stable Diffusion WebUI搭建Stable Diffusion XL推理流程中,Rocky已经详细讲解了如何搭建Stable Diffusion WebUI框架,未使用过的朋友可以按照这个流程快速搭建起Stable Diffusion WebUI。
要想使用SDXL LoRA进行AI绘画,首先我们需要将SDXL底模型和SDXL LoRA模型分别放入Stable Diffusion WebUI的/models/Stable-diffusion文件夹和/models/Lora文件夹下。
然后我们在Stable Diffusion WebUI中分别选用底模型与LoRA即可: 完成上图中的操作后,我们就可以进行猫女图片的生成啦!
【1】训练时的底模型+猫女LoRA
首先我们使用训练时的底模型作为测试底模型,应选用训练好的猫女LoRA,并将LoRA的权重设为1,看看我们生成的图片效果如何: 我们可以看到,生成的猫女图片的完成度还是非常好的,不管是整体质量还是细节都能展现出猫女该有的气质与魅力。并且在本次训练中猫女的手部特征也得到了较好的学习,优化了一直困扰AI绘画的手部问题 。
【2】设置LoRA的不同权重
接下来,我们设置LoRA的权重分别为[0.2, 0.4, 0.6, 0.8, 1],进行对比测试,看看不同SDXL LoRA权重下的图片生成效果如何: 从上图的对比中可以看出,当SDXL LoRA设置的权重越高时,训练集中的特征越能载生成图片中展现,比如说猫女的人物特征,猫女的服装特征以及生成的猫女有无面罩等。但LoRA的权重也不是越高越好,当设置权重为0.6-0.8之间,生成的图片会有更多的泛化性 。
【3】切换不同的底模型
完成了在单个底模型上的SDXL LoRA不同权重的效果测试,接下来我们切换不同的底模型,看看会生成的猫女图片会有什么变化吧。
首先,我们将底模型切换成SDXL Base模型,使用猫女LoRA并设置权重为1: 从上面的图中可以看出,使用SDXL Base模型作为底模型后,生成的猫女图片整体质感已经发生改变,背景也有了更多光影感 。
我们再使用SDXL的二次元模型作为底模型,同样使用猫女LoRA并设置权重为1: 可以看到,换用二次元模型作为底模型后,生成的猫女图片整体质感开始卡通化。但是由于训练数据集中全是三次元图片,所以二次元底模型+三次元LoRA生成的图片并没有完全的二次元化。
【4】使用不同提示词改变图片风格
最后,我们再尝试通过有添加提示词prompt,来改变生成的猫女图片的风格。
首先,我们在提示词prompt中加入赛博朋克风格“Cyberpunk style”,这是生成的猫女图片中就会加入赛博朋克元素了:到这里,关于SDXL LoRA的全流程攻略就全部展示给大家了,大家如果觉得好,欢迎给Rocky的劳动点个赞,支持一下Rocky,谢谢大家!
如果大家对SDXL LoRA还有想要了解的知识或者不懂的地方,欢迎在评论区留言,Rocky也会持续优化本文内容,能让大家都能快速了解SDXL LoRA知识,并训练自己的专属LoRA模型!
4.6 SDXL训练结果测试评估
之前的章节讲述了SDXL模型微调和SDXL LoRA模型训练后的效果测试评估流程,那么在本小节,Rocky向大家介绍一下AI绘画模型测试评估的一些通用流程与技巧。
在进行AI绘画时,我们需要输入正向提示词(positive prompts)和负向提示词(negative prompts)。
正向提示词一般需要输入我们想要生成的图片内容,包括我们训练好的特殊tag等。
不过在正向提示词的开头,一般都需要加上提高生成图片整体质量的修饰词,Rocky这里推荐一套“万金油”修饰词,方便大家使用:
(masterpiece,best quality,ultra_detailed,highres,absurdres:1.2)
负向提示词一般需要输入我们不想生成的内容,在这里Rocky再分享一套基于SDXL的“万金油”负向提示词,方便大家使用:
(worst quality, low quality, ugly:1.4), poorly drawn hands, poorly drawn feet, poorly drawn face, out of frame, mutation, mutated, extra limbs, extra legs, extra arms, disfigured, deformed, cross-eye, blurry, (bad art, bad anatomy:1.4), blurred, text, watermark
当然的,我们也可以使用ChatGPT辅助生成提示词 ,在此基础上我们再加入训练好的特殊tag并对提示词进行修改润色。
在我们进行模型测试的时候,如果存在生成图片质量不好,生成图片样式单一或者生成图片崩坏的情况,就需要优化数据或者参数配置,重新训练了。
4.7 SDXL训练经验分享(持续更新!)
在本节中,Rocky将向大家持续分享关于SDXL和SDXL LoRA等模型的训练经验,大家有自己的经验,也欢迎在评论区补充,我们一起让AIGC和AI绘画领域更加繁荣!
数据质量标准 :图片的文件容量(占用的内存)越大越好,图像的分辨率越大越好,同时数据内容的是符合我们训练的领域的专业审美与标准的。
数据质量最为重要 :切勿在没有保证数据质量的前提下,盲目扩充数据数量,这样只会导致低质量数据污染整个数据集,从而导致模型训练后的图片生成效果不理想。
数据集中类别均衡 :确保数据集中每种风格、主题、概念等各种维度的类别有大致相同的数量。使用均衡的数据集训练出来的SDXL模型,具备多功能性,可以作为未来训练的基础SDXL模型。
细分类别精细化训练 :对整个数据集,我们进行统一的训练,整体上效果是可以保证的。但是可能会存在一些难类别/难样本/难细节等,在这些场景中模型的训练效果不好。这时可以针对这些bad case,补充庞大且高质量的素材进行优化训练(每个素材强化训练80-100步)。
数据标签质量 :每张图片都需要经过仔细的数据标注,能够较好的表达呈现图片中的内容,才算是一个好的标签。高质量的数据标签能够增强模型用最少的提示词生成高质量图片的能力和生成图片内容的准确性。
数据增强手段 :数据多尺寸处理、素材去水印、图像特殊部分(手部、服装等)mask处理等。
Rocky将持续把Stable Diffusion XL训练的经验与思考分享出来,大家先点赞收藏敬请期待!!!
5. 生成式模型的性能测评
到目前为止,AIGC领域的测评过程整体上还是比较主观。Stable Diffusion XL在性能测评时使用了FID(Fréchet inception distance),CLIP score以及人类视觉系统(HVS)评价这三个指标作为文生图的标价指标 ,其中人类视觉系统依旧是占据主导地位 。
下面,跟着Rocky一起来看看各个评价指标的意义与特点,以及在不同的实际场景中,该如何对生成式模型做出有效的评估。
5.1 FID(Fréchet inception distance)
FID(Fréchet inception distance) 表示生成图像与真实图像之间的相似性 ,即图像的真实度。FID表示的是生成图像的特征向量与真实图像的特征向量之间的距离,该距离越近(值越小),表明生成模型的效果越好 ,即图像的清晰度高,且多样性丰富。
FID是通过Inception模型进行计算的。主要流程是将生成图像和真实图像输入到Inception模型中,并提取倒数第二层的2048维向量进行输出,最后计算两者特征向量之间的距离。
由于Stable Diffusion XL模型是文生图模型,并不存在原本的真实图像,所以一般选用COCO验证集上的zero-shot FID-30K(选择30K的样本)与生成图像进行求FID操作,并将其中最小的FID用于不同模型之间的性能对比 。
但是有研究指出,FID对深入的文本理解,独特艺术风格之间的精细区分,以及明显的视觉美感等AIGC时代特有的特征不能很好的评估。同时也有研究表明,zero-shot FID-30K与视觉美学呈负相关 。
5.2 CLIP score
CLIP score 可以用于评估文生图/图生图中生成图像与输入Prompt文本以及生成图像与输入原图像的匹配度 。以文生图为例,我们使用CLIP模型将Prompt文本和生成图像分别转换为特征向量,然后计算它们之间的余弦相似度。当CLIP Score较高时,表示生成图像与输入Prompt文本之间的匹配度较高;当CLIP Score较低时,表示生成图像与输入Prompt文本之间的匹配度较低 。 从上表可以看出,SDXL在CLIP score上得分最高 ,由于使用了两个CLIP Text Encoder进行约束,SDXL对文本内容的控制力确实强了不少。但是SDXL在FID指标上也同步上升了 ,并且比之前的系列都要高,刚才在介绍FID指标的内容中,Rocky已经阐述过很多研究都表明FID在AIGC时代不能很好的作为美学评价指标,甚至与视觉美学呈负相关,在SDXL的论文中更加证实了这一点。所以在此基础上,最后又增加了人类视觉系统作为评价指标(同样的参数让SD系列的不同模型生成图像,并让人工评价出最好的图像),在人类评估者眼中,明显更加喜欢SDXL生成的图片 ,结果如下所示:
5.3 Aesthetics Scorer(美学评分)
除了上述提到的三种评价指标,我们还可以用Aesthetics Scorer(美学评分) 对Stable DIffusion系列模型生成的图片进行评分。Aesthetics Scorer背后的评价标准数据集是基于LAION-Aesthetics ,也就是Stable Diffusion系列训练时有用到的数据集,所以Aesthetics Scorer有一定的可靠性。
5.4 与Midjourney系列进行对比
完成和Stable Diffusion之前系列的对比之后,SDXL还与Midjourney v5.1和Midjourney v5.2进行了对比。
这里主要使用谷歌提出的文生图测试prompts:PartiPrompts(P2) 作为测试基准。Parti Prompts(P2)包含了1600多个英文prompts ,覆盖了不同的类别与复杂度,可以说是一个高价值基准。 在具体比较时,从PartiPrompts(P2)的每个类别中选择五个随机prompts,并由Midjourney v5.1和SDXL分别生成四张1024×1024分辨率的图像。然后将这些图像提交给AWS GroundTruth工作组,工作组根据图像与prompts的匹配度进行投票(Votes) 。投票结果如下图所示,总体而言,SDXL的生成效果略高于Midjourney v5.1(54.9%:45.1%):
除了Midjourney v5.1之外,SDXL还与DeepFloyd IF、DALLE-2、Bing Image Creator和Midjourney v5.2进行了定性比较,这些都是AIGC领域的高价值与强生态模型 ,对比结果已经在下图展示,大家可以对比了解一下:总的来说,不管是在传统深度学习时代还是在AIGC时代,生成式模型的生成效果一直存在难以量化和难以非常客观评价的问题,需要人类视觉系统去进行兜底与约束。
那么,在不同的实际场景中,我们该如何对SDXL等生成式模型做出务实的评价呢?
5.5 不同实际场景的务实评估
其实在不同的实际场景中,最务实有效的AIGC模型评估手段是判断模型是否具备价值 。
从投资视角看 ,价值是有产生类ChatGPT效应或者类妙鸭相机流量的潜在势能,比如在团队内部或者让潜在投资人产生了“哇塞时刻”。
从CEO角度看 ,价值是在ToB领域能解决客户的问题;在ToC领域能获得用户的好评并存在成为爆款的潜在可能性。
从CTO角度看 ,价值是能够在严谨的验证中发表论文;能够在顶级算法竞赛中斩获冠军;能够作为产品解决方案的一部分,让产品“焕然一新”。
由于模型本身是“黑盒”,无法量化分析模型结构本身,而评估模型生成的内容质量的指标又离不开人类视觉系统的支持。那就把模型融入到产品中,融入到算法解决方案中,在一次次的实际商业“厮杀”中,来反馈验证模型的性能。
6. SDXL Turbo模型核心基础内容完整讲解
2023年11月29日,StabilityAI官方发布了最新的快速文生图模型SDXL Turbo ,目前代码、模型和技术报告已经全部开源 。
6.1 SDXL Turbo整体架构初识
SDXL Turbo模型是在SDXL 1.0模型的基础上设计了全新的蒸馏训练方案(Adversarial Diffusion Distillation,ADD),经过蒸馏训练得到的。SDXL Turbo模型只需要1-4步就能够生成高质量图像,这接近实时的性能,无异让AI绘画领域的发展更具爆炸性,同时也为未来AI视频的爆发奠定坚实的基础。
SDXL Turbo模型本质上依旧是SDXL模型,其网络架构与SDXL一致,可以理解为一种经过蒸馏训练后的SDXL模型,优化的主要是生成图像时的采样步数。
不过SDXL Turbo模型并不包含Refiner部分,只包含U-Net(Base)、VAE和CLIP Text Encoder三个模块 。在FP16精度下SDXL Turbo模型大小6.94G(FP32:13.88G),其中U-Net(Base)大小5.14G,VAE模型大小167M以及两个CLIP Text Encoder:一大一小分别是1.39G和246M。
6.2 SDXL Turbo核心原理详解
既然我们已经知道SDXL Turbo模型结构本质上是和SDXL一致,那么其接近实时的图片生成性能主要还是得益于最新的Adversarial Diffusion Distillation(ADD)蒸馏方案 。
模型蒸馏技术在传统深度学习时代就应用广泛,只是传统深度学习的落地场景只局限于ToB,任务范围不大且目标定义明确,大家往往人工设计轻量型的目标检测、分割、分类小模型来满足实际应用需求,所以当时模型蒸馏技术显得有些尴尬。
但是到了AIGC时代,大模型成为“AI舞台“上最耀眼的明星,让模型蒸馏技术重新繁荣,应用于各个大模型的性能实时化中,Rocky相信模型蒸馏技术将在AIGC时代成为一个非常关键的AI技术工具 。
接下来,就让我们一起解析ADD蒸馏方案的核心知识吧。首先ADD蒸馏方案的整体架构如下图所示:
ADD蒸馏方案的核心流程包括:将预训练好的SDXL 1.0 Base模型作为学生模型(预训练好的网络能显著提高对抗性损失(adversarial loss)的训练效果 ),它接收经过forward diffusion process后的噪声图片,并输出去噪后的图片,然后用这个去噪后的图片与原图输入判别器中计算adversarial loss以及与教师模型(一个冻结权重的强力Diffusion Model)输出的去噪图片计算distillation loss。ADD蒸馏算法中主要通过优化这两个loss来训练得到SDXL Turbo模型:
adversarial loss :借鉴了GAN的思想,设计了Hinge loss(支持向量机SVM中常用的损失函数)作为SDXL Turbo模型的adversarial loss,通过一个Discriminator来辨别学生模型(SDXL 1.0 Base模型)生成的图像和真实的图像,以确保即使在一个或两个采样步数的低步数状态下也能有高图像保真度,同时避免了其他蒸馏方法中常见的失真或模糊问题 。
distillation loss :经典的蒸馏损失函数,让一个强力Diffusion Model作为教师模型并冻结参数,让学生模型(SDXL 1.0 Base模型)的输出和教师模型的输出尽量一致,具体计算方式使用的是机器学习中经典的L2损失 。
最后,ADD蒸馏训练中总的损失函数就是adversarial loss和distillation loss的加权和,如下图所示,其中权重 λ lambda λ=2.5:
6.3 SDXL Turbo效果测试
因为SDXL Turbo网络结构与SDXL一致,所以大家可以直接在Stable Diffusion WebUI上使用SDXL Turbo模型,我们只需按照本文3.3章中的教程使用Stable Diffusion WebUI即可。
同时ComfyUI也支持SDXL Turbo的使用:ComfyUI SDXL Turbo Examples ,然后我们按照本文3.1章的教程使用ComfyUI工作流即可运行SDXL Turbo。
当然的,diffusers库最早原生支持SDXL Turbo的使用运行,可以进行文生图和图生图的任务 ,相关代码和操作流程如下所示:
# 加载diffusers和torch依赖库
from diffusers import AutoPipelineForText2Image
import torch
# 构建SDXL Turbo模型的Pipeline,加载SDXL Turbo模型
pipe = AutoPipelineForText2Image.from_pretrained("/本地路径/sdxl-turbo", torch_dtype=torch.float16, variant="fp16")
# "/本地路径/sdxl-turbo"表示我们需要加载的SDXL Turbo模型,
# 大家可以关注Rocky的公众号WeThinkIn,后台回复:SDXL模型,即可获得资源链接,里面包含SDXL Turbo模型权重文件
# "fp16"代表启动fp16精度。比起fp32,fp16可以使模型显存占用减半。
# 使用GPU进行Pipeline的推理
pipe.to("cuda")
# 输入提示词
prompt = "A cinematic shot of a baby racoon wearing an intricate italian priest robe."
# Pipeline进行推理
image = pipe(prompt=prompt, num_inference_steps=1, guidance_scale=0.0).images[0]
# Pipeline生成的images包含在一个list中:[]
#所以需要使用images[0]来获取list中的PIL图像
运行上面的整个代码流程,我们就能生成一张小浣熊的图片了。这里要注意的是,SDXL Turbo模型在diffusers库中进行文生图操作时不需要使用guidance_scale和negative_prompt参数,所以我们设置guidance_scale=0.0 。
接下来,Rocky再带大家完成SDXL Turbo模型在diffusers中图生图的整个流程:
from diffusers import AutoPipelineForImage2Image
from diffusers.utils import load_image
pipe = AutoPipelineForImage2Image.from_pretrained("/本地路径/sdxl-turbo", torch_dtype=torch.float16, variant="fp16")
pipe.to("cuda")
init_image = load_image("/本地路径/用于图生图的原始图片").resize((913, 512))
prompt = "Miniature model, axis shifting, reality, clarity, details, panoramic view, suburban mountain range, game suburban mountain range, master work, ultra-high quality, bird's-eye view, best picture quality, 8K, higher quality, high details, ultra-high resolution, masterpiece, full of tension, realistic scene, top-level texture, top-level light and shadow, golden ratio point composition, full of creativity, color, future city, technology, smart city, aerial three-dimensional transportation, pedestrian and vehicle separation, green building, macaron color, gorgeous, bright"
image = pipe(prompt, image=init_image, num_inference_steps=2, strength=0.5, guidance_scale=0.0).images[0]
运行上面的整个代码流程,我们就能生成一张新的城郊山脉的图片。需要注意的是,当在diffusers中使用SDXL Turbo模型进行图生图操作时,需要确保num_inference_steps * strength大于或等于1。因为前向推理的步数等于int(num_inference_steps * strength)步 。比如上面的例子中,我们就使用SDXL-Turbo模型前向推理了0.5 * 2.0 = 1 步。
Stability AI官方发布的技术报告中表示SDXL Turbo和SDXL相比,在推理速度上有大幅的提升。在A100上,SDXL Turbo以207ms的速度生成一张512×512的图像(prompt encoding + a single denoising step + decoding, fp16),其中U-Net部分耗时占用了67ms 。
Rocky也测试了一下SDXL Turbo的图像生成效率,确实非常快,在V100上,4 steps生成512×512尺寸的图像基本可以做到实时响应(1.02秒,平均1 step仅需250ms) 。
在我们输入完最后一个prompt后,新生成的图像就能马上显示,推理速度确实超过了Midjourney、DALL·E 3以及之前的Stable Difusion系列模型,可谓是“天下武功,无坚不破,唯快不破”的典范。SDXL Turbo在生成速度快的同时,生成的图像质量也非常高,可以比较精准地还原prompt的描述 。
为了测试SDXL Turbo的性能,StabilityAI使用相同的文本提示,将SDXL Turbo与SDXL、LCM-XL等不同版本的文生图模型进行了比较。测试结果显示,在图像质量和Prompt对齐方面,SDXL Turbo只用1个step,就击败了LCM-XL用4个steps生成的图像,并且达到了SDXL 1.0 Base通过50个steps生成的图像效果 。
接着当我们将采样步数提高到4时,SDXL Turbo在图像质量和Prompt对齐方面都已经略微超过SDXL 1.0 Base模型:
论文里表示目前SDXL Turbo只能生成512×512像素的图片 ,Rocky推测当前开源的SDXL Turbo只在单一尺寸上进行了蒸馏训练,后续估计会有更多优化版本发布。Rocky也在512×512像素下测试了不同steps(1-8 steps)时SDXL Turbo的图片生成效果,对比结果如下所示:
可以看到当steps为1和4时,效果都非常好,并且4steps比1step效果更好 ,这是可以理解的。不过当steps大于4之后,生成的图像明显开始出现过拟合现象 。总的来说,如果是急速出图的场景,可以选择1 step;如果想要生成更高质量图像,推荐选择4 steps 。
同时Rocky测试了一下SDXL Turbo在不同尺寸(768×768,1024×1024,512×768,768×1024,768×512,1024×768共6中尺寸 )下的图像生成质量,可以看到除了1024×1024存在一定的图片特征不完善的情况,其余也具备一定的效果,但是整体上确实不如512×512的效果好。
SDXL Turbo的一个直接应用,就是与游戏相结合,获得2fps的风格迁移后的游戏画面:
SDXL Turbo的另外一个直接应用是成为SDXL的“化身” ,代替SDXL去快速验证各种AI绘画工作流的有效性,助力AI绘画领域的持续繁荣与高效发展。
SDXL Turbo发布后,未来AI绘画和AI视频领域有了更多的想象空间。一定程度上再次整合加速了AIGC领域的各种工作流应用,未来的潜力非常大。不过由于SDXL Turbo模型需要通过蒸馏训练获得,并且其中包含了GAN的对抗损失训练,在开源社区中像训练自定义的SDXL模型一样训练出特定SDXL Turbo模型,并且能保证出图的质量,目前来看是有一定难度的 。
SD Turbo模型介绍
SD Turbo模型是在Stable Diffusion V2.1的基础上,通过蒸馏训练得到的精简版本,其本质上还是一个Stable Diffusion V2.1模型,其网络架构不变。
比起SDXL Turbo,SD Turbo模型更小、速度更快,但是生成图像的质量和Prompt对齐方面不如前者。
但是在AI视频领域,SD Turbo模型有很大的想象空间,因为Stable Video Diffusion的基础模型是Stable Diffusion V2.1,所以未来SD Turbo模型在AI视频领域很可能成为AI视频加速生产的有力工具之一。
为了测试SD Turbo的性能,StabilityAI使用相同的文本提示,将SD Turbo与LCM-LoRA 1.5和LCM-LoRA XL等不同版本的文生图模型进行了比较。测试结果显示,在图像质量和Prompt对齐方面,SD Turbo只用1个step,就击败了LCM-LoRA 1.5和LCM-LoRA XL生成的图像。
diffusers库已经支持SDXL Turbo的使用运行了,可以进行文生图和图生图的任务 ,相关代码和操作流程如下所示:
from diffusers import AutoPipelineForText2Image
import torch
pipe = AutoPipelineForText2Image.from_pretrained("/本地路径/sd-turbo", torch_dtype=torch.float16, variant="fp16")
pipe.to("cuda")
prompt = "A cinematic shot of a baby racoon wearing an intricate italian priest robe."
image = pipe(prompt=prompt, num_inference_steps=1, guidance_scale=0.0).images[0]
这里要注意的是,SD Turbo模型在diffusers库中进行文生图操作时不需要使用guidance_scale和negative_prompt参数,所以我们设置guidance_scale=0.0 。
接下来,Rocky再带大家完成SD Turbo模型在diffusers中图生图的整个流程:
from diffusers import AutoPipelineForImage2Image
from diffusers.utils import load_image
import torch
pipe = AutoPipelineForImage2Image.from_pretrained("/本地路径/sd-turbo", torch_dtype=torch.float16, variant="fp16")
pipe.to("cuda")
init_image = load_image("/本地路径/test.png").resize((512, 512))
prompt = "cat wizard, gandalf, lord of the rings, detailed, fantasy, cute, adorable, Pixar, Disney, 8k"
image = pipe(prompt, image=init_image, num_inference_steps=2, strength=0.5, guidance_scale=0.0).images[0]
需要注意的是,当在diffusers中使用SD Turbo模型进行图生图操作时,需要确保num_inference_steps*strength大于或等于1。因为前向推理的步数等于int(num_inference_steps * strength)步。比如上面的例子中,我们就使用SD Turbo模型前向推理了0.5 * 2.0 = 1 步 。
7. Playground v2.5核心基础内容完整讲解
2024年2月28号,Playground发布了最新的文生图模型Playground v2.5,其是Playground v2.0模型的升级版本 。Playground v2.5在美学质量,颜色和对比度,多尺度生成以及以人为中心的细节处理 等方面有比较大的提升,使得Playground v2.5显著优于主流的开源模型(如SDXL、Playground v2和PixArt-⍺)和闭源模型(如Midjourney v5.2和DALL-E 3)。 下面,Rocky就和大家一起研究探讨Playground v2.5的优化方法。
7.1 Playground v2.5模型整体架构讲解
Playground v2.5的模型架构与SDXL的模型架构完全一致 ,在此基础上Playground v2.5设计了针对性的优化训练方法(增强颜色和对比度、改善多种长宽比的图像生成效果,以及改善以人为中心的细节 )来显著提升生成图片的质量。
总的来说,把Playground v2.5看作是SDXL的调优版本也不为过,这些优化训练的方法具备很强的兼容性,能在AI绘画领域的其他模型上进行迁移应用,非常有价值!
7.1.1 增强颜色和对比度
基于Latent Diffusion架构的AI绘画模型通常难以生成色彩鲜艳、对比度高的图像,这是SD 1.x系列以来就存在的问题。尽管SDXL在生成图片的美学质量上相比之前的版本有了显著的改进,但它的色彩和对比度依然较为柔和,有概率无法生成纯色图像或者无法将生成主体放置在纯色背景上。
这个问题源于扩散模型在扩散过程设置的noise schedule:Stable Diffusion的信噪比太高,即使在离散噪声水平达到最大时也是如此 。Offset Noise 和Zero Terminal SNR 等工作能够优化这个问题,因此SDXL在训练的最后阶段采用了Offset Noise,有一定的优化效果。
Playground v2.5模型则采取了更为直接的方法,从零开始使用EDM框架训练,而不是在SDXL的基础上进行微调训练 。EDM框架为Playground v2.5带来了显著的性能优势,EDM的noise schedule在最后的Timestep中展示出接近零的信噪比,我们可以不再使用offset noise的情况下增强AI绘画模型出图的颜色和对比度,同时能让模型在训练中更快的收敛。
下图是Playground v2.5模型和SDXL模型的生成图片效果对比,可以看到Playground v2.5模型生成的图片对比度更好: 下图是Playground v2.5模型生成图片的颜色与对比度质量:
7.1.2 改善多种长宽比的图像生成效果
在AI绘画领域中,生成多种长宽比(1:1、1:2、2:1、3:4、4:3、9:16、16:9等)尺寸的高质量图像是AI绘画模型能够在学术界、工业界、竞赛界以及用户侧受欢迎的重要能力。
目前很多主流的AI绘画模型在训练时一般只采用一种分辨率(比如通过随机或中心裁剪获得1:1尺寸)进行训练,虽然这些AI绘画模型中包含了卷积结构,卷积的平移不变性能一定程度上适应在推理时生成任何分辨率的图像,但是如果训练时只使用了一种尺寸,那么AI绘画模型大概率会过拟合在一个尺寸上,在其他不同尺寸上的出图效果会有问题(泛化性差、图像结构错误、内容缺失等) 。
为了解决这个问题,SDXL尝试了NovelAI提出的一种宽高比分桶策略,确实是有一定的效果。但是如果数据集的分辨率分布本身已经很不均衡了,这时SDXL仍然会学习到数据集里的长宽尺寸的不均衡偏见 。
Playground v2.5在SDXL的分桶策略基础上,设计了更加细分的数据Bucket管道,来确保一个更平衡的桶采样策略。新的分桶策略避免了AI绘画模型在训练时对尺寸的灾难性遗忘,并帮助AI绘画模型不会偏向某个特定的尺寸 。
7.1.3 改善以人为中心的细节
改善以人为中心的细节,即使AI绘画模型的输出结果与人类偏好对齐 。在AIGC时代,不管是AI绘画大模型还是AI对话大模型,都存在模型产生“幻觉”的情况。这在AI绘画领域的具体表现包括写实人物的人体特征崩坏(如手、脸、躯干等结构错误和特征缺失),这使得一张构图和风格都非常高质量的图片也可能存在“恐怖谷”效应。
为了缓解这个问题,Playground v2.5设计了一种类似于SFT(SFT是在LLM s中常用的策略,用于使模型与人类偏好对齐并减少错误 )的对齐策略,用于AI绘画模型。新的对齐策略使Playground v2.5在至少四个重要的以人为中心的类别上超越了SDXL的效果:
面部细节、清晰度和生动度
眼睛的形状和凝视状态
头发的纹理质地
整体的光照、颜色、饱和度和景深
7.2 Playground v2.5模型效果测试
Playground官方在AIGC时代引入了互联网产品思维 ,直接将Playground v2.5模型上线到产品中让用户进行测试评估(用户评估,User Evaluations)。Playground官方认为这是收集用户反馈、测评AI绘画模型的最佳环境与方式,并且是最严格的测试 ,能判断AI绘画模型是否真正为用户提供了有价值和收到用户喜爱,从而能够反哺整个AI绘画生态与社区。 我们首先来看一下Playground官方的模型测试评估效果。
首先将Playground v2.5与世界级的主流开源AI绘画模型SDXL(提高了4.8倍)、PixArt-α(提高了2.4倍)和Playground v2(提高了1.6倍),以及世界级的闭源模型Midjourney v5.2(提高了1.2倍)和DALL·E 3(提高了1.5倍)进行了对比测试,Playground v2.5的美学质量显著优于当前最先进的这些AI绘画模型。
接着,在9:16、2:3、3:4、1:1、4:3、3:2、16:9等多分辨率尺寸生成质量方面,Playground v2.5也远远超过了SDXL模型。
人像写实图像是AI绘画领域的生成主力军,能占到AI绘画生成总量的80%左右 。所以针对人像生成这块,官方将Playground v2.5与SDXL、RealStock v2两个模型进行测试对比,RealStock v2模型在SDXL的基础上针对人像场景进行了微调训练。从下图中可以看出,Playground v2.5在人像生成方面的美学质量远远超过了这两个模型。
最后,在MJHQ-30K评测上,Playground v2.5在总体FID和所有类别FID指标(所有FID指标都是在1024×1024的分辨率下计算的 )上都超过了Playground v2和SDXL,特别是在人物和时尚类别上。MJHQ-30K评测结果与用户评估的结果一致,这也表明人类偏好与MJHQ-30K基准的FID得分之间存在着相关性。 目前Playground v2.5模型可以在diffusers中直接使用,可以进行文生图和图生图的任务,生成1024×1024分辨率及以上的高质量图片 。相关代码和操作流程如下所示:
# 注意需要安装diffusers >= 0.27.0
from diffusers import DiffusionPipeline
import torch
pipe = DiffusionPipeline.from_pretrained(
"/本地路径/playground-v2.5-1024px-aesthetic",
torch_dtype=torch.float16,
variant="fp16",
).to("cuda")
# # Optional: Use DPM++ 2M Karras scheduler for crisper fine details
# from diffusers import EDMDPMSolverMultistepScheduler
# pipe.scheduler = EDMDPMSolverMultistepScheduler()
prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
image = pipe(prompt=prompt, num_inference_steps=50, guidance_scale=3).images[0]
我们在使用Playground v2.5模型时,推荐使用EDMDPMSolverMultistepScheduler调度器,能够生成更加清晰的图像,这时推荐设置guidance_scale = 3.0 。如果我们使用EDMEulerScheduler调度器,推荐设置guidance_scale = 5.0。
Playground官方认为SDXL系列模型架构还有很大的优化空间 ,主要方向包括:更好的文本-图像对齐效果、增强模型的泛化能力、增强Latent特征空间、更精确的图像编辑等。
8. AI绘画领域的未来发展
8.1 AI绘画的“数据工厂”
看完本文的从0到1进行Stable Diffusion XL模型训练章节内容,大家可能都有这样一种感觉,整个数据处理流程占据了整个SDXL模型开发流程的60-70%甚至更多的时间,并且在数据量级不断增大的情况下,数据产生的内容护城河开始显现 ,模型的“数据飞轮”效应会给产品带来极大的势能 。
可以看到,数据侧是如此重要,AIGC时代也需要像传统深度学习时代一样,设立“数据工厂”为AIGC模型的优化迭代提供强有力的数据支持 。
在传统深度学习时代,数据工厂能够将图片中的目标类别进行精准标注 ;而到了AIGC时代,数据工厂的标注内容就发生了变化,需要对图片进行理解,并且通过文字与关键词完整描述出图片中的内容 。
除此之外,数据工厂的数据收集、数据整理、数据供给等功能都是跨周期的需求 ,在传统深度学习时代已经证明,数据工厂能大大增强算法团队的工作效率,为整个AI算法解决方案和AI产品的开发、交付、迭代提供有力支持。
Rocky相信,未来AIGC时代的数据工厂会是一个非常大的机会点 ,作为AIGC领域的上游产业,不管是大厂自建数据工厂,还是专门的AIGC数据工厂公司,都会像在传统深度学习时代那样,成为AIGC产业链中不可或缺的关键一环 。
8.2 AI绘画的“工作流”产品
2022年是AIGC元年,各路大模型争先恐后的发布,“百模大战”一触即发 。
但是,市场真的需要这么多大模型吗?用户真的需要这么多大模型吗?
答案显而易见是否定的 。并且大模型并不是万能的,有着明显的能力边界,单个大模型不足以形成足够的技术护城河与产品普惠 。
历史不总是重复,但是会押韵。从AIGC之前的深度学习时代,也有非常多的公司迷信当时的人脸检测、人脸识别、目标检测、图像分割、图像分类算法。但时间告诉我们,深度学习时代的红利与价值,最后只赋能了互联网行业、安防行业、智慧城市行业以及智慧工业等强B端行业 。
那么,AIGC时代和深度学习时代的区别是什么呢?
也很简单,AIGC时代有类似移动互联网时代那样的ToC可能性 。因为不管是开源社区,还是AIGC时代的互联网大厂和AI公司,亦或者是绘画领域专业的个人,都开始尝试大模型+辅助工具的“工作流”产品,并且让这些产品触达每个用户 。像妙鸭相机等APP已经显现移动互联网时代独有的快速商业落地与流量闭环能力。
Rocky在这里再举一些热门AI绘画“工作流”产品例子:
Stable Diffusion + LoRA + ControlNet的“三巨头”组合。
Stable Diffusion + 其他生成式模型(ChatPT,GAN等)的组合。
Stable Diffusion + 深度学习模型(分类,分割,检测等)的组合。
Stable Diffusion + 视频模型的组合。
Stable Diffusion + 数字人模型的组合。
…
这些“工作流”式的AIGC产品,不管是对ToB还是ToC,都有很强的普惠性与优化迭代可能性。同时可以为工业界、学术界以及竞赛界的AI绘画未来 发展带来很多的势能与“灵感”,Rocky相信这会成为AI绘画行业未来持续繁荣的核心关键。
8.3 AI绘画模型未来需要突破的瓶颈
SDXL虽然是先进的开源AI绘画模型,但是其同样存在一些需要突破的瓶颈。
SDXL有时仍难以处理包含详细空间安排和详细描述的复杂提示词。同时手部生成依旧存在一定的问题,会出现多手指、少手指、鸡爪指、断指以及手部特征错乱等情况。除此之外,两个概念的互相渗透、互相混淆,或者是概念溢出等问题还是存在。
下图中展示了这些问题,左上角的图片展示了手部生成失败的例子;左下角和右下角的图片展示了概念渗透,互相混淆的例子;右上角的图片展示了对复杂描述与详细空间安排的提示词生成失败的例子: 客观来说,目前AI绘画领域的模型一定程度上都存在上述的瓶颈,既然有瓶颈,那么就有突破的方向与动力 。
SDXL论文中也给出了future work,向我们阐述了未来图像生成式模型的研究重点(科研界风向标 ):
Single stage(单阶段模型) :目前,SDX是二阶段的级联模型,使得显存占用和运算耗时都增大了。所以未来的一个价值点是想办法提出和SDXL有相似性能或者更强性能的单阶段模型。
Text synthesis(文本合成) :持续优化Text Encoder模型,提升模型对文本的理解能力。使用更加细粒度的文本编码器或者使用额外的约束增加文本与图像的一致性,或许是AI绘画领域的X因素。
Architecture(架构) :SDXL论文中简单地尝试了基于纯Transformer的架构,比如UViT和DiT,目前暂没有太大的进展。但是SDXL论文中认为通过精心的超参数研究,最终将能够扩展到以Transformer结构为主导的更高效的模型架构中。
Distillation(蒸馏) :通过指导性蒸馏、知识性蒸馏和逐步蒸馏等技术,来降低SDXL推理所需的计算量,并减少推理耗时。
New Model(新模型) :未来基于连续时间的EDM框架是非常有势能的候选扩散模型框架,因为它允许更大的采样灵活性,并且不需要噪声调度修正。
8.4 构建AI绘画产品的开发流程
就如同深度学习时代一样,构建AIGC时代算法产品与算法解决方案的开发流程是每个AIGC公司的必修课。
与传统深度学习时代作类比的话,我们可以发现AIGC时代中的算法产品开发流程有很多与之相似的地方。
下面是Rocky在AIGC时代积累的算法产品开发流程方法论,大家可以参考:
产品需求定义(与传统深度学习类似)
数据收集、筛选、标注(与传统深度学习不同,需要细分领域的专家对数据进行评估)
模型选择(与传统深度学习无脑选择的YOLO,ResNet,U-Net不同,AIGC时代对模型的选择也需要根据细分领域进行评估)
模型训练(与传统深度学习类似)
模型测试评估(与传统深度学习不同,需要细分领域的专家通过Prompt工程挖掘评估模型能力 )
前处理与后处理(与传统深度学习类似)
工程化部署(与传统深度学习类似,在传统深度学习只能ToB的基础上,多了ToC可能性,既能端侧部署,也能上线部署)
8.5 AI绘画的多模态发展
在2023年OpenAI的开发者大会上,GPTs这个重量级产品正式发布,让人感到惊艳的同时,其生态快速繁荣。
如果说2023年年初是“百模大战”的话,那么2023年的年末就是“千GPTs大战” 。
如此强的ToC普惠是传统深度学习时代未曾出现的,就连移动互联网时代在如此的势能面前都稍逊一筹,然而AIGC时代才刚刚开始 。
所以Rocky认为AIGC时代的AI产品与应用会以AI绘画+AI视频+AI对话+AI语音+AI大模型+数字人等多模态的形式呈现 ,AI绘画会成为AI应用的关键一环,发挥重要作用。多模态的AI产品形态,会极大增强AI产品的ToC/ToB的普惠势能,也是AIGC时代发展的必经之路 。
8.6 AI绘画的轻量化与端侧部署
在传统深度学习时代,AI模型的轻量化和端侧部署为ToB的可能性打下了坚实的基础,在端侧快速高效的使用目标检测、图像分割、图像分类、目标跟踪等算法,能够为智慧城市、智慧交通、智慧工业能领域创造非常大的价值。
历史不会重复,但会押韵 。在AIGC时代中,AI绘画模型的轻量化和端侧部署依旧在ToC和ToB领域有着巨大的势能与市场,在可预见的未来,如果每个人都能方便快速的在端侧设备中使用AI绘画模型生成内容,这将大大推动各行各业的变革与重构。
同时,实时高效的生成AIGC内容,将是未来的元宇宙时代的“核心基建” 。
更多思考与感悟,Rocky会持续补充,大家敬请期待!码字确实不易,希望大家能一键三连,多多点赞!
关于AI绘画技术储备
学好 AI绘画 不论是就业还是做副业赚钱都不错,但要学会 AI绘画 还是要有一个学习规划。最后大家分享一份全套的 AI绘画 学习资料,给那些想学习 AI绘画 的小伙伴们一点帮助!
对于0基础小白入门:
如果你是零基础小白,想快速入门AI绘画是可以考虑的。
一方面是学习时间相对较短,学习内容更全面更集中。 二方面是可以找到适合自己的学习方案
包括:stable diffusion安装包、stable diffusion0基础入门全套PDF,视频学习教程。带你从零基础系统性的学好AI绘画!
需要的可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
1.stable diffusion安装包 (全套教程文末领取哈)
随着技术的迭代,目前 Stable Diffusion 已经能够生成非常艺术化的图片了,完全有赶超人类的架势,已经有不少工作被这类服务替代,比如制作一个 logo 图片,画一张虚拟老婆照片,画质堪比相机。
最新 Stable Diffusion 除了有win多个版本,就算说底端的显卡也能玩了哦!此外还带来了Mac版本,仅支持macOS 12.3或更高版本 。
2.stable diffusion视频合集
我们在学习的时候,往往书籍代码难以理解,阅读困难,这时候视频教程教程是就很适合了,生动形象加上案例实战,一步步带你入门stable diffusion,科学有趣才能更方便的学习下去。
3.stable diffusion模型下载
stable diffusion往往一开始使用时图片等无法达到理想的生成效果,这时则需要通过使用大量训练数据,调整模型的超参数(如学习率、训练轮数、模型大小等),可以使得模型更好地适应数据集,并生成更加真实、准确、高质量的图像。
4.stable diffusion提示词
提示词是构建由文本到图像模型解释和理解的单词的过程。可以把它理解为你告诉 AI 模型要画什么而需要说的语言,整个SD学习过程中都离不开这本提示词手册。
5.AIGC视频教程合集
观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
实战案例
纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。这份完整版的学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】
文章来源于互联网:深入浅出完整解析Stable Diffusion XL(SDXL)核心基础知识
原文:深入浅出完整解析Stable Diffusion(SD)核心基础知识 Rocky的公众号:WeThinkIn Rocky的知乎:Rocky Ding 想要获取更多AI行业干货内容与前沿资讯,欢迎关注Rocky的CSDN、知乎、公众号~
2023.08.26最新消息,本文已经撰写Stable Diffusion 1.x-2.x系列和对应LoRA的训练全流程与详细解读内容,同时发布对应的保姆级训练资源,大家可以愉快地训练属于自己的SD和LoRA模型了!
2023.07.26最新消息,由于Stable Diffusion模型的网络结构比较复杂,不好可视化,导致大家看的云里雾里。因此本文中已经发布Stable Diffusion中VAE,U-Net和CLIP三大模型的可视化网络结构图,大家可以下载用于学习!
Rocky也一直在更新Stable Diffusion系列的文章内容,包括最新发布的Stable Diffusion XL。Rocky都进行了全方位的深入浅出的解析,码字真心不易,希望大家能给Rocky正在撰写更新的下面两篇文章多多点赞,万分感谢:
深入浅出完整解析Stable Diffusion XL(SDXL)核心基础知识
深入浅出完整解析Stable Diffusion(SD)核心基础知识
大家好,我是Rocky。
2022年,Stable Diffusion模型横空出世,成为AI行业从传统深度学习时代走向AIGC时代的标志性模型之一 ,并为工业界、投资界、学术界和竞赛界都注入了新的AI想象空间,让AI再次“性感” 。
Stable Diffusion(简称SD)是AI绘画 领域的一个核心模型 ,能够进行文生图(txt2img)和图生图(img2img)等图像生成任务。与Midjourney 不同的是,Stable Diffusion是一个完全开源的项目(模型、代码、训练数据、论文、生态等全部开源),这使得其能快速构建强大繁荣的上下游生态(AI绘画社区、基于SD的自训练AI绘画模型、丰富的辅助AI绘画工具与插件等),并且吸引了越来越多的AI绘画爱好者加入其中,与AI行业从业者一起推动AIGC领域的发展与普惠 。
也正是Stable Diffusion的开源属性、繁荣的上下游生态以及各行各业AI绘画爱好者的参与,使得AI绘画火爆出圈,让AI绘画的影响触达到了全球各行各业人们的生活中。可以说,AI绘画的ToC普惠在AIGC时代的早期就已经显现 ,这是之前的传统深度学习时代从未有过的。而ToC普惠也是最让Rocky兴奋的AIGC属性,让Rocky相信未来的十五年会是像移动互联网时代那样,充满科技变革与机会的时代 。
Rocky从传统深度学习时代走来,与图像分类领域的ResNet系列、图像分割领域的U-Net系列以及目标检测领域的YOLO系列模型打过多年交道,Rocky相信Stable Diffusion是AI绘画领域的“YOLO” 。
因此本文中,Rocky将以AI绘画开源社区中最为火爆的Stable Diffusion 1.5模型为例,对Stable Diffusion模型的全维度各个细节做一个深入浅出的分析与总结 (SD模型结构解析、SD模型经典应用场景介绍、SD模型性能优化、SD模型从0到1保姆级训练教程,SD模型不同AI绘画框架从0到1推理运行保姆级教程、最新SD模型资源汇总分享、SD相关配套工具使用等),和大家一起交流学习,让我们能快速地入门Stable Diffusion及其背后的AIGC领域,在AIGC时代中更好地融入和从容。
1. Stable Diffusion系列资源
Rocky会持续把更多Stable Diffusion的资源更新发布到本节中,让大家更加方便的查找SD系列模型的最新资讯。
2. 零基础深入浅出理解Stable Diffusion核心基础原理
2.1 零基础理解Stable Diffusion模型工作流程(包含详细图解)
Stable Diffusion(SD)模型是由Stability AI和LAION等公司共同开发的生成式模型 ,总共有1B左右的参数量 ,可以用于文生图,图生图,图像inpainting,ControlNet控制生成,图像超分等丰富的任务,本节中我们以**文生图(txt2img)和 图生图(img2img)**任务展开对Stable Diffusion模型的工作流程进行通俗的讲解。
文生图任务是指将一段文本输入到SD模型中 ,经过一定的迭代次数,SD模型输出一张符合输入文本描述的图片 。比如下图中输入了“天堂,巨大的,海滩”,于是SD模型生成了一个美丽沙滩的图片。
而图生图任务在输入本文的基础上,再输入一张图片 ,SD模型将根据文本的提示,将输入图片进行重绘以更加符合文本的描述 。比如下图中,SD模型将“海盗船”添加在之前生成的那个美丽的沙滩图片上。那么输入的文本信息如何成为SD模型能够理解的机器数学信息呢?
很简单,我们需要给SD模型一个文本信息与机器数据信息之间互相转换的“桥梁”——CLIP Text Encoder模型 。如下图所示,我们使用CLIP Text Encoder模型作为SD模型中的前置模块 ,将输入的文本信息进行编码,生成与文本信息对应的Text Embeddings特征矩阵,再将Text Embeddings用于SD模型中来控制图像的生成: 完成对文本信息的编码后,就会输入到SD模型的“图像优化模块”中对图像的优化进行“控制”。
如果是图生图任务,我们在输入文本信息的同时,还需要将原图片通过图像编码器(VAE Encoder)生成Latent Feature(隐空间特征)作为输入。
如果是文生图任务,我们只需要输入文本信息,再用random函数生成一个高斯噪声矩阵 作为Latent Feature的“替代”输入到SD模型的“图像优化模块”中。
“图像优化模块”作为SD模型中最为重要的模块,其工作流程是什么样的呢?
首先,“图像优化模块”是由一个U-Net网络 和一个Schedule算法 共同组成,U-Net网络负责预测噪声,不断优化生成过程,在预测噪声的同时不断注入文本语义信息 。而schedule算法对每次U-Net预测的噪声进行优化处理(动态调整预测的噪声,控制U-Net预测噪声的强度) ,从而统筹生成过程的进度。在SD中,U-Net的迭代优化步数(Timesteps)大概是50或者100次,在这个过程中Latent Feature的质量不断的变好(纯噪声减少,图像语义信息增加,文本语义信息增加 )。整个过程如下图所示: U-Net网络和Schedule算法的工作完成以后,SD模型会将优化迭代后的Latent Feature输入到图像解码器(VAE Decoder)中,将Latent Feature重建成像素级图像。
我们对比一下文生图任务中,初始Latent Feature和经过SD的“图像优化模块”处理后,再用图像解码器重建出来的图片之间的区别: 可以看到,上图左侧是初始Latent Feature经过图像解码器重建后的图片,显然是一个纯噪声图片;上图右侧是经过SD的“图像优化模块”处理后,再用图像解码器重建出来的图片,可以看到是一张包含丰富内容信息的有效图片。
我们再将U-Net网络+Schedule算法的迭代去噪过程的每一步结果都用图像解码器进行重建,我们可以直观的感受到从纯噪声到有效图片的全过程: 以上就是SD模型工作的完整流程,下面Rocky再将其进行总结归纳制作成完整的Stable Diffusion前向推理流程图,方便大家更好的理解SD模型的前向推理过程:
2.2 零基础读懂Stable Diffusion模型核心基础原理(包含详细图解)
在传统深度学习时代,凭借生成器与判别器对抗训练这个开创性的哲学思想,GAN(Generative adversarial networks)可以说是在生成式模型中一枝独秀。同样的,在AIGC时代,以Stable Diffusion模型为代表的扩散模型接过GAN的衣钵,在AI绘画领域一路“狂飙” 。
与GAN等生成式模型一致的是,SD模型同样拟合训练集分布,并能够生成与训练集分布相似的输出结果,但与GAN相比,SD模型训练过程更稳定,而且具备更强的泛化性能 。这些都归功于扩散模型中核心的前向扩散过程(Forward Diffusion Process)和 反向扩散过程(Reverse Diffusion Process) 。
在前向扩散过程中,SD模型持续对一张图像添加高斯噪声直至变成随机噪声矩阵 。而在反向扩散过程中,SD模型进行去噪声过程 ,将一个随机噪声矩阵逐渐去噪直至生成一张图像。具体流程与图解如下所示:
前向扩散过程(Forward Diffusion Process)
→
rightarrow
→ 图片中持续添加噪声
反向扩散过程(Reverse Diffusion Process)
→
rightarrow
→ 持续去除图片中的噪声
2.2.1 扩散模型的基本原理详解
在Stable Diffusion这个扩散模型中,无论是前向扩散过程还是反向扩散过程都是一个参数化的马尔可夫链(Markov chain) ,如下图所示: 看到这里,大家是不是感觉概念有点复杂了,don‘t worry,Rocky在本文不会讲太多复杂难懂的公式,大家只要知道Stable Diffusion模型的整个流程遵循参数化的马尔可夫链,前向扩散过程是对图像增加噪声,反向扩散过程是去噪过程即可,这对于面试 、工业界应用、竞赛界厮杀来说,都已经足够了 。
如果有想要深入理解扩散模型数学原理的读者,Rocky这里推荐阅读原论文:Denoising Diffusion Probabilistic Models
Rocky再从AI绘画应用角度解释一下扩散模型的基本原理,让大家能够对扩散模型有更多通俗易懂的认识:
如果从艺术和美学的角度来理解扩散模型,我们可以将其视为一种创作过程。想象这种情况,艺术家在画布的一角开始创作,颜色和形状逐渐扩散到整个画布。每一次画笔的触碰都可能对画布的内容产生影响,从而产生新的颜色和形状的组合。
此外,扩散过程也可以看作是一种艺术表达。例如,抽象派艺术家可能会利用颜色和形状的扩散来表达他们的想法和感情,这种扩散过程可以看作是一种元素间的动态交互。扩散过程中的动态平衡,反映了美学中的对称和平衡的原则。同时,扩散过程的不确定性和随机性,也反映了现代美学中对创新和突破的追求 。
总的来说,从艺术和美学的角度来看,扩散模型可以被理解为一种创作和表达过程,其中的元素通过互动和影响,形成一种动态的、有机的整体结构 。
2.2.2 扩散模型的前向扩散过程详解
接下来,我们再详细分析一下扩散模型的前向扩散过程,其是一个不断往图像上加噪声的过程 。我们举个例子,如下图所示,我们在猫的图片中多次增加高斯噪声直至图片变成随机噪声矩阵。可以看到,对于初始数据,我们设置扩散步数为K步,每一步增加一定的噪声,如果我们设置的K足够大,那么我们就能够将初始数据转化成随机噪声矩阵 。 一般来说,**扩散过程是固定的,由上节中提到的Schedule算法进行统筹控制。**同时扩散过程也有一个重要的性质:我们可以基于初始数据
X
0
X_{0}
X 0 和任意的扩散步数
K
i
K_{i}
K i ,采样得到对应的数据
X
i
X_{i}
X i 。
2.2.3 扩散模型的反向扩散过程详解
扩散模型的反向扩散过程和前向扩散过程正好相反,是一个在图像上不断去噪的过程 。下面是一个直观的例子,将随机高斯噪声矩阵通过扩散模型的反向扩散过程,预测噪声并逐步去噪,最后生成一个小别墅的清晰图片。 其中每一步预测并去除的噪声分布,都需要扩散模型在训练中学习。
讲好了扩散模型的前向扩散过程和反向扩散过程,他们的目的都是服务于扩散模型的训练,训练目标也非常简单:将扩散模型每次预测出的噪声和每次实际加入的噪声做回归,让扩散模型能够准确的预测出每次实际加入的真实噪声 。
下面是扩散模型反向扩散过程的完整图解:
2.2.4 引入Latent思想让Stable Diffusion模型彻底“进化破圈”
如果说前面讲到的扩散模型相关基础知识是为SD模型打下地基的话,引入Latent思想则让SD模型“一遇风雨便化龙”,成为了AIGC时代图像生成模型的领军者 。
那么Latent又是什么呢?为什么Latent有如此魔力呢?
首先,我们已经知道了扩散模型会设置一个迭代次数,并不会像GAN网络那样只进行一次输入和一次输出,虽然扩散模型这样输出的效果会更好更稳定,但是会导致生成过程耗时的增加。
再者,Stable Diffusion出现之前的扩散模型虽然已经有非常强的生成能力与泛化性能,但缺点是不管是前向扩散过程还是反向扩散过程,都需要在像素级的图像上进行,当图像分辨率和Timesteps很大时,不管是训练还是前向推理,都非常的耗时 。
而基于Latent的扩散模型可以将这些过程压缩在低维的Latent隐空间 ,这样一来大大降低了显存占用和计算复杂度 ,这是常规扩散模型和基于Latent的扩散模型之间的主要区别,也是SD模型火爆出圈的关键一招 。
我们举个形象的例子理解一下,如果SD模型将输入数据压缩的倍数设为8,那么原本尺寸为[3,512,512]的数据就会进入[3,64,64]的Latent隐空间中,显存和计算量直接缩小64倍,整体效率大大提升 。也正是因为这样,SD模型能够在2080Ti级别的显卡上进行前向推理,生成各种各样精美的图像,大大推动了SD模型的普惠与AI绘画生态的繁荣 。
到这里,大家应该对SD模型的核心基础原理有一个清晰的认识了,Rocky这里再帮大家总结一下:
SD模型是生成式模型 :输入可以是文本、文本和图像、以及更多控制条件等,输出是生成的图像。
SD模型属于扩散模型 :扩散模型的特点是生成过程分步化与可迭代,这让整个生成过程更加灵活,同时为引入更多约束与优化提供了可能。
SD模型是基于Latent的扩散模型 :将输入数据压缩到Latent隐空间中,这比起常规扩散模型,大幅提高计算效率的同时,降低了显存占用,成为了SD模型破圈的关键一招。
站在AIGC时代的视角,Rocky认为Stable Diffusion本质上是一个优化噪声的AI艺术工具 。
2.3 零基础读懂Stable Diffusion训练全过程(包含详细图解)
Stable Diffusion的整个训练过程在最高维度上可以看成是如何加噪声和如何去噪声的过程,并在针对噪声的“对抗与攻防”中学习到生成图片的能力。
Stable Diffusion整体的训练逻辑也非常清晰:
从数据集中随机选择一个训练样本
从K个噪声量级随机抽样一个timestep
将timestep
t
t
t 对应的高斯噪声添加到图片中
将加噪图片输入U-Net中预测噪声
计算真实噪声和预测噪声的L2损失
计算梯度并更新SD模型参数
下图是SD训练过程Epoch迭代的图解:
下图是SD每个训练step的详细图解过程:
下面Rocky再对SD模型训练过程中的一些关键环节进行详细的讲解。
2.3.1 SD训练集加入噪声
SD模型训练时,我们需要把加噪的数据集输入模型中,每一次迭代我们用random函数生成从强到弱各个强度的噪声,通常来说会生成0-1000一共1001种不同的噪声强度,通过Time Embedding嵌入到SD的训练过程中。
Time Embedding由Timesteps(时间步长)编码而来,引入Timesteps能够模拟一个随时间逐渐向图像加入噪声扰动的过程 。每个Timestep代表一个噪声强度(较小的Timestep代表较弱的噪声扰动,而较大的Timestep代表较强的噪声扰动 ),通过多次增加噪声来逐渐改变干净图像的特征分布。
下图是一个简单的加噪声流程,可以帮助大家更好地理解SD训练时数据是如何加噪声的。首先从数据集中选择一张干净样本,然后再用random函数生成0-3一共4种强度的噪声,然后每次迭代中随机一种强度的噪声,增加到干净图片上,完成图片的加噪流程。
2.3.2 SD训练中加噪与去噪
具体地,在训练过程中,我们首先看一下前向扩散过程,主要是对干净样本进行加噪处理,采用多次逐步增加噪声的方式,直至干净样本转变成为纯噪声。
接着,在前向扩散过程进行的每一步中,SD同样进行反向扩散过程 。SD模型在每一步都会预测当前步加入的噪声,不断学习提升去噪能力。
其中,将去噪过程具象化,就得到使用U-Net预测噪声,并结合Schedule算法逐步去噪的过程。 我们可以看到,加噪和去噪过程都是逐步进行的,我们假设进行
K
K
K 步,那么每一步,SD都要去预测噪声,从而形成“小步快跑的稳定去噪”,类似于移动互联网时代的产品逻辑,这是足够伟大的关键一招。
与此同时,在加噪过程中,每次增加的噪声量级可以不同,假设有5种噪声量级,那么每次都可以取一种量级的噪声,增加噪声的多样性,如下图所示: 那么怎么让网络知道目前处于
K
K
K 的哪一步呢?本来SD模型其实需要K个噪声预测模型,这时我们可以增加一个Time Embedding (类似Positional embeddings)进行处理,通过将timestep编码进网络中,从而只需要训练一个共享的U-Net模型,就让网络知道现在处于哪一步。
我们希望SD中的U-Net模型在刚开始的反向扩散过程中可以先生成一些物体的大体轮廓,随着反向扩散过程的深入,在即将完成完整图像的生成时,再生成一些高频的特征信息。
我们了解了训练中的加噪和去噪过程,SD训练的具体过程就是对每个加噪和去噪过程进行梯度计算,从而优化SD模型参数,如下图所示分为四个步骤:
从训练集中选取一张加噪过的图片和噪声强度(timestep),然后将其输入到U-Net中。
让U-Net预测噪声(下图中的U-Net Prediction)。
接着再计算预测噪声与真实噪声的误差(loss)。
最后通过反向传播更新U-Net的权重参数。 完成SD模型的训练,我们就可以用U-Net对噪声图片进行去噪,逐步重建出有效图像的Latent Feature了!
在噪声图上逐步减去被U-Net预测出来的噪声,从而得到一个我们想要的高质量的图像Latent特征,去噪流程如下图所示:
2.3.3 文本信息对图片生成的控制
SD模型在生成图片时,需要输入prompt提示词,那么这些文本信息是如何影响图片的生成呢?
答案非常简单:通过注意力机制。
在SD模型的训练中,每个训练样本都会对应一个文本描述的标签,我们将对应标签通过CLIP Text Encoder输出Text Embeddings,并将Text Embeddings以Cross Attention 的形式与U-Net结构耦合并注入,使得每次输入的图片信息与文本信息进行融合训练,如下图所示: 上图中的token 是NLP领域的一个基础概念,可以理解为最小语义单元。与之对应的分词操作为tokenization。Rocky举一个简单的例子来帮助大家理解:“WeThinkIn是伟大的自媒体”是一个句子,我们需要将其切分成一个token序列,这个操作就是tokenization 。经过tokenization操作后,我们获得[“WeThinkIn”, “是”, “伟大的”, “自媒体”]这个句子的token序列,从而完成对文本信息的预处理。
2.3.4SD模型训练时的输入
有了上面的介绍,我们在这里可以小结一下SD模型训练时的输入,一共有三个部分组成:图片、文本以及噪声强度 。其中图片和文本是固定的,而噪声强度在每一次训练参数更新时都会随机选择一个进行叠加。
2.4 其他主流生成式模型介绍
在AIGC时代中,虽然SD模型已经成为核心的生成式模型,但是曾在传统深度学习时代火爆的GAN、VAE、Flow-based model等模型也跨过周期在SD模型身边作为辅助模型,发挥了巨大的作用 。
下面是主流生成式模型各自的生成逻辑:
GAN网络在AIGC时代依然发挥了巨大的作用,配合SD模型完成了很多AI绘画算法工作流,比如:图像超分、脸部修复、风格迁移、图像编辑、图像重绘、图像定权等。
所以Rocky在这里简单讲解一下GAN的基本原理,让大家有个了解。GAN由生成器
G
G
G 和判别器
D
D
D 组成。其中,生成器主要负责生成相应的样本数据,输入一般是由高斯分布随机采样得到的噪声
Z
Z
Z 。而判别器的主要职责是区分生成器生成的样本与
g
t
(
G
r
o
u
n
d
T
r
u
t
h
)
gt(GroundTruth)
g t ( G ro u n d T r u t h ) 样本,输入一般是
g
t
gt
g t 样本与相应的生成样本,我们想要的是对
g
t
gt
g t 样本输出的置信度越接近1越好,而对生成样本输出的置信度越接近0越好。与一般神经网络不同的是,GAN在训练时要同时训练生成器与判别器,所以其训练难度是比较大的 。
我们可以将GAN中的生成器比喻为印假钞票的犯罪分子,判别器则被当作警察。犯罪分子努力让印出的假钞看起来逼真,警察则不断提升对于假钞的辨识能力。二者互相博弈,随着时间的进行,都会越来越强。在图像生成任务中也是如此,生成器不断生成尽可能逼真的假图像。判别器则判断图像是
g
t
gt
g t 图像还是生成的图像。二者不断博弈优化 ,最终生成器生成的图像使得判别器完全无法判别真假。
关于Flow-based models,其在AIGC时代的作用还未显现,可以持续关注。
最后,VAE将在本文后面的3.2章节中详细讲解,因为正是VAE将输入数据压缩至Latent隐空间中,故其成为了SD模型的核心结构之一 。
3. Stable Diffusion核心网络结构解析(全网最详细)
3.1 SD模型整体架构初识
Stable Diffusion模型整体上是一个End-to-End模型 ,主要由VAE(变分自编码器,Variational Auto-Encoder),U-Net以及CLIP Text Encoder三个核心组件构成。
在FP16精度下Stable Diffusion模型大小2G(FP32:4G),其中U-Net大小1.6G,VAE模型大小160M以及CLIP Text Encoder模型大小235M(约123M参数)。其中U-Net结构包含约860M参数,以FP32精度下大小为3.4G左右。
3.2 VAE模型
在Stable Diffusion中,VAE(变分自编码器,Variational Auto-Encoder)是基于Encoder-Decoder架构的生成模型 。VAE的Encoder(编码器)结构能将输入图像转换为低维Latent特征,并作为U-Net的输入。VAE的Decoder(解码器)结构能将低维Latent特征重建还原成像素级图像。
3.2.1 Stable Diffusion中VAE的核心作用
总的来说,在Stable Diffusion中,VAE模型主要起到了图像压缩和图像重建的作用 ,如下图所示: 当我们输入一个尺寸为
H
×
W
×
C
H times W times C
H × W × C 的数据,VAE的Encoder模块会将其编码为一个大小为
h
×
w
×
c
h times w times c
h × w × c 的低维Latent特征,其中
f
=
H
h
=
W
w
f = frac {H} {h} = frac {W} {w}
f = h H = w W 为VAE的下采样率(Downsampling Factor) 。反之,VAE的Decoder模块有一个相同的**上采样率(Upsampling Factor)**将低维Latent特征重建成像素级别的图像。
为什么VAE可以将图像压缩到一个非常小的Latent space(潜空间)后能再次对图像进行像素级重建呢?
因为虽然VAE对图像的压缩与重建过程是一个有损压缩与重建过程,但图像全图级特征关联并不是随机的,它们的分布具有很强的规律性 :比如人脸的眼睛、鼻子、脸颊和嘴巴之间遵循特定的空间关系,又比如一只猫有四条腿,并且这是一个特定的生物结构特征。下面Rocky也使用VAE将图像重建成不同尺寸的生成图像,实验结论发现如果我们重建生成的图像尺寸在
512
×
512
512 times 512
512 × 512 之上时,其实特征损失带来的影响非常小。
3.2.2 Stable Diffusion中VAE的高阶作用
与此同时,VAE模型除了能进行图像压缩和图像重建的工作外,如果我们在SD系列模型中切换不同微调训练版本的VAE模型,能够发现生成图片的细节与整体颜色也会随之改变(更改生成图像的颜色表现,类似于色彩滤镜) 。
目前在开源社区常用的VAE模型有 :vae-ft-mse-840000-ema-pruned.ckpt、kl-f8-anime.ckpt、kl-f8-anime2.ckpt、YOZORA.vae.pt、orangemix.vae.pt、blessed2.vae.pt、animevae.pt、ClearVAE.safetensors、pastel-waifu-diffusion.vae.pt、cute_vae.safetensors、color101VAE_v1.pt等。
这里Rocky使用了10种不同的VAE模型,在其他参数保持不变的情况下,对比了SD模型的出图效果,如下所示: 可以看到,我们在切换VAE模型进行出图时,除了pastel-waifu-diffusion.vae.pt模型外,其余VAE模型均不会对构图进行大幅改变,只对生成图像的细节与颜色表现进行调整 。
Rocky目前也在整理汇总高价值的VAE模型(持续更新!),方便大家获取使用。大家可以关注Rocky的公众号WeThinkIn ,后台回复:SDVAE ,即可获得资源链接,包含上述的全部VAE模型权重和更多高价值VAE模型权重 。
3.2.3 Stable Diffusion中VAE模型的完整结构图(全网最详细)
下图是Rocky梳理的Stable Diffusion VAE的完整结构图 ,大家可以感受一下其魅力,看着这个完整结构图学习Stable Diffusion VAE模型部分,相信大家脑海中的思路也会更加清晰:
SD VAE模型中有三个基础组件:
GSC组件:GroupNorm+Swish+Conv
Downsample组件:Padding+Conv
Upsample组件:Interpolate+Conv
同时SD VAE模型还有两个核心组件:ResNetBlock模块和SelfAttention模型,两个模块的结构如上图所示。
SD VAE Encoder部分包含了三个DownBlock模块、一个ResNetBlock模块以及一个MidBlock模块,将输入图像压缩到Latent空间,转换成为Gaussian Distribution。
而VAE Decoder部分正好相反,其输入Latent空间特征,并重建成为像素级图像作为输出。其包含了三个UpBlock模块、一个ResNetBlock模块以及一个MidBlock模块。
3.2.4 Stable Diffusion中VAE的训练过程与损失函数
在Stable Diffusion中,需要对VAE模型进行微调训练,主要采用了L1回归损失和感知损失 (perceptual loss,Learned Perceptual Image Patch Similarity,LPIPS)作为损失函数,同时使用了基于patch的对抗训练策略 。
L1回归损失作为传统深度学习时代的经典回归损失,用在回归问题中衡量预测值与真实值之间的差异,在生成模型中很常用,其公式如下所示:
L
1
(
y
,
y
^
)
=
∑
i
=
1
n
∣
y
i
−
y
^
i
∣
L_1(y, hat{y}) = sum_{i=1}^n |y_i – hat{y}_i|
L 1 ( y , y ^ ) = i = 1 ∑ n ∣ y i − y ^ i ∣
其中,
y
i
y_{i}
y i 是输入数据的真实值,
y
^
i
hat{y}_i
y ^ i 是模型生成数据的预测值,
n
n
n 是数据总数。
感知损失 同样作为传统深度学习时代的经典回归损失,在AIGC时代继续繁荣。感知损失的核心思想是比较原始图像和生成图像在传统深度学习模型(VGG、ResNet、ViT等)不同层中特征图之间的相似度,而不直接进行像素级别的对比 。
传统深度学习模型能够提取图像的高维语义信息的特征,如果两个图像在高维语义信息的特征上接近,那么它们在像素级别的语意上也应该是相似的 ,感知损失在图像重建、风格迁移等任务中非常有效。
感知损失的公式如下所示:
L
perceptual
=
∑
l
λ
l
⋅
∥
ϕ
l
(
I
pred
)
−
ϕ
l
(
I
target
)
∥
2
2
L_{text{perceptual}} = sum_l lambda_l cdot | phi_l(I_{text{pred}}) – phi_l(I_{text{target}}) |_2^2
L perceptual = l ∑ λ l ⋅ ∥ ϕ l ( I pred ) − ϕ l ( I target ) ∥ 2 2
其中:
ϕ
l
phi_l
ϕ l 表示在预训练模型(比如VGG/ResNet网络)的第
l
l
l 层的激活特征。
I
pred
I_{text{pred}}
I pred 是模型生成的图像。
(
I
target
(I_{text{target}}
( I target 是真实图像。
λ
l
lambda_l
λ l 是第
l
l
l 层的权重,可以根据实际情况设置合适值。
最后就是基于patch的对抗训练策略 ,我们使用PatchGAN的判别器 来对VAE模型进行对抗训练,通过优化判别器损失,来提升生成图像的局部真实性(纹理和细节)与清晰度 。
PatchGAN是GAN系列模型的一个变体,其判别器架构不再评估整个生成图像是否真实,而是评估生成图像中的patch部分是否真实 。具体来说,PatchGAN的判别器接收一张图像,并输出一个矩阵,矩阵中的每个元素代表图像中对应区域的真实性。这种方法能够专注于优化生成图像的局部特征,生成更细腻、更富有表现力的纹理,同时计算负担相对较小。特别适合于那些细节和纹理特别重要的任务,例如图像超分辨率、风格迁移或图生图等任务。
到这里,Rocky已经帮大家分析好Stable Diffusion中VAE训练的三大主要损失函数 :L1回归损失、感知损失以及PachGAN的判别器损失。
与此同时,为了防止在Latent空间的任意缩放导致的标准差过大 ,在训练VAE模型的过程中引入了正则化损失 ,主要包括KL(Kullback-Leibler)正则化与VQ(Vector Quantization)正则化。KL正则化 主要是让Latnet特征不要偏离正态分布太远,同时设置了较小的权重(~10e-6)来保证VAE的重建效果。VQ正则化 通过在decoder模块中引入一个VQ-layer,将VAE转换成VQ-GAN,同样为了保证VAE的重建效果,设置较高的codebook采样维度(8192)。
Stable Diffusion论文中实验了不同参数下的VAE模型性能表现,具体如下图所示。当
f
f
f 较小和
c
c
c 较大时,重建效果较好(PSNR值较大),因为此时图像的压缩率较小。但是VAE模型在ImageNet数据集上训练时发现设置过小的
f
f
f (比如1和2)会导致VAE模型收敛速度慢,SD模型需要更长的训练周期。如果设置过大的
f
f
f 会导致VAE模型的生成质量较差,因为此时压缩损失过大。论文中实验发现,当设置
f
f
f 在4~16的区间时,VAE模型可以取得相对好的生成效果。
通过综合评估正则化损失项、
f
f
f 项以及
c
c
c 项,最终Stable Diffusion中的VAE模型选择了KL正则化进行优化训练,同时设置下采样率
f
=
8
f = 8
f = 8 ,设置特征维度为
c
=
4
c = 4
c = 4 。此时当输入图像尺寸为768×768时,将得到尺寸为96x96x4的Latent特征。 讲到这里,终于可以给大家展示Stable DIffusion中VAE模型的完整损失函数了,下面是Stable Diffusion中VAE训练的完整损失函数:
L
Autoencoder
=
min
ϵ
,
D
max
ψ
(
L
rec
(
x
,
D
(
ϵ
(
x
)
)
)
−
L
adv
(
D
(
ϵ
(
x
)
)
)
+
log
D
ψ
(
x
)
+
L
reg
(
x
;
ϵ
,
D
)
)
mathcal{L}_{text{Autoencoder}} = min_{epsilon,D} max_{psi} left( mathcal{L}_{text{rec}}(x, D(epsilon(x))) – mathcal{L}_{text{adv}}(D(epsilon(x))) + log D_{psi}(x) + mathcal{L}_{text{reg}}(x; epsilon, D) right)
L Autoencoder = ϵ , D min ψ max ( L rec ( x , D ( ϵ ( x ))) − L adv ( D ( ϵ ( x ))) + log D ψ ( x ) + L reg ( x ; ϵ , D ) )
其中
ϵ
(
x
)
epsilon(x)
ϵ ( x ) 表示VAE重建的图像,
L
rec
mathcal{L}_{text{rec}}
L rec 表示L1回归损失和感知损失,
L
adv
+
log
D
ψ
mathcal{L}_{text{adv}} +log D_{psi}
L adv + log D ψ 表示PachGAN的判别器损失,
L
reg
mathcal{L}_{text{reg}}
L reg 表示KL正则损失。
虽然VAE模型使用了KL正则化,但是由于KL正则化的权重系数非常小,实际生成的Latent特征的标准差依旧存在比较大的情况,所以Stable Diffusion论文中提出了一种rescaling方法强化正则效果 。首先我们计算第一个batch数据中Latent特征的标准差
σ
sigma
σ ,然后采用
1
σ
frac{1}{sigma}
σ 1 的系数来rescale后续所有的Latent特征使其标准差接近于1。同时在Decoder模块进行重建时,只需要将生成的Latent特征除以
1
σ
frac{1}{sigma}
σ 1 ,再进行像素级重建即可。在SD中,U-Net模型使用的是经过rescaling后的Latent特征,并且将rescaling系数设置为0.18215 。
3.2.5 使用Stable Diffusion中VAE对图像的压缩与重建效果示例
在本小节中,Rocky将用diffusers库来快速加载Stable Diffusion 1.5中的VAE模型,并通过可视化的效果直观展示VAE的压缩与重建效果,完整代码如下所示:
import cv2
import torch
import numpy as np
from diffusers import AutoencoderKL
VAE = AutoencoderKL. from_pretrained( "/本地路径/stable-diffusion-v1-5" , subfolder= "vae" )
VAE. to( "cuda" , dtype= torch. float16)
raw_image = cv2. imread( "catwoman.png" )
raw_image = cv2. cvtColor( raw_image, cv2. COLOR_BGR2RGB)
raw_image = cv2. resize( raw_image, ( 1024 , 1024 ) )
image = raw_image. astype( np. float32) / 127.5 - 1.0
image = image. transpose( 2 , 0 , 1 )
image = image[ None , : , : , : ]
image = torch. from_numpy( image) . to( "cuda" , dtype= torch. float16)
with torch. inference_mode( ) :
latent = VAE. encode( image) . latent_dist. sample( )
rec_image = VAE. decode( latent) . sample
rec_image = ( rec_image / 2 + 0.5 ) . clamp( 0 , 1 )
rec_image = rec_image. cpu( ) . permute( 0 , 2 , 3 , 1 ) . numpy( )
rec_image = ( rec_image * 255 ) . round ( ) . astype( "uint8" )
rec_image = rec_image[ 0 ]
cv2. imwrite( "reconstructed_catwoman.png" , cv2. cvtColor( rec_image, cv2. COLOR_RGB2BGR) )
接下来,我们分别使用1024×1024分辨率的真实场景图片和1024×1536分辨率的二次元图片,使用SD 1.5 VAE模型进行四种尺寸下的压缩与重建,重建效果如下所示: 可以看到,VAE在对图像进行压缩和重建时,是存在精度损失的,比如256×256分辨率和256×768分辨率下重建,会出现人脸崩坏的情况。同时我们可以看到,二次元图片比起真实场景图片更加鲁棒,在不同尺寸下重建时,二次元图片的主要特征更容易保留下来,局部特征畸变的情况较少,损失程度较低 。
为了避免压缩与重建的损失影响Stable Diffusion生成图片的质量,我们可以在微调训练、文生图、图生图等场景中进行如下设置:
文生图场景:生成图像尺寸尽量在512×512以上。
图生图场景:对输出图像进行缩放生成时,生成图像尺寸尽量在512×512以上。
微调训练:训练数据集尺寸尽量在512×512以上。
同时,StabilityAI官方也对VAE模型进行了优化 ,首先发布了基于模型指数滑动平均(EMA)技术微调的vae-ft-ema-560000-ema-pruned版本 ,训练集使用了LAION两个1:1比例数据子集,目的是增强VAE模型对扩散模型数据集的适应性,同时改善脸部的重建效果。在此基础上,使用MSE损失继续微调优化并发布了vae-ft-mse-840000-ema-pruned版本,这个版本的重建效果更佳平滑自然 。两个优化版本都只优化了VAE的Decoder部分,由于SD在微调训练中只需要Encoder部分提供Latent特征,所以优化训练后的VAE模型可以与开源社区的所有SD模型都兼容。
3.2.6 DaLL-E 3同款解码器consistency-decoder
OpenAI 开源的一致性解码器(consistency-decoder) ,能生成质量更高的图像内容、更稳定的图像构图,比如在多人脸、带文字图像以及线条控制方面有更好的效果。consistency-decoder既能用于DaLL-E 3模型,同时也支持作为Stable Diffusion 1.x和2.x的VAE模型。
下图是将原生SD VAE模型与consistency-decoder模型在256×256分辨率下的图像重建效果对比 ,可以看到在小分辨率情况下,consistency-decoder模型确实有更好的重建效果:
我们用diffusers库可以快速加载consistency-decoder模型使用,完整代码如下所示:
import torch
from diffusers import DiffusionPipeline, ConsistencyDecoderVAE
vae = ConsistencyDecoderVAE. from_pretrained( "/本地路径/consistency-decoder" , torch_dtype= pipe. torch_dtype)
pipe = StableDiffusionPipeline. from_pretrained(
"/本地路径/stable-diffusion-v1-5" , vae= vae, torch_dtype= torch. float16
) . to( "cuda" )
pipe( "horse" , generator= torch. manual_seed( 0 ) ) . images
但是由于consistency-decoder模型较大(FP32:2.49G,FP16:1.2G),重建耗时会比原生的SD VAE模型大得多,并且在高分辨率(比如1024×1024)下效果并没有明显高于原生的SD VAE模型,所以最好将consistency-decoder模型作为补充储备模型之用。
3.3 U-Net模型
3.3.1 Stable Diffusion中U-Net的核心作用
在Stable Diffusion中,U-Net模型是一个关键核心部分,能够预测噪声残差 ,并结合Sampling method(调度算法:DDPM、DDIM、DPM++等)对输入的特征矩阵进行重构,逐步将其从随机高斯噪声转化成图片的Latent Feature 。
具体来说,在前向推理过程中,SD模型通过反复调用 U-Net,将预测出的噪声残差从原噪声矩阵中去除,得到逐步去噪后的图像Latent Feature,再通过VAE的Decoder结构将Latent Feature重建成像素级图像,如下图所示:
Rocky再从AI绘画应用视角解释一下SD中U-Net的原理与作用 。其实大家在使用Stable Diffusion WebUI时,点击Generate按钮后,页面右下角图片生成框中展示的从噪声到图片的生成过程,其中就是U-Net在不断的为大家去除噪声的过程。到这里大家应该都能比较清楚的理解U-Net的作用了。
3.3.2 Stable Diffusion中U-Net模型的完整结构图(全网最详细)
好了,我们再回到AIGC算法工程师视角。
Stable Diffusion中的U-Net,在传统深度学习时代的Encoder-Decoder结构的基础上,增加了ResNetBlock(包含Time Embedding)模块,Spatial Transformer(SelfAttention + CrossAttention + FeedForward)模块以及CrossAttnDownBlock,CrossAttnUpBlock和CrossAttnMidBlock模块 。
那么各个模块都有什么作用呢?不着急,咱们先看看SD U-Net的整体架构(AIGC算法工程师面试核心考点)。
下图是Rocky梳理的Stable Diffusion U-Net的完整结构图 ,大家可以感受一下其魅力,看着这个完整结构图学习Stable Diffusion U-Net部分,相信大家脑海中的思路也会更加清晰:
上图中包含Stable Diffusion U-Net的十四个基本模块:
GSC模块:Stable Diffusion U-Net中的最小组件之一,由GroupNorm+SiLU+Conv三者组成。
DownSample模块:Stable Diffusion U-Net中的下采样组件,使用了Conv(kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))进行采下采样。
UpSample模块:Stable Diffusion U-Net中的上采样组件,由插值算法(nearest)+Conv组成。
ResNetBlock模块:借鉴ResNet模型的“残差结构”,让网络能够构建的更深的同时,将Time Embedding信息嵌入模型。
CrossAttention模块:将文本的语义信息与图像的语义信息进行Attention机制,增强输入文本Prompt对生成图片的控制。
SelfAttention模块:SelfAttention模块的整体结构与CrossAttention模块相同,这是输入全部都是图像信息,不再输入文本信息。
FeedForward模块:Attention机制中的经典模块,由GeGlU+Dropout+Linear组成。
BasicTransformer Block模块:由LayerNorm+SelfAttention+CrossAttention+FeedForward组成,是多重Attention机制的级联,并且也借鉴ResNet模型的“残差结构”。通过加深网络和多Attention机制,大幅增强模型的学习能力与图文的匹配能力。
Spatial Transformer模块:由GroupNorm+Conv+BasicTransformer Block+Conv构成,ResNet模型的“残差结构”依旧没有缺席。
DownBlock模块:由两个ResNetBlock模块组成。
UpBlock_X模块:由X个ResNetBlock模块和一个UpSample模块组成。
CrossAttnDownBlock_X模块:是Stable Diffusion U-Net中Encoder部分的主要模块,由X个(ResNetBlock模块+Spatial Transformer模块)+DownSample模块组成。
CrossAttnUpBlock_X模块:是Stable Diffusion U-Net中Decoder部分的主要模块,由X个(ResNetBlock模块+Spatial Transformer模块)+UpSample模块组成。
CrossAttnMidBlock模块:是Stable Diffusion U-Net中Encoder和ecoder连接的部分,由ResNetBlock+Spatial Transformer+ResNetBlock组成。
接下来,Rocky将为大家全面分析SD模型中U-Net结构的核心知识,码字实在不易,希望大家能多多点赞,谢谢!
3.3.2.1 ResNetBlock模块
在传统深度学习时代,ResNet的残差结构在图像分类,图像分割,目标检测等主流方向中几乎是不可或缺,其简洁稳定有效的“残差思想”终于在AIGC时代跨过周期,在SD模型的U-Net结构中继续繁荣 。
值得注意的是,Time Embedding正是输入到ResNetBlock模块中,为U-Net引入了时间信息(时间步长T,T的大小代表了噪声扰动的强度),模拟一个随时间变化不断增加不同强度噪声扰动的过程,让SD模型能够更好地理解时间相关性 。
同时,在SD模型调用U-Net重复迭代去噪的过程中,我们希望在迭代的早期,能够先生成整幅图片的轮廓与边缘特征,随着迭代的深入,再补充生成图片的高频和细节特征信息。由于在每个ResNetBlock模块中都有Time Embedding,就能告诉U-Net现在是整个迭代过程的哪一步,并及时控制U-Net够根据不同的输入特征和迭代阶段而预测不同的噪声残差 。
Rocky再从AI绘画应用视角解释一下Time Embedding的作用 。Time Embedding能够让SD模型在生成图片时考虑时间的影响,使得生成的图片更具有故事性、情感和沉浸感等艺术效果。并且Time Embedding可以帮助SD模型在不同的时间点将生成的图片添加完善不同情感和主题的内容,从而增加了AI绘画的多样性和表现力。
定义Time Embedding的代码如下所示,可以看到Time Embedding的生成方式,主要通过sin和cos函数再经过Linear层进行变换:
def time_step_embedding ( self, time_steps: torch. Tensor, max_period: int = 10000 ) :
half = self. channels // 2
frequencies = torch. exp(
- math. log( max_period) * torch. arange( start= 0 , end= half, dtype= torch. float32) / half
) . to( device= time_steps. device)
args = time_steps[ : , None ] . float ( ) * frequencies[ None ]
return torch. cat( [ torch. cos( args) , torch. sin( args) ] , dim= - 1 )
讲完Time Embedding的相关核心知识,我们再学习一下ResNetBlock模块的整体知识。
在上面的Stable Diffusion U-Net完整结构图中展示了完整的ResNetBlock模块,其输入包括Latent Feature和 Time Embedding。首先Latent Feature经过GSC(GroupNorm+SiLU激活函数+卷积)模块后和Time Embedding(经过SiLU激活函数+全连接层处理)做加和操作 ,之后再经过GSC模块和Skip Connection而来的输入Latent Feature做加和操作 ,进行两次特征融合 后最终得到ResNetBlock模块的Latent Feature输出,增强SD模型的特征学习能力 。
同时,和传统深度学习时代的U-Net结构一样,Decoder结构中的ResNetBlock模块不单单要接受来自上一层的Latent Feature,还要与Encoder结构中对应层的ResNetBlock模块的输出Latent Feature进行concat操作 。举个例子,如果Decoder结构中ResNetBlock Structure上一层的输出结果的尺寸为 [512, 512, 1024],Encoder结构对应 ResNetBlock Structure的输出结果的尺寸为 [512, 512, 2048],那么这个Decoder结构中ResNeBlock Structure得到的Latent Feature的尺寸为 [512, 512, 3072]。
3.3.2.2 CrossAttention模块
CrossAttention模块是我们使用输入文本Prompt控制SD模型图片内容生成的关键一招。
上面的Stable Diffusion U-Net完整结构图中展示了Spatial Transformer(Cross Attention)模块的结构。Spatial Transformer模块和ResNetBlock模块一样接受两个输入 :一个是ResNetBlock模块的输出,另外一个是输入文本Prompt经过CLIP Text Encoder模型编码后的Context Embedding。
两个输入首先经过Attention机制(将Context Embedding对应的语义信息与图片中对应的语义信息相耦合 ),输出新的Latent Feature,再将新输出的Latent Feature与输入的Context Embedding再做一次Attention机制,从而使得SD模型学习到了文本与图片之间的特征对应关系 。
Spatial Transformer模块不改变输入输出的尺寸,只在图片对应的位置上融合了语义信息,所以不管是在传统深度学习时代,还是AIGC时代,Spatial Transformer都是将本文与图像结合的一个“万金油”模块。
看CrossAttention模块的结构图,大家可能会疑惑为什么Context Embedding用来生成K和V,Latent Feature用来生成Q呢?
原因也非常简单:因为在Stable Diffusion中,主要的目的是想把文本信息注入到图像信息中里,所以用图片token对文本信息做 Attention实现逐步的文本特征提取和耦合。
Rocky再从AI绘画应用视角解释一下CrossAttention模块的作用 。CrossAttention模块在AI绘画应用中可以被视为一种连接和表达的工具,它有助于在输入文本和生成图片之间建立联系,创造更具深度和多样性的艺术作品,引发观众的思考和情感共鸣。CrossAttention模块可以将图像和文本信息关联起来,就像艺术家可以将不同的元素融合到一幅作品中,这有助于在创作中实现不同信息之间的协同和互动,产生更具创意性的艺术作品。再者CrossAttention模块可以用于将文本中的情感元素传递到生成图片中,这种情感的交互可以增强艺术作品的表现力和观众的情感共鸣。
3.3.2.3 BasicTransformer Block模块
BasicTransformer Block模块是在CrossAttention子模块的基础上,增加了SelfAttention子模块和Feedforward子模块共同组成的,并且每个子模块都是一个残差结构 ,这样除了能让文本的语义信息与图像的语义信息更好的融合之外,还能通过SelfAttention机制让模型更好的学习图像数据的特征 。
写到这里,可能还有读者会问,Stable Diffusion U-Net中的SelfAttention到底起了什么作用呀?
首先,在Stable Diffusion U-Net的SelfAttention模块中,输入只有图像信息,所以SelfAttention主要是为了让SD模型更好的学习图像数据的整体特征 。
再者,SelfAttention可以将输入图像的不同部分(像素或图像Patch)进行交互,从而实现特征的整合和全局上下文的引入,能够让模型建立捕捉图像全局关系的能力,有助于模型理解不同位置的像素之间的依赖关系,以更好地理解图像的语义 。
在此基础上,SelfAttention还能减少平移不变性问题 ,SelfAttention模块可以在不考虑位置的情况下捕捉特征之间的关系,因此具有一定的平移不变性。
Rocky再从AI绘画应用视角解释一下SelfAttention的作用 。SelfAttention模块可以让SD模型在图片生成过程中捕捉内在关系、创造性表达情感和思想、突出重要元素,并创造出丰富多彩、具有深度和层次感的艺术作品。
3.3.2.4 Spatial Transformer模块
更进一步的,在BasicTransformer Block模块基础上,加入GroupNorm和两个卷积层就组成Spatial Transformer模块。Spatial Transformer模块是SD U-Net中的核心Base结构,Encoder中的CrossAttnDownBlock模块,Decoder中的CrossAttnUpBlock模块以及CrossAttnMidBlock模块都包含了大量的Spatial Transformer子模块。
在生成式模型中,GroupNorm的效果一般会比BatchNorm更好 ,生成式模型通常比较复杂,因此需要更稳定和适应性强的归一化方法。
而GroupNorm主要有以下一些优势,让其能够成为生成式模型的标配:
对训练中不同Batch-Size的适应性 :在生成式模型中,通常需要使用不同的Batch-Size进行训练和微调。这会导致 BatchNorm在训练期间的不稳定性,而GroupNorm不受Batch-Size的影响,因此更适合生成式模型。
能适应通道数变化 :GroupNorm 是一种基于通道分组的归一化方法,更适应通道数的变化,而不需要大量调整。
更稳定的训练 :生成式模型的训练通常更具挑战性,存在训练不稳定性的问题。GroupNorm可以减轻训练过程中的梯度问题,有助于更稳定的收敛。
能适应不同数据分布 :生成式模型通常需要处理多模态数据分布,GroupNorm 能够更好地适应不同的数据分布,因为它不像 Batch Normalization那样依赖于整个批量的统计信息。
3.3.2.5 CrossAttnDownBlock/CrossAttnUpBlock/CrossAttnMidBlock模块
在Stable Diffusion U-Net的Encoder部分中,使用了三个CrossAttnDownBlock模块,其由ResNetBlock Structure+BasicTransformer Block+Downsample构成 。Downsample通过使用一个卷积(kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))来实现。
在Decoder部分中,使用了三个CrossAttnUpBlock模块,其由ResNetBlock Structure+BasicTransformer Block+Upsample构成 。Upsample使用插值算法+卷积来实现,插值算法将输入的Latent Feature尺寸扩大一倍,同时通过一个卷积(kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))改变Latent Feature的通道数,以便于输入后续的模块中。
在CrossAttnMidBlock模块中,包含ResNetBlock Structure+BasicTransformer Block+ResNetBlock Structure ,作为U-Net的Encoder与Decoder之间的媒介。
3.3.2.6 Stable Diffusion U-Net整体宏观角度小结
从整体上看,不管是在训练过程还是前向推理过程,Stable Diffusion中的U-Net在每次循环迭代中Content Embedding部分始终保持不变,而Time Embedding每次都会发生变化。
和传统深度学习时代的U-Net一样,Stable Diffusion中的U-Net也是不限制输入图片的尺寸,因为这是个基于Transformer和卷积的模型结构 。
3.3.3 Stable Diffusion中U-Net的训练过程与损失函数
在我们进行Stable Diffusion模型训练时,VAE部分和CLIP部分都是冻结的,所以说官方在训练SD系列模型的时候,训练过程一般主要训练U-Net部分。
我们之前我们已经讲过在Stable Diffusion中U-Net主要是进行噪声残差,在SD系列模型训练时和DDPM一样采用预测噪声残差的方法来训练U-Net,其损失函数如下所示:
L
S
D
=
E
x
0
,
ϵ
∼
N
(
0
,
I
)
,
t
[
∥
ϵ
−
ϵ
θ
(
α
ˉ
t
x
0
+
1
−
α
ˉ
t
ϵ
,
t
,
c
)
∥
2
]
L_{SD}=mathbb{E}_{mathbf{x}_{0},mathbf{epsilon}sim mathcal{N}(mathbf{0}, mathbf{I}), t}Big[ | mathbf{epsilon}- mathbf{epsilon}_thetabig(sqrt{bar{alpha}_t}mathbf{x}_0 + sqrt{1 – bar{alpha}_t}mathbf{epsilon}, t, mathbf{c}big)|^2Big]
L S D = E x 0 , ϵ ∼ N ( 0 , I ) , t [ ∥ ϵ − ϵ θ ( α ˉ t
x 0 + 1 − α ˉ t
ϵ , t , c ) ∥ 2 ]
这里的
c
mathbf{c}
c 为Text Embeddings。
到这里,Stable Diffusion U-Net的完整核心基础知识就介绍好了,欢迎大家在评论区发表自己的观点,也希望大家能多多点赞,Rocky会持续完善本文的全部内容,大家敬请期待!
3.3.4 SD模型融合详解(Merge Block Weighted,MBW)
不管是传统深度学习时代,还是AIGC时代,模型融合永远都是学术界、工业界以及竞赛界的一个重要Trick。
在AI绘画领域,很多AI绘画开源社区里都有SD融合模型的身影,这些融合模型往往集成了多个SD模型的优点,同时规避了不足,让这些SD融合模型在开源社区中很受欢迎。
接下来Rocky将带着大家详细了解SD模型的模型融合过程与方法,大家可能会好奇为什么SD模型融合会在介绍SD U-Net的章节中讲到,原因是SD的模型融合方法主要作用于U-Net部分 。
首先,我们需要知道SD模型融合的形式,一共三种有如下所示:
SD模型 + SD模型 -> 新SD模型
SD模型 + LoRA模型 -> 新SD模型
LoRA模型 + LoRA模型 -> 新LoRA模型
3.4 CLIP Text Encoder模型
作为文生图模型,Stable Diffusion中的文本编码模块直接决定了语义信息的优良程度,从而影响到最后图片生成的质量和与文本的一致性。
在这里,多模态领域的神器——CLIP(Contrastive Language-Image Pre-training) ,跨过了周期,从传统深度学习时代进入AIGC时代,成为了SD系列模型中文本和图像之间的“桥梁 ”。并且从某种程度上讲,正是因为CLIP模型的前置出现,加速推动了AI绘画领域的繁荣 。
那么,什么是CLIP呢?CLIP有哪些优良的性质呢?为什么是CLIP呢?
首先,CLIP模型是一个基于对比学习的多模态模型,主要包含Text Encoder和Image Encoder两个模型 。其中Text Encoder用来提取文本的特征,可以使用NLP中常用的text transformer模型作为Text Encoder;而Image Encoder主要用来提取图像的特征,可以使用CNN/Vision transformer模型(ResNet和ViT等)作为Image Encoder。与此同时,他直接使用4亿个图片与标签文本对数据集进行训练,来学习图片与本文内容的对应关系 。
与U-Net的Encoder和Decoder一样,CLIP的Text Encoder和Image Encoder也能非常灵活的切换,庞大图片与标签文本数据的预训练赋予了CLIP强大的zero-shot分类能力。
灵活的结构,简洁的思想,让CLIP不仅仅是个模型,也给我们一个很好的借鉴,往往伟大的产品都是大道至简的。更重要的是,CLIP把自然语言领域的抽象概念带到了计算机视觉领域。
CLIP在训练时,从训练集中随机取出一张图片和标签文本,接着CLIP模型的任务主要是通过Text Encoder和Image Encoder分别将标签文本和图片提取embedding向量 ,然后用余弦相似度 (cosine similarity)来比较两个embedding向量的相似性 ,以判断随机抽取的标签文本和图片是否匹配,并进行梯度反向传播,不断进行优化训练。
上面讲了Batch为1时的情况,当我们把训练的Batch提高到
N
N
N 时,其实整体的训练流程是不变的。只是现在CLIP模型需要将
N
N
N 个标签文本和
N
N
N 个图片的两两组合预测出
N
2
N^{2}
N 2 个可能的文本-图片对的余弦相似性,即下图所示的矩阵。这里共有
N
N
N 个正样本,即真正匹配的文本和图片(矩阵中的对角线元素),而剩余的
N
2
−
N
N^{2} – N
N 2 − N 个文本-图片对为负样本,这时CLIP模型的训练目标就是最大化
N
N
N 个正样本的余弦相似性,同时最小化
N
2
−
N
N^{2} – N
N 2 − N 个负样本的余弦相似性。
完成CLIP的训练后,输入配对的图片和标签文本,则Text Encoder和Image Encoder可以输出相似的embedding向量 ,计算余弦相似度就可以得到接近1的结果。同时对于不匹配的图片和标签文本,输出的embedding向量计算余弦相似度则会接近0 。
就这样,CLIP成为了计算机视觉和自然语言处理这两大AI方向的“桥梁”,从此AI领域的多模态应用有了经典的基石模型。
上面我们讲到CLIP模型主要包含Text Encoder和Image Encoder两个部分 ,在Stable Diffusion中主要使用了Text Encoder部分。CLIP Text Encoder模型将输入的文本Prompt进行编码,转换成Text Embeddings(文本的语义信息) ,通过前面章节提到的U-Net网络的CrossAttention模块嵌入Stable Diffusion中作为Condition条件,对生成图像的内容进行一定程度上的控制与引导 ,目前SD模型使用的的是CLIP ViT-L/14 中的Text Encoder模型。
CLIP ViT-L/14 中的Text Encoder是只包含Transformer结构的模型,一共由12个CLIPEncoderLayer模块组成,模型参数大小是123M,具体CLIP Text Encoder模型结构如下图所示。其中特征维度为768,token数量是77,所以输出的Text Embeddings的维度为77×768 。
CLIPEncoderLayer(
( self_attn) : CLIPAttention(
( k_proj) : Linear( in_features= 768 , out_features= 768 , bias= True )
( v_proj) : Linear( in_features= 768 , out_features= 768 , bias= True )
( q_proj) : Linear( in_features= 768 , out_features= 768 , bias= True )
( out_proj) : Linear( in_features= 768 , out_features= 768 , bias= True )
)
( layer_norm1) : LayerNorm( ( 768 , ) , eps= 1e-05 , elementwise_affine= True )
( mlp ) : CLIPMLP(
( activation_fn) : QuickGELUActivation( )
( fc1) : Linear( in_features= 768 , out_features= 3072 , bias= True )
( fc2) : Linear( in_features= 3072 , out_features= 768 , bias= True )
)
( layer_norm2) : LayerNorm( ( 768 , ) , eps= 1e-05 , elementwise_affine= True )
)
下图是Rocky梳理的Stable Diffusion CLIP Text Encoder的完整结构图 ,大家可以感受一下其魅力,看着这个完整结构图学习Stable Diffusion CLIP Text Encoder部分,相信大家脑海中的思路也会更加清晰: 下面Rocky将使用transofmers库演示调用CLIP Text Encoder,给大家一个更加直观的SD模型的文本编码全过程:
from transformers import CLIPTextModel, CLIPTokenizer
text_encoder = CLIPTextModel. from_pretrained( "/本地路径/stable-diffusion-v1-5" , subfolder= "text_encoder" ) . to( "cuda" )
text_tokenizer = CLIPTokenizer. from_pretrained( "/本地路径/stable-diffusion-v1-5" , subfolder= "tokenizer" )
prompt = "1girl,beautiful"
text_token_ids = text_tokenizer(
prompt,
padding= "max_length" ,
max_length= text_tokenizer. model_max_length,
truncation= True ,
return_tensors= "pt"
) . input_ids
print ( "text_token_ids' shape:" , text_token_ids. shape)
print ( "text_token_ids:" , text_token_ids)
text_embeddings = text_encoder( text_token_ids. to( "cuda" ) ) [ 0 ]
print ( "text_embeddings' shape:" , text_embeddings. shape)
print ( text_embeddings)
- - - - - - - - - - - - - - - - 运行结果 - - - - - - - - - - - - - - - -
text_token_ids' shape: torch. Size( [ 1 , 77 ] )
text_token_ids: tensor( [ [ 49406 , 272 , 1611 , 267 , 1215 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ] ] )
text_embeddings' shape: torch. Size( [ 1 , 77 , 768 ] )
tensor( [ [ [ - 0.3884 , 0.0229 , - 0.0522 , . . . , - 0.4899 , - 0.3066 , 0.0675 ] ,
[ - 0.8425 , - 1.1393 , 1.2756 , . . . , - 0.2595 , 1.6293 , - 0.7857 ] ,
[ 0.1753 , - 0.9846 , 0.1879 , . . . , 0.0664 , - 1.4935 , - 1.2614 ] ,
. . . ,
[ 0.2039 , - 0.7296 , - 0.3212 , . . . , 0.6748 , - 0.5813 , - 0.7323 ] ,
[ 0.1921 , - 0.7344 , - 0.3045 , . . . , 0.6803 , - 0.5852 , - 0.7230 ] ,
[ 0.2114 , - 0.6436 , - 0.3047 , . . . , 0.6624 , - 0.5575 , - 0.7586 ] ] ] ,
device= 'cuda:0' , grad_fn= NativeLayerNormBackward0> )
一般来说,我们提取CLIP Text Encoder模型最后一层特征作为CrossAttention模块的输入,但是开源社区的不断实践为我们总结了如下经验:当我们生成二次元内容时,可以选择提取CLIP Text Encoder模型倒数第二层特征;当我们生成写实场景内容时,可以选择提取CLIP Text Encoder模型最后一层的特征。这让Rocky想起了SRGAN以及感知损失,其也是提取了VGG网络的中间层特征才达到了最好的效果,AI领域的“传承”与共性,往往在这些不经意间,让人感到人工智能的魅力与美妙 。
由于CLIP训练时所采用的最大Token数是77,所以在SD模型进行前向推理时,当输入Prompt的Token数量超过77时,将通过Clip操作拉回77×768,而如果Token数不足77则会使用padding操作得到77×768。如果说全卷积网络的设计让图像输入尺寸不再受限,那么CLIP的这个设置就让输入的文本长度不再受限(可以是空文本) 。无论是非常长的文本,还是空文本,最后都将得到一样维度的特征矩阵。
同时在SD模型的训练中,一般来说CLIP的整体性能是足够支撑我们的下游细分任务的,所以CLIP Text Encoder模型参数是冻结的,我们不需要对其重新训练 。
在AIGC时代,我们使用语言文字表达的创意与想法,可以轻松让Stable Diffusion生成出一幅幅精美绝伦、创意十足、飞速破圈的图片。而这些背后,都有CLIP的功劳,CLIP不仅仅连接了文本和图像,也连接了AI行业与千万个需要生成图片和视频的行业,AI绘画的ToC普惠如此之强,Rocky认为CLIP就是那个“隐形冠军” 。
3.5 SD官方训练细节解析
上面我们已经介绍了Stable Diffusion的核心网络结构,在本节中我们再介绍一下SD的官方训练细节,主要包括训练数据、训练过程、训练资源、模型测评等。
3.5.1 SD官方训练数据集
首先我们介绍一下训练数据集,Stable Diffusion是在LAION-5B数据集(包含58.5 亿个高质量图像文本数据对 )的一个子集LAION2B-en数据集 (23.2 亿个纯英语高质量图像文本数据对 )上进行训练的。
LAION-5B是一个大规模的图像-文本对数据集,由LAION(Large-scale Artificial Intelligence Open Network)组织发布。这个数据集包含了大约58.5亿个经过CLIP模型筛选的图像-文本对,是当前AIGC领域非常热门的公开图像-文本对数据集,旨在推动机器学习和人工智能领域,特别是在视觉和语言融合、生成模型等方面的研究和应用。
LAION2B-en数据集的元信息(图片的width、height以及对应的Text length)统计分析如下所示: 可以看到,LAION2B-en数据集中的图片长宽均大于256的数据量有1324M,大于512的数据量有488M,大于1024的数据量有76M。同时LAION2B-en数据集中图片对应的文本标签的平均长度为67。
LAION数据集中除了上面讲到的图片元信息外,每张图片还包含以下信息:
3.5.2 SD官方训练过程
上面我们已经讲完LAION数据集的内容,接下来我们再介绍一下SD官方训练的具体过程。
SD的训练是多阶段的,先在256×256尺寸上预训练,然后在512×512尺寸上微调训练,不同的训练方式产生了不同的版本:
SD 1.1:先在LAION2B-en数据集上用256×256分辨率训练237,000步(LAION2B-en数据集中256分辨率以上的数据一共有1324M);然后在LAION-5B的高分辨率数据集 (laion-high-resolution:LAION-5B数据集中图像分辨率在1024×1024以上的样本,共170M样本)用512×512分辨率接着训练194,000步。
SD 1.2:以SD 1.1为初始权重,在laion-improved-aesthetics数据集(LAION2B-en数据集中美学评分在5分以上并且分辨率大于512×512的无水印数据子集,一共约有600M个样本。这里设置了pwatermark>0.5为水印图片的规则来过滤含有水印的图片)上用512×512分辨率训练了515,000步。
SD 1.3:以SD 1.2为初始权重,在laion-improved-aesthetics数据集上继续用512×512分辨率训练了195,000步,并且采用了CFG技术(训练时以10%的概率dropping掉Text Embeddings)进行优化。
SD 1.4:以SD 1.2为初始权重,在laion-aesthetics v2 5+数据集上采用CFG技术用512×512分辨率训练了225,000步。
SD 1.5:以SD 1.2为初始权重,在laion-aesthetics v2 5+数据集上采用CFG技术用512×512分辨率训练了595,000步。
根据上面官方的训练过程,我们可以看到SD 1.3、SD 1.4以及SD 1.5模型都是在SD 1.2的基础上结合CFG技术在laion-improved-aesthetics和laion-aesthetics v2 5+数据集持续训练得到的不同阶段的模型权重,目前最热门的版本是Stable Diffusion 1.5模型 。
3.5.3 SD官方训练资源
官方在从0到1训练SD模型时,一共配置了32台8卡A100服务器 (32 x 8 x A100_40GB GPUs)作为算力,AI绘画核心模型的诞生成本确实很高。
同时设置单张GPU的训练batch size为4,并设置gradient accumulation steps=2,SD模型训练时总的batch size = 32x8x2x4 = 2048 。
SD官方训练时优化器采用AdamW,在训练初期采用warmup,在初始10,000步后学习速率升到0.0001 ,后面保持不变(constant)。
SD模型总的训练时间,在32台8卡A100服务器马力全开时共花费了150,000/(32×8)= 586小时约等于25天。
3.5.4 SD模型测评
对于AI绘画模型,目前常用的定量指标是FID (Fréchet inception distance)和CLIP score ,其中FID可以衡量生成图像的逼真度(image fidelity),而CLIP score可以测评生成图像与输入文本的一致性。其中FID值越低越好,而CLIP score则越大越好 。
当CFG的gudiance scale参数设置不同时,FID和CLIP score会发生变化,下图为8种不同的gudiance scale参数情况下,SD模型在COCO2017验证集上的评测结果,注意这里是zero-shot评测(SD模型并没有在COCO训练数据集上微调): 从上图可以看到,SD 1.5模型整体效果是最好的。同时当gudiance scale=3时,FID处在最低值;当gudiance scale逐步增大时,CLIP score随之提升,但是FID也会增大。从不同SD版本的曲线对比可以看到采用CFG训练是有效果的,SD采用CFG训练后的1.3-1.5三个版本整体性能明显比未采用CFG训练的版本好。
4. Stable Diffusion经典应用场景
在本章节中,Rocky将详细介绍Stable Diffusion的五大经典应用,并梳理各个经典应用场景的完整工作流(Workflow) ,清晰直观的展示SD应用场景的每个细节流程,让大家对SD经典应用场景有更深的理解。
4.1 文本生成图像(txt2img)
文本生成图像是SD系列模型最基础也是最核心的应用功能,下面是SD系列模型进行文本生成图像的完整流程:
根据上面的完整流程图,我们结构化分析一下SD系列模型进行文本生成图像的脉络:
输入 :将输入的文本(prompt)通过Text Encoder提取出Text Embeddings特征(77×768);同时初始化一个Latent空间的随机高斯噪声矩阵(维度为64x64x4,对应512×512分辨率图像)。
生成过程 :将Text Embeddings特征和随机高斯噪声矩阵通过CrossAttention机制送入U-Net中,结合Scheduler algorithm(调度算法)迭代去噪,经过N次迭代后生成去噪后的Latent特征。
输出 :将去噪后的Latent特征送入VAE的Decoder模块,重建出像素级图像(512×512分辨率)。
下面Rocky再用节点式结构图 展示一下SD模型进行文本生成图像的全部流程:
其中Load Checkpoint模块代表对SD系列模型的主要结构的权重进行加载初始化(VAE、U-Net、Text Encoder),CLIP Text Encode表示文本编码器,可以输入Prompt和Negative Prompt,来控制图像的生成,Empty Latent Image表示初始化的高斯噪声,KSampler表示调度算法以及SD相关生成参数,VAE Decode表示使用VAE的解码器将Latent特征转换成像素级图像。
下面Rocky再和大家一起分析一下SD在推理过程中的几个重要参数:
生成图片的尺寸(width和height)
推理步数(steps、num_inference_steps或者Sampling steps)
guidance_scale(guidance_scale或者CFG Scale)
Negative Prompt
4.1.1 生成图片的尺寸(width和height)
我们首先来探讨一下SD生成图片的尺寸对生成效果的影响。之前我们已经讲过,SD模型是在512×512分辨率的数据上进行训练的,所以在默认情况下生成512×512分辨率的图片效果最好 。
但是实际上开源社区用户的使用习惯更多是生成任意尺寸的图像 ,同时SD本身的模型结构也是支持任意尺寸的图像生成的,因为SD模型中的VAE支持任意尺寸图像的编码和解码,U-Net部分(只有卷积结构和Attention机制,没有全连接层)也是支持任意尺寸的Latent特征的生成 。
然而,由于原生SD模型在训练时输入尺寸是固定的,这就导致了实际使用时生成512×512分辨率以外的图像会出现问题。在生成低分辨率(比如256×256)图像时,图像的质量会大幅度下降;在生成高分辨率(比如768×512、512×768、768×768、1024×1024)的图像时,图像质量虽然没问题,但是可能会出现物体特征重复、物体被拉长、主体结构崩坏等问题。
解决这个问题的一个直观有效的方法是进行多尺度训练。在传统深度学习时代,这是YOLO系列模型的一个必备训练方法,终于跨过周期在AIGC时代重新繁荣,并由NovelAI优化后变成了适合于SD系列模型的Aspect Ratio Bucketing 策略。
4.1.2 推理步数(steps、num_inference_steps或者Sampling steps)
num_inference_steps表示SD系列模型在推理过程中的去噪次数或者采样步数 。一般来说,我们可以设置num_inference_steps在20-50之间,其中设置的采样步数越大,图像的生成效果越好,但同时生成所需的时间就越长。
到这里大家可能会有疑问,为什么SD系列模型在训练时设置1000的noise scheduler,在推理时却只用设置20-50的noise scheduler?
这是因为,虽然SD模型在训练时参照DDPM采样方法,但推理时可以使用DDIM这个采样方法,DDIM通过去马尔可夫化,让SD模型在推理时可以进行“跳步”,抽取短的子序列作为noise scheduler,大大减少了推理步数 。
当然的,除了使用DDIM采样方法,我们也可以使用其他的采样方法,目前主流的采样方法有DPM系列、DPM++系列、Euler系列、LMS系列、Heun、UniPC、Restart等。
4.1.3 guidance_scale(guidance_scale或者CFG Scale)
guidance_scale代表CFG(无分类指引,Classifier-free guidance,guidance_scale)的权重 ,当设置的guidance_scale越大时,文本的控制力会越强,SD模型生成的图像会和输入文本更一致 。通常guidance_scale可以设置在7-8.5之间,就会有不错的生成效果。如果使用非常大的guidance_scale值(比如11-12),生成的图像可能会过饱和,同时多样性会降低 。
当我们使用CFG之后,SD模型在去噪过会同时依赖条件扩散模型和无条件扩散模型:
pred_noise
=
w
⋅
cond_pred_noise
+
(
1
−
w
)
⋅
uncond_pred_noise
text{pred_noise} = w cdot text{cond_pred_noise} + (1 – w) cdot text{uncond_pred_noise}
pred_noise = w ⋅ cond_pred_noise + ( 1 − w ) ⋅ uncond_pred_noise
其中
w
w
w 代表guidance_scale,当
w
w
w 越大时,输入文本起的作用越大,即生成的图像更和输入文本一致,当
w
w
w 被设置为0时,图像的生成是无条件的,输入文本会被忽略。
4.1.4 Negative Prompt
我们可以使用Negative Prompt来避免生成我们不想要的内容 ,从而改善图像生成效果。
Negative Prompt和CFG有关,下面的公式中包含了条件扩散模型和无条件扩散模型:
pred_noise
=
w
ϵ
θ
(
x
t
,
t
,
c
)
+
(
1
−
w
)
ϵ
θ
(
x
t
,
t
)
=
ϵ
θ
(
x
t
,
t
)
+
w
(
ϵ
θ
(
x
t
,
t
,
c
)
−
ϵ
θ
(
x
t
,
t
)
)
text{pred_noise}=wmathbf{epsilon}_thetabig(mathbf{x}_t, t, mathbf{c}big)+(1-w)mathbf{epsilon}_thetabig(mathbf{x}_t, tbig)=mathbf{epsilon}_thetabig(mathbf{x}_t, tbig)+w(mathbf{epsilon}_thetabig(mathbf{x}_t, t, mathbf{c}big)-mathbf{epsilon}_thetabig(mathbf{x}_t, tbig))
pred_noise = w ϵ θ ( x t , t , c ) + ( 1 − w ) ϵ θ ( x t , t ) = ϵ θ ( x t , t ) + w ( ϵ θ ( x t , t , c ) − ϵ θ ( x t , t ) )
Negative Prompt就是无条件扩散模型的文本输入 ,只是SD模型的训练过程中我们将文本设置为空字符串来实现无条件扩散模型,即negative_prompt = “”。当推理阶段我们开始使用Negative Prompt时,这部分的文本不再为空,并且从上述公式可以看出无条件扩散模型是我们想远离的分布。
4.2 图像生成图像(img2img)
SD模型的图生图功能是以文生图功能为基础的一个拓展功能 ,和文生图相比,图生图的初始Latent特征不再是一个随机噪声,而是初始输入图像通过VAE编码之后加上一定高斯噪声(扩散过程)的Latent特征 。然后使用SD模型进行去噪操作,此时去噪的步数要和加噪的步数保持一致 ,这样才能生成整体布局与初始图像一致的无噪声图像。 与此同时,我们设置一个去噪强度(Denoising strength)来控制加入多少噪声 。如果设置Denoising strength = 0,就不添加噪声。如果设置Denoising strength = 1,则添加噪声原始图像成为一个随机噪声矩阵,此时就相当于进行文生图的流程了。 讲完了图生图的完整流程,我们在结构化分析一下SD系列模型进行图生图的脉络:
输入 :将输入的文本(prompt)通过Text Encoder提取出Text Embeddings特征(77×768);同时将初始图像通过VAE编码成一个Latent特征(维度为64x64x4,对应512×512分辨率图像)。
生成过程 :通过扩散过程往Latent特征中加入N次迭代的噪声,再将Text Embeddings特征和随机高斯噪声矩阵通过CrossAttention机制送入U-Net中,结合Scheduler algorithm(调度算法)迭代去噪,经过N次迭代后生成去噪后的Latent特征。
输出 :将去噪后的Latent特征送入VAE的Decoder模块,重建出像素级图像(512×512分辨率)。
下面Rocky再用节点式结构图 展示一下SD模型进行图生图的全部流程: 其中Load Checkpoint模块代表对SD模型的主要结构进行初始化(VAE、U-Net、Text Encoder),CLIP Text Encode表示文本编码器,可以输入Prompt和Negative Prompt,来控制图像的生成,Load Image表示输入的初始图像,KSampler表示调度算法以及SD相关生成参数,VAE Encode表示使用VAE的编码器将初始图像转换成Latent特征,VAE Decode表示使用VAE的解码器将Latent特征转换成像素级图像。
4.3 图像重绘(Inpainting)
图像inpainting最初用在图像修复 上,是一种图像修复技术,可以将图像中的水印、噪声、标志等瑕疵去除。
传统的图像inpainting过程可以分为两步:1. 找到图像中的瑕疵部分 2. 对瑕疵部分进行重绘去除,并填充图像内容使得图像语义完整自然。
在AIGC时代,图像inpainting再次繁荣,成为Stable Diffusion的经典应用场景,在图像编辑 上重新焕发生机。
那么什么是图像编辑呢?
图像编辑是指对图像进行修改、调整和优化的过程。它可以包括对图像的颜色、对比度、亮度、饱和度等进行调整,以及修复图像中的缺陷、删除不需要的元素、添加新的图像内容等操作。 在SD中,主要是通过给定一个想要编辑的区域mask,并在这个区域mask圈定的范围内进行文本生成图像的操作,从而编辑mask区域的图像内容。
SD中的图像inpainting流程如下所示:
从上图可以看出,图像inpainting整体上和图生图流程一致,不过为了保证mask以外的图像区域不发生改变,在去噪过程的每一步,我们利用mask将Latent特征中不需要重建的部分都替换成原图最初的特征,只在mask部分进行特征的重建与优化。
在加入了mask后,SD模型的输入通道数也发生了变化,文生图和图生图任务中,SD的输入是64x64x4,而在图像inpainting任务中,增加了mask(64x64x1),所以此时SD的输入为64x64x5。
讲完了图像inpainting的完整流程,我们在结构化分析一下SD系列模型进行图像inpainting的脉络:
输入 :将输入的文本(prompt)通过Text Encoder提取出Text Embeddings特征(77×768);同时将初始图像和Mask通过VAE分别编码成两个Latent特征(维度分别为64x64x4和64x64x1,对应512×512分辨率图像)。
生成过程 :通过扩散过程往Latent特征中加入N次迭代的噪声,但只影响Mask涵盖的区域,再将Text Embeddings特征和随机高斯噪声矩阵通过CrossAttention机制送入U-Net中,结合Scheduler algorithm(调度算法)迭代去噪,经过N次迭代后生成去噪后的Latent特征。
输出 :将去噪后的Latent特征送入VAE的Decoder模块,重建出像素级图像(512×512分辨率)。
下面Rocky再用节点式结构图 展示一下SD模型进行图像inpainting的全部流程:
其中Load Checkpoint模块代表对SD模型的主要结构进行加载(VAE、U-Net、Text Encoder)。CLIP Text Encode表示SD模型的文本编码器,可以输入Prompt和Negative Prompt,来引导图像的生成。Load Image表示输入的图像和mask。KSampler表示调度算法以及SD相关生成参数。VAE Encode表示使用VAE的Encoder将输入图像和mask转换成Latent特征,VAE Decode表示使用VAE的Decoder将Latent特征重建成像素级图像。
下面就是进行图像inpainting的直观过程: 由于图像inpainting和图生图的操作一样,只是在SD模型原有的基础上扩展了它的能力,并没有去微调SD模型,所以如何调整各种参数成为了生成优质图片的关键。
当然的,也有专门用于图像inpainting的SD模型,比如说Stable Diffusion Inpainting模型,是以SD 1.2为基底模型微调而来 ,同时在输入端增加了经过mask处理的图像的Latent特征(64x64x4)和mask(64x64x1),所以此时SD的输入为64x64x9,同时新增的部分设置权重全零初始化。Stable Diffusion Inpainting模型由于经过专门的inpainting训练,在生成细节上比起常规SD模型会更好,但是相应的常规文生图的能力会有一定的减弱。
4.4 图像的可控生成(使用ControlNet辅助生成)
SD系列模型的可控生成主要依赖于ControlNet等控制模型,可以与文生图、图生图以及图像Inpainting等任务结合使用。
如果大家想要了解ControlNet的核心基础知识,可以阅读Rocky写的这篇文章:
深入浅出完整解析ControlNet核心基础知识
下面Rocky用节点式结构图 展示一下SD模型使用ControlNet辅助生成的全部流程: 其中Load Checkpoint模块代表对SD模型的主要结构进行初始化(VAE、U-Net、Text Encoder),CLIP Text Encode表示文本编码器,可以输入Prompt和Negative Prompt,来控制图像的生成,Load Image表示输入的ControlNet需要的预处理图,Empty Latent Image表示初始化的高斯噪声,Load ControlNet Model表示对ControlNet进行初始化,KSampler表示调度算法以及SD相关生成参数,VAE Decode表示使用VAE的解码器将Latent特征转换成像素级图像。
4.5 图像超分辨率重建
图像超分辨率重建可以说是图像生成任务的一个后处理功能,用于获得高分辨率的高质量图像。
目前主流的超分模型主要分两类,一类是基于传统深度学习时代的GAN模型(R-ESRGAN、ESRGAN、ScuNET GAN等),另外一类是基于AIGC时代的扩散模型(LDSR、stable-diffusion-x4-upscaler等)。
下面Rocky用节点式结构图 展示一下SD模型进行图像超分辨率重建的全部流程:
在结构图中可以看到,整体流程与文生图和图生图一致,在此基础上增加了Upscale Image表示对生成的图片进行超分操作。
5. 从0到1搭建使用Stable Diffusion模型进行AI绘画(全网最详细讲解)
目前能够加载Stable Diffusion模型并进行图像生成的主流AI绘画框架有四种:
diffusers框架
Stable Diffusion WebUI框架
ComfyUI框架
SD.Next框架
为了方便大家使用主流AI绘画框架,Rocky这里也总结汇总了相关的资源,方便大家直接部署使用:
Stable Diffusion WebUI资源包可以关注公众号WeThinkIn ,后台回复“WebUI资源 ”获取。
ComfyUI的500+高质量工作流资源包可以关注公众号WeThinkIn ,并回复“ComfyUI ”获取。
SD.Next资源包可以关注公众号WeThinkIn ,后台回复“SD.Next资源 ”获取。
接下来,为了让大家能够从0到1搭建使用Stable Diffusion这个当前开源生态最繁荣的AI绘画大模型,Rocky将详细的讲解如何用这四个框架构建Stable Diffusion推理流程 。那么,跟随着Rocky的脚步,让我们开始吧。
5.1 零基础使用diffusers搭建Stable Diffusion推理流程
每次SD系列技术在更新迭代时,diffusers库一般都是最先原生支持其功能的,所以在diffusers中能够非常高效的构建Stable Diffusion推理流程 。但是由于diffusers目前没有现成的可视化界面,Rocky将在Jupyter Notebook中搭建完整的Stable Diffusion推理工作流,让大家能够快速的学习掌握。
首先,我们需要安装diffusers库,并确保diffusers的版本 >= 0.18.0,我们只需要在命令行中输入以下命令进行安装即可:
pip install diffusers - - upgrade - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
显示如下log表示安装成功:
Successfully installed diffusers- 0.18 .2 huggingface- hub- 0.16 .4
接着,我们继续安装其他的依赖库:
pip install transformers== 4.27 .0 accelerate== 0.12 .0 safetensors== 0.2 .7 invisible_watermark - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
显示如下log表示安装成功:
Successfully installed transformers- 4.27 .0 accelerate== 0.12 .0 safetensors== 0.2 .7 invisible_watermark- 0.2 .0
完成了上述依赖库的安装,我们就可以搭建Stable Diffusion模型的完整工作流程了,具体的pipeline流程代码如下所示:
from diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline. from_pretrained( "/本地路径/stable-diffusion-v1-5" )
pipe. to( "cuda" )
pipe = StableDiffusionPipeline. from_pretrained( "/本地路径/stable-diffusion-v1-5" , revision= "fp16" , torch_dtype= torch. float16)
prompt = "a photograph of an astronaut riding a horse"
image = pipe( prompt) . images[ 0 ]
diffusers格式的SD模型权重文件夹中有很多文件,很多朋友可能不太清楚每个文件的含义,Rocky这里再带着大家进行逐一的解读。
首先我们打开下载好的SD模型权重文件夹,可以看到主要由以下几个部分组成:
text_encoder、tokenizer、scheduler、unet、vae以及safety_checker。
其中text_encoder、scheduler、unet和vae文件夹分别保存了SD模型的核心结构权重。
同时我们还可以看到tokenizer文件夹,表示标记 器。tokenizer首先将Prompt中的每个词转换为一个称为标记(token)的数字,符号化(Tokenization)是计算机理解单词的方式 。然后,通过Text Encoder将每个标记都转换为一个768值的向量,称为嵌入(embedding),用于U-Net的condition条件。safety_checker文件夹中是一个NSFW检测器模型 ,用于检测生成的图片是否包含NSFW内容。有时候我们运行完pipeline之后,会出现纯黑色图片,这表示我们本次生成的图片触发了NSFW机制,出现了一些违规的图片,我们可以修改seed重新进行生成。
了解完diffusers格式的SD模型权重文件,接下来我们继续深入使用diffusers框架。我们可以调整不同的参数(seed、steps、CFG等),来优化SD模型的图片生成效果:
import torch
prompt = "a photograph of an astronaut riding a horse"
generator = torch. Generator( "cuda" ) . manual_seed( 1024 )
steps = 25
CFG = 7.5
image = pipe( prompt, guidance_scale= CFG, height= 512 , width= 768 , num_inference_steps= steps, generator= generator) . images[ 0 ]
除了将SD模型权重整体加载,我们还可以将SD模型的不同组件权重进行单独加载:
from transformers import CLIPTextModel, CLIPTokenizer
from diffusers import AutoencoderKL, UNet2DConditionModel, PNDMScheduler
from diffusers import LMSDiscreteScheduler
vae = AutoencoderKL. from_pretrained( "/本地路径/stable-diffusion-v1-5" , subfolder= "vae" )
tokenizer = CLIPTokenizer. from_pretrained( "openai/clip-vit-large-patch14" )
text_encoder = CLIPTextModel. from_pretrained( "openai/clip-vit-large-patch14" )
unet = UNet2DConditionModel. from_pretrained( "/本地路径/stable-diffusion-v1-5" , subfolder= "unet" )
scheduler = LMSDiscreteScheduler( beta_start= 0.00085 , beta_end= 0.012 , beta_schedule= "scaled_linear" , num_train_timesteps= 1000 )
虽然diffusers库是原生支持SD模型的,但是在开源社区中流行使用safetensors格式的SD模型,所以我们想用diffusers库运行开源社区的很多SD模型时,需要首先将其转成diffusers格式 。Rocky在这里也总结了一套SD模型的格式转换教程,方便大家快速转换格式,使用diffusers库运行模型。主要流程如下所示:
pip install diffusers== 0.20 .0 transformers== 4.38 .1 accelerate== 0.27 .2
git clone https: // github . com/ huggingface/ diffusers. git
cd diffusers/ scripts
python convert_original_stable_diffusion_to_diffusers. py - - checkpoint_path / 本地路径/ safetensors格式模型 - - dump_path / 本地路径/ 转换后diffusers格式模型的保存路径 - - from_safetensors
成功运行上述代码后,我们可以看到一个包含scheduler、vae、unet、text_encoder、tokenizer文件夹以及model_index.json文件的diffusers格式的SD模型。
5.2 零基础使用Stable Diffusion WebUI搭建Stable Diffusion推理流程
目前Stable Diffusion WebUI可以说是开源社区使用Stable Diffusion模型进行AI绘画最热门的框架。
Stable Diffusion WebUI 是AI绘画领域最为流行的框架 ,其生态极其繁荣,非常多的上下游插件能够与Stable Diffusion WebUI一起完成诸如AI视频生成,AI证件照生成等工作流,可玩性非常强。
接下来,咱们就使用这个流行框架搭建Stable Diffusion推理流程吧。
首先,我们需要下载安装Stable Diffusion WebUI框架,我们只需要在命令行 输入如下代码即可:
git clone https: // github. com/ AUTOMATIC1111/ stable- diffusion- webui. git
安装好后,我们可以看到本地的stable-diffusion-webui文件夹。
下面我们需要安装其依赖库,我们进入Stable Diffusion WebUI文件夹,并进行以下操作:
cd stable- diffusion- webui
pip install - r requirements. txt - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
和SD.Next的配置流程类似,我们还需要配置Stable Diffusion WebUI的repositories插件,我们需要运行下面的代码:
sh webui. sh
如果发现repositories插件下载速度较慢,出现很多报错,don’t worry,大家可以直接使用Rocky已经配置好的资源包,可以快速启动Stable Diffusion WebUI框架。Stable Diffusion WebUI资源包可以关注公众号WeThinkIn ,后台回复“WebUI资源 ”获取。
在完成了依赖库和repositories插件的安装后,我们就可以配置模型了,我们将Stable Diffusion模型放到/stable-diffusion-webui/models/Stable-diffusion/路径下 。这样一来,等我们开启可视化界面后,就可以选择Stable Diffusion模型用于推理生成图片了。
完成上述的步骤后,我们可以启动Stable Diffusion WebUI了!我们到/stable-diffusion-webui/路径下 ,运行launch.py即可:
python launch. py - - listen - - port 8888
运行完成后,可以看到命令行中出现的log:
To see the GUI go to: http://0.0.0.0:8888
我们将http://0.0.0.0:8888输入到我们本地的网页中,即可打开如下图所示的Stable Diffusion WebUI可视化界面,愉快的使用Stable Diffusion模型进行AI绘画了。
进入Stable Diffusion WebUI可视化界面后,我们可以在红色框中选择SD模型,然后在黄色框中输入我们的Prompt和负向提示词,同时在绿色框中设置我们想要生成的图像分辨率(推荐设置成768×768 ),然后我们就可以点击Generate按钮,进行AI绘画了。
等待片刻后,图像就生成好了,并展示在界面的右下角,同时也会保存到/stable-diffusion-webui/outputs/txt2img-images/路径下 ,大家可以到对应路径下查看。
5.3 零基础使用ComfyUI搭建Stable Diffusion推理流程
ComfyUI 是一个基于节点式 的Stable Diffusion AI绘画工具。和Stable Diffusion WebUI相比,ComfyUI通过将Stable Diffusion模型生成推理的pipeline拆分成独立的节点,实现了更加精准的工作流定制和清晰的可复现性 。
目前ComfyUI能够非常成熟的使用Stable Diffusion模型,下面是Rocky使用ComfyUI来加载Stable Diffusion模型并生成图片的完整Pipeline:
大家可以看到上图是文生图的工作流,如果感觉复杂,不用担心,Rocky已经为大家保存了这个工作流 ,大家只需关注Rocky的公众号WeThinkIn ,并回复“ComfyUI ”,就能获取这个工作流以及文生图、图生图、图像Inpainting、ControlNet以及图像超分在内的所有Stable Diffusion经典工作流json文件,大家只需在ComfyUI界面右侧点击Load按钮 选择对应的json文件,即可加载对应的工作流,开始愉快的AI绘画之旅。
话说回来,下面Rocky将带着大家一步一步使用ComfyUI搭建Stable Diffusion推理流程,从而实现上图所示的生成过程。
首先,我们需要安装ComfyUI框架,这一步非常简单,在命令行 输入如下代码即可:
git clone https: // github. com/ comfyanonymous/ ComfyUI. git
安装好后,我们可以看到本地的ComfyUI文件夹。
ComfyUI框架安装到本地后,我们需要安装其依赖库,我们只需以下操作:
cd ComfyUI
pip install - r requirements. txt - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
完成这些配置工作后,我们就可以配置模型了,我们将Stable Diffusion模型放到ComfyUI/models/checkpoints/路径下 。这样一来,等我们开启可视化界面后,就可以选择Stable Diffusion模型进行AI绘画了。
接下来,我们就可以启动ComfyUI了!我们到ComfyUI/路径下,运行main.py 即可:
python main. py - - listen - - port 8888
运行完成后,可以看到命令行中出现的log:
To see the GUI go to: http://0.0.0.0:8888
我们将http://0.0.0.0:8888输入到我们本地的网页中,即可打开如上图所示的ComfyUI可视化界面,愉快的使用Stable Diffusion模型生成我们想要的图片了。
接下来就是ComfyUI的节点式模块讲解了,具体如下所示: Rocky已经进行了比较详细的注释,首先大家可以在红框中选择我们的模型(Stable Diffusion),接着填入Prompt和负向Prompt,并且配置生成推理过程的参数(迭代次数,CFG,Seed等),然后在绿色框中设置好生成图片的分辨率,然后在紫色框中点击Queue Prompt按钮 ,整个推理过程就开始了。等整个推理过程完成之后,生成的图片会在图中黄色箭头所指的地方进行展示,并且会同步将生成图片保存到本地的ComfyUI/output/路径下 。
到此为止,Rocky已经详细讲解了如何使用ComfyUI来搭建Stable Diffusion模型进行AI绘画,大家可以按照Rocky的步骤进行尝试。
5.4 零基础使用SD.Next搭建Stable Diffusion推理流程
SD.Next 原本是Stable Diffusion WebUI的一个分支,再经过不断的迭代优化后,最终成为了一个独立版本。
SD.Next与Stable Diffusion WebUI相比,包含了更多的高级功能,也兼容Stable Diffusion、Stable Diffusion XL、Kandinsky以及DeepFloyd IF等模型结构 ,是一个功能十分强大的AI绘画框架。
那么我们马上开始SD.Next的搭建与使用吧。
首先,我们需要安装SD.Next框架,这一步非常简单,在命令行 输入如下代码即可:
git clone https: // github. com/ vladmandic/ automatic
安装好后,我们可以看到本地的automatic文件夹。
SD.Next框架安装到本地后,我们需要安装其依赖库,我们只需以下操作:
cd automatic
pip install - r requirements. txt - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
除了安装依赖库之外,还需要配置SD.Next所需的repositories插件,我们需要运行一下代码:
cd automatic
python installer. py
如果发现extensions插件下载速度较慢,出现很多报错,大家可以直接使用Rocky已经配置好的资源包,可以快速启动SD.Next框架。SD.Next资源包可以关注公众号WeThinkIn ,后台回复“SD.Next资源 ”获取。
在完成了依赖库和repositories插件的安装后,我们就可以配置模型了,我们将Stable Diffusion模型放到/automatic/models/Stable-diffusion/路径下 。这样一来,等我们开启可视化界面后,就可以选择Stable Diffusion模型用于推理生成图片了。
完成上述的步骤后,我们可以启动SD.Next了!我们到/automatic/路径下,运行launch.py 即可:
python launch. py - - listen - - port 8888
运行完成后,可以看到命令行中出现的log:
To see the GUI go to: http://0.0.0.0:8888
我们将http://0.0.0.0:8888输入到我们本地的网页中,即可打开如下图所示的SD.Next可视化界面,愉快的使用Stable Diffusion模型进行AI绘画了。
我们只需要在可视化界面中选择SD模型,并且输入Prompt,最后点击Generate,我们就可以使用SD.Next加载Stable Diffusion进行AI绘画了!
5.5 Stable Diffusion生成图像示例
示例一:未来主义的城市风格
Prompt:Stunning sunset over a futuristic city, with towering skyscrapers and flying vehicles, golden hour lighting and dramatic clouds, high detail, moody atmosphere
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion生成结果:
示例二:天堂海滩风格
Prompt:Serene beach scene with crystal clear water and white sand, tropical palm trees swaying in the breeze, perfect paradise, seascape
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion生成结果: 示例三:未来机甲风格
Prompt:Giant robots fighting in a futuristic city, with buildings falling and explosions all around, intense, fast-paced, dramatic, stylized, futuristic
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion生成结果: 示例四:马斯克风格
Prompt:Elon Musk standing in a workroom, in the style of industrial machinery aesthetics, deutscher werkbund, uniformly staged images, soviet, light indigo and dark bronze, new american color photography, detailed facial features
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion生成结果: 更多关于SD 1.5、SD 2.1以及SDXL的生成效果对比,大家可以从这个项目中查看:
benchmark/SDXL_SDv2.1_SDv1.5
6. 从0到1上手使用Stable Diffusion训练自己的AI绘画模型(全网最详细讲解)
我们能够看到目前AI绘画领域的持续繁荣,很大程度上是因为开源社区持续出现新的不同主题、不同画风、不同概念的Stable Diffusion模型与LoRA模型 。有了这些模型,我们就能有更多的AI绘画工具,有更多的奇思妙想能够去尝试实现,而这也是AI绘画领域能够爆发式繁荣的关键。
那么我们如何快速训练Stable Diffusion和LoRA模型呢。不要担心,Rocky详细梳理总结了从0到1的保姆级训练教程,方便大家快速上手学习入门与进阶。
6.0 Stable Diffusion训练资源分享
SD训练脚本:Rocky整理优化过的SD完整训练资源SD-Train项目,大家只用在SD-Train中就可以完成SD的模型训练工作,方便大家上手实操 。SD-Train项目资源包可以通过关注公众号WeThinkIn ,后台回复“SD-Train ”获取。
本文中的SD微调训练数据集:宝可梦数据集 ,大家可以关注公众号WeThinkIn ,后台回复“宝可梦数据集 ”获取。
本文中的SD微调训练底模型:WeThinkIn_SD_二次元模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SD_二次元模型 ”获取模型资源链接。
本文中的SD LoRA训练数据集:小丑女数据集 ,大家可以关注公众号WeThinkIn ,后台回复“小丑女数据集 ”获取。
本文中的SD LoRA训练底模型:WeThinkIn_SD_真人模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SD_真人模型 ”获取模型资源链接。
6.1 Stable Diffusion模型训练初识
Stable Diffusion系列模型的训练流程主要分成以下几个步骤:
训练集制作 :数据质量评估,标签梳理,数据清洗,数据标注,标签清洗,数据增强等。
训练文件配置 :预训练模型选择,训练环境配置,训练步数设置,其他超参数设置等。
模型训练 :运行SD模型/LoRA模型训练脚本,使用TensorBoard监控模型训练等。
模型测试 :将训练好的自训练SD模型/LoRA模型用于效果评估与消融实验。
讲完Stable Diffusion模型训练的方法论,Rocky再向大家推荐一些Stable Diffusion的训练资源:
目前我们对Stable Diffusion的训练流程与所需资源有了初步的了解,接下来,就让我们跟随着Rocky的脚步,从0到1使用Stable Diffusion模型和训练资源一起训练自己的Stable Diffusion绘画模型与LoRA绘画模型吧!
6.2 配置训练环境与训练文件
6.2.1原生SD/SD LoRA训练项目
首先,我们需要下载训练资源,只需在命令行输入下面的代码即可:
git clone https://github.com/Linaqruf/kohya-trainer.git
kohya-trainer项目包含了Stable Diffusion的核心训练脚本,并通过kohya-trainer-XL.ipynb和kohya-LoRA-trainer-XL.ipynb文件来生成数据集制作脚本和训练参数配置脚本。
我们打开kohya-trainer项目可以看到,里面包含了两个SD的训练脚本和对应的.ipynb文件:
正常情况下,我们需要运行kohya-trainer项目中两个SD的.ipynb文件的内容,生成训练数据处理脚本(数据标注,数据预处理,数据Latent特征提取,数据分桶(make buckets)等)和训练参数配置文件。
我们使用数据处理脚本完成训练集的制作,然后再运行kohya-trainer项目的训练脚本,同时读取训练参数配置文件,为SD模型的训练过程配置超参数。
完成上面一整套流程,SD模型的训练流程就算跑通了。但是由于kohya-trainer项目中的两个.ipynb文件内容较为复杂,整个流程比较繁琐,对新手非常不友好,并且想要完成一整套训练流程,我们还需要对两个.ipynb文件进行改写,非常不方便 。
6.2.2 一键上手的SD-Train项目:方便快速训练SD/SD LoRA模型
所以在此基础上,Rocky这边帮大家对两个项目进行了整合归纳,总结了简单易上手的SD模型以及相应LoRA模型的训练流程,制作成SD完整训练资源SD-Train项目,大家只用在SD-Train中就可以完成SD的模型训练工作,方便大家上手实操。
SD-Train项目资源包可以通过关注公众号WeThinkIn ,后台回复“SD-Train ”获取。
下面是SD-Train项目中的主要内容,大家可以看到SD的数据处理脚本 与kohya-trainer-XL.ipynb和kohya-LoRA-trainer-XL.ipynb两个文件中提取出来的训练参数文件 都已包含在内,大家可以方便的进行使用:
我们下载了SD-Train项目后,首先进入SD-Train项目中,安装SD训练所需的依赖库,我们只需在命令行输入以下命令即可:
cd SD- Train
pip install - r requirements. txt - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
pip install accelerate== 0.16 .0 - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
在完成上述的依赖库安装后,我们需要确认一下目前的Python、PyTroch、CUDA以及cuDNN的版本是否兼容 ,我们只需要在命令行输入以下命令即可:
>> > python
Python 3.9
>> > import torch
>> > print ( torch. __version__)
1.13 .1 + cu117
>> > print ( torch. version. cuda)
11.7
>> > print ( torch. backends. cudnn. version( ) )
8500
>> > print ( torch. cuda. is_available( ) )
True
如果大家在本地自己验证的时候和Rocky上述的版本一致,说明SD模型的训练环境已经全部兼容!
安装和验证好所有SD训练所需的依赖库后,我们还需要设置一下SD的训练环境参数,我们主要使用accelerate库的能力,accelerate库能让PyTorch的训练和推理变得更加高效简洁 。我们只需在命令行输入以下命令,并对每个设置逐一进行填写即可:
accelerate config
In which compute environment are you running?
This machine
Which type of machine are you using?
multi- GPU
How many different machines will you use ( use more than 1 for multi- node training) ? [ 1 ] : 1
Do you wish to optimize your script with torch dynamo?[ yes/ NO] :
Do you want to use DeepSpeed? [ yes/ NO] :
Do you want to use FullyShardedDataParallel? [ yes/ NO] :
Do you want to use Megatron- LM ? [ yes/ NO] :
How many GPU( s) should be used for distributed training? [ 1 ] : 2
What GPU( s) ( by id ) should be used for training on this machine as a comma- seperated list ? [ all ] : all
Do you wish to use FP16 or BF16 ( mixed precision) ?
fp16
accelerate configuration saved at / root/ . cache/ huggingface/ accelerate/ default_config. yaml
后续进行SD与LoRA模型训练的时候,只需要加载对应的default_config.yaml配置文件即可使用配置好的训练环境,具体的调用方法,后续的6.4和6.5章节中会详细讲解。
6.2.3 依赖文件与依赖模型配置
还有一点需要注意的是,我们进行SD模型的训练时,SD的CLIP Text Encoder会调用clip-vit-large-patch14这个配置文件 。一般情况下SD模型会从huggingface上将配置文件下载到~/.cache/huggingface/目录中,但是由于网络原因很可能会下载失败,从而导致训练的失败。
所以为了让大家能更方便的训练SD模型,Rocky已经将clip-vit-large-patch14这个配置文件放入SD-Train项目的utils_json文件夹中,并且已经为大家配置好依赖路径,大家只要使用SD-Train项目便无需做任何修改 。如果大家想要修改clip-vit-large-patch14依赖文件夹的调用路径,大家可以找到SD-Train/library/model_util.py脚本中的第898行,将”utils_json/clip-vit-large-patch14″部分修改成自己的本地自定义路径比如“/本地路径/utils_json/clip-vit-large-patch14”即可。
完成上述的流程后,接下来我们就可以进行SD训练数据的制作和训练脚本的配置流程了!
6.3 SD训练数据集制作
首先,我们需要对数据集进行清洗,和传统深度学习时代一样,数据清洗工作依然占据了AIGC时代模型训练70%-80%左右的时间 。
并且这个过程必不可少,因为数据质量决定了机器学习的上限,而算法和模型只是在不断逼近这个上限而已 。
我们需要筛除分辨率较低,质量较差(比如说768*768分辨率的图片),存在破损,以及和任务目标无关的数据,接着去除数据里面可能包含的水印,干扰文字等,最后就可以开始进行数据标注了。
数据标注可以分为自动标注 和手动标注 。自动标注主要依赖像BLIP和Waifu Diffusion 1.4这样的模型,手动标注则依赖标注人员。
6.3.1 使用BLIP自动标注caption
我们先用BLIP对数据进行自动标注,BLIP输出的是自然语言标签 ,我们进入到SD-Train/finetune/路径下,运行以下代码即可获得自然语言标签(caption标签):
cd SD- Train/ finetune/
python make_captions. py "/数据路径" - - batch_size= 8 - - caption_weights= "/本地BLIP模型路径" - - beam_search - - min_length= 5 - - max_length= 75 - - debug - - caption_extension= ".caption" - - max_data_loader_n_workers= 2
注意:在使用BLIP进行数据标注时需要依赖bert-base-uncased模型,Rocky这边已经帮大家配置好了,大家只要使用SD-Train项目便无需做任何修改 。同时,如果大家想要修改bert-base-uncased模型的调用路径,可以找到SD-Train/finetune/blip/blip.py脚本的第189行,将“…/bert-base-uncased”部分修改成自己的本地自定义路径比如“/本地路径/bert-base-uncased”即可。
从上面的代码可以看到,我们第一个传入的参数是训练集的路径 。下面Rocky再向大家介绍一下其余参数的意义:
– caption_weights:表示加载的本地BLIP模型,如果不传入本地模型路径,则默认从云端下载BLIP模型。
– batch_size:表示每次传入BLIP模型进行前向处理的数据数量。
– beam_search:设置为波束搜索,默认Nucleus采样。
– min_length:设置caption标签的最短长度。
– max_length:设置caption标签的最长长度。
– debug:如果设置,将会在BLIP前向处理过程中,打印所有的图片路径与caption标签内容,以供检查。
– caption_extension:设置caption标签的扩展名,一般为”.caption”。
– max_data_loader_n_workers:设置大于等于2,加速数据处理。
讲完了上述的运行代码以及相关参数,下面Rocky再举一个美女图片标注的例子, 让大家能够更加直观的感受到BLIP处理数据生成caption标签的过程: 上图是单个图像的标注示例,整个数据集的标注流程也是同理的。等整个数据集的标注后,Stable Diffusion训练所需的caption标注就完成了 。
6.3.2 使用Waifu Diffusion v1.4模型自动标注tag标签
接下来我们可以使用Waifu Diffusion v1.4模型对训练数据进行自动标注,Waifu Diffusion v1.4模型输出的是tag关键词标签,其由一个个关键词短语组成 :
这里需要注意的是,调用Waifu Diffusion v1.4模型需要安装特定版本(2.10.0)的Tensorflow库 ,不然运行时会报“DNN library is not found“错误。我们只需要在命令行输入以下命令即可完成Tensorflow库的版本检查与安装适配:
pip show tensorflow
Name: tensorflow
Version: 2.10 .0
Summary: TensorFlow is an open source machine learning framework for everyone.
pip install tensorflow== 2.10 .0 - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
完成上述的环境配置后,我们依然进入到SD-Train/finetune/路径下,运行以下代码即可获得tag自动标注:
cd SD- Train/ finetune/
python tag_images_by_wd14_tagger. py "/数据路径" - - batch_size= 8 - - model_dir= "../tag_models/wd-v1-4-moat-tagger-v2" - - remove_underscore - - general_threshold= 0.35 - - character_threshold= 0.35 - - caption_extension= ".txt" - - max_data_loader_n_workers= 2 - - debug - - undesired_tags= ""
从上面的代码可以看到,我们第一个传入的参数是训练集的路径 。然后Rocky再详细介绍一下传入Waifu Diffusion v1.4自动标注的其他主要参数:
–batch_size:表示每次传入Waifu Diffusion v1.4模型进行前向处理的数据数量。
–model_dir:表示加载的本地Waifu Diffusion v1.4模型路径。
–remove_underscore:如果开启,会将输出tag关键词中的下划线替换为空格(long_hair -> long hair)。
–general_threshold:设置常规tag关键词的筛选置信度 ,比如1girl、solo、long_hair、1boy、smile、looking at viewer、blue eyes、hat、full body、dress等约7000个基础概念标签 。
–character_threshold:设置特定人物特征tag关键词的筛选置信度 ,比如初音未来(hatsune miku)、羽衣啦啦(agoromo lala)、博麗靈夢(hakurei reimu)等约2100个特定人物特征标签 。
–caption_extension:设置tag关键词标签的扩展名,一般为”.txt”即可。
-max_data_loader_n_workers:设置大于等于2,加速数据处理。
–debug:如果设置,将会在Waifu Diffusion 1.4模型前向处理过程中,打印所有的图片路径与tag关键词标签内容,供我们检查。
–undesired_tags:设置不需要保存的tag关键词。
下面Rocky依然用之前的美女图片作为例子, 让大家能够更加直观的感受到Waifu Diffusion v1.4模型处理数据生成tag关键词标签的过程 : 上图是单个图像的标注示例,整个数据集的标注流程也是同理的。等整个数据集都完成标注后,Stable Diffusion训练所需的tag关键词标签就完成了 。
上面Rocky是使用了Waifu Diffusion v1.4系列模型中的wd-v1-4-moat-tagger-v2模型,目前Waifu Diffusion v1.4系列模型一共有5个版本,除了刚才介绍到的wd-v1-4-moat-tagger-v2模型,还包括wd-v1-4-swinv2-tagger-v2模型、wd-v1-4-convnext-tagger-v2模型、wd-v1-4-convnextv2-tagger-v2模型以及wd-v1-4-vit-tagger-v2模型。
Rocky也分别对他们的自动标注效果进行了对比,在这里Rocky使用了一张生成的“猫女”图片,分别输入到这五个自动标注模型中,一起来看看不同版本的Waifu Diffusion v1.4模型的效果: 从上图可以看到,在将general_threshold和character_threshold同时设置为0.5时,wd-v1-4-moat-tagger-v2模型的标注效果整体上是最好的,内容丰富且最能反映图片中的语义信息。所以在这里,Rocky也推荐大家使用wd-v1-4-moat-tagger-v2模型 。
大家也可以在SD-Train项目的tag_models文件夹下调用这些模型,进行对比测试,感受不同系列Waifu Diffusion v1.4模型的标注效果。
6.3.3 补充标注特殊tag
完成了caption和tag的自动标注之后,如果我们需要训练一些特殊标注 的话,还可以进行手动的补充标注。
SD-Trian项目中也提供了对数据进行补充标注的代码,Rocky在这里将其进行提炼总结,方便大家直接使用。
大家可以直接拷贝以下的代码,并按照Rocky在代码中提供的注释进行参数修改,然后运行代码即可对数据集进行补充标注:
import os
train_data_dir = "/本地数据集路径"
extension = ".txt"
custom_tag = "WeThinkIn"
sub_folder = ""
append = False
remove_tag = False
recursive = False
if sub_folder == "" :
image_dir = train_data_dir
elif sub_folder == "--all" :
image_dir = train_data_dir
recursive = True
elif sub_folder. startswith( "/content" ) :
image_dir = sub_folder
else :
image_dir = os. path. join( train_data_dir, sub_folder)
os. makedirs( image_dir, exist_ok= True )
def read_file ( filename) :
with open ( filename, "r" ) as f:
contents = f. read( )
return contents
def write_file ( filename, contents) :
with open ( filename, "w" ) as f:
f. write( contents)
def process_tags ( filename, custom_tag, append, remove_tag) :
contents = read_file( filename)
tags = [ tag. strip( ) for tag in contents. split( ',' ) ]
custom_tags = [ tag. strip( ) for tag in custom_tag. split( ',' ) ]
for custom_tag in custom_tags:
custom_tag = custom_tag. replace( "_" , " " )
if remove_tag:
while custom_tag in tags:
tags. remove( custom_tag)
else :
if custom_tag not in tags:
if append:
tags. append( custom_tag)
else :
tags. insert( 0 , custom_tag)
contents = ', ' . join( tags)
write_file( filename, contents)
def process_directory ( image_dir, tag, append, remove_tag, recursive) :
for filename in os. listdir( image_dir) :
file_path = os. path. join( image_dir, filename)
if os. path. isdir( file_path) and recursive:
process_directory( file_path, tag, append, remove_tag, recursive)
elif filename. endswith( extension) :
process_tags( file_path, tag, append, remove_tag)
tag = custom_tag
if not any (
[ filename. endswith( extension) for filename in os. listdir( image_dir) ]
) :
for filename in os. listdir( image_dir) :
if filename. endswith( ( ".png" , ".jpg" , ".jpeg" , ".webp" , ".bmp" ) ) :
open (
os. path. join( image_dir, filename. split( "." ) [ 0 ] + extension) ,
"w" ,
) . close( )
if custom_tag:
process_directory( image_dir, tag, append, remove_tag, recursive)
看完了上面的完整代码流程,如果大家觉得代码太复杂,don‘t worry,大家只需要复制 上面的全部代码,并将train_data_dir =”/本地数据集路径”和custom_tag =”WeThinkIn”设置成自己数据集的本地路径和想要添加的特殊标注,然后运行代码即可,非常简单实用 。
还是以之前的美女图片为例子,当运行完上面的代码后,可以看到txt文件中,最开头的tag为“WeThinkIn”: 大家注意,一般我们会将手动补充的特殊tag放在第一位,因为和caption标签不同,tags标签是有顺序的,最开始的tag权重最大,越靠后的tag权重越小 。
到这里,Rocky已经详细讲解了在Stable Diffusion训练前,如何对数据集进行caption标注,tag标注以及补充一些关键标注的完整步骤与流程 ,在数据标注完毕后,接下来我们就要进入训练数据预处理的阶段了。
6.3.4 训练数据预处理
首先,我们需要对刚才生成的后缀为.caption和.txt的标注文件进行整合,存储成一个json格式的文件,方便后续SD模型训练时调取训练数据与标注。
我们需要进入SD-Train项目的finetune文件夹中,运行merge_all_to_metadata.py脚本即可:
cd SD- Train
python . / finetune/ merge_all_to_metadata. py "/本地数据路径" "/本地数据路径/meta_clean.json"
如下图所示,我们依旧使用之前的美图女片作为例子,运行完merge_all_to_metadata.py脚本后,我们在数据集路径中得到一个meta_clean.json文件,打开可以看到图片名称对应的tag和caption标注都封装在了文件中,让人一目了然,非常清晰。
在整理好标注文件的基础上,我们接下来需要对数据进行分桶与保存Latent特征,并在meta_clean.json的基础上,将图片的分辨率信息也存储成json格式,并保存一个新的meta_lat.json文件。
我们需要进入SD-Train项目的finetune文件夹中,运行prepare_buckets_latents.py脚本即可:
cd SDXL- Train
python . / finetune/ prepare_buckets_latents. py "/本地数据路径" "/本地数据路径/meta_clean.json" "/本地数据路径/meta_lat.json" "想要调用的SD模型路径" - - min_bucket_reso= 256 - - max_bucket_reso= 1024 - - batch_size 4 - - max_data_loader_n_workers= 2 - - max_resolution "1024,1024" - - mixed_precision= "no"
运行完脚本,我们即可在数据集路径中获得meta_lat.json文件,其在meta_clean.json基础上封装了图片的分辨率信息,用于SD训练时快速进行数据分桶。
同时我们可以看到,美女图片的Latent特征保存为了.npz文件,用于SD模型训练时,快速读取数据的Latent特征,加速训练过程。
好的,到目前为止,我们已经完整的进行了SD训练所需的数据集制作与预处理流程。总结一下,我们在一张美女图片的基础上,一共获得了以下5个不同的训练配置文件 :
meta_clean.json
meta_lat.json
自然语言标注(.caption)
关键词tag标注(.txt)
数据的Latent特征信息(.npz)
在完成以上所有数据处理过程后,接下来我们就可以进入SD训练的阶段了,我们可以对SD进行全参微调(finetune),也可以基于SD训练对应的LoRA模型。
6.4 Stable Diffusion微调(finetune)训练
微调(finetune)训练是让SD全参数重新训练的一种方法,理想的状态是让SD模型在原有能力的基础上,再学习到一个或几个细分领域的数据特征与分布 ,从而能在工业界,学术界以及竞赛界满足不同的应用需求。
Rocky为大家举一个形象的例子,让大家能够很好理解SD全参微调的意义。比如我们要训练一个二次元SD模型,应用于二次元领域。那么我们首先需要寻找合适的基于SD的预训练底模型,比如一个能生成二次元图片的SD A模型。然后我们用A模型作为预训练底模型,并收集二次元优质数据作为训练集,有了模型和数据,再加上Rocky为大家撰写的SD微调训练全流程攻略,我们就能训练获得一个能生成二次元人物的SD行业模型,并作为二次元相关产品的核心大模型 。
那么话不多说,下面Rocky将告诉大家从0到1使用SD模型进行微调训练的全流程攻略 ,让我们一起来训练属于自己的SD模型吧!
6.4.1 SD微调(finetune)数据集制作
在SD全参数微调中,SD能够学习到大量的主题,人物,画风或者抽象概念等信息特征 ,所以我们需要对一个细分领域的数据进行广泛的收集,并进行准确的标注。
Rocky这边收集整理了833张宝可梦数据,包含多样的宝可梦种类,组成宝可梦数据集 ,作为本次SD微调训练的训练集。
接下来,我们就可以按照本文6.3 Stable Diffusion数据集制作章节里的步骤 ,进行数据的清洗,自动标注,以及添加特殊tag。
Rocky认为对SD模型进行微调训练主要有两个目的:增强SD模型的图像生成能力与增加SD对新prompt的触发能力 。
我们应该怎么理解这两个目的呢。我们拿宝可梦数据集为例,我们想要让SD模型学习宝可梦的各种特征,包括脸部特征,形状特征,姿势特征,二次元背景特征,以及二次元画风特征等。通过训练不断让SD模型“学习”这些数据的内容,从而增强SD模型生成新宝可梦图片的能力 。与此同时,我们通过自动标注与特殊tag,将图片的特征与标注信息进行对应,让SD在学习图片数据特征的同时,学习到对应的标注信息,能够在前向推理的过程中,通过二次元的专属标签生成对应的新宝可梦图像 。
理解了上面的内容,咱们的数据处理部分就告一段落了。为了方便大家使用宝可梦数据集进行后续的SD模型微调训练,Rocky这边已经将处理好的宝可梦数据集开源(包含原数据,标注文件,读取数据的json文件等) ,大家可以关注公众号WeThinkIn ,后台回复“宝可梦数据集 ”获取。
6.4.2 SD微调训练参数配置
本节中,Rocky主要介绍Stable Diffusion全参微调(finetune)训练 的参数配置和训练脚本。
Rocky已经帮大家整理好了SD全参微调训练的全部参数与训练脚本,大家可以在SD-Train项目的train_config文件夹中找到相应的训练参数配置(config文件夹),并且可以在SD-Train项目中运行SD_finetune.sh脚本,进行SD的全参微调训练。
接下来,Rocky将带着大家从头到尾走通SD全参微调训练过程,并讲解训练参数的意义。首先,我们可以看到config文件夹中有两个配置文件config_file.toml和sample_prompt.toml,他们分别存储着SD的训练超参数与训练中的验证prompt。 其中config_file.toml文件主要包含了model_arguments,optimizer_arguments,dataset_arguments,training_arguments,sample_prompt_arguments以及saving_arguments六个维度的的参数信息,下面Rocky为大家依次讲解各个超参数的作用:
[ model_arguments]
v2 = false
v_parameterization = false
pretrained_model_name_or_path = "/本地路径/SD模型文件"
v2和v_parameterization:两者同时设置为true时,开启Stable Diffusion V2版本的训练。
pretrained_model_name_or_path:读取本地Stable Diffusion预训练模型用于微调训练。
[ optimizer_arguments]
optimizer_type = "AdamW8bit"
learning_rate = 2e-6
max_grad_norm = 1.0
train_text_encoder = false
lr_scheduler = "constant"
lr_warmup_steps = 0
optimizer_type:选择优化器类型。一共有:[“AdamW”(default), “AdamW8bit”, “Lion”, “SGDNesterov”, “SGDNesterov8bit”, “DAdaptation”, “AdaFactor”]七种优化器可以选择。其中当我们不进行选择优化器类时,默认会启动AdamW优化器;当我们的显存不太充足时,可以选择AdamW8bit优化器,能降低训练时的显存占用,但代价是轻微地性能损失;Lion优化器是目前优化器方向上最新的版本,性能较为优异,但是使用Lion优化器时学习率需要设置较小,比如设置为AdamW优化器下的 1/3。
learning_rate:训练学习率,单卡推荐设置2e-6,多卡推荐设置1e-7。
max_grad_norm:最大梯度范数,0表示没有clip,1表示将梯度clip到1。 在传统深度学习时代,GAN模型就经常使用这种梯度裁剪技巧 ,其公式计算如下:
new_gradient
=
max_grad_norm
old_gradient_norm
×
old_gradient
text{new_gradient} = frac{text{max_grad_norm}}{text{old_gradient_norm}} times text{old_gradient}
new_gradient = old_gradient_norm max_grad_norm × old_gradient
其中,new_gradient 是剪裁后的梯度,max_grad_norm 是设定的最大梯度范数阈值,old_gradient_norm 是原始梯度的L2范数,old_gradient 是原始梯度向量。
train_text_encoder:是否在SD模型训练时对Text Encoder进行微调,如果设置为true,则对Text Encoder进行微调。
lr_scheduler:设置学习率调度策略,可以设置成linear, cosine, cosine_with_restarts, polynomial, constant (default), constant_with_warmup, adafactor。如果不单独指定,则默认会使用constant学习率调度策略。
lr_warmup_steps:在启动学习率调度策略前,先固定学习率训练的步数。
[ dataset_arguments]
debug_dataset = false
in_json = "/本地路径/data_meta_lat.json"
train_data_dir = "/本地路径/训练集"
dataset_repeats = 10
shuffle_caption = true
keep_tokens = 0
resolution = "512,512"
caption_dropout_rate = 0
caption_tag_dropout_rate = 0
caption_dropout_every_n_epochs = 0
color_aug = false
token_warmup_min = 1
token_warmup_step = 0
debug_dataset:训练时对数据进行debug处理,不让破损数据中断训练进程。
in_json:读取数据集json文件,json文件中包含了数据名称,数据标签,数据分桶等信息。
train_data_dir:读取本地数据集存放路径。
dataset_repeats:整个数据集重复训练的次数,也可以理解为每个epoch中,训练集数据迭代的次数。(经验分享:如果数据量级小于一千,可以设置为10;如果数据量级在一千与一万之间,可以设置为5;如果数据量级大于一万,可以设置为2 )
shuffle_caption:当设置为true时,对训练标签进行打乱,能一定程度提高模型的泛化性。
keep_tokens:在训练过程中,会将txt中的tag进行随机打乱。如果将keep tokens设置为n,那前n个token的顺序在训练过程中将不会被打乱。
resolution:设置训练时的数据输入分辨率,分别是width和height。
caption_dropout_rate:针对一个数据丢弃全部标签的概率,默认为0。
caption_tag_dropout_rate:针对一个数据丢弃部分标签的概率,默认为0。(类似于传统深度学习的Dropout逻辑 )
caption_dropout_every_n_epochs:每训练n个epoch,将数据标签全部丢弃。
color_aug:数据颜色增强,建议不启用,其与caching latents不兼容,若启用会导致训练时间大大增加 (由于每次训练迭代时输入数据都会改变,无法提前获取 latents)。
token_warmup_min:在训练一开始学习每个数据的前n个tag(标签用逗号分隔后的前n个tag,比如girl,boy,good)
token_warmup_step:训练中学习标签数达到最大值所需的步数,默认为0,即一开始就能学习全部的标签。
[ training_arguments]
output_dir = "/本地路径/模型权重保存地址"
output_name = "sd_finetune_WeThinkIn"
save_precision = "fp16"
save_n_epoch_ratio = 1
save_state = false
train_batch_size = 1
max_token_length = 225
mem_eff_attn = false
xformers = true
max_train_steps = 2500
max_data_loader_n_workers = 8
persistent_data_loader_workers = true
gradient_checkpointing = false
gradient_accumulation_steps = 1
mixed_precision = "fp16"
clip_skip = 2
logging_dir = "/本地路径/logs"
log_prefix = "sd_finetune_WeThinkIn"
output_dir:模型保存的路径。
output_name:模型名称。
save_precision:模型保存的精度,一共有[“None”, “float”, “fp16”, “bf16”]四种选择,默认为“None”,即FP32精度。
save_n_epoch_ratio:每n个steps保存一次模型权重。
save_state:设置为true时,每次保存模型权重的同时会额外保存训练状态(包括优化器状态等)。
train_batch_size:训练Batch-Size,与传统深度学习一致。
max_token_length:设置Text Encoder最大的Token数,有[None, 150, 225]三种选择,默认为“None”,即75。
mem_eff_attn:对Cross Attention进行轻量化。
xformers:xformers插件可以使SDXL模型在训练时显存减少一半左右。
max_train_steps:SD模型训练的总步数。
max_data_loader_n_workers:数据加载的DataLoader worker数量,默认为8。
persistent_data_loader_workers:能够让DataLoader worker持续挂载,减少训练中每个epoch之间的数据读取时间,但是会增加内存消耗。
gradient_checkpointing:设为true时开启梯度检查,通过以更长的计算时间为代价,换取更少的显存占用。相比于原本需要存储所有中间变量以供反向传播使用,使用了checkpoint的部分不存储中间变量而是在反向传播过程中重新计算这些中间变量。模型中的任何部分都可以使用gradient checkpoint。
gradient_accumulation_steps:如果显存不足,我们可以使用梯度累积步数,默认为1。
mixed_precision:训练中是否使用混合精度,一共有[“no”, “fp16”, “bf16”]三种选择,默认为“no”。
clip_skip:当设置clip_skip为2时,提取CLIP Text Encoder倒数第二层的输出;如果设置clip_skip为1,则提取CLIP Text Encoder倒数最后一层的输出。 CLIP Text Encoder模型一共有12层,越往深层模型输出的特征就越抽象,跳过过于抽象的信息可以防止过拟合。Rocky推荐二次元模型选择 clip_skip = 2,三次元模型选择 clip_skip = 1 。
logging_dir:设置训练log保存的路径。
log_prefix:增加log文件的文件名前缀,比如sd_finetune_WeThinkIn1234567890。
[ sample_prompt_arguments]
sample_every_n_steps = 100
sample_sampler = "ddim"
[ saving_arguments]
save_model_as = "safetensors"
sample_every_n_steps:在训练中每n步测试一次模型效果。
sample_sampler:设置训练中测试模型效果时使用的sampler,可以选择[“ddim”,“pndm”,“lms”,“euler”,“euler_a”,“heun”,“dpm_2”,“dpm_2_a”,“dpmsolver”,“dpmsolver++”,“dpmsingle”, “k_lms”,“k_euler”,“k_euler_a”,“k_dpm_2”,“k_dpm_2_a”],默认是“ddim”。
save_model_as:每次模型权重保存时的格式,可以选择[“ckpt”, “safetensors”, “diffusers”, “diffusers_safetensors”],目前SD WebUI兼容”ckpt”和”safetensors”格式模型。
6.4.3 SD训练的关键参数详解
【1】pretrained_model_name_or_path对SD模型微调训练的影响
pretrained_model_name_or_path参数中我们需要加载本地的SD模型作为训练底模型。
在SD全参数微调训练中,底模型的选择可以说是最为重要的一环。我们需要挑选一个生成能力分布与训练数据分布近似的SD模型作为训练底模型(比如说我们训练二次元人物数据集,可以选择生成二次元图片能力强的SD模型)。SD在微调训练的过程中,在原有底模型的很多能力与概念上持续扩展优化学习,从而得到底模型与数据集分布的一个综合能力。
【2】xformers加速库对SD模型微调训练的影响
当我们将xformers设置为true时,使用xformers加速库能对SD训练起到2倍左右的加速 ,因为其能使得训练显存占用降低2倍,这样我们就能增大我们的Batch Size数。
想要启动xformers加速库,需要先安装xformers库源,这也非常简单,我们只需要在命令行 输入如下命令即可:
pip install xformers - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
【3】learning_rate对SD模型微调训练的影响
SD训练过程对学习率的设置非常敏感,如果我们将学习率设置的过大,很有可能导致SD模型训练跑飞,在前向推理时生成非常差的图片;如果我们将学习率设置的过小,可能会导致模型无法跳出极小值点 。
Rocky这里总结了相关的SD学习率设置经验,分享给大家。如果我们总的Batch Size(单卡Batch Size x GPU数)小于10,可以设置学习率2e-6;如果我们总的Batch Size大于10小于100,可以设置学习率1e-7 。
【4】使用save_state和resume对SD模型训练的中断重启
在AI绘画领域,很多时候我们需要进行大规模数据的训练优化,数据量级在10万甚至100万以上,这时候整个训练周期需要一周甚至一个月,训练中可能会出现一些通讯/NCCL超时等问题,导致训练中断。
经典NCCL超时问题如下所示:
[ E ProcessGroupNCCL. cpp: 828 ] [ Rank 0 ] Watchdog caught collective operation timeout: WorkNCCL( SeqNum= 213 , OpType= ALLREDUCE, Timeout( ms) = 1800000 ) ran for 1809831 milliseconds before timing out.
这些训练中断问题会导致我们的训练成本大大增加,为了解决这个问题,我们可以在config_file.toml中设置save_state = true,这样我们在训练模型时不单单保存模型权重,还会保存相关的optimizer states等训练状态。
接着,我们在config_file.toml中设置resume = “/本地路径/模型权重保存地址”,重新运行SD训练脚本,这时会直接调取训练中断前的模型权重与训练状态,接着继续训练。
【5】resolution的设置对SD模型微调训练的影响
一般情况下,resolution设置为32的倍数,比如512、768、1024或者更大。设置越大的resolution,SD模型能从数据中学习到越多的信息,从而提升SD模型在推理阶段的出图效果。
6.4.4 SD模型训练
完成训练参数配置后,我们就可以运行训练脚本进行SD模型的全参微调训练了。
我们本次训练用的底模型选择了WeThinkIn_SD_二次元模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SD_二次元模型 ”获取模型资源链接。
我们打开SD_finetune.sh脚本,可以看到以下的代码:
accelerate launch
- - config_file accelerate_config. yaml
- - num_cpu_threads_per_process= 8
/ 本地路径/ SD- Train/ fine_tune. py
- - sample_prompts= "/本地路径/SD-Train/train_config/sample_prompt.txt"
- - config_file= "/本地路径/SD-Train/train_config/config_file.toml"
我们把训练脚本封装在accelerate库里,这样就能启动我们一开始配置的训练环境了。在本文的6.2节中,我们已经详细介绍了如何配置accelerate训练环境,如果我们想要切换不同的训练环境参数,我们只需要将accelerate_config.yaml改成我们所需要的配置文件与路径即可(比如:/本地路径/new_accelrate_config.yaml)。
除了上述的训练环境参数传入,最重要的还是将刚才配置好的config_file.toml和sample_prompt.txt参数传入训练脚本中。
接下来,就到了激动人心的时刻,我们只需在命令行输入以下命令,就能开始SD模型的全参微调训练啦:
cd SD- Train
sh SD_finetune. sh
训练脚本启动后,会打印出以下的log,方便我们查看整个训练过程的节奏:
running training / 学習開始
num examples / サンプル数: 10240
num batches per epoch / 1epochのバッチ数: 640
num epochs / epoch数: 100
batch size per device / バッチサイズ: 2
gradient accumulation steps / 勾配を合計するステップ数 = 1
total optimization steps / 学習ステップ数: 64000
当我们设置1024分辨率+FP16精度+xformers加速时,SD模型进行Batch Size = 1的微调训练需要约17.1G的显存,进行Batch Size=4的微调训练需要约26.7G的显存 ,所以想要微调训练SD模型,最好配置一个24G以上的显卡,能让我们更加从容地进行训练。
到此为止,Rocky已经将SD全参微调训练的全流程都做了详细的拆解 ,等训练完成后,我们就可以获得属于自己的SD模型了!
6.4.5 加载自训练SD模型进行AI绘画
SD模型微调训练完成后,会将模型权重保存在我们之前设置的output_dir路径下。接下来,我们使用Stable Diffusion WebUI作为框架,加载SD宝可梦模型进行AI绘画 。
在本文4章中,Rocky已经详细讲解了如何搭建Stable Diffusion WebUI框架,未使用过的朋友可以按照这个流程快速搭建起Stable Diffusion WebUI。
要想使用SD模型进行AI绘画,首先我们需要将训练好的SD宝可梦模型放入Stable Diffusion WebUI的/models/Stable-diffusion文件夹下。
然后我们在Stable Diffusion WebUI中分别选用SD宝可梦模型即可: 完成上图中的操作后,我们就可以进行新宝可梦图片的生成啦!
下面是使用本教程训练出来的SD宝可梦模型生成的图片:到这里,关于SD微调训练的全流程攻略就全部展示给大家了,大家如果觉得好,欢迎给Rocky的劳动点个赞,支持一下Rocky,谢谢大家!
如果大家对SD全参数微调训练还有想要了解的知识或者不懂的地方,欢迎在评论区留言,Rocky也会持续优化本文内容,能让大家都能快速了解SD训练知识,并训练自己的专属SD绘画模型!
6.5 基于Stable Diffusion训练LoRA模型
基于Stable Diffusion的生态之所以如此繁荣,LoRA模型绝对功不可没。LoRA模型的训练成本是Stable Diffusion全参微调训练成本1/10左右 ,不断训练各式各样的LoRA模型并发布到开源社区是持续繁荣SD生态的高效选择。
如果大家想要了解LoRA模型的核心基础知识,LoRA的优势,热门LoRA模型推荐等内容,可以阅读Rocky之前写的文章:
深入浅出完整解析LoRA(Low-Rank Adaptation)模型核心基础知识
在本节,Rocky将告诉大家从0到1使用SD模型训练对应的LoRA的全流程攻略 ,让我们一起来训练属于自己的SD LoRA模型吧!
6.5.1 SD LoRA数据集制作
首先,我们需要确定数据集主题,比如说人物,画风或者某个抽象概念等。本次我们选择用Rocky自己搜集的人物主题数据集——小丑女数据集 来进行SD LoRA模型的训练。
为了方便大家使用小丑女数据集进行后续的LoRA训练,Rocky这边已经将处理好的小丑女数据集开源(包含原数据,标注文件,读取数据的json文件等) ,大家可以关注公众号WeThinkIn ,后台回复“小丑女数据集 ”获取。
6.5.2 SD LoRA训练参数配置
训练Stable Diffusion LoRA的参数配置与Stable Diffusion全参微调的训练配置有相同的部分(上述的前六个维度),也有LoRA的特定参数需要配置(additional_network_arguments)。
下面我们首先看看这些共同的维度中,有哪些需要注意的事项吧:
[ model_arguments]
v2 = false
v_parameterization = false
pretrained_model_name_or_path = "/本地路径/SD模型文件"
[ optimizer_arguments]
optimizer_type = "AdamW8bit"
learning_rate = 0.0001
max_grad_norm = 1.0
lr_scheduler = "constant"
lr_warmup_steps = 0
[ dataset_arguments]
debug_dataset = false
in_json = "/本地路径/data_meta_lat.json"
train_data_dir = "/本地路径/训练集"
dataset_repeats = 10
shuffle_caption = true
keep_tokens = 0
resolution = "512,512"
caption_dropout_rate = 0
caption_tag_dropout_rate = 0
caption_dropout_every_n_epochs = 0
color_aug = false
token_warmup_min = 1
token_warmup_step = 0
[ training_arguments]
output_dir = "/本地路径/模型权重保存地址"
output_name = "sd_LoRA_WeThinkIn"
save_precision = "fp16"
save_every_n_epochs = 1
train_batch_size = 6
max_token_length = 225
mem_eff_attn = false
xformers = true
max_train_epochs = 10
max_data_loader_n_workers = 8
persistent_data_loader_workers = true
gradient_checkpointing = false
gradient_accumulation_steps = 1
mixed_precision = "fp16"
clip_skip = 2
logging_dir = "/本地路径/logs"
log_prefix = "sd_LoRA_WeThinkIn"
lowram = true
[ sample_prompt_arguments]
sample_every_n_epochs = 1
sample_sampler = "ddim"
[ saving_arguments]
save_model_as = "safetensors"
除了上面的参数,训练SD LoRA时还需要设置一些专属参数,这些参数非常关键,下面Rocky将给大家一一讲解:
[ additional_network_arguments]
no_metadata = false
unet_lr = 0.0001
text_encoder_lr = 5e-5
network_module = "networks.lora"
network_dim = 32
network_alpha = 16
network_train_unet_only = false
network_train_text_encoder_only = false
no_metadata:保存模型权重时不附带Metadata数据,建议关闭,能够减少保存下来的LoRA大小。
unet_lr:设置U-Net 的学习率,默认值是1e-4。当我们将LoRA的network_dimension设置的较大时,比如128,这时我们需要设置更多的steps与更小的学习率(1e-5) 。
text_encoder_lr:设置CLIP Text Encoder的学习率,默认为5e-5。一般来说,CLIP Text Encoder 的学习率可以设置成unet_lr的1/15。小学习率有助于CLIP Text Encoder对tag更敏感 。
network_module:选择训练的LoRA模型结构,可以从[“networks.lora”, “networks.dylora”, “lycoris.kohya”]中选择,最常用的LoRA结构默认选择”networks.lora” 。
network_dim:设置LoRA的RANK,设置的数值越大表示表现力越强,但同时需要更多的显存和时间来训练。
network_alpha:设置缩放权重,用于防止下溢并稳定训练的alpha值。
network_train_unet_only:如果设置为true,那么只训练U-Net部分。
network_train_text_encoder_only:如果设置为true,那么只训练CLIP Text Encoder部分。
6.5.3 SD LoRA关键参数详解
【1】LoRA模型变体:LoCon
LoCon模型 (Conventional LoRA)在LoRA模型的基础上,还用同样的方法调整了ResNet。
【2】LoRA模型变体:LoHa
LoHa (LoRA with Hadamard Product): 通过哈达马积进一步降低参数的量,理论上在相同的dim下能容纳更多的信息。
LoHa论文:FedPara Low-Rank Hadamard Product For Communication-Efficient Federated Learning 。
【3】train_batch_size对SD LoRA模型训练的影响
和传统深度学习一样,train_batch_size即为训练时的batch size,表示一次性送入SD LoRA模型进行训练的图片数量。
我们在训练SD LoRA模型时,一般来说数据量级是比较小的(10-300为主),我们可以设置batch size为2-6即可。
当我们设置训练的基础分辨率为1024*1024时,在24G显存的NVIDIA GeForce RTX 3090显卡上最大batch_size可以设置为6。
一般来说batch size =
2
n
2^{n}
2 n 时计算效率较高。
6.5.4 SD LoRA模型训练
完成训练参数配置后,我们就可以运行训练脚本进行SD LoRA模型的训练了。
我们本次训练用的底模型选择了WeThinkIn_SD_真人模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SD_真人模型 ”获取模型资源链接。
我们打开SD_fintune_LoRA.sh脚本,可以看到以下的代码:
accelerate launch
- - config_file accelerate_config. yaml
- - num_cpu_threads_per_process= 8
/ 本地路径/ SD- Train/ train_network. py
- - sample_prompts= "/本地路径/SD-Train/train_config/LoRA_config/sample_prompt.txt"
- - config_file= "/本地路径/SD-Train/train_config/LoRA_config/config_file.toml"
我们把训练脚本封装在accelerate库里,这样就能启动我们一开始配置的训练环境了,同时我们将刚才配置好的config_file.toml和sample_prompt.txt参数传入训练脚本中。
接下来,就到了激动人心的时刻,我们只需在命令行输入以下命令,就能开始SD LoRA训练啦:
cd SD- Train
sh SD_fintune_LoRA. sh
当我们基于SD训练SD LoRA模型时,我们设置分辨率为1024+FP16精度+xformers加速时,进行Batch Size = 1的微调训练需要约8G的显存,进行Batch Size=4的微调训练需要约19.1G的显存 ,所以想要微调训练SD LoRA模型,最好配置一个12G以上的显卡,能让我们更加从容地进行训练。
6.5.5 加载SD LoRA模型进行AI绘画
SD LoRA模型训练完成后,会将模型权重保存在我们之前设置的output_dir路径下。接下来,我们使用Stable Diffusion WebUI作为框架,加载SD LoRA模型进行AI绘画。
在本文4.3节零基础使用Stable Diffusion WebUI搭建Stable Diffusion推理流程中,Rocky已经详细讲解了如何搭建Stable Diffusion WebUI框架,未使用过的朋友可以按照这个流程快速搭建起Stable Diffusion WebUI。
要想使用SD LoRA进行AI绘画,首先我们需要将SD底模型和SD LoRA模型分别放入Stable Diffusion WebUI的/models/Stable-diffusion文件夹和/models/Lora文件夹下。
然后我们在Stable Diffusion WebUI中分别选用底模型与LoRA即可:
6.6 SD训练结果测试评估
之前的章节讲述了SD模型微调和SD LoRA模型训练后的效果测试评估流程,那么在本小节,Rocky向大家介绍一下AI绘画模型测试评估的一些通用流程与技巧。
在进行AI绘画时,我们需要输入正向提示词(positive prompts)和负向提示词(negative prompts)。
正向提示词一般需要输入我们想要生成的图片内容,包括我们训练好的特殊tag等。
不过在正向提示词的开头,一般都需要加上提高生成图片整体质量的修饰词,Rocky这里推荐一套“万金油”修饰词,方便大家使用:
( masterpiece) , ( exquisite facial features) , ( 8k resolution) , ( prefect face) , ( official art, extremely detailed CG unity 8k wallpaper) , ( highly detailed) , ( absurdres) , ( best quality)
负向提示词一般需要输入我们不想生成的内容,在这里Rocky再分享一套基于SD的“万金油”负向提示词,方便大家使用:
( worst quality) ,( low quality) ,( normal quality) , watermark, too many fingers, long neck, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, jpeg artifacts, signature, username, blurry, bad feet, poorly drawn hands, poorly drawn face, deformed, ugly, blurry, bad anatomy, extra limbs, cloned face, missing arms, missing legs, extra arms, extra legs, mutated hands, fused fingers, too many fingers, long neck, missing fingers
当然的,我们也可以使用ChatGPT辅助生成提示词 ,在此基础上我们再加入训练好的特殊tag并对提示词进行修改润色。
在我们进行模型测试的时候,如果存在生成图片质量不好,生成图片样式单一或者生成图片崩坏的情况,就需要优化数据或者参数配置,重新训练了。
7. Stable Diffusion不同版本模型详解
7.1 Stable Diffusion 2.0系列模型
现在Stable Diffusion XL已经发布了,我们会发现Stable Diffusion 2.x系列模型非常尴尬 。
如果将AIGC时代与传统深度学习时代进行对比的话,那么Stable Diffusion全系列模型无疑就是AIGC时代的“YOLO”。Stable Diffusion 1.x是“YOLOv1”,那么Stable Diffusion 2.x就是“YOLOv2”,最新的Stable Diffusion XL就是“YOLOv3”。
就如同YOLOv2一样,Stable Diffusion 2.x系列同样面临相同的境遇,前有Stable Diffusion开创新时代的余威与繁荣的开源生态,后有Stable Diffusion XL这个整体性能强大的最新版本模型和飞速发展的社区生态,都让Stable Diffusion 2.x系列模型成为了“鸡肋”。
但是,Rocky相信Stable Diffusion 2.x系列模型依然是AIGC时代里一个有效的AI绘画工具,可以作为AI绘画技术知识储备 。
与此同时,Stable Diffusion 2.x系列模型中的优化技术与Tricks,是AI绘画领域的一笔宝贵财富,能让工业界、学术界、竞赛界、应用界都能从中获得灵感与思路 。
Stable Diffusion 2.0模型在2022年11月由Stability AI公司发布。与SD 1.5模型相比,SD 2.0模型主要改动了模型结构 和训练数据 两个部分。
7.1.1 SD 2.0模型结构改动
Stable Diffusion 1.x系列中的Text Encoder部分是采用OpenAI开源的CLIP ViT-L/14模型 ,其模型参数量为123.65M;而Stable Diffusion V2系列则换成了新的OpenCLIP模型——CLIP ViT-H/14模型 (基于LAION-2b数据集训练),其参数量为354.03M,比SD 1.x的Text Encoder模型大了3倍左右。具体对比如下表所示:
Model name
Text Params
Imagen et top1
Mscoco image retrieval at 5
Flickr30k image retrieval at 5
Openai L/14
123.65M
75.4%
61%
87%
CLIP ViT-H/14
354.03M
78.0%
73.4%
94%
可以看到,SD 2.0使用的CLIP ViT-H/14模型相比SD 1.x使用的 OpenAI CLIP ViT-L/14模型,在Imagenet top1(分类准确率75.4% -> 78.0%)、Mscoco image retrieval at 5(多模态检索任务指标61% -> 73.4%)以及Flickr30k image retrieval at 5(多模态检索任务指标87% -> 94%)上均有明显的提升,表明CLIP ViT-H/14模型的Text Encoder能够输出更准确的文本语义信息。
与此同时,SD 2.0在Text Encoder部分还有一个细节优化是使用Text Encoder倒数第二层的特征来作为U-Net模型的文本信息输入,这与SD 1.x所使用的Text Encoder倒数第一层的特征不同。Imagen和novelai在训练时也采用了Text Encoder倒数第二层的特征,因为倒数第一层的特征存在部分丢失细粒度文本信息的情况,而这些细粒度文本信息有助于SD模型更快地学习某些概念特征 。
SD2.0和SD1.x的VAE部分是一致的 。由于切换了Text Encoder模型,在SD 2.0中U-Net的cross attention dimension从SD 1.x U-Net的768变成了1024,从而U-Net部分的整体参数量有一些增加(860M -> 865M ),除此之外SD 2.0 U-Net与SD 1.x U-Net的整体架构是一样的 。与此同时,在SD 2.0 U-Net中不同stage的attention模块的attention head dim是不固定的(5、10、20、20),而SD 1.x则是不同stage的attention模块采用固定的attention head数量(8),这个改动不会影响模型参数量。
7.1.2 SD 2.0官方训练数据与训练过程
除了上面讲到的Text Encoder模型的区别,Stable Diffusion V1和Stable Diffusion V2在训练数据也有较大的不同 :
Stable Diffusion 2.0模型从头开始在LAION-5B数据集的子集(该子集通过LAION-NSFW分类器过滤掉了NSFW数据,过滤标准是punsafe=0.1和美学评分>= 4.5)上以256×256的分辨率训练了550k步 ,然后接着以512×512的分辨率在同一数据集上进一步训练了850k步 。
前面讲过SD 1.x系列模型主要采用LAION-5B中美学评分>= 5以上的子集来训练,而到了SD 2.0版本采用美学评分>= 4.5以上的子集,这相当于扩大了训练数据集 。
StabilityAi官方基于SD 2.0架构一共发布了5个版本的模型 ,具体如下所示:
512-base-ema.ckpt :SD 2.0的基础版本模型,训练方法刚才已经讲过。
768-v-ema.ckpt :先在512-base-ema.ckpt模型的基础上,使用v-objective(Progressive Distillation for Fast Sampling of Diffusion Models) 损失函数训练了150k步,接着以768×768分辨率在LAION-5B数据集的子集上又进行了140k步的训练最终得到768-v-ema.ckpt模型。
512-depth-ema.ckpt :stable-diffusion-2-depth模型在512-base-ema.ckpt模型的基础上继续进行了200k步的微调训练。只不过在训练过程中增加了图像深度图(深度图信息由MiDaS 算法生成)作为控制条件。具体的深度信息控制效果如下所示:
接下来我们用diffusers库来运行stable-diffusion-2-depth模型,具体代码如下所示:
import torch
import requests
from PIL import Image
from diffusers import StableDiffusionDepth2ImgPipeline
pipe = StableDiffusionDepth2ImgPipeline. from_pretrained(
"/本读路径/stable-diffusion-2-depth" ,
torch_dtype= torch. float16,
) . to( "cuda" )
url = "http://images.cocodataset.org/val2017/000000039769.jpg"
init_image = Image. open ( requests. get( url, stream= True ) . raw)
prompt = "two tigers"
n_propmt = "bad, deformed, ugly, bad anotomy"
image = pipe( prompt= prompt, image= init_image, negative_prompt= n_propmt, strength= 0.7 ) . images[ 0 ]
512-inpainting-ema.ckpt :stable-diffusion-2-inpainting模型在512-base-ema.ckpt模型的基础上继续训练了200k步。和stable-diffusion-inpainting模型一样,使用LAMA 中提出的Mask生成策略,将Mask作为一个额外条件加入模型训练,从而获得一个图像inpainting模型。 接下来我们用diffusers库来运行stable-diffusion-2-inpainting模型,具体代码如下所示:
from diffusers import StableDiffusionInpaintPipeline
pipe = StableDiffusionInpaintPipeline. from_pretrained(
"/本地路径/stable-diffusion-2-inpainting" ,
torch_dtype= torch. float16,
)
pipe. to( "cuda" )
prompt = "Face of a yellow cat, high resolution, sitting on a park bench"
image = pipe( prompt= prompt, image= image, mask_image= mask_image) . images[ 0 ]
image. save( "./yellow_cat_on_park_bench.png" )
x4-upscaling-ema.ckpt :stable-diffusion-x4-upscaler模型是基于Latent Diffusion架构的4倍超分模型 ,采用了基于VQ-reg正则的VAE模型 ,下采样率设置为 。这个模型使用LAION中分辨率大于2048×2048的子集(10M)作为训练集训练迭代了1.25M步,同时在训练过程中设置512×512的crop操作来降低显存占用与加速训练。如果我们用SD系列模型生成512×512分辨率的图像,再输入stable-diffusion-x4-upscaler模型就可以得到2048×2048分辨率的图像。
与传统深度学习时代的GAN网络的超分逻辑不同,stable-diffusion-x4-upscaler模型是经典的生成式超分模型 。由于VAE将高分辨率图像压缩为原来的1/4,而低分辨率图像也是高分辨率图像的1/4,所以两者的维度是一致的,可以将低分辨率图像和noisy latent拼接在一起送入U-Net。同时在训练过程中使用了noise conditioning augmentation策略,通过扩散过程(独立的scheduler和timestep)来给低分辨率图像加上高斯噪音,将噪声特征通过class labels的方式输入U-Net,让U-Net知道添加噪音的强度。 接下来我们用diffusers库来运行stable-diffusion-x4-upscaler模型,具体代码如下所示:
import requests
from PIL import Image
from io import BytesIO
from diffusers import StableDiffusionUpscalePipeline
import torch
model_id = "/本地路径/stable-diffusion-x4-upscaler"
pipeline = StableDiffusionUpscalePipeline. from_pretrained( model_id, torch_dtype= torch. float16)
pipeline = pipeline. to( "cuda" )
url = "https://huggingface.co/datasets/hf-internal-testing/diffusers-images/resolve/main/sd2-upscale/low_res_cat.png"
response = requests. get( url)
low_res_img = Image. open ( BytesIO( response. content) ) . convert( "RGB" )
low_res_img = low_res_img. resize( ( 128 , 128 ) )
prompt = "a white cat"
upscaled_image = pipeline( prompt= prompt, image= low_res_img, noise_level= 10 ) . images[ 0 ]
upscaled_image. save( "upsampled_cat.png" )
SD 2.0和SD 1.x的性能对比:
下图是SD 2.0和SD 1.5在COCO2017验证集上的性能测试,设置了8个不同的classifier-free guidance scales 值(1.5, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0),随机采样了1000个Prompt进行50步的DDIM扩散过程,生成了512×512分辨率的图像进行效果对比:
可以看到,SD 2.0相比SD 1.5在CLIP scores这个指标上有明显的提升,但是FID指标也有一定的上升。总结来说,尽管Stable Diffusion 2.0在文本编码器和训练数据方面取得了重大进步,从而提高了生成图像质量,但还是需要使用者根据实际场景与需求对两个模型进行选择使用 。
7.2 Stable Diffusion 2.1系列模型
Stable Diffusion 2.1是Stable Diffusion 2.0的增强版本,同样由Stability AI发布。
SD 2.0在训练过程中采用NSFW检测器过滤掉了可能包含安全风险的图像(punsafe=0.1),但是同时也过滤了很多人像图片,这导致SD 2.0在人像生成上效果并不理想,所以SD 2.1在SD 2.0的基础上放开了过滤限制(punsafe=0.98),在SD 2.0的基础上继续进行微调训练 。
最终SD 2.1的人像的生成效果得到了优化和增强,同时与SD 2.0相比也提高了生成图片的整体质量,其base生成分辨率有512×512和768×768两个版本 ,具体细节如下:
512-base-ema.ckpt(stable-diffusion-2-1-base模型) :在stable-diffusion-2-base(512-base-ema.ckpt) 模型的基础上,放开NSFW检测器限制(punsafe=0.98),使用相同的训练集继续微调训练220k步。
768-v-ema.ckpt(stable-diffusion-2-1模型) :在stable-diffusion-2(768-v-ema.ckpt 2.0)模型的基础上,使用相同NSFW检测器规则(punsafe=0.1)和相同数据集继续微调训练了55k步,然后放开NSFW检测器限制(punsafe=0.98),额外再微调训练了155k步。
但是尽管如此,SD 2.1模型依旧没有在开源社区中爆发训练和使用的热潮,反响平平。加上前有开源生态繁荣的SD 1.5和后有性能强大的SDXL,SD 2.x系列模型更显鸡肋,这也是开源社区没有采取进一步的行动的原因之一。
但是虽然SD 2.1没有在AI绘画开源社区中爆发,但是它熬过了低谷,在AI视频领域成为Stable Video Diffusion的核心基础模型,未来其发展势能非常强劲。
7.3 Stable Diffusion 2.1 unclip模型
2023年3月24号,Stability AI继续在SD 2.1的基础上发布了Stable Diffusion 2.1 unclip模型。与之前的SD系列模型不同的是,Stable Diffusion 2.1 unclip模型首创在SD系列模型中使用CLIP模型中的Image Encoder模块来提取Image Embeddings作为conditions条件来控制图像的生成过程 。
因为有了Image Embeddings这个强大的图像特征作为conditions条件,SD 2.1 unclip可以实现图像的变换(image variations)功能,具体效果如下图所示: 那么SD 2.1 unclip具体是怎么使用Image Embeddings特征的呢?
首先SD 2.1 unclip模型是在stable-diffusion-2-1模型的基础上以768×768分辨率继续微调的,并在训练过程中对CLIP的Image Encoder提取的Image Embeddings施加一定的噪声,这个加噪过程也是一个扩散过程,噪声量级可以通过noise_level指定(0表示无噪声,1000表示全噪声),这样就得到Noisy CLIP Image Embeddings 作为conditions条件,然后将noise_level对应的Time Embeddings和Noisy CLIP Image Embeddings拼接(concat),最后再以class labels的方式送入U-Net进行训练。SD 2.1 unclip模型的训练集依旧是LAION-5B,只是使用NSFW检测器进一步的过滤了风险数据(p_unsafe = 0.1)。
在diffusers库中,我们可以通过StableUnCLIPImg2ImgPipeline来加载SD 2.1 unclip模型实现图像的变换功能:
from diffusers import StableUnCLIPImg2ImgPipeline
from diffusers. utils import load_image
import torch
pipe = StableUnCLIPImg2ImgPipeline. from_pretrained( "/本地路径/stable-diffusion-2-1-unclip-small" , torch_dtype= torch. float16)
pipe. to( "cuda" )
url = "https://huggingface.co/datasets/hf-internal-testing/diffusers-images/resolve/main/stable_unclip/tarsila_do_amaral.png"
image = load_image( url)
image = pipe( image) . images[ 0 ]
SD 2.1 unclip模型一共发布了两个变体版本:Stable unCLIP-L 和 Stable unCLIP-H,分别使用CLIP ViT-L 和 ViT-H的Image Embeddings作为condition条件。
7.4 SD Turbo模型
SD Turbo模型是在Stable Diffusion V2.1的基础上,通过蒸馏训练得到的精简版本,其本质上还是一个Stable Diffusion V2.1模型,其网络架构不变 。
与SDXL Turbo相比,SD Turbo模型更小、速度更快,但是生成图像的质量和Prompt对齐方面不如前者。
但是在AI视频领域,SD Turbo模型有很大的想象空间,因为Stable Video Diffusion的基础模型是Stable Diffusion 2.1,所以未来SD Turbo模型在AI视频领域很可能成为AI视频加速生产的有力工具之一 。
关于SD Turbo蒸馏训练中使用的Adversarial Diffusion Distillation(ADD)技术 ,Rocky在《深入浅出完整解析Stable Diffusion XL(SDXL)核心基础知识》文章中已经详细解析,感兴趣的朋友可以阅读对应文章的第六章节内容:
深入浅出完整解析Stable Diffusion XL(SDXL)核心基础知识
为了测试SD Turbo的性能,StabilityAI使用相同的文本提示,将SD Turbo与LCM-LoRA 1.5和LCM-LoRA XL等不同版本的文生图模型进行了比较。测试结果显示,在图像质量和Prompt对齐方面,SD Turbo只用1个step,就击败了LCM-LoRA 1.5和LCM-LoRA XL生成的图像 。diffusers库已经支持SDXL Turbo的使用运行了,可以进行文生图和图生图的任务 ,相关代码和操作流程如下所示:
from diffusers import AutoPipelineForText2Image
import torch
pipe = AutoPipelineForText2Image. from_pretrained( "/本地路径/sd-turbo" , torch_dtype= torch. float16, variant= "fp16" )
pipe. to( "cuda" )
prompt = "A cinematic shot of a baby racoon wearing an intricate italian priest robe."
image = pipe( prompt= prompt, num_inference_steps= 1 , guidance_scale= 0.0 ) . images[ 0 ]
这里要注意的是,SD Turbo模型在diffusers库中进行文生图操作时不需要使用guidance_scale和negative_prompt参数,所以我们设置guidance_scale=0.0。
接下来,Rocky再带大家完成SD Turbo模型在diffusers中图生图的整个流程:
from diffusers import AutoPipelineForImage2Image
from diffusers. utils import load_image
import torch
pipe = AutoPipelineForImage2Image. from_pretrained( "/本地路径/sd-turbo" , torch_dtype= torch. float16, variant= "fp16" )
pipe. to( "cuda" )
init_image = load_image( "/本地路径/test.png" ) . resize( ( 512 , 512 ) )
prompt = "cat wizard, gandalf, lord of the rings, detailed, fantasy, cute, adorable, Pixar, Disney, 8k"
image = pipe( prompt, image= init_image, num_inference_steps= 2 , strength= 0.5 , guidance_scale= 0.0 ) . images[ 0 ]
需要注意的是,当在diffusers中使用SD Turbo模型进行图生图操作时,需要确保num_inference_steps*strength大于或等于1。因为前向推理的步数等于int(num_inference_steps * strength)步。比如上面的例子中,我们就使用SD Turbo模型前向推理了0.5 * 2.0 = 1 步。
8. Stable Diffusion系列模型的性能优化
AI行业从2022年开始进入AIGC时代后,Stable Diffusion等AI绘画领域中的大模型在未来将面临着传统深度学习时代YOLO模型一样的轻量化、端侧部署、实时性能 等应用需求,这也是AIGC时代未来10年中工业界、竞赛界以及学术界研究实践的一个重要方向。
Rocky在本章中也会持续补充能够优化Stable Diffusion系列模型性能的实用技术方法,方便大家学习与使用。
8.1 从精度角度优化Stable Diffusion系列模型的性能
8.1.1 使用FP16半精度加速SD模型训练与推理
一般情况下,Stable Diffusion系列模型使用**32Bit浮点格式(FP32)来进行训练或者推理,我们可以使用 半精度浮点格式(FP16)**来加速SD系列模型的训练和推理。
具体代码如下所示:
import torch
from diffusers import DiffusionPipeline
pipe = DiffusionPipeline. from_pretrained(
"/本地路径/stable-diffusion-v1-5" ,
torch_dtype= torch. float16,
) . to( 'cuda' )
pipe = DiffusionPipeline. from_pretrained(
'/本地路径/stable-diffusion-v1-5' ,
use_safetensors= True ,
torch_dtype= torch. float16,
variant= 'fp16' ,
) . to( 'cuda' )
使用FP16半精度进行模型训练与前向推理的优势 :
前向推理:减少了一半的显存占用,同时推理速度大幅提升,一个Batch中生成图片的数量增加。
模型训练:减少了一半的显存占用,同时模型训练速度大幅提升,我们可以进一步将batch大小翻倍,一些GPU如V100、2080Ti等针对FP16计算进行了优化,能自动加速3-8倍。
8.1.2 使用TF32精度加速SD模型训练与推理
TF32精度(TensorFloat-32)是介于FP32和FP16之间的一种格式,能够让一些NVIDIA显卡(如A100或H100)使用张量核心执行计算。它使用与FP32相同的Bit来表示指数,使用与FP16相同的Bit来表示小数部分。
启用TF32精度的代码非常简洁,如下所示:
import torch
torch. backends. cuda. matmul. allow_tf32 = True
TF32在性能和精度上实现了平衡。下面是TF32精度的一些作用和优势:
加速训练速度:使用TF32精度可以在保持相对较高的模型精度的同时,加快模型训练的速度。
减少内存需求:TF32精度相对于传统的浮点数计算(如FP32)需要更少的显存存储。这对于训练AIGC模型尤为重要,可以减少显存的占用。
可接受的模型精度损失:使用TF32精度会导致一定程度的模型精度损失,因为低精度计算可能无法精确表示一些小的数值变化。然而,对于大多数AIGC应用,TF32精度仍然可以提供足够的模型精度。
8.2 从整体Pipeline角度优化Stable Diffusion系列模型的性能
8.2.1 对注意力模块进行切片
SD系列模型中存在大量的注意力模块,我们可以对注意力模块进行切片操作,使得每个注意模块的注意力头依次进行计算,从而大幅减少显存占用,但随之而来的是推理时间增加约10%。
import torch
from diffusers import DiffusionPipeline
pipe = DiffusionPipeline. from_pretrained( "/本地路径/stable-diffusion-v1-5" ,
torch_dtype= torch. float16,
)
pipe = pipe. to( "cuda" )
pipe. enable_attention_slicing( )
8.2.2 对VAE进行切片(VAE slicing)
和注意力模块切片一样,我们也可以对SD系列模型中的VAE部分进行切片。原本VAE将并行处理一个Batch中的所有图片,使用VAE slicing技术后,可以让VAE串行逐一处理一个Batch中的所有图片,从而大幅减少显存占用。
举个列子,如果我们设置Batch Size为32,当我们使用VAE slicing技术后,显存占用与Batch Size为1的情况一致。
下面是启动VAE slicing技术的代码,非常简洁:
import torch
from diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline. from_pretrained(
"/本地路径/stable-diffusion-v1-5" ,
torch_dtype= torch. float16,
)
pipe = pipe. to( "cuda" )
prompt = "a photo of an astronaut riding a horse on mars"
pipe. enable_vae_slicing( )
images = pipe( [ prompt] * 32 ) . images
8.2.3 模型权重CPU GPU切换
可以将整个SD模型权重先加载到CPU中,等到模型推理时再将需要的部分权重加载到GPU中。主要有两种转换形式:
Model CPU Offload :在推理时,每次从CPU中读取SD主要模块级别的权重,比如说VAE、U-Net以及Text Encoder。Model CPU Offload能够降低约50.27%的显存占用,但是会增加15.6%左右的推理耗时,适合用于显存只有6-8G的显卡。
Sequential CPU Offload :在推理时,每次从CPU中读取SD主要模块的子模块级别的权重,比如说U-Net的encoder部分等。Sequential CPU Offload能够降低约64.06%的显存占用,但是会增加353.9%左右的推理耗时,适合于显存小于4G的显卡。
下面是在diffusers库中使用CPU GPU切换的一个例子:
import torch
from diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline. from_pretrained(
"/本地路径/stable-diffusion-v1-5" ,
torch_dtype= torch. float16,
)
pipe. enable_sequential_cpu_offload( )
pipe. enable_model_cpu_offload( )
8.2.4 变换Memory Format
在AI领域,两种比较常见的memory format是channels first(NCHW)和channels last(NHWC)。将channels first转变成为channels last可能会提升推理速度,不过这也需要依AI框架和硬件而定。
在Channels Last内存格式中,张量的维度顺序为:(batch_size, height, width, channels)。其中,batch_size表示批处理大小,height和width表示图像或特征图的高度和宽度,channels表示通道数。
相比而言,Channels First是另一种内存布局,其中通道维度被放置在张量的第二个维度上。在Channels First内存格式中,张量的维度顺序为:(batch_size, channels, height, width)。
选择Channels Last或Channels First内存格式通常取决于硬件平台以及所使用的AI框架。不同的平台和框架可能对内存格式有不同的偏好和支持程度。
在一些情况下,Channels Last内存格式可能具有以下优势:
内存访问效率:在一些硬件架构中,如CPU和GPU,Channels Last内存格式能够更好地利用内存的连续性,从而提高数据访问的效率。
硬件加速器支持:一些硬件加速器(如NVIDIA的Tensor Cores)对于Channels Last内存格式具有特定的优化支持,可以提高计算性能。
跨平台兼容性:某些深度学习框架和工具更倾向于支持Channels Last内存格式,使得在不同的平台和框架之间迁移模型更加容易。
需要注意的是,选择内存格式需要根据具体的硬件、软件和AI框架来进行评估。某些特定的操作、模型结构或框架要求可能会对内存格式有特定的要求或限制。因此,建议在特定环境和需求下进行测试和选择,以获得最佳的性能和兼容性。
print ( pipe. unet. conv_out. state_dict( ) [ "weight" ] . stride( ) )
pipe. unet. to( memory_format= torch. channels_last)
print ( pipe. unet. conv_out. state_dict( ) [ "weight" ] . stride( ) )
8.3 从加速插件角度优化Stable Diffusion系列模型的性能
8.3.1 使用xFormers加速SD模型训练与推理
使用xFormers插件能够优化SD系列模型中的Attention模块,提升20%左右的运算速度,同时大幅降低显存占用,从而提升SD系列模型的图像生成速度。
from diffusers import DiffusionPipeline
import torch
pipe = DiffusionPipeline. from_pretrained(
"/本地路径/stable-diffusion-v1-5" ,
torch_dtype= torch. float16,
) . to( "cuda" )
pipe. enable_xformers_memory_efficient_attention( )
同样的,xFormers插件也能加速SD系列模型的训练过程。
8.3.2 使用tomesd加速SD模型推理
我们可以在使用xFormers插件的基础上,再使用tomesd插件,在无需额外训练的情况下能够对SD系列模型达到5.4倍左右的提速,同时减少了显存消耗,并且仍能产生高质量的图像,具体效果如下图所示:
tomesd插件中的核心Token Merging(ToMe)技术通过减少SD模型需要处理的tokens数量(Prompt and Negative Prompt)来加速推理过程。在SD模型推理过程中许多tokens是冗余的,对这些冗余的tokens进行合并不会对出图质量产生太多影响。由于是对tokens进行优化,所以ToMe技术对于Stable Diffusion全系列模型来说都是一个即插即用的高效辅助工具 。
实际操作中,tomesd插件中设置了一个控制参数来调节合并的tokens比例(0%-60%),具体效果如下图所示:
由上图的左半部分可以看到,ToMe技术主要作用在SD模型的CrossAttention模块,从而达到加速与降低显存占用的效果。
我们可以使用diffusers库来快速搭建SD系列模型的Pipeline,并使用tomesd工具进行加速,具体代码如下所示:
import torch, tomesd
from diffusers import StableDiffusionPipeline
pipe = StableDiffusionPipeline. from_pretrained( "/本地路径/stable-diffusion-v1-5" , torch_dtype= torch. float16) . to( "cuda" )
tomesd. apply_patch( pipe, ratio= 0.5 )
image = pipe( "a photo of an astronaut riding a horse on mars" ) . images[ 0 ]
image. save( "astronaut.png" )
通常我们设置ratio参数为0.5即可获得较好的效果,这时SD模型加速约1.87倍,显存占用降低约3.83倍。
8.3.3 使用torch.compile加速SD推理
我们在SD系列模型准备推理之前,可以将模型传递给torch.compile函数进行预编译(耗时3分钟左右)。这样,在实际推理时,SD系列模型就能以更高的效率运行。
torch.compile函数主要进行三方面的优化:
优化模型推理路径 :通过分析SD模型的计算图(computation graph),torch.compile能够合并推理过程中的冗余操作、减少不必要的数据传输等。
减少冗余计算 :在SD模型推理过程中,存在重复和不必要的计算操作,torch.compile通过对SD模型的预编译,有效减少冗余计算成本。
硬件加速 :torch.compile针对GPU、TPU等硬件平台进行优化,确保模型能够充分利用硬件资源。
下面是使用diffusers+torch.compile优化SD模型推理的例子:
from diffusers import DiffusionPipeline
import torch
pipe = DiffusionPipeline. from_pretrained(
"/本地路径/stable-diffusion-v1-5" ,
torch_dtype= torch. float16,
) . to( "cuda" )
pipe. unet = torch. compile ( pipe. unet, mode= "reduce-overhead" , fullgraph= True )
通过上述优化,SD系列模型的前向推理速度可以提升20%-30%左右 。
8.3.4 使用TensorRT加速SD系列模型推理
使用TensorRT需要对模型进行编译,编译完成后SD系列模型的推理过程可以加速约57.14%左右。 使用TensorRT加速的完整代码如下所示:
git clone https: // github. com/ rajeevsrao/ TensorRT
pip install torch torchvision - - index- url https: // download. pytorch. org/ whl/ cu118
pip install transformers accelerate diffusers cuda- python nvtx onnx colored scipy polygraphy
pip install - - pre - - extra- index- url https: // pypi. nvidia. com tensorrt
pip install - - pre - - extra- index- url https: // pypi. ngc. nvidia. com onnx_graphsurgeon
cd demo/ Diffusion
pip install - r requirements. txt
python - c "import tensorrt; print(tensorrt.__version__)"
cd TensorRT/ demo/ Diffusion
python3 demo_txt2img_xl. py
"Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
- - build- static- batch
- - use- cuda- graph
- - num- warmup- runs 1
- - width 1024
- - height 1024
- - denoising- steps 30
- - onnx- base- dir / 本地路径/ stable- diffusion- xl- 1.0 - tensorrt/ sdxl- 1.0 - base
- - onnx- refiner- dir / 本地路径/ stable- diffusion- xl- 1.0 - tensorrt/ sdxl- 1.0 - refiner
除了编译耗时2-10分钟外,我们还需要前置设定特定分辨率和批次大小优化TensorRT引擎来提高性能,一共有动态引擎和静态引擎两种:
静态引擎 :支持单一特定输出分辨率(比如512×512)和批次大小(比如4)。
静态引擎 :支持一定范围的分辨率(比如512×512到1024×1024之间)和批次大小(比如1-4),但会以略微降低性能为代价。范围越宽,使用的VRAM就越多。
TensorRT模型权重百度云网盘 :关注Rocky的公众号WeThinkIn ,后台回复:TensorRT模型 ,即可获得资源链接,包含SDXL 1.0 Base TensorRT模型权重、SDXL 1.0 Refiner TensorRT模型权重、SDXL-LCM TensorRT模型权重以及SDXL-LCM LoRA TensorRT模型权重 。
8.3.5 使用OneDiff加速SD系列模型推理
OneDiff是一个适配了Diffusers、ComfyUI和Stable Diffusion webUI三个AI绘画主流框架的优化库,采用了量化、注意力机制改进和模型编译等技术。
OneDiff的代码也非常简洁:
import oneflow as flow
from onediff. infer_compiler import oneflow_compile
pipe = StableDiffusionPipeline. from_pretrained(
'/本地路径/stable-diffusion-xl-base-1.0' ,
use_safetensors= True ,
torch_dtype= torch. float16,
variant= 'fp16' ,
) . to( 'cuda' )
pipe. unet = oneflow_compile( pipe. unet)
在使用OneDiff时需要对模型进行编译,大概需要1分钟左右。OneDiff可以使SD系列的推理时加速约44.68%,同时显存占用并没有明显增加。
8.3.6 使用Stable Fast库来加速SD系列模型推理
Stable Fast库通过CUDNN卷积融合、低精度&融合GEMM、NHWC&融合GroupNorm、融合多头自注意力以及CUDA Graph等一系列技术来加速SD系列模型。
比起TensorRT那样需要几分钟来进行SD模型的编译,Stable Fast库只需要10-20秒左右即可以完成。
我们想要使用Stable Fast库,首先需要安装一些依赖,包括Triton、xFormers等:
pip install stable- fast
pip install torch torchvision triton xformers - - index- url https: // download. pytorch. org/ whl/ cu118
完成了上面依赖的安装,我们就可以使用Stable Fast库了,使用方法如下所示:
import xformers
import triton
from sfast. compilers. diffusion_pipeline_compiler import ( compile , CompilationConfig)
pipe = StableDiffusionPipeline. from_pretrained(
'/本地路径/stable-diffusion-xl-base-1.0' ,
use_safetensors= True ,
torch_dtype= torch. float16,
variant= 'fp16' ,
) . to( 'cuda' )
config = CompilationConfig. Default( )
config. enable_xformers = True
config. enable_triton = True
config. enable_cuda_graph = True
pipe = compile ( pipe, config)
除了一开始需要对模型进行编译预热,使用Stable Fast库可以使得SD系列模型生成图像获得约40.43%左右的加速,同时显存使用量增加约7.74%左右。
9. 推荐阅读
Rocky会持续分享AIGC的干货文章、实用教程、商业应用/变现案例以及对AIGC行业的深度思考与分析 ,欢迎大家多多点赞、喜欢、收藏和转发 ,给Rocky的义务劳动多一些动力吧,谢谢各位!
9.1 深入浅出完整解析Stable Diffusion XL(SDXL)核心基础知识
Rocky也对Stable Diffusion XL的核心基础知识 作了全面系统的梳理与解析:
深入浅出完整解析Stable Diffusion XL(SDXL)核心基础知识
9.2 深入浅出完整解析Stable Diffusion中U-Net的前世今生与核心知识
Rocky对Stable Diffusion中最为关键的U-Net结构 进行了深入浅出的全面解析,包括其在传统深度学习中的价值和在AIGC中的价值:
深入浅出完整解析Stable Diffusion中U-Net的前世今生与核心知识
9.3 深入浅出完整解析LoRA(Low-Rank Adaptation)模型核心基础知识
对于AIGC时代中的**“ResNet”——LoRA模型**,Rocky也进行了深入浅出的全面讲解:
深入浅出完整解析LoRA(Low-Rank Adaptation)模型核心基础知识
9.4 深入浅出完整解析ControlNet核心基础知识
AI绘画作为AIGC时代的一个核心方向,开源社区已经形成以Stable Difffusion为核心,ConrtolNet和LoRA作为首要AI绘画辅助工具的变化万千的AI绘画工作流。
ControlNet正是让AI绘画社区无比繁荣的关键一环,它让AI绘画生成过程更加的可控,更有助于广泛地将AI绘画应用到各行各业中 :
深入浅出完整解析ControlNet核心基础知识
9.5 深入浅出完整解析主流AI绘画框架核心基础知识
AI绘画框架正是AI绘画“工作流”的运行载体,目前主流的AI绘画框架有Stable Diffusion WebUI、ComfyUI以及Fooocus等 。在传统深度学习时代,PyTorch、TensorFlow以及Caffe是传统深度学习模型的基础运行框架,到了AIGC时代,Rocky相信Stable Diffusion WebUI就是AI绘画领域的“PyTorch”、ComfyUI就是AI绘画领域的“TensorFlow”、Fooocus就是AI绘画领域的“Caffe” :
深入浅出完整解析主流AI绘画框架(Stable Diffusion WebUI、ComfyUI、Fooocus)核心基础知识
9.6 手把手教你成为AIGC算法工程师,斩获AIGC算法offer!
在AIGC时代中,如何快速转身,入局AIGC产业?如何成为AIGC算法工程师?如何在学校中系统性学习AIGC知识,斩获心仪的AIGC算法offer?
Don‘t worry,Rocky为大家总结整理了全面的AIGC算法工程师成长秘籍 ,为大家答疑解惑,希望能给大家带来帮助:
手把手教你成为AIGC算法工程师,斩获AIGC算法offer!(持续更新)
9.7 AIGC产业的深度思考与分析
2023年3月21日,微软创始人比尔·盖茨在其博客文章《The Age of AI has begun》中表示,自从1980年首次看到图形用户界面(graphical user interface)以来,以OpenAI为代表的科技公司发布的AIGC模型是他所见过的最具革命性的技术进步。
Rocky也认为,AIGC及其生态,会成为AI行业重大变革的主导力量。AIGC会带来一个全新的红利期,未来随着AIGC的全面落地和深度商用,会深刻改变我们的工作、生活、学习以及交流方式,各行各业都将被重新定义,过程会非常有趣。
那么,在此基础上,我们该如何更好的审视AIGC的未来?我们该如何更好地拥抱AIGC引领的革新?Rocky准备从技术、产品、商业模式、长期主义等维度持续分享一些个人的核心思考与观点,希望能帮助各位读者对AIGC有一个全面的了解 :
2023年“疯狂三月”之后,深入浅出全面分析AIGC的核心价值 (持续更新)
9.8 算法工程师的独孤九剑秘籍
为了方便大家实习、校招以及社招的面试准备,同时帮助大家提升扩展技术基本面 ,Rocky将符合大厂和AI独角兽价值的算法高频面试知识点撰写总结成**《三年面试五年模拟之独孤九剑秘籍》,并制作成 pdf版本**,大家可在公众号WeThinkIn 后台**【精华干货】菜单**或者回复关键词“三年面试五年模拟 ”进行取用:
【三年面试五年模拟】算法工程师的求职面试秘籍
【三年面试五年模拟】算法工程师的求职面试“独孤九剑”秘籍(持续更新中)
9.9 深入浅出完整解析AIGC时代中GAN系列模型的前世今生与核心知识
GAN网络作为传统深度学习时代的最热门生成式Al模型,在AIGC时代继续繁荣,作为Stable Diffusion系列模型的“得力助手”,广泛活跃于Al绘画的产品与工作流中:
深入浅出完整解析AIGC时代中GAN系列模型的前世今生与核心知识
Rocky一直在运营技术交流群 (WeThinkIn-技术交流群),这个群的初心主要聚焦于AI行业话题的讨论与研究,包括但不限于算法、开发、竞赛、科研以及工作求职等。群里有很多AI行业的大牛,欢迎大家入群一起交流探讨~(请备注来意,添加小助手微信Jarvis8866,邀请大家进群~)
文章来源于互联网:深入浅出完整解析Stable Diffusion(SD)核心基础知识
原文:深入浅出完整解析Stable Diffusion XL(SDXL)核心基础知识 Rocky的公众号:WeThinkIn Rocky的知乎:Rocky Ding 更多AI行业干货内容欢迎关注Rocky的CSDN、知乎、公众号~
码字不易,希望大家能多多点赞,给我更多坚持写下去的动力,谢谢大家!
2024.03.04最新消息,本文已经增加对Playground v2.5模型的解读。
2023.11.29最新消息,本文已经增加对SDXL Turbo模型的解读。
2023.09.26最新消息,由于Stable Diffusion XL模型的网络结构比较复杂,不好可视化,导致大家看的云里雾里。因此本文中已经发布Stable Diffusion XL中VAE,U-Net,Refiner,OpenCLIP ViT-bigG和OpenAI CLIP ViT-L五大模型的可视化网络结构图,大家可以下载用于学习!
2023.08.26最新消息,本文已经撰写Stable Diffusion XL以及对应LoRA的训练全流程与详细解读内容,同时发布对应的保姆级训练资源,大家可以愉快地训练属于自己的SDXL和LoRA模型了!
大家好,我是Rocky。
2022年作为AIGC(Artificial Intelligence Generated Content)时代的元年 ,各个领域的AIGC模型与技术都有一个迅猛的发展(比如Stable Diffusion、ChatGPT、Midjourney 等),未来15年的科技新浪潮已然来临,AIGC无疑给工业界、投资界、学术界以及竞赛界都注入了新的“AI活力”与“AI势能”。
其中在AI绘画 领域,Stable Diffusion模型当仁不让地成为了开源社区中持续繁荣的AI绘画核心模型,并且快速破圈让AIGC的ToC可能性比肩移动互联网时代的产品,每个人都能感受到AI带来的力量与影响 。Rocky之前撰写过深入浅出解析Stable Diffusion模型的文章(依旧在持续补充完善中,欢迎大家点赞,给我更多坚持写下去的动力):
深入浅出完整解析Stable Diffusion(SD)核心基础知识
本文中介绍的Stable Diffusion XL系列模型(简称SDXL)是Stable Diffusion的最新优化版本 ,由Stability AI发布。比起Stable Diffusion,Stable Diffusion XL做了全方位的优化,Rocky相信,Stable Diffusion是AI绘画领域的“YOLO”,而Stable Diffusion XL就是“YOLOv3” 。
因此在本文中,Rocky主要对Stable Diffusion XL系列模型(Stable Diffusion XL 1.0、Stable Diffusion XL 0.9、Stable Diffusion XL Turbo等)的全维度各个方面都做一个深入浅出的分析总结 (SDXL模型结构解析、SDXL模型从0到1保姆级训练教程、SDXL模型不同AI绘画框架从0到1推理运行保姆级教程、最新SDXL资源汇总分享、AI绘画模型的性能测评、AI绘画领域未来发展、SDXL相关配套工具使用等),和大家一些探讨学习,让我们在AIGC时代能够更好地融入和从容。
1. Stable Diffusion XL资源分享
Rocky会持续把更多Stable Diffusion XL的资源更新发布到本节中,让大家更加方便的查找SDXL系列模型的最新资讯。
2. Stable Diffusion XL核心基础内容
与Stable Diffusion 1.x-2.x相比,Stable Diffusion XL主要进行如下的优化:
对Stable Diffusion 1.x-2.x的U-Net,VAE,CLIP Text Encoder三大核心模型都做了改进。
增加一个独立的基于Latent的Refiner模型,也是一个扩散模型,用来提升生成图像的精细化程度。
设计了很多训练Tricks,包括图像尺寸条件化策略、图像裁剪参数条件化策略以及多尺度训练策略等。
先发布Stable Diffusion XL 0.9测试版本,基于用户的使用体验和图片生成的反馈情况,针对性增加数据集和使用RLHF(Reinforcement Learning from Human Feedback,基于人类反馈的强化学习)技术优化训练后,推出了Stable Diffusion XL 1.0正式版。
2.1 SDXL整体架构初识
Stable Diffusion XL是一个二阶段的级联扩散模型(Latent Diffusion Model) ,包括Base模型和Refiner模型。其中Base模型的主要工作和Stable Diffusion 1.x-2.x一致 ,具备文生图(txt2img)、图生图(img2img)、图像inpainting等能力。在Base模型之后,级联了Refiner模型,对Base模型生成的图像Latent特征进行精细化提升,其本质上是在做图生图的工作 。
SDXL Base模型由U-Net、VAE以及CLIP Text Encoder(两个)三个模块组成 ,在FP16精度下Base模型大小6.94G(FP32:13.88G),其中U-Net占5.14G、VAE模型占167M以及两个CLIP Text Encoder一大一小(OpenCLIP ViT-bigG和OpenAI CLIP ViT-L)分别是1.39G和246M。
SDXL Refiner模型同样由U-Net、VAE和CLIP Text Encoder(一个)三个模块组成 ,在FP16精度下Refiner模型大小6.08G,其中U-Net占4.52G、VAE模型占167M(与Base模型共用)以及CLIP Text Encoder模型(OpenCLIP ViT-bigG)大小1.39G(与Base模型共用)。
从下图可以看到,Stable Diffusion XL无论是对模型的整体工作流还是对不同子模块(U-Net、VAE、CLIP Text Encoder)都做了大幅的改进,能够生成1024×1024分辨率及以上的高质量图片。同时这些改进思想无论是对AIGC时代的模型还是传统深度学习时代的模型,都有非常大的迁移应用价值 。
比起Stable Diffusion 1.x-2.x,Stable Diffusion XL的参数量增加到了66亿(Base模型35亿+Refiner模型31亿),并且先后发布了模型结构完全相同的0.9和1.0两个版本 。Stable Diffusion XL 1.0在0.9版本上使用更多训练集+RLHF来优化生成图像的色彩、对比度、光线以及阴影方面,使得生成图像的构图比0.9版本更加鲜明准确。
Rocky相信,以Stable Diffusion XL 1.0版本为核心的AI绘画和AI视频生态将会持续繁荣。
Stable Diffusion XL Base模型参数:SDXL-Base
Stable Diffusion XL Refiner模型参数:SDXL-Refiner
下图中展示了Stability AI用户对SDXL 1.0、SDXL 0.9、SD 1.5以及SD 2.1的性能评估结果。可以看到单独的SDXL 1.0 Base模型的表现明显优于之前的所有SD版本,而完整的SDXL 1.0模型(Base模型 + Refiner模型)则实现了最佳的图像生成整体性能。
2.2 VAE模型(包含详细图解)
VAE模型(变分自编码器,Variational Auto-Encoder)是一个经典的生成式模型,其基本原理就不过多介绍了。在传统深度学习时代,GAN的风头完全盖过了VAE,但VAE简洁稳定的Encoder-Decoder架构,以及能够高效提取数据Latent特征和Latent特征像素级重建的关键能力 ,让其跨过了周期,在AIGC时代重新繁荣。
Stable Diffusion XL依旧是基于Latent 的扩散模型,所以VAE的Encoder和Decoder结构依旧是Stable Diffusion XL提取图像Latent特征和图像像素级重建的关键一招 。
当输入是图片时,Stable Diffusion XL和Stable Diffusion一样,首先会使用VAE的Encoder结构将输入图像转换为Latent特征 ,然后U-Net不断对Latent特征进行优化,最后使用VAE的Decoder结构将Latent特征重建出像素级图像 。除了提取Latent特征和图像的像素级重建外,VAE还可以改进生成图像中的高频细节,小物体特征和整体图像色彩 。
当Stable Diffusion XL的输入是文字时,这时我们不需要VAE的Encoder结构,只需要Decoder进行图像重建。VAE的灵活运用,让Stable Diffusion系列增添了几分优雅。
Stable Diffusion XL使用了和之前Stable Diffusion系列一样的VAE结构(KL-f8) ,但在训练中选择了更大的Batch-Size(256 vs 9) ,并且对模型进行指数滑动平均操作(EMA ,exponential moving average),EMA对模型的参数做平均,从而提高性能并增加模型鲁棒性。
下面是Rocky梳理的Stable Diffusion XL的VAE完整结构图 ,希望能让大家对这个在Stable DIffusion系列中未曾改变架构的模型有一个更直观的认识,在学习时也更加的得心应手: SDXL VAE模型中有三个基础组件:
GSC组件:GroupNorm+SiLU+Conv
Downsample组件:Padding+Conv
Ups ample组件:Interpolate+Conv
同时SDXL VAE模型还有两个核心组件:ResNetBlock模块和SelfAttention模型,两个模块的结构如上图所示。
SDXL VAE Encoder部分包含了三个DownBlock模块、一个ResNetBlock模块以及一个MidBlock模块,将输入图像压缩到Latent空间,转换成为Gaussian Distribution。
而VAE Decoder部分正好相反,其输入Latent空间特征,并重建成为像素级图像作为输出。其包含了三个UpBlock模块、一个ResNetBlock模块以及一个MidBlock模块。
在损失函数方面,使用了久经考验的生成领域“交叉熵”—感知损失(perceptual loss)以及L1回归损失 来约束VAE的训练过程。
下表是Stable Diffusion XL的VAE在COCO2017 验证集上,图像大小为256×256像素的情况下的性能。
(注:Stable Diffusion XL的VAE是从头开始训练的 )
上面的表中的三个VAE模型结构是一样的,不同点在于SD 2.x VAE是基于SD 1.x VAE微调训练了Decoder部分,同时保持Encoder部分权重不变,使他们有相同的Latent特征分布,所以SD 1.x和SD 2.x的VAE模型是互相兼容的 。而SDXL VAE是重新从头开始训练的,所以其Latent特征分布与之前的两者不同。
由于Latent特征分布产生了变化,SDXL VAE的缩放系数 也产生了变化。VAE在将Latent特征送入U-Net之前,需要对Latent特征进行缩放让其标准差尽量为1,之前的Stable Diffusion系列采用的缩放系数为0.18215 ,由于Stable Diffusion XL的VAE进行了全面的重训练,所以缩放系数重新设置为0.13025 。
注意:由于缩放系数的改变,Stable Diffusion XL VAE模型与之前的Stable Diffusion系列并不兼容。如果在SDXL上使用之前系列的VAE,会生成充满噪声的图片。
与此同时,与Stable Diffusion一样,VAE模型在Stable Diffusion XL中除了能进行图像压缩和图像重建的工作外,通过切换不同微调训练版本的VAE模型,能够改变生成图片的细节与整体颜色(更改生成图像的颜色表现,类似于色彩滤镜) 。
目前在开源社区常用的SDXL VAE模型有 :sdxl_vae.safetensors、lastpiecexlVAE_baseonA0897.safetensors、fixFP16ErrorsSDXLLowerMemoryUse_v10.safetensors、xlVAEC_f1.safetensors、flatpiecexlVAE_baseonA1579.safetensors等。
这里Rocky使用了6种不同的SDXL VAE模型,在其他参数保持不变的情况下,对比了SDXL模型的出图效果,如下所示: 可以看到,我们在SDXL中切换VAE模型进行出图时,均不会对构图进行大幅改变,只对生成图像的细节与颜色表现进行调整 。
Rocky目前也在整理汇总高价值的SDXL VAE模型(持续更新),方便大家获取使用。大家可以关注Rocky的公众号WeThinkIn ,后台回复:SDXLVAE ,即可获得资源链接,包含上述的全部SDXL VAE模型权重和更多高价值SDXL VAE模型权重 。
官方的Stable Diffusion XL VAE的权重已经开源:sdxl-vae
需要注意的是,原生Stable Diffusion XL VAE采用FP16精度时会出现数值溢出成NaNs的情况,导致重建的图像是一个黑图,所以必须使用FP32精度进行推理重建。如果大家想要FP16精度进行推理,可以使用sdxl-vae-fp16-fix 版本的SDXL VAE模型,其对FP16出现的NANs的情况进行了修复。
在官网如果遇到网络问题或者下载速度很慢的问题,可以关注Rocky的公众号WeThinkIn ,后台回复:SDXL模型 ,即可获得Stable Diffusion XL VAE模型权重(包含原生SDXL VAE与FP16修复版本)资源链接 。
接下来Rocky将用diffusers库来快速加载Stable Diffusion XL中的VAE模型,并通过可视化的效果直观展示SDXL VAE的压缩与重建效果,完整代码如下所示:
import cv2
import torch
import numpy as np
from diffusers import AutoencoderKL
VAE = AutoencoderKL. from_pretrained( "/本地路径/sdxl-vae" )
VAE. to( "cuda" )
raw_image = cv2. imread( "test_vae.png" )
raw_image = cv2. cvtColor( raw_image, cv2. COLOR_BGR2RGB)
raw_image = cv2. resize( raw_image, ( 1024 , 1024 ) )
image = raw_image. astype( np. float32) / 127.5 - 1.0
image = image. transpose( 2 , 0 , 1 )
image = image[ None , : , : , : ]
image = torch. from_numpy( image) . to( "cuda" )
with torch. inference_mode( ) :
latent = VAE. encode( image) . latent_dist. sample( )
rec_image = VAE. decode( latent) . sample
rec_image = ( rec_image / 2 + 0.5 ) . clamp( 0 , 1 )
rec_image = rec_image. cpu( ) . permute( 0 , 2 , 3 , 1 ) . numpy( )
rec_image = ( rec_image * 255 ) . round ( ) . astype( "uint8" )
rec_image = rec_image[ 0 ]
cv2. imwrite( "reconstructed_sdxl.png" , cv2. cvtColor( rec_image, cv2. COLOR_RGB2BGR) )
接下来,我们分别使用1024×1024分辨率的真实场景图片和二次元图片,使用SDXL VAE模型进行四种尺寸下的压缩与重建,重建效果如下所示: 从对比结果中可以看到,SDXL VAE在对图像进行压缩和重建时,虽然依然存在一定的精度损失,但只在256×256分辨率下会明显出现,比如说人脸特征丢失的情况 。同时比起SD 1.5 VAE模型,SDXL VAE模型在图像压缩与重建时的精度损失大幅降低 。并且不管是二次元图片还是真实场景图片,在不同尺寸下重建时,图片的主要特征都能保留下来,局部特征畸变的情况较少,损失程度较低 。
2.3 U-Net模型(Base部分,包含详细图解)
上表是Stable Diffusion XL与之前的Stable Diffusion系列的对比,从中可以看出,Stable Diffusion 1.x的U-Net参数量只有860M,就算是Stable Diffusion 2.x,其参数量也不过865M。但等到Stable Diffusion XL,U-Net模型(Base部分)参数量就增加到2.6B,参数量增加幅度达到了3倍左右 。
下图是Rocky梳理的Stable Diffusion XL Base U-Net的完整结构图 ,大家可以感受一下其魅力,看着这个完整结构图学习Stable Diffusion XL Base U-Net部分,相信大家脑海中的思路也会更加清晰:
上图中包含Stable Diffusion XL Base U-Net的十四个基本模块:
GSC模块 :Stable Diffusion Base XL U-Net中的最小组件之一,由GroupNorm+SiLU+Conv三者组成。
DownSample模块 :Stable Diffusion Base XL U-Net中的下采样组件,使用了Conv(kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))进行采下采样 。
UpSample模块 :Stable Diffusion Base XL U-Net中的上采样组件,由插值算法(nearest) +Conv组成。
ResNetBlock模块 :借鉴ResNet模型的“残差结构”,让网络能够构建的更深的同时,将Time Embedding信息嵌入模型 。
CrossAttention模块 :将文本的语义信息与图像的语义信息进行Attention机制,增强输入文本Prompt对生成图像的控制。
SelfAttention模块 :SelfAttention模块的整体结构与CrossAttention模块相同,这是输入全部都是图像信息,不再输入文本信息。
FeedForward模块 :Attention机制中的经典模块,由GeGlU+Dropout+Linear组成。
BasicTransformer Block模块 :由LayerNorm+SelfAttention+CrossAttention+FeedForward组成,是多重Attention机制的级联,并且每个Attention机制都是一个“残差结构”。通过加深网络和多Attention机制,大幅增强模型的学习能力与图文的匹配能力 。
SDXL_Spatial Transformer_X模块 :由GroupNorm+Linear+X个BasicTransformer Block +Linear构成,同时ResNet模型的“残差结构”依旧没有缺席。
SDXL_DownBlock模块 :由两个ResNetBlock+一个DownSample组成。
SDXL_UpBlock_X模块 :由X个ResNetBlock模块组成。
CrossAttnDownBlock_X_K模块 :是Stable Diffusion XL Base U-Net中Encoder部分的主要模块,由K个(ResNetBlock模块+SDXL_Spatial Transformer_X模块 )+一个DownSample模块组成。
CrossAttnUpBlock_X_K模块 :是Stable Diffusion XL Base U-Net中Decoder部分的主要模块,由K个(ResNetBlock模块+SDXL_Spatial Transformer_X模块 )+一个UpSample模块组成。
CrossAttnMidBlock模块 :是Stable Diffusion XL Base U-Net中Encoder和ecoder连接的部分,由ResNetBlock+SDXL_Spatial Transformer_10 +ResNetBlock组成。
可以看到,其中增加的SDXL_Spatial Transformer_X模块(主要包含Self Attention + Cross Attention + FeedForward)数量占新增参数量的主要部分 ,Rocky在上表中已经用红色框圈出。U-Net的Encoder和Decoder结构也从之前系列的4stage改成3stage([1,1,1,1] -> [0,2,10]),同时SDXL只使用两次下采样和上采样,而之前的SD系列模型都是三次下采样和上采样。并且比起Stable Diffusion 1.x-2.x,Stable Diffusion XL在第一个stage中不再使用Spatial Transformer Blocks,而在第二和第三个stage中大量增加了Spatial Transformer Blocks(分别是2和10),那么这样设计有什么好处呢?
首先,在第一个stage中不使用SDXL_Spatial Transformer_X模块,可以明显减少显存占用和计算量 。然后在第二和第三个stage这两个维度较小的feature map上使用数量较多的SDXL_Spatial Transformer_X模块,能在大幅提升模型整体性能(学习能力和表达能力)的同时,优化了计算成本 。整个新的SDXL Base U-Net设计思想也让SDXL的Base出图分辨率提升至1024×1024。在出图参数保持一致的情况下,Stable Diffusion XL生成图片的耗时只比Stable Diffusion多了20%-30%之间,这个拥有2.6B参数量的模型已经足够伟大 。
在SDXL U-Net的Encoder结构中,包含了两个CrossAttnDownBlock结构和一个SDXL_DownBlock结构;在Decoder结构中,包含了两个CrossAttnUpBlock结构和一个SDXL_UpBlock结构;与此同时,Encoder和Decoder中间存在Skip Connection,进行信息的传递与融合。
从上面讲到的十四个基本模块中可以看到,BasicTransformer Block模块是整个框架的基石,由SelfAttention,CrossAttention和FeedForward三个组件构成,并且使用了循环残差模式,让SDXL Base U-Net不仅可以设计的更深,同时也具备更强的文本特征和图像体征的学习能力 。
接下来,Rocky再给大家讲解CrossAttention模块的一些细节内容,让大家能更好地理解这个关键模块。
Stable Diffusion XL中的Text Condition信息由两个Text Encoder提供(OpenCLIP ViT-bigG和OpenAI CLIP ViT-L) ,通过Cross Attention组件嵌入,作为K Matrix和V Matrix。与此同时,图片的Latent Feature作为Q Matrix。
但是大家知道Text Condition是三维的,而Latent Feature是四维的,那它们是怎么进行Attention机制的呢?
其实在每次进行Attention机制前,我们需要将Latent Feature从[batch_size,channels,height,width]转换到[batch_size,height*width,channels] ,这样就变成了三维特征,就能够和Text Condition做CrossAttention操作。
在完成CrossAttention操作后,我们再将Latent Feature从[batch_size,height*width,channels]转换到[batch_size,channels,height,width] ,这样就又重新回到原来的维度。
还有一点是Text Condition如何跟latent Feature大小保持一致呢?因为latent embedding不同位置的H和W是不一样的,但是Text Condition是从文本中提取的,其H和W是固定的。这里在CorssAttention模块中有一个非常巧妙的点,那就是在不同特征做Attention操作前,使用Linear层将不同的特征的尺寸大小对齐 。
2.4 Text Encoder模型(包含详细图解)
Stable Diffusion XL模型采用的Text Encoder依然是基于CLIP架构的 。我们知道,CLIP模型主要包含Text Encoder和Image Encoder两个模块 ,Stable Diffusion 1.x系列使用的是OpenAI CLIP ViT-L/14(123.65M)中的Text Encoder模型,而Stable Diffusion 2.x系列则使用OpenCLIP ViT-H/14(354.03M)中的Text Encoder模型。
Stable Diffusion XL和Stable Diffusion 1.x-2.x系列一样,只使用Text Encoder模块从文本信息中提取Text Embeddings 。
不同的是,Stable Diffusion XL与之前的系列相比使用了两个CLIP Text Encoder,分别是OpenCLIP ViT-bigG(694M)和OpenAI CLIP ViT-L/14(123.65M),从而大大增强了Stable Diffusion XL对文本的提取和理解能力,同时提高了输入文本和生成图片的一致性。
其中OpenCLIP ViT-bigG是一个只由Transformer模块组成的模型,一共有32个CLIPEncoder模块,是一个强力的特征提取模型。其单个CLIPEncoder模块结构如下所示:
CLIPEncoderLayer(
( self_attention) : CLIPAttention(
( k_Matric) : Linear( in_features= 1280 , out_features= 1280 , bias= True )
( v_Matric) : Linear( in_features= 1280 , out_features= 1280 , bias= True )
( q_Matric) : Linear( in_features= 1280 , out_features= 1280 , bias= True )
( out_proj) : Linear( in_features= 1280 , out_features= 1280 , bias= True )
)
( layer_norm1) : LayerNorm( ( 1280 , ) , eps= 1e-05 , elementwise_affine= True )
( mlp ) : CLIPMLP(
( activation_fn) : GELUActivation( )
( fc1) : Linear( in_features= 1280 , out_features= 5120 , bias= True )
( fc2) : Linear( in_features= 5120 , out_features= 1280 , bias= True )
)
( layer_norm2) : LayerNorm( ( 1280 , ) , eps= 1e-05 , elementwise_affine= True )
)
下图是Rocky梳理的SDXL OpenCLIP ViT-bigG的完整结构图 ,大家可以感受一下其魅力,看着这个完整结构图学习Stable Diffusion XL OpenCLIP ViT-bigG部分,相信大家脑海中的思路也会更加清晰: OpenAI CLIP ViT-L/14同样是一个只由Transformer模块组成的模型,一共有12个CLIPEncoder模块,其单个CLIPEncoder模块结构如下所示:
CLIPEncoderLayer(
( self_attention) : CLIPAttention(
( k_Matric) : Linear( in_features= 768 , out_features= 768 , bias= True )
( v_Matric) : Linear( in_features= 768 , out_features= 768 , bias= True )
( q_Matric) : Linear( in_features= 768 , out_features= 768 , bias= True )
( out_proj) : Linear( in_features= 768 , out_features= 768 , bias= True )
)
( layer_norm1) : LayerNorm( ( 768 , ) , eps= 1e-05 , elementwise_affine= True )
( mlp) : CLIPMLP(
( activation_fn) : QuickGELUActivation( )
( fc1) : Linear( in_features= 768 , out_features= 3072 , bias= True )
( fc2) : Linear( in_features= 3072 , out_features= 768 , bias= True )
)
( layer_norm2) : LayerNorm( ( 768 , ) , eps= 1e-05 , elementwise_affine= True )
)
下图是Rocky梳理的SDXL OpenAI CLIP ViT-L/14的完整结构图 ,大家可以感受一下其魅力,看着这个完整结构图学习Stable Diffusion XL OpenAI CLIP ViT-L/14部分,相信大家脑海中的思路也会更加清晰: 由上面两个结构对比可知,OpenCLIP ViT-bigG的优势在于模型结构更深,特征维度更大,特征提取能力更强,但是其两者的基本CLIPEncoder模块是一样的。
下面Rocky将使用transofmers库演示调用SDXL OpenAI CLIP ViT-L/14 和OpenCLIP ViT-bigG,给大家一个更加直观的SDXL模型的文本编码全过程。
首先是SDXL OpenAI CLIP ViT-L/14的文本编码过程:
from transformers import CLIPTextModel, CLIPTokenizer
text_encoder = CLIPTextModel. from_pretrained( "/本地路径/stable-diffusion-xl-base-1.0" , subfolder= "text_encoder" ) . to( "cuda" )
text_tokenizer = CLIPTokenizer. from_pretrained( "/本地路径/stable-diffusion-xl-base-1.0" , subfolder= "tokenizer" )
prompt = "1girl,beautiful"
text_token_ids = text_tokenizer(
prompt,
padding= "max_length" ,
max_length= text_tokenizer. model_max_length,
truncation= True ,
return_tensors= "pt"
) . input_ids
print ( "text_token_ids' shape:" , text_token_ids. shape)
print ( "text_token_ids:" , text_token_ids)
text_embeddings = text_encoder( text_token_ids. to( "cuda" ) ) [ 0 ]
print ( "text_embeddings' shape:" , text_embeddings. shape)
print ( text_embeddings)
- - - - - - - - - - - - - - - - 运行结果 - - - - - - - - - - - - - - - -
text_token_ids' shape: torch. Size( [ 1 , 77 ] )
text_token_ids: tensor( [ [ 49406 , 272 , 1611 , 267 , 1215 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ,
49407 , 49407 , 49407 , 49407 , 49407 , 49407 , 49407 ] ] )
text_embeddings' shape: torch. Size( [ 1 , 77 , 768 ] )
tensor( [ [ [ - 0.3885 , 0.0230 , - 0.0521 , . . . , - 0.4901 , - 0.3065 , 0.0674 ] ,
[ - 0.8424 , - 1.1387 , 1.2767 , . . . , - 0.2598 , 1.6289 , - 0.7855 ] ,
[ 0.1751 , - 0.9847 , 0.1881 , . . . , 0.0657 , - 1.4940 , - 1.2612 ] ,
. . . ,
[ 0.2039 , - 0.7298 , - 0.3206 , . . . , 0.6751 , - 0.5814 , - 0.7320 ] ,
[ 0.1921 , - 0.7345 , - 0.3039 , . . . , 0.6806 , - 0.5852 , - 0.7228 ] ,
[ 0.2112 , - 0.6438 , - 0.3042 , . . . , 0.6628 , - 0.5576 , - 0.7583 ] ] ] ,
device= 'cuda:0' , grad_fn= NativeLayerNormBackward0> )
接着是SDXL OpenCLIP ViT-bigG的文本编码过程:
from transformers import CLIPTextModel, CLIPTokenizer
text_encoder = CLIPTextModel. from_pretrained( "/本地路径/stable-diffusion-xl-base-1.0" , subfolder= "text_encoder_2" ) . to( "cuda" )
text_tokenizer = CLIPTokenizer. from_pretrained( "/本地路径/stable-diffusion-xl-base-1.0" , subfolder= "tokenizer_2" )
prompt = "1girl,beautiful"
text_token_ids = text_tokenizer(
prompt,
padding= "max_length" ,
max_length= text_tokenizer. model_max_length,
truncation= True ,
return_tensors= "pt"
) . input_ids
print ( "text_token_ids' shape:" , text_token_ids. shape)
print ( "text_token_ids:" , text_token_ids)
text_embeddings = text_encoder( text_token_ids. to( "cuda" ) ) [ 0 ]
print ( "text_embeddings' shape:" , text_embeddings. shape)
print ( text_embeddings)
- - - - - - - - - - - - - - - - 运行结果 - - - - - - - - - - - - - - - -
text_token_ids' shape: torch. Size( [ 1 , 77 ] )
text_token_ids: tensor( [ [ 49406 , 272 , 1611 , 267 , 1215 , 49407 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , 0 , 0 , 0 , 0 , 0 , 0 ] ] )
text_embeddings' shape: torch. Size( [ 1 , 77 , 1280 ] )
tensor( [ [ [ - 0.1025 , - 0.3104 , 0.1660 , . . . , - 0.1596 , - 0.0680 , - 0.0180 ] ,
[ 0.7724 , 0.3004 , 0.5225 , . . . , 0.4482 , 0.8743 , - 1.0429 ] ,
[ - 0.3963 , 0.0041 , - 0.3626 , . . . , 0.1841 , 0.2224 , - 1.9317 ] ,
. . . ,
[ - 0.8887 , - 0.2579 , 1.3508 , . . . , - 0.4421 , 0.2193 , 1.2736 ] ,
[ - 0.9659 , - 0.0447 , 1.4424 , . . . , - 0.4350 , - 0.1186 , 1.2042 ] ,
[ - 0.5213 , - 0.0255 , 1.8161 , . . . , - 0.7231 , - 0.3752 , 1.0876 ] ] ] ,
device= 'cuda:0' , grad_fn= NativeLayerNormBackward0> )
与传统深度学习中的模型融合类似 ,Stable Diffusion XL分别提取两个Text Encoder的倒数第二层特征 ,并进行concat操作作为文本条件(Text Conditioning)。其中OpenCLIP ViT-bigG的特征维度为77×1280,而OpenAI CLIP ViT-L/14的特征维度是77×768,所以输入总的特征维度是77×2048(77是最大的token数,2048是SDXL的context dim),再通过Cross Attention模块将文本信息传入Stable Diffusion XL的训练过程与推理过程中。
从上图可以看到,OpenCLIP ViT-bigG和OpenAI CLIP ViT-L/14在ImageNet上zero-shot性能分别为80.1%和75.4%,Rocky有点疑惑的是,为什么不用CoCa或者将OpenAI CLIP ViT-L/14替换成penAI CLIP ViT-H呢。
和Stable Diffusion 1.x-2.x一致的是,Stable Diffusion XL输入的最大Token数依旧是77,当输入文本的Token数量超过77后,将通过Clip操作拉回77×2048;如果Token数不足77则会通过padding操作得到77×2048。
与此同时,Stable Diffusion XL还提取了OpenCLIP ViT-bigG的pooled text embedding,将其嵌入到Time Embeddings中(add操作),作为辅助约束条件(强化文本的整体语义信息),但是这种辅助条件的强度是较为微弱的。
和之前的系列一样,SDXL Text Encoder在官方训练时是冻结的 ,我们在对SDXL模型进行微调训练时,可以同步开启Text Encoder的微调训练,能够使得Text Encoder对生成图片的控制力增强,使其生成内容更加贴近训练集的分布。
2.5 Refiner模型(包含详细图解)
Rocky看到Stable Diffusion XL的Refiner部分时,脑海里马上联想到了DeepFloyd和StabilityAI联合开发的DeepFloyd IF模型。
DeepFloyd IF是一种基于像素的文本到图像三重级联扩散模型 ,大大提升了扩散模型的图像生成能力。
这次,Stable Diffusion XL终于也开始使用级联策略,在U-Net(Base)之后,级联Refiner模型,进一步提升生成图像的细节特征与整体质量 。
通过级联模型提升生成图片的质量,这可以说这是AIGC时代里的模型融合(ensemble)。和传统深度学习时代的多模型融合策略一样,不管是在学术界、工业界还是竞赛界,都是“行业核武”般的存在。
由于已经有U-Net(Base)模型生成了图像的Latent特征,所以Refiner模型的主要工作是在Latent特征进行小噪声去除和细节质量提升 。
Refiner模型和Base模型一样是基于Latent的扩散模型 ,也采用了Encoder-Decoder结构,和U-Net兼容同一个VAE模型。不过在Text Encoder部分,Refiner模型只使用了OpenCLIP ViT-bigG的Text Encoder,同样提取了倒数第二层特征以及进行了pooled text embedding的嵌入。
下图是Rocky梳理的Stable Diffusion XL Refiner模型的完整结构图 ,大家可以先感受一下其魅力,在学习Refiner模型时可以与Base模型中的U-Net进行对比,会有更多直观的认识:
接下来Rocky给大家分析一下SDXL Refiner模型和SDXL Base模型在结构上的异同:
SDXL Base的Encoder和Decoder结构都采用4个stage,而SDXL Base设计的是3个stage。
SDXL Refiner和SDXL Base一样,在第一个stage中没有使用Attention模块。
在经过第一个卷积后,SDXL Refiner设置初始网络特征维度为384,而SDXL Base 采用的是320。
SDXL Refiner的Attention模块中SDXL_Spatial Transformer结构数量均设置为4。
SDXL Refiner的参数量为2.3B,比起SDXL Base的2.6B参数量略小一些。
SDXL Refiner模型的训练逻辑与SDXL Base一样,不过Refiner模型只在前200个Timesteps上训练(设置的noise level较低)。
在Stable Diffusion XL推理阶段,输入一个prompt,通过VAE和U-Net(Base)模型生成Latent特征,接着给这个Latent特征进行扩散过程加上一定的噪音。在此基础上,再使用Refiner模型进行去噪,以提升图像的整体质量与局部细节。
从下图中可以看到,在使用Refiner模型后,生成图片的背景和人脸部分效果有了一定的提升:
可以看到,Refiner模型主要做了图像生成图像(img2img)的工作 ,其具备很强的迁移兼容能力 ,可以作为Stable Diffusion、Midjourney、DALL-E、GAN、VAE等生成式模型的级联组件,成为AI绘画领域的一个强力后处理工具 ,这不管是对学术界、工业界还是竞赛界,都是一个巨大的利好。
由上表可以看出,Stable Diffusion XL Base模型的效果已经大幅超过SD 1.5和SD 2.1,当增加Refiner模型之后,完整的Stable Diffusion XL模型达到了更加优秀的图像生成效果。
2.6 SDXL官方训练技巧&细节
Stable Diffusion XL在训练阶段提出了很多优化方法,包括图像尺寸条件化策略,图像裁剪参数条件化策略以及多尺度训练策略。这些优化方法对整个AIGC领域都有很好的参考与借鉴意义,其通用性和迁移性能普惠其他的生成式模型的训练与优化 。
2.6.1 图像尺寸条件化
之前在Stable Diffusion的训练过程中,主要分成两个阶段,一个是在256×256的图像尺寸上进行预训练,然后在512×512的图像尺寸上继续训练。
而这两个阶段的训练过程都要对最小图像尺寸进行约束。第一阶段中,会将尺寸小于256×256的图像舍弃;同样的,在第二阶段,会将尺寸小于512×512的图像筛除。这样的约束会导致训练数据中的大量数据被丢弃,从而很可能导致模型性能和泛化性的降低 。
下图展示了如果将尺寸小于256×256的图像筛除,整个数据集将减少39%的数据 。如果加上尺寸小于512×512的图像,未利用数据占整个数据集的百分比将更大 。
针对上述数据集利用率的问题,常规思路可以借助超分模型将尺寸过小的图像放大。但是面对对于图像尺寸过小的场景,目前的超分模型可能会在对图像超分的同时会引入一些噪声伪影,影响模型的训练,导致生成一些模糊的图像 。
Stable Diffusion XL为了在解决数据集利用率问题的同时不引入噪声伪影,将U-Net(Base)模型与原始图像分辨率相关联,核心思想 是将输入图像的原始高度和宽度作为额外的条件嵌入U-Net模型中,表示为
C
s
i
z
e
=
(
h
e
i
g
h
t
,
w
i
d
t
h
)
C_{size} = (height, width)
C s i ze = ( h e i g h t , w i d t h ) 。height和width都使用傅里叶特征编码进行独立嵌入,然后将特征concat后加在Time Embedding上,将图像尺寸作为条件引入训练过程 。这样一来,模型在训练过程中能够学习到图像的原始分辨率信息,从而在推理生成阶段更好地适应不同尺寸的图像生成,而不会产生噪声伪影的问题。
如下图所示,在使用了图像尺寸条件化策略后,Base模型已经对不同图像分辨率有了“自己的判断 ”。当输入低分辨率条件时,生成的图像较模糊;在不断增大分辨率条件时,生成的图像质量不断提升。
2.6.2 图像裁剪参数条件化
之前的Stable Diffusion系列模型,由于需要输入固定的图像尺寸用作训练,很多数据在预处理阶段会被裁剪。生成式模型中典型的预处理方式是先调整图像尺寸,使得最短边与目标尺寸匹配,然后再沿较长边对图像进行随机裁剪或者中心裁剪 。虽然裁剪是一种数据增强方法,但是训练中对图像裁剪导致的图像特征丢失,可能会导致AI绘画模型在图像生成过程中出现不符合训练数据分布的特征 。
如下图所示,对一个骑士的图片做了裁剪操作后,丢失了头部和脚部特征,再将裁剪后的数据放入模型中训练,就会影响模型对骑士这个概念的学习和认识 。
下图中展示了SD 1.4和SD 1.5的经典失败案例,生成图像中的猫出现了头部缺失的问题,龙也出现了体征不完整的情况:
其实之前NovelAI就发现了这个问题,并提出了基于分桶(Ratio Bucketing)的多尺度训练策略,其主要思想是先将训练数据集按照不同的长宽比(aspect ratio)进行分组(groups)或者分桶(buckets)。在训练过程中,每次在buckets中随机选择一个bucket并从中采样Batch个数据进行训练 。将数据集进行分桶可以大量减少裁剪图像的操作,并且能让模型学习多尺度的生成能力;但相对应的,预处理成本大大增加,特别是数据量级较大的情况下。
并且尽管数据分桶成功解决了数据裁剪导致的负面影响,但如果能确保数据裁剪不把负面影响引入生成过程中,裁剪这种数据增强方法依旧能给模型增强泛化性能。所以Stable Diffusion XL使用了一种简单而有效的条件化方法,即图像裁剪参数条件化策略。其主要思想是在加载数据时,将左上角的裁剪坐标通过傅里叶编码后加在Time Embedding上,并嵌入U-Net(Base)模型中,并与原始图像尺寸一起作为额外的条件嵌入U-Net模型,从而在训练过程中让模型学习到对“图像裁剪”的认识 。
从下图中可以看到,将不同的
c
c
r
o
p
=
(
0
,
0
)
c_{crop} = (0,0)
c cro p = ( 0 , 0 ) 坐标条件的生成图像进行了对比,当我们设置 时可以生成主要物体居中并且无特征缺失的图像,而采用其它的坐标条件则会出现有裁剪效应的图像:
图像尺寸条件化策略和图像裁剪参数条件化策略都能在SDXL训练过程中使用(在线方式应用),同时也可以很好的迁移到其他AIGC生成式模型的训练中 。下图详细给出了两种策略的通用使用流程:
可以看到,SDXL在训练过程中的数据处理流程和之前的系列是一样的,只是需要再将图像原始长宽(width和height)以及图像进行crop操作时的左上角的裁剪坐标top和left作为条件输入 。
2.6.3 多尺度训练
Stable Diffusion XL采用了多尺度训练策略,这个是在传统深度学习时代的王牌模型YOLO系列中常用的增强模型鲁棒性与泛化性的策略,终于在AIGC领域应用并常规化了,并且Stable Diffusion XL在多尺度训练的基础上,增加了分桶策略。
SDXL的论文中说训练时采用的是内部数据集作为训练集,Rocky推测大概率是基于LAION数据集为基础构建的。Stable Diffusion XL首先采用图像尺寸条件化和图像裁剪参数条件化这两种策略在256×256和512×512的图像尺寸上分别预训练600000步和200000步(batch size = 2048),总的数据量约等于 (600000 + 200000) x 2048 = 16.384亿 。
接着Stable Diffusion XL在1024×1024的图像尺寸上采用多尺度方案来进行微调,并将数据分成不同纵横比的桶(bucket),并且尽可能保持每个桶的像素数接近1024×1024 ,同时相邻的bucket之间height或者width一般相差64像素左右,Stable Diffusion XL的具体分桶情况如下图所示: 其中Aspect Ratio = Height / Width ,表示高宽比。
在训练过程中,一个Batch从一个桶里的图像采样,并且我们在每个训练步骤(step)中可以在不同的桶之间交替切换。除此之外,Aspect Ratio也会作为条件嵌入到U-Net(Base)模型中,嵌入方式和上面提到的其他条件嵌入方式一致,让模型能够更好地学习到“多尺度特征” 。
与此同时,SDXL在多尺度微调阶段依然使用图像裁剪参数条件化策略,进一步增强SDXL对图像裁剪的敏感性。
在完成了多尺度微调后,SDXL就可以进行不同Aspect Ratio的图像生成了,不过官方推荐生成尺寸默认为1024×1024 。
2.6.4 使用Offset Noise
在SDXL进行微调时,使用了Offset Noise操作,能够让SDXL生成的图像有更高的色彩自由度(纯黑或者纯白背景的图像) 。SD 1.x和SD 2.x一般只能生成中等亮度的图片,即生成平均值相对接近 0.5 的图像(全黑图像为 0,全白图像为 1),之所以会出现这个问题,是因为SD系列模型训练和推理过程的不一致造成的。
SD模型在训练中进行noise scheduler流程并不能将图像完全变成随机高斯噪声,但是推理过程中,SD模型是从一个随机高斯噪声开始生成的,因此就会存在训练与推理的噪声处理过程不一致 。
Offset Noise操作是解决这个问题的一种直观并且有效的方法 ,我们只需要在SD模型的微调训练时,把额外从高斯分布中采样的偏置噪声引入图片添加噪声的过程中,这样就对图像的色彩均值造成了破坏,从而提高了SDXL生成图像的“泛化性能” 。 具体的Offset Noise代码如下所示:
def apply_noise_offset ( latents, noise, noise_offset, adaptive_noise_scale) :
if noise_offset is None :
return noise
if adaptive_noise_scale is not None :
latent_mean = torch. abs ( latents. mean( dim= ( 2 , 3 ) , keepdim= True ) )
noise_offset = noise_offset + adaptive_noise_scale * latent_mean
noise_offset = torch. clamp( noise_offset, 0.0 , None )
noise = noise + noise_offset * torch. randn( ( latents. shape[ 0 ] , latents. shape[ 1 ] , 1 , 1 ) , device= latents. device)
return noise
上述代码中的noise_offset默认是采用0.1,SDXL在官方的训练中采用的是0.05 。在后面的SDXL训练教程章节中,我们采用的是0.0357,大家可按照实际训练效果调整noise_offset值。
2.6.5 SDXL的条件注入与训练细节
上面我们已经详细讲解了SDXL的四个额外的条件信息注入(pooled text embedding,图像尺寸条件,图像裁剪参数条件和图像多尺寸条件),其中三个图像条件可以像Timestep一样采用傅立叶编码得到Embedding特征,然后再和pooled text embedding特征concat,得到维度为2816的embeddings特征。
接着再将这个embeddings特征通过两个Linear层映射到和Time Embedding一样的维度空间,然后加(add)到Time Embedding上即可作为SDXL U-Net的条件输入,上述流程的具体代码实现如下所示:
import math
from einops import rearrange
import torch
batch_size = 64
pooled_dim = 1280
adm_in_channels = 2816
time_embed_dim = 1280
def fourier_embedding ( timesteps, outdim= 256 , max_period= 10000 ) :
"""
Classical sinusoidal timestep embedding
as commonly used in diffusion models
: param inputs : batch of integer scalars shape [b ,]
: param outdim : embedding dimension
: param max_period : max freq added
: return : batch of embeddings of shape [b, outdim ]
"""
half = outdim // 2
freqs = torch. exp( - math. log( max_period) * torch. arange( start= 0 , end= half, dtype= torch. float32) / half) . to( device= timesteps. device)
args = timesteps[ : , None ] . float ( ) * freqs[ None ]
embedding = torch. cat( [ torch. cos( args) , torch. sin( args) ] , dim= - 1 )
return embedding
def cat_along_channel_dim ( x: torch. Tensor, ) - > torch. Tensor:
if x. ndim == 1 :
x = x[ . . . , None ]
assert x. ndim == 2
b, d_in = x. shape
x = rearrange( x, "b din -> (b din)" )
emb = fourier_embedding( x)
d_f = emb. shape[ - 1 ]
emb = rearrange( emb, "(b din) df -> b (din df)" , b= b, din= d_in, df= d_f)
return emb
def concat_embeddings (
c_size: torch. Tensor,
c_crop: torch. Tensor,
c_tgt_size: torch. Tensor ,
c_pooled_txt: torch. Tensor, ) - > torch. Tensor:
c_size_emb = cat_along_channel_dim( c_size)
c_crop_emb = cat_along_channel_dim( c_crop)
c_tgt_size_emb = cat_along_channel_dim( c_tgt_size)
return torch. cat( [ c_pooled_txt, c_size_emb, c_crop_emb, c_tgt_size_emb] , dim= 1 )
adm_proj = torch. nn. Sequential(
torch. nn. Linear( adm_in_channels, time_embed_dim) ,
torch. nn. SiLU( ) ,
torch. nn. Linear( time_embed_dim, time_embed_dim)
)
c_size = torch. zeros( ( batch_size, 2 ) ) . long ( )
c_crop = torch. zeros( ( batch_size, 2 ) ) . long ( )
c_tgt_size = torch. zeros( ( batch_size, 2 ) ) . long ( )
c_pooled = torch. zeros( ( batch_size, pooled_dim) ) . long ( )
c_concat = concat_embeddings( c_size, c_crop, c_tgt_size, c_pooled)
adm_emb = adm_proj( c_concat)
print ( "c_size:" , c_size. shape)
print ( "c_crop:" , c_crop. shape)
print ( "c_tgt_size:" , c_tgt_size. shape)
print ( "c_pooled:" , c_pooled. shape)
print ( "c_concat:" , c_concat. shape)
print ( "adm_emb:" , adm_emb. shape)
- - - - - - - - - - - - - - - - 运行结果 - - - - - - - - - - - - - - - -
c_size: torch. Size( [ 64 , 2 ] )
c_crop: torch. Size( [ 64 , 2 ] )
c_tgt_size: torch. Size( [ 64 , 2 ] )
c_pooled: torch. Size( [ 64 , 1280 ] )
c_concat: torch. Size( [ 64 , 2816 ] )
adm_emb: torch. Size( [ 64 , 1280 ] )
可以看到,上面的代码流程已经清晰的展示了SDXL进行额外条件注入的全部流程。
讲到这里,SDXL在架构上的优化和训练技巧上的优化都已经介绍好了,最后我们在介绍一下SDXL在训练中的配置。和SD 1.x系列一样,SDXL在训练时采用了1000步的DDPM和相同的noise scheduler,同时依旧采用基于预测noise的损失函数,和SD 1.x系列一致:
L
S
D
X
L
=
E
x
0
,
ϵ
∼
N
(
0
,
I
)
,
t
[
∥
ϵ
−
ϵ
θ
(
α
ˉ
t
x
0
+
1
−
α
ˉ
t
ϵ
,
t
,
c
)
∥
2
]
L_{SDXL}=mathbb{E}_{mathbf{x}_{0},mathbf{epsilon}sim mathcal{N}(mathbf{0}, mathbf{I}), t}Big[ | mathbf{epsilon}- mathbf{epsilon}_thetabig(sqrt{bar{alpha}_t}mathbf{x}_0 + sqrt{1 – bar{alpha}_t}mathbf{epsilon}, t, mathbf{c}big)|^2Big]
L S D X L = E x 0 , ϵ ∼ N ( 0 , I ) , t [ ∥ ϵ − ϵ θ ( α ˉ t
x 0 + 1 − α ˉ t
ϵ , t , c ) ∥ 2 ] 这里的
c
mathbf{c}
c 为Text Embeddings。
3. 从0到1搭建使用Stable Diffusion XL进行AI绘画(全网最详细讲解)
目前能够加载Stable Diffusion XL模型并进行图像生成的主流AI绘画框架有四种:
diffusers框架
Stable Diffusion WebUI框架
ComfyUI框架
SD.Next框架
为了方便大家使用主流AI绘画框架,Rocky这里也总结汇总了相关的资源,方便大家直接部署使用:
Stable Diffusion WebUI资源包可以关注公众号WeThinkIn ,后台回复“WebUI资源 ”获取。
ComfyUI的500+高质量工作流资源包可以关注公众号WeThinkIn ,并回复“ComfyUI ”获取。
SD.Next资源包可以关注公众号WeThinkIn ,后台回复“SD.Next资源 ”获取。
接下来,为了让大家能够从0到1搭建使用Stable Diffusion XL这个当前性能优异的AI绘画大模型,Rocky将详细的讲解如何用这四个框架构建Stable Diffusion XL推理流程 。那么,跟随着Rocky的脚步,让我们开始吧。
3.1 零基础使用diffusers搭建Stable Diffusion XL推理流程
每次SDXL系列技术在更新迭代时,diffusers库一般都是最先原生支持其功能的,所以在diffusers中能够非常高效的构建Stable Diffusion XL推理流程 。但是由于diffusers目前没有现成的可视化界面,Rocky将在Jupyter Notebook中搭建完整的Stable Diffusion XL推理工作流,让大家能够快速的掌握。
首先,我们需要安装diffusers库,并确保diffusers的版本 >= 0.18.0 ,我们只需要在命令行中输入以下命令进行安装即可:
pip install diffusers - - upgrade - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
显示如下log表示安装成功:
Successfully installed diffusers- 0.18 .2 huggingface- hub- 0.16 .4
接着,我们继续安装其他的依赖库:
pip install transformers== 4.27 .0 accelerate== 0.12 .0 safetensors== 0.2 .7 invisible_watermark - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
显示如下log表示安装成功:
Successfully installed transformers- 4.27 .0 accelerate== 0.12 .0 safetensors== 0.2 .7 invisible_watermark- 0.2 .0
(注意:想要在diffusers中以fp16的精度加载Stable Diffusion XL模型,必须满足transformers库的版本>=4.27.0)
完成了上述依赖库的安装,我们就可以搭建Stable Diffusion XL模型的完整工作流了。
我们先单独使用Stable Diffusion XL中的Base模型来生成图像:
from diffusers import DiffusionPipeline
import torch
pipe = DiffusionPipeline. from_pretrained( "/本地路径/stable-diffusion-xl-base-1.0" , torch_dtype= torch. float16, variant= "fp16" )
pipe. to( "cuda" )
prompt = "Watercolor painting of a desert landscape, with sand dunes, mountains, and a blazing sun, soft and delicate brushstrokes, warm and vibrant colors"
negative_prompt = "(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)"
seed = torch. Generator( "cuda" ) . manual_seed( 42 )
image = pipe( prompt, negative_prompt= negative_prompt, generator= seed) . images[ 0 ]
image. save( "SDXL-Base.png" )
完成上面的整个代码流程,我们可以生成一张水彩风格 的沙漠风景画,如果大家按照Rocky的参数进行操作,应该能确保生成下面的图片 :
接着,我们将SDXL Base模型和SDXL Refiner模型级联来生成图像:
from diffusers import DiffusionPipeline
import torch
pipe = DiffusionPipeline. from_pretrained( "/本地路径/stable-diffusion-xl-base-1.0" , torch_dtype= torch. float16, variant= "fp16" )
pipe. to( "cuda" )
prompt = "Watercolor painting of a desert landscape, with sand dunes, mountains, and a blazing sun, soft and delicate brushstrokes, warm and vibrant colors"
negative_prompt = "(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)"
seed = torch. Generator( "cuda" ) . manual_seed( 42 )
image = pipe( prompt= prompt, negative_prompt= negative_prompt, generator= seed, output_type= "latent" ) . images
pipe = DiffusionPipeline. from_pretrained( "/本地路径/stable-diffusion-xl-refiner-1.0" , torch_dtype= torch. float16, variant= "fp16" )
pipe. to( "cuda" )
images = pipe( prompt= prompt, negative_prompt= negative_prompt, generator= seed, image= image) . images
images[ 0 ] . save( "SDXL-Base-Refiner.png" )
完成了上述的代码流程,我们再来看看这次Base模型和Refiner模型级联生成的图片:
为了更加直观的对比,我们将刚才生成的两张图片放在一起对比: 我们可以清楚的看到,使用了Refiner模型之后,生成图片的整体质量和细节有比较大的增强改善,构图色彩更加柔和 。
当然的,我们也可以单独使用SDXL Refiner模型对图片的质量进行优化提升(img2img任务):
import torch
from diffusers import StableDiffusionXLImg2ImgPipeline
from diffusers. utils import load_image
pipe = StableDiffusionXLImg2ImgPipeline. from_pretrained( "/本地路径/stable-diffusion-xl-base-1.0" , torch_dtype= torch. float16, variant= "fp16" )
pipe = pipe. to( "cuda" )
image_path = "/本地路径/test.png"
init_image = load_image( image_path) . convert( "RGB" )
prompt = "Watercolor painting of a desert landscape, with sand dunes, mountains, and a blazing sun, soft and delicate brushstrokes, warm and vibrant colors"
negative_prompt = "(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)"
seed = torch. Generator( "cuda" ) . manual_seed( 42 )
image = pipe( prompt, negative_prompt= negative_prompt, generator= seed, image= init_image) . images[ 0 ]
image. save( "SDXL-refiner.png" )
Rocky这里是使用了未来机甲风格的图片进行测试对比,可以从下图看到,Refiner模型优化图像质量的效果还是非常明显的,图像毛刺明显消除,整体画面更加自然柔和,细节特征也有较好的补充和重建 。 虽然diffusers库是原生支持SDXL模型的,但是在开源社区中流行使用safetensors格式的SDXL模型,所以我们想用diffusers库运行开源社区的很多SDXL模型时,需要首先将其转成diffusers格式 。Rocky在这里也总结了一套SDXL模型的格式转换教程,方便大家快速转换格式,使用diffusers库运行模型。主要流程如下所示:
pip install diffusers== 0.26 .3 transformers== 4.38 .1 accelerate== 0.27 .2
git clone https: // github . com/ huggingface/ diffusers. git
cd diffusers/ scripts
python convert_original_stable_diffusion_to_diffusers. py - - checkpoint_path / 本地路径/ safetensors格式模型 - - dump_path / 本地路径/ 转换后diffusers格式模型的保存路径 - - from_safetensors
成功运行上述代码后,我们可以看到一个包含scheduler、vae、unet、text_encoder、tokenizer、text_encoder_2、tokenizer_2文件夹以及model_index.json文件的diffusers格式的SDXL模型。
3.2 零基础使用Stable Diffusion WebUI搭建Stable Diffusion XL推理流程
目前Stable Diffusion WebUI已经全面支持Stable Diffusion XL中的Base模型和Refiner模型。
Stable Diffusion WebUI 是AI绘画领域最为流行的框架 ,其生态极其繁荣,非常多的上下游插件能够与Stable Diffusion WebUI一起完成诸如AI视频生成,AI证件照生成等工作流,可玩性非常强。
接下来,咱们就使用这个流行框架搭建Stable Diffusion XL推理流程吧。
首先,我们需要下载安装Stable Diffusion WebUI框架,我们只需要在命令行输入如下代码即可:
git clone https: // github. com/ AUTOMATIC1111/ stable- diffusion- webui. git
安装好后,我们可以看到本地的stable-diffusion-webui文件夹。
下面我们需要安装其依赖库,我们进入Stable Diffusion WebUI文件夹,并进行以下操作:
cd stable- diffusion- webui
pip install - r requirements. txt - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
和SD.Next的配置流程类似,我们还需要配置Stable Diffusion WebUI的repositories插件,我们需要运行下面的代码:
sh webui. sh
如果发现repositories插件下载速度较慢,出现很多报错,don’t worry,大家可以直接使用Rocky已经配置好的资源包,可以快速启动与Stable Diffusion XL兼容的Stable Diffusion WebUI框架。Stable Diffusion WebUI资源包可以关注公众号WeThinkIn ,后台回复“WebUI资源 ”获取。
在完成了依赖库和repositories插件的安装后,我们就可以配置模型了,我们将Stable Diffusion XL模型放到/stable-diffusion-webui/models/Stable-diffusion/路径下 。这样一来,等我们开启可视化界面后,就可以选择Stable Diffusion XL模型用于推理生成图片了。
完成上述的步骤后,我们可以启动Stable Diffusion WebUI了!我们到/stable-diffusion-webui/路径下,运行launch.py 即可:
python launch. py - - listen - - port 8888
运行完成后,可以看到命令行中出现的log:
To see the GUI go to: http: // 0.0 .0 .0 : 8888
我们将http://0.0.0.0:8888输入到我们本地的网页中,即可打开如下图所示的Stable Diffusion WebUI可视化界面,愉快的使用Stable Diffusion XL模型进行AI绘画了。 进入Stable Diffusion WebUI可视化界面后,我们可以在红色框中选择SDXL模型,然后在黄色框中输入我们的Prompt和负向提示词,同时在绿色框中设置我们想要生成的图像分辨率(推荐设置成1024×1024 ),然后我们就可以点击Generate按钮,进行AI绘画了。
等待片刻后,图像就生成好了,并展示在界面的右下角,同时也会保存到/stable-diffusion-webui/outputs/txt2img-images/路径下 ,大家可以到对应路径下查看。
3.3 零基础使用ComfyUI搭建Stable Diffusion XL推理流程
ComfyUI 是一个基于节点式 的Stable Diffusion AI绘画工具。和Stable Diffusion WebUI相比,ComfyUI通过将Stable Diffusion模型生成推理的pipeline拆分成独立的节点,实现了更加精准的工作流定制和清晰的可复现性 。
同时其完善的模型加载和图片生成机制,让其能够在2080Ti显卡上构建Stable Diffusion XL的工作流,并能生成1024×1024分辨率的图片 ,如此算力友好,可谓是初学者的福音。
目前ComfyUI已经能够兼容Stable Diffusion XL的Base模型和Refiner模型,下面两张图分别是Rocky使用ComfyUI来加载Stable Diffusion XL Base模型和Stable Diffusion XL Base + Refiner模型并生成图片的完整Pipeline:大家如果看了感觉复杂,不用担心,Rocky已经为大家保存了这两个工作流 ,大家只需关注Rocky的公众号WeThinkIn ,并回复“ComfyUI ”,就能获取这两个工作流以及文生图,图生图,图像Inpainting,ControlNet以及图像超分在内的所有Stable Diffusion经典工作流json文件,大家只需在ComfyUI界面右侧点击Load按钮 选择对应的json文件,即可加载对应的工作流,开始愉快的AI绘画之旅。
话说回来,下面Rocky将带着大家一步一步使用ComfyUI搭建Stable Diffusion XL推理流程,从而实现上面两张图的生成过程。
首先,我们需要安装ComfyUI框架,这一步非常简单,在命令行 输入如下代码即可:
git clone https: // github. com/ comfyanonymous/ ComfyUI. git
安装好后,我们可以看到本地的ComfyUI文件夹。
ComfyUI框架安装到本地后,我们需要安装其依赖库,我们只需以下操作:
cd ComfyUI
pip install - r requirements. txt - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
完成这些配置工作后,我们就可以配置模型了,我们将Stable Diffusion XL模型放到ComfyUI/models/checkpoints/路径下 。这样一来,等我们开启可视化界面后,就可以选择Stable Diffusion XL模型进行AI绘画了。
接下来,我们就可以启动ComfyUI了!我们到ComfyUI/路径下,运行main.py 即可:
python main. py - - listen - - port 8888
运行完成后,可以看到命令行中出现的log:
To see the GUI go to: http: // 0.0 .0 .0 : 8888
我们将http://0.0.0.0:8888输入到我们本地的网页中,即可打开如上图所示的ComfyUI可视化界面,愉快的使用Stable Diffusion XL模型生成我们想要的图片了。
接下来就是ComfyUI的节点式模块讲解了,首先是只加载Base模型的情况: Rocky已经进行了比较详细的注释,首先大家可以在红框中选择我们的模型(Stable Diffusion XL Base),接着填入Prompt和负向Prompt,并且配置生成推理过程的参数(迭代次数,CFG,Seed等),然后在绿色框中设置好生成图片的分辨率,然后在紫色框中点击Queue Prompt按钮 ,整个推理过程就开始了。等整个推理过程完成之后,生成的图片会在图中黄色箭头所指的地方进行展示,并且会同步将生成图片保存到本地的ComfyUI/output/路径下 。
完成了Stable Diffusion Base模型的推理流程,我们再来看看Base+Refiner模型的推理流程如何搭建: 和Base模型的构建十分相似,首先大家可以在红框中选择我们的Refiner模型(Stable Diffusion XL Refiner),Refiner模型使用的Prompt和负向Prompt与Base模型一致,并且配置生成推理过程的参数(迭代次数,CFG,Seed等),绿色箭头表示将Base模型输出的Latent特征作为Refiner模型的输入 ,然后在蓝色框中点击Queue Prompt按钮 ,整个Refiner精修过程就开始了。等整个推理过程完成之后,生成的图片会在图中紫色箭头所指的地方进行展示,并且会同步将生成图片保存到本地的ComfyUI/output/路径下 。
到此为止,Rocky已经详细讲解了如何使用ComfyUI来搭建Stable Diffusion XL模型进行AI绘画,大家可以按照Rocky的步骤进行尝试。
3.4 零基础使用SD.Next搭建Stable Diffusion XL推理流程
SD.Next 原本是Stable Diffusion WebUI的一个分支,再经过不断的迭代优化后,最终成为了一个独立版本。
SD.Next与Stable Diffusion WebUI相比,包含了更多的高级功能,也兼容Stable Diffusion, Stable Diffusion XL, Kandinsky, DeepFloyd IF等模型结构 ,是一个功能十分强大的AI绘画框架。
那么我们马上开始SD.Next的搭建与使用吧。
首先,我们需要安装SD.Next框架,这一步非常简单,在命令行 输入如下代码即可:
git clone https: // github. com/ vladmandic/ automatic
安装好后,我们可以看到本地的automatic文件夹。
SD.Next框架安装到本地后,我们需要安装其依赖库,我们只需以下操作:
cd automatic
pip install - r requirements. txt - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
除了安装依赖库之外,还需要配置SD.Next所需的repositories插件,我们需要运行以下代码:
cd automatic
python installer. py
如果发现extensions插件下载速度较慢,出现很多报错,大家可以直接使用Rocky已经配置好的资源包,可以快速启动SD.Next框架。SD.Next资源包可以关注公众号WeThinkIn ,后台回复“SD.Next资源 ”获取。
在完成了依赖库和repositories插件的安装后,我们就可以配置模型了,我们将Stable Diffusion XL模型放到/automatic/models/Stable-diffusion/路径下 。这样一来,等我们开启可视化界面后,就可以选择Stable Diffusion XL模型用于推理生成图片了。
完成上述的步骤后,我们可以启动SD.Next了!我们到/automatic/路径下,运行launch.py 即可:
python launch. py - - listen - - port 8888
运行完成后,可以看到命令行中出现的log:
To see the GUI go to: http: // 0.0 .0 .0 : 8888
我们将http://0.0.0.0:8888输入到我们本地的网页中,即可打开如下图所示的SD.Next可视化界面,愉快的使用Stable Diffusion XL模型进行AI绘画了。 进入SD.Next可视化界面后,我们可以在红色框中选择模型,然后需要修改Settings中的配置,来让SD.Next能够加载Stable Diffusion XL模型。
我们点击上图蓝色框中的Settings,进入Settings配置界面: 从上面图示中可以看到,我们需要做的修改是将Settings -> Stable Diffusion -> Stable Diffusion backend设置为diffusers,并在Stable Diffusion refiner栏中选择Refiner模型 。
然后我们需要将Settings -> Diffusers Settings-> Select diffuser pipeline when loading from safetensors栏设置为Stable Diffusion XL 。
完成了上述的配置修改后,我们就可以使用SD.Next加载Stable Diffusion XL进行AI绘画了!
3.5 SDXL生成图像示例
示例一:未来主义的城市风格
Prompt:Stunning sunset over a futuristic city, with towering skyscrapers and flying vehicles, golden hour lighting and dramatic clouds, high detail, moody atmosphere
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion XL Base+Refiner生成结果: 示例二:天堂海滩风格
Prompt:Serene beach scene with crystal clear water and white sand, tropical palm trees swaying in the breeze, perfect paradise, seascape
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion XL Base+Refiner生成结果:
示例三:未来机甲风格
Prompt:Giant robots fighting in a futuristic city, with buildings falling and explosions all around, intense, fast-paced, dramatic, stylized, futuristic
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion XL Base+Refiner生成结果: 示例四:马斯克风格
Prompt:Elon Musk standing in a workroom, in the style of industrial machinery aesthetics, deutscher werkbund, uniformly staged images, soviet, light indigo and dark bronze, new american color photography, detailed facial features
Negative Prompt:(EasyNegative),(watermark), (signature), (sketch by bad-artist), (signature), (worst quality), (low quality), (bad anatomy), NSFW, nude, (normal quality)
Stable Diffusion XL Base+Refiner生成结果:
4. 从0到1上手使用Stable Diffusion XL训练自己的AI绘画模型(全网最详细讲解)
4.0 SDXL训练资源分享
SDXL训练脚本:Rocky整理优化过的SDXL完整训练资源SDXL-Train项目,大家只用在SDXL-Train中就可以完成SDXL的模型训练工作,方便大家上手实操 。SDXL-Train项目资源包可以通过关注公众号WeThinkIn ,后台回复“SDXL-Train ”获取。
本文中的SDXL微调训练数据集:二次元人物数据集 ,大家可以关注公众号WeThinkIn ,后台回复“二次元人物数据集 ”获取。
本文中的SDXL微调训练底模型:WeThinkIn_SDXL_二次元模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SDXL_二次元模型 ”获取模型资源链接。
本文中的SDXL LoRA训练数据集:猫女数据集 ,大家可以关注公众号WeThinkIn ,后台回复“猫女数据集 ”获取。
本文中的SDXL LoRA训练底模型:WeThinkIn_SDXL_真人模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SDXL_真人模型 ”获取模型资源链接。
4.1 SDXL训练脉络初识
Stable Diffusion系列模型的训练过程主要分成以下几个步骤,Stable Diffusion XL也不例外:
训练集制作 :数据质量评估,标签梳理,数据清洗,数据标注,标签清洗,数据增强等。
训练文件配置 :预训练模型选择,训练环境配置,训练步数设置,其他超参数设置等。
模型训练 :运行SDXL模型/LoRA模型训练脚本,使用TensorBoard监控模型训练等。
模型测试 :将训练好的自训练SDXL模型/LoRA模型用于效果评估与消融实验。
讲完SDXL训练的方法论,Rocky再向大家推荐一些SDXL训练资源:
https://github.com/qaneel/kohya-trainer(本文中主要的训练工程)
https://github.com/Linaqruf/kohya-trainer(此项目中的kohya-trainer-XL.ipynb和kohya-LoRA-trainer-XL.ipynb可以用于制作数据集和配置训练参数)
https://github.com/bmaltais/kohya_ss(此项目可以GUI可视化训练)
Rocky整理优化过的SDXL完整训练资源SDXL-Train项目,大家只用在SDXL-Train中就可以完成SDXL的模型训练工作,方便大家上手实操 。SDXL-Train项目资源包可以通过关注公众号WeThinkIn ,后台回复“SDXL-Train ”获取。
目前我们对SDXL的训练流程与所需资源有了初步的了解,接下来,就让我们跟随着Rocky的脚步,从0到1使用SDXL模型和训练资源一起训练自己的SDXL绘画模型与LoRA绘画模型吧!
4.2 配置训练环境与训练文件
首先,我们需要下载两个训练资源,只需在命令行输入下面的代码即可:
git clone https: // github. com/ qaneel/ kohya- trainer. git
git clone https: // github. com/ Linaqruf/ kohya- trainer. git
qaneel/kohya-trainer项目包含了Stable Diffusion XL的核心训练脚本 ,而我们需要用Linaqruf/kohya-trainer项目中的kohya-trainer-XL.ipynb和kohya-LoRA-trainer-XL.ipynb文件来生成数据集制作脚本和训练参数配置脚本 。
我们打开Linaqruf/kohya-trainer项目可以看到,里面包含了两个SDXL的.ipynb文件:
接着我们再打开qaneel/kohya-trainer项目,里面包含的两个python文件就是我们后续的训练主脚本: 正常情况下,我们需要运行Linaqruf/kohya-trainer项目中两个SDXL的.ipynb文件的内容,生成训练数据处理脚本(数据标注,数据预处理,数据Latent特征提取,数据分桶(make buckets)等)和训练参数配置文件。
我们使用数据处理脚本完成训练集的制作,然后再运行qaneel/kohya-trainer项目的训练脚本,同时读取训练参数配置文件,为SDXL模型的训练过程配置超参数。
完成上面一整套流程,SDXL模型的训练流程就算跑通了。但是由于Linaqruf/kohya-trainer项目中的两个.ipynb文件内容较为复杂,整个流程比较繁琐,对新手非常不友好,并且想要完成一整套训练流程,需要我们一直在两个项目之前切换,非常不方便 。
所以Rocky这边帮大家对两个项目进行了整合归纳,总结了简单易上手的SDXL模型以及相应LoRA模型的训练流程,制作成SDXL完整训练资源SDXL-Train项目,大家只用在SDXL-Train中就可以完成SDXL的模型训练工作,方便大家上手实操。
SDXL-Train项目资源包可以通过关注公众号WeThinkIn ,后台回复“SDXL-Train ”获取。
下面是SDXL-Train项目中的主要内容,大家可以看到SDXL的数据处理脚本与训练脚本都已包含在内: 我们首先进入SDXL-Train项目中,安装SDXL训练所需的依赖库,我们只需在命令行输入以下命令即可:
cd SDXL- Train
pip install - r requirements. txt - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
pip install accelerate== 0.16 .0 - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
pip install torch== 2.0 .1 - i https: // pypi. tuna. tsinghua. edu. cn/ simple some- package
在完成上述的依赖库安装后,我们需要确认一下目前的Python、PyTroch、CUDA以及cuDNN的版本是否兼容 ,我们只需要在命令行输入以下命令即可:
>> > python
Python 3.9
>> > import torch
>> > print ( torch. __version__)
2.0 .1 + cu117
>> > print ( torch. version. cuda)
11.7
>> > print ( torch. backends. cudnn. version( ) )
8500
>> > print ( torch. cuda. is_available( ) )
True
如果大家在本地自己验证的时候和Rocky上述的版本一致,说明训练环境已经全部兼容!
安装和验证好所有SDXL训练所需的依赖库后,我们还需要设置一下SDXL的训练环境,我们主要使用accelerate库的能力,accelerate库能让PyTorch的训练和推理变得更加高效简洁 。我们只需在命令行输入以下命令,并对每个设置逐一进行填写即可:
accelerate config
In which compute environment are you running?
This machine
Which type of machine are you using?
multi- GPU
How many different machines will you use ( use more than 1 for multi- node training) ? [ 1 ] : 1
Do you wish to optimize your script with torch dynamo?[ yes/ NO] :
Do you want to use DeepSpeed? [ yes/ NO] :
Do you want to use FullyShardedDataParallel? [ yes/ NO] :
Do you want to use Megatron- LM ? [ yes/ NO] :
How many GPU( s) should be used for distributed training? [ 1 ] : 2
What GPU( s) ( by id ) should be used for training on this machine as a comma- seperated list ? [ all ] : all
Do you wish to use FP16 or BF16 ( mixed precision) ?
fp16
accelerate configuration saved at / root/ . cache/ huggingface/ accelerate/ default_config. yaml完成上述的流程后,接下来我们就可以进行SDXL训练数据的制作和训练脚本的配置流程了!
后续进行SDXL与SDXL LoRA模型训练的时候,只需要加载对应的default_config.yaml配置文件即可,具体的调用方法,本文后续的章节会进行详细讲解。
还有一点需要注意的是,我们进行SDXL模型的训练时,SDXL的CLIP Text Encoder会调用CLIP-ViT-bigG-14-laion2B-39B-b160k和clip-vit-large-patch14两个配置文件 。一般情况下SDXL模型会从huggingface上将配置文件下载到~/.cache/huggingface/目录中,但是由于网络原因很可能会下载失败,从而导致训练的失败。
所以为了让大家能更方便的训练SDXL模型,Rocky已经将CLIP-ViT-bigG-14-laion2B-39B-b160k和clip-vit-large-patch14这两个配置文件放入SDXL-Train项目的utils_json文件夹中,并且已经为大家配置好依赖路径,大家只要使用SDXL-Train项目便无需做任何修改 。如果大家想要修改CLIP-ViT-bigG-14-laion2B-39B-b160k和clip-vit-large-patch14这两个依赖文件夹的调用路径,大家可以找到SDXL-Train/library/sdxl_train_util.py脚本中的第122行,将”utils_json/”部分修改成自己的本地自定义路径比如“/本地路径/utils_json/”即可。
完成上述的流程后,接下来我们就可以进行SDXL训练数据的制作和训练脚本的配置流程了!
4.3 SDXL训练数据集制作
首先,我们需要对数据集进行清洗,和传统深度学习时代一样,数据清洗工作依然占据了AIGC时代模型训练70%-80%左右的时间。
并且这个过程必不可少,因为数据质量决定了机器学习性能的上限,而算法和模型只是在不断逼近这个上限而已 。
我们需要筛除分辨率较低、质量较差(比如说768*768分辨率的图片)、存在破损以及和任务目标无关的数据,接着再去除数据里面可能包含的水印,干扰文字等污染特征 。
同时,我们需要优先保证数据集的质量,在有质量的基础上再去增加数据集的数量与丰富度 。
为了满足AI绘画生成图片时的尺寸适应度,我们可以对数据进行多尺度的增强 ,比如进行1:1,1:2,2:1,1:3,3:4,4:3,9:16,16:9等等尺寸的裁剪与缩放操作。但是切记不能在多尺度增强的时候将图片的主体特征裁剪掉(比如人脸,建筑等)。
完成上述的数据筛选与清洗工作后,我们就可以开始进行数据标注了。
数据标注可以分为自动标注 和手动标注 。自动标注主要依赖像BLIP(img2caption)和Waifu Diffusion 1.4(img2tag)等能够进行图片生成标签的模型,手动标注则依赖标注人员。
4.3.1 使用BLIP自动标注caption
我们先用BLIP对数据进行自动标注,BLIP输出的是自然语言标签 ,我们进入到SDXL-Train/finetune/路径下,运行以下代码即可获得自然语言标签(caption标签):
cd SDXL- Train/ finetune/
python make_captions. py "/数据路径" - - caption_weights “/ 本地BLIP模型路径” - - batch_size= 8 - - beam_search - - min_length= 5 - - max_length= 75 - - debug - - caption_extension= ".caption" - - max_data_loader_n_workers= 2
注意:在使用BLIP进行数据标注时需要依赖bert-base-uncased模型,Rocky这边已经帮大家配置好了,大家只要使用SDXL-Train项目便无需做任何修改 。同时,如果大家想要修改bert-base-uncased模型的调用路径,可以找到SDXL-Train/finetune/blip/blip.py脚本的第189行,将“…/bert-base-uncased”部分修改成自己的本地自定义路径比如“/本地路径/bert-base-uncased”即可。
从上面的代码可以看到,我们第一个传入的参数是训练集的路径 。下面Rocky再一一向大家介绍一下其余参数的意义:
–caption_weights:表示加载的本地BLIP模型,如果不传入本地模型路径,则默认从云端下载BLIP模型。
–batch_size:表示每次传入BLIP模型进行前向处理的数据数量。
–beam_search:设置为波束搜索,默认Nucleus采样。
–min_length:设置caption标签的最短长度。
–max_length:设置caption标签的最长长度。
–debug:如果设置,将会在BLIP前向处理过程中,打印所有的图片路径与caption标签内容,以供检查。
–caption_extension:设置caption标签的扩展名,一般为”.caption”。
–max_data_loader_n_workers:设置大于等于2,加速数据处理。
讲完了上述的运行代码以及相关参数,下面Rocky再举一个例子, 让大家能够更加直观的感受到BLIP处理数据生成caption标签的过程:
上图是单个图像的标注示例,整个数据集的标注流程也是同理的。等整个数据集的标注后,Stable Diffusion XL训练所需的caption标注就完成了 。
4.3.2 使用Waifu Diffusion 1.4自动标注tag
接下来我们可以使用Waifu Diffusion 1.4进行自动标注,Waifu Diffusion 1.4输出的是tag关键词 ,这里需要注意的是,调用Waifu Diffusion 1.4模型需要安装Tensorflow库,并且需要下载特定的版本(2.10.1) ,不然运行时会报“DNN library is not found“错误。我们只需要在命令行输入以下命令即可:
pip install tensorflow== 2.10 .1
完成上述的环境配置后,我们依然进入到SDXL-Trian/finetune/路径下,运行以下代码即可获得tag自动标注:
cd SDXL- Train/ finetune/
python tag_images_by_wd14_tagger. py "/数据路径" - - batch_size= 8 - - model_dir= "/本地路径/wd-v1-4-moat-tagger-v2" - - remove_underscore - - general_threshold= 0.35 - - character_threshold= 0.35 - - caption_extension= ".txt" - - max_data_loader_n_workers= 2 - - debug - - undesired_tags= ""
从上面的代码可以看到,我们第一个传入的参数是训练集的路径 。
–batch_size:表示每次传入Waifu Diffusion 1.4模型进行前向处理的数据数量。
–model_dir:表示加载的本地Waifu Diffusion 1.4模型路径。
–remove_underscore:如果开启,会将输出tag关键词中的下划线替换为空格。
–general_threshold:设置常规tag关键词的筛选置信度。
–character_threshold:设置人物特征tag关键词的筛选置信度。
–caption_extension:设置tag关键词标签的扩展名,一般为”.txt”。
-max_data_loader_n_workers:设置大于等于2,加速数据处理。
–debug:如果设置,将会在Waifu Diffusion 1.4模型前向处理过程中,打印所有的图片路径与tag关键词标签内容,以供检查。
–undesired_tags:设置不需要输出的tag关键词。
下面Rocky依然用美女图片作为例子, 让大家能够更加直观的感受到Waifu Diffusion 1.4模型处理数据生成tag关键词标签的过程: 上图是单个图像的标注示例,整个数据集的标注流程也是同理的。等整个数据集的标注后,Stable Diffusion XL训练所需的tag关键词标注就完成了 。
上面Rocky是使用了Waifu Diffusion v1.4系列模型中的wd-v1-4-moat-tagger-v2模型,目前Waifu Diffusion v1.4系列模型一共有5个版本,除了刚才介绍到的wd-v1-4-moat-tagger-v2模型,还包括wd-v1-4-swinv2-tagger-v2模型、wd-v1-4-convnext-tagger-v2模型、wd-v1-4-convnextv2-tagger-v2模型以及wd-v1-4-vit-tagger-v2模型。
Rocky也分别对他们的自动标注效果进行了对比,在这里Rocky使用了一张生成的“猫女”图片,分别输入到这五个自动标注模型中,一起来看看不同版本的Waifu Diffusion v1.4模型的效果: 从上图可以看到,在将general_threshold和character_threshold同时设置为0.5时,wd-v1-4-moat-tagger-v2模型的标注效果整体上是最好的,内容丰富且最能反映图片中的语义信息。所以在这里,Rocky也推荐大家使用wd-v1-4-moat-tagger-v2模型 。
大家也可以在SDXL-Train项目的tag_models文件夹下调用这些模型,进行对比测试,感受不同系列Waifu Diffusion v1.4模型的标注效果。
4.3.3 补充标注特殊tag
完成了caption和tag的自动标注之后,如果我们需要训练一些特殊标注 的话,还可以进行手动的补充标注。
SDXL-Trian项目中也提供了对数据进行补充标注的代码,Rocky在这里将其进行提炼总结,方便大家直接使用。
大家可以直接拷贝以下的代码,并按照Rocky在代码中提供的注释进行参数修改,然后运行代码即可对数据集进行补充标注:
import os
train_data_dir = "/本地数据集路径"
extension = ".txt"
custom_tag = "WeThinkIn"
sub_folder = ""
append = False
remove_tag = False
recursive = False
if sub_folder == "" :
image_dir = train_data_dir
elif sub_folder == "--all" :
image_dir = train_data_dir
recursive = True
elif sub_folder. startswith( "/content" ) :
image_dir = sub_folder
else :
image_dir = os. path. join( train_data_dir, sub_folder)
os. makedirs( image_dir, exist_ok= True )
def read_file ( filename) :
with open ( filename, "r" ) as f:
contents = f. read( )
return contents
def write_file ( filename, contents) :
with open ( filename, "w" ) as f:
f. write( contents)
def process_tags ( filename, custom_tag, append, remove_tag) :
contents = read_file( filename)
tags = [ tag. strip( ) for tag in contents. split( ',' ) ]
custom_tags = [ tag. strip( ) for tag in custom_tag. split( ',' ) ]
for custom_tag in custom_tags:
custom_tag = custom_tag. replace( "_" , " " )
if remove_tag:
while custom_tag in tags:
tags. remove( custom_tag)
else :
if custom_tag not in tags:
if append:
tags. append( custom_tag)
else :
tags. insert( 0 , custom_tag)
contents = ', ' . join( tags)
write_file( filename, contents)
def process_directory ( image_dir, tag, append, remove_tag, recursive) :
for filename in os. listdir( image_dir) :
file_path = os. path. join( image_dir, filename)
if os. path. isdir( file_path) and recursive:
process_directory( file_path, tag, append, remove_tag, recursive)
elif filename. endswith( extension) :
process_tags( file_path, tag, append, remove_tag)
tag = custom_tag
if not any (
[ filename. endswith( extension) for filename in os. listdir( image_dir) ]
) :
for filename in os. listdir( image_dir) :
if filename. endswith( ( ".png" , ".jpg" , ".jpeg" , ".webp" , ".bmp" ) ) :
open (
os. path. join( image_dir, filename. split( "." ) [ 0 ] + extension) ,
"w" ,
) . close( )
if custom_tag:
process_directory( image_dir, tag, append, remove_tag, recursive)
看完了上面的完整代码流程,如果大家觉得代码太复杂,don‘t worry,大家只需要复制 上面的全部代码,并将train_data_dir =”/本地数据集路径”和custom_tag =”WeThinkIn”设置成自己数据集的本地路径和想要添加的特殊标注,然后运行代码即可,非常简单实用 。
还是以之前的美女图片为例子,当运行完上面的代码后,可以看到txt文件中,最开头的tag为“WeThinkIn”: 大家注意,一般我们会将手动补充的特殊tag放在第一位,因为和caption标签不同,tags标签是有顺序的,最开始的tag权重最大,越靠后的tag权重越小 。
到这里,Rocky已经详细讲解了在Stable Diffusion XL训练前,如何对数据集进行caption标注,tag标注以及补充一些关键标注的完整步骤与流程 ,在数据标注完毕后,接下来我们就要进入数据预处理的阶段了。
4.3.4 训练数据预处理
首先,我们需要对刚才生成的后缀为.caption和.txt的标注文件进行整合,存储成一个json格式的文件,方便后续SDXL模型训练时调取训练数据与标注。
我们需要进入SDXL-Train项目的finetune文件夹中,运行merge_all_to_metadata.py脚本即可:
cd SDXL- Train
python . / finetune/ merge_all_to_metadata. py "/本地数据路径" "/本地数据路径/meta_clean.json"
如下图所示,我们依旧使用之前的美图女片作为例子,运行完merge_all_to_metadata.py脚本后,我们在数据集路径中得到一个meta_clean.json文件,打开可以看到图片名称对应的tag和caption标注都封装在了文件中,让人一目了然,非常清晰。 在整理好标注文件的基础上,接下来我们需要对数据进行分桶与保存Latent特征,并在meta_clean.json的基础上,将图片的分辨率信息也存储成json格式,并保存一个新的meta_lat.json文件。
我们需要进入SDXL-Train项目的finetune文件夹中,运行prepare_buckets_latents.py脚本即可:
cd SDXL- Train
python . / finetune/ prepare_buckets_latents. py "/本地数据路径" "/本地数据路径/meta_clean.json" "/本地数据路径/meta_lat.json" "调用的SDXL模型路径" - - batch_size 4 - - max_resolution "1024,1024"
运行完脚本,我们即可在数据集路径中获得meta_lat.json文件,其在meta_clean.json基础上封装了图片的分辨率信息,用于SDXL训练时快速进行数据分桶。 同时我们可以看到,美女图片的Latent特征保存为了.npz文件,用于SDXL模型训练时,快速读取数据的Latent特征,加速训练过程。
好的,到目前为止,我们已经完整的进行了SDXL训练所需的数据集制作与预处理流程。总结一下,我们在一张美女图片的基础上,一共获得了以下5个不同的训练配置文件 :
meta_clean.json
meta_lat.json
自然语言标注(.caption)
关键词tag标注(.txt)
数据的Latent特征信息(.npz)
在完成以上所有数据处理过程后,接下来我们就可以进入SDXL训练的阶段了,我们可以对SDXL进行全参微调(finetune),也可以基于SDXL训练对应的LoRA模型。
4.4 SDXL微调(finetune)训练
微调(finetune)训练是让SDXL全参数重新训练的一种方法,理想的状态是让SDXL模型在原有能力的基础上,再学习到一个或几个细分领域的数据特征与分布 ,从而能在工业界,学术界以及竞赛界满足不同的应用需求。
Rocky为大家举一个形象的例子,让大家能够能好理解SDXL全参微调的意义。比如我们要训练一个真人写真SDXL模型,应用于写真领域。那么我们首先需要寻找合适的基于SDXL的预训练底模型,比如一个能生成真人图片的SDXL A模型。然后我们用A模型作为预训练底模型,并收集写真行业优质数据作为训练集,有了模型和数据,再加上Rocky为大家撰写的SDXL微调训练全流程攻略,我们就能训练获得一个能生成真人写真的SDXL行业模型,并作为真人写真相关产品的核心大模型 。
那么话不多说,下面Rocky将告诉大家从0到1使用SDXL模型进行微调训练的全流程攻略 ,让我们一起来训练属于自己的SDXL模型吧!
4.4.1 SDXL 微调(finetune)数据集制作
在SDXL全参数微调中,SDXL能够学习到大量的主题,人物,画风或者抽象概念等信息特征 ,所以我们需要对一个细分领域的数据进行广泛的收集,并进行准确的标注。
Rocky这边收集整理了838张二次元人物数据,包含多样的人物,多样的画风,涵盖了大量的二次元专属信息特征,组成二次元人物数据集 ,作为本次SDXL微调训练的训练集。
Rocky一开始收集了5000张数据,经过筛选只剩838张作为最后的模型训练集,数据集质量决定生成效果的上限 ,所以前期对数据集的清洗工作是非常重要的,Rocky总结了以下的用于SDXL全参微调的数据集筛选要求 :
数据尺寸需要在512×512像素以上。
数据的大小最好大于300K。
数据种类尽量丰富,不同主题,不同画风,不同概念都要充分采集。
一个特殊tag对应的图像特征在数据集中需要一致,不然在推理过程触发这个tag时可能会生成多个特征的平均。
每个数据都要符合我们的审美和评判标准!每个数据都要符合我们的审美和评判标准!每个数据都要符合我们的审美和评判标准!
接下来,我们就可以按照本文4.3 Stable Diffusion XL数据集制作章节里的步骤 ,进行数据的清洗,自动标注,以及添加特殊tag。
Rocky认为对SDXL模型进行微调训练主要有两个目的:增强SDXL模型的图像生成能力与增加SDXL对新prompt的触发能力 。
我们应该怎么理解这两个目的呢。我们拿二次元人物数据集为例,我们想要让SDXL模型学习二次元人物的各种特征,包括脸部特征,服装特征,姿势特征,二次元背景特征,以及二次元画风特征等。通过训练不断让SDXL模型“学习”这些数据的内容,从而增强SDXL模型生成二次元人物图片的能力 。与此同时,我们通过自动标注与特殊tag,将图片的特征与标注信息进行对应,让SDXL在学习图片数据特征的同时,学习到对应的标注信息,能够在前向推理的过程中,通过二次元的专属标签生成对应的二次元人物图像 。
理解了上面的内容,咱们的数据处理部分就告一段落了。为了方便大家使用二次元人物数据集进行后续的SDXL模型微调训练,Rocky这边已经将处理好的二次元人物数据集开源(包含原数据,标注文件,读取数据的json文件等) ,大家可以关注公众号WeThinkIn ,后台回复“二次元人物数据集 ”获取。
4.4.2SDXL 微调训练参数配置
本节中,Rocky主要介绍Stable Diffusion XL全参微调(finetune)训练 的参数配置和训练脚本。
Rocky已经帮大家整理好了SDXL全参微调训练的全部参数与训练脚本,大家可以在SDXL-Trian项目的train_config文件夹中找到相应的训练参数配置(XL_config文件夹),并且可以在SDXL-Trian项目中运行SDXL_finetune.sh脚本,进行SDXL的全参微调训练。
接下来,Rocky将带着大家从头到尾走通SDXL全参微调训练过程,并讲解训练参数的意义。首先,我们可以看到XL_config文件夹中有两个配置文件config_file.toml和sample_prompt.toml,他们分别存储着SDXL的训练超参数与训练中的验证prompt。
其中config_file.toml文件中的配置信息包含了sdxl_arguments,model_arguments,dataset_arguments,training_arguments,logging_arguments,sample_prompt_arguments,saving_arguments,optimizer_arguments八个维度的参数信息,下面Rocky为大家依次讲解各个超参数的作用:
[ sdxl_arguments]
cache_text_encoder_outputs = true
no_half_vae = true
min_timestep = 0
max_timestep = 1000
shuffle_caption = false
cache_text_encoder_outputs:Stable Diffusion XL训练时需要打开,用于两个Text Encoder输出结果的缓存与融合。注:当cache_text_encoder_outputs设为true时,shuffle_caption将不起作用。
no_half_vae:当此参数为true时,VAE在训练中使用float32精度;当此为false时,VAE在训练中使用fp16精度。
min_timestep:Stable Diffusion XL Base U-Net在训练时的最小时间步长(默认为0)。
max_timestep:Stable Diffusion XL Base U-Net在训练时的最大时间步长(默认为1000)。
shuffle_caption:当设置为true时,对训练标签进行打乱,能一定程度提高模型的泛化性。
[ model_arguments]
pretrained_model_name_or_path = "/本地路径/SDXL模型文件"
vae = "/本地路径/VAE模型文件"
pretrained_model_name_or_path:读取本地Stable Diffusion XL预训练模型用于微调。
vae:读取本地VAE模型,如果不传入本参数,在训练中则会读取Stable Diffusion XL自带的VAE模型。
[ dataset_arguments]
debug_dataset = false
in_json = "/本地路径/data_meta_lat.json"
train_data_dir = "/本地路径/训练集"
dataset_repeats = 10
keep_tokens = 0
resolution = "1024,1024"
caption_dropout_rate = 0
caption_tag_dropout_rate = 0
caption_dropout_every_n_epochs = 0
color_aug = false
token_warmup_min = 1
token_warmup_step = 0
debug_dataset:训练时对数据进行debug处理,不让破损数据中断训练进程。
in_json:读取数据集json文件,json文件中包含了数据名称,数据标签,数据分桶等信息。
train_data_dir:读取本地数据集存放路径。
dataset_repeats:整个数据集重复训练的次数。(经验分享:如果数据量级小于一千,可以设置为10;如果数据量级在一千与一万之间,可以设置为5;如果数据量级大于一万,可以设置为2 )
keep_tokens:在训练过程中,会将txt中的tag进行随机打乱。如果将keep tokens设置为n,那前n个token的顺序在训练过程中将不会被打乱。
resolution:设置训练时的数据输入分辨率,分别是width和height。
caption_dropout_rate:针对一个数据丢弃全部标签的概率,默认为0。
caption_tag_dropout_rate:针对一个数据丢弃部分标签的概率,默认为0。(类似于传统深度学习的Dropout逻辑 )
caption_dropout_every_n_epochs:每训练n个epoch,将数据标签全部丢弃。
color_aug:数据颜色增强,建议不启用,其与caching latents不兼容,若启用会导致训练时间大大增加 。
token_warmup_min:在训练一开始学习每个数据的前n个tag(标签用逗号分隔后的前n个tag,比如girl,boy,good)
token_warmup_step:训练中学习标签数达到最大值所需的步数,默认为0,即一开始就能学习全部的标签。
[ training_arguments]
output_dir = "/本地路径/模型权重保存地址"
output_name = "sdxl_finetune_WeThinkIn"
save_precision = "fp16"
save_every_n_steps = 1000
train_batch_size = 4
max_token_length = 225
mem_eff_attn = false
xformers = true
max_train_steps = 100000
max_data_loader_n_workers = 8
persistent_data_loader_workers = true
gradient_checkpointing = true
gradient_accumulation_steps = 1
mixed_precision = "fp16"
output_dir:模型保存的路径。
output_name:模型名称。
save_precision:模型保存的精度,一共有[“None”, “float”, “fp16”, “bf16”]四种选择,默认为“None”,即FP32精度。
save_every_n_steps:每n个steps保存一次模型权重。
train_batch_size:训练Batch-Size,与传统深度学习一致。
max_token_length:设置Text Encoder最大的Token数,有[None, 150, 225]三种选择,默认为“None”,即75。
mem_eff_attn:对CrossAttention模块进行轻量化,能够一定程度上加速模型训练并降低显存占用,开启mem_eff_attn后xformers失效。
xformers:xformers插件可以使SDXL模型在训练时显存减少一半左右。
max_train_steps:训练的总步数。
max_data_loader_n_workers:数据加载的DataLoader worker数量,默认为8。
persistent_data_loader_workers:能够让DataLoader worker持续挂载,减少训练中每个epoch之间的数据读取时间,但是会增加内存消耗。
gradient_checkpointing:设为true时开启梯度检查,通过以更长的计算时间为代价,换取更少的显存占用。相比于原本需要存储所有中间变量以供反向传播使用,使用了checkpoint的部分不存储中间变量而是在反向传播过程中重新计算这些中间变量。模型中的任何部分都可以使用gradient checkpoint。
gradient_accumulation_steps:如果显存不足,我们可以使用梯度累积步数,默认为1。
mixed_precision:训练中是否使用混合精度,一共有[“no”, “fp16”, “bf16”]三种选择,默认为“no”。
[ logging_arguments]
log_with = "tensorboard"
logging_dir = "/本地路径/logs"
log_prefix = "sdxl_finetune_WeThinkIn"
log_with:选择训练log保存的格式,可以从[“tensorboard”, “wandb”, “all”]三者中选择,也可以不设置。
logging_dir:设置训练log保存的路径。
log_prefix:增加log文件的文件名前缀,比如sdxl_finetune_WeThinkIn1234567890。
[ sample_prompt_arguments]
sample_every_n_steps = 100
sample_sampler = "euler_a"
[ saving_arguments]
save_model_as = "safetensors"
sample_every_n_steps:在训练中每n步测试一次模型效果。
sample_sampler:设置训练中测试模型效果时使用的sampler,可以选择[“ddim”,“pndm”,“lms”,“euler”,“euler_a”,“heun”,“dpm_2”,“dpm_2_a”,“dpmsolver”,“dpmsolver++”,“dpmsingle”, “k_lms”,“k_euler”,“k_euler_a”,“k_dpm_2”,“k_dpm_2_a”],默认是“ddim”。
save_model_as:每次模型权重保存时的格式,可以选择[“ckpt”, “safetensors”, “diffusers”, “diffusers_safetensors”],目前SD WebUI兼容”ckpt”和”safetensors”格式模型。
[ optimizer_arguments]
optimizer_type = "AdaFactor"
learning_rate = 1e-7
train_text_encoder = false
max_grad_norm = 0
optimizer_args = [ "scale_parameter=False" , "relative_step=False" , "warmup_init=False" ,]
lr_scheduler = "constant_with_warmup"
lr_warmup_steps = 100
optimizer_type:AdamW (default),Lion, SGDNesterov,AdaFactor等。
learning_rate:训练学习率,单卡推荐设置2e-6,多卡推荐设置1e-7。
train_text_encoder:是否在SDXL训练时同步微调Text Encoder。如果设置为true,则在SDXL训练时同时开启Text Encoder模型的微调训练,增强Text Encoder模型对数据集中标签的控制力,能够让生成图片的特征更加趋近于训练数据集分布。
max_grad_norm:最大梯度范数,0表示没有clip。
optimizer_args:设置优化器额外的参数,比如”weight_decay=0.01 betas=0.9,0.999 …”。
lr_scheduler:设置学习率调度策略,可以设置成linear, cosine, cosine_with_restarts, polynomial, constant (default), constant_with_warmup, adafactor等。
lr_warmup_steps:在启动学习率调度策略前,先固定学习率训练的步数。
到这里,config_file.toml中八个维度的训练超参数就全部讲好了,大家可以根据自己的实际情况这些超参数进行调整。
除了config_file.toml之外,我们配置的文件还有sample_prompt.toml,其主要作用是在训练中阶段性验证模型的性能,里面包含了模型生成验证图片的相关参数:
[ prompt]
width = 1024
height = 1024
scale = 7
sample_steps = 28
[ [ prompt.subset] ]
prompt = "1girl, aqua eyes, baseball cap, blonde hair, closed mouth, earrings, green background, hat, hoop earrings, jewelry, looking at viewer, shirt, short hair, simple background, solo, upper body, yellow shirt"
现在我们已经对SDXL训练的整体参数有了比较充分的了解,下面Rocky再对一些关键参数进行深度的解析,让大家能够更好的理解。
4.4.3 SDXL训练的关键参数详解
【1】pretrained_model_name_or_path对SDXL模型微调训练的影响
pretrained_model_name_or_path参数中我们需要加载本地的SDXL模型作为训练底模型。
在SDXL全参数微调训练中,底模型的选择可以说是最为重要的一环。我们需要挑选一个生成能力分布与训练数据分布近似的SDXL模型作为训练底模型(比如说我们训练二次元人物数据集,可以选择生成二次元图片能力强的SDXL模型)。SDXL在微调训练的过程中,在原有底模型的很多能力与概念上持续扩展优化学习,从而得到底模型与数据集分布的一个综合能力。
【2】xformers加速库对SDXL模型微调训练的影响
当我们将xformers设置为true时,使用xformers加速库能对SDXL训练起到2倍左右的加速 ,因为其能使得训练显存占用降低2倍,这样我们就能增大我们的Batch Size数。
想要启动xformers加速库,需要先安装xformers库源,这也非常简单,我们只需要在命令行 输入如下命令即可:
pip install xformers -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
【3】learning_rate对SDXL模型微调训练的影响
SDXL训练过程对学习率的设置非常敏感,如果我们将学习率设置的过大,很有可能导致SDXL模型训练跑飞,在前向推理时生成非常差的图片;如果我们将学习率设置的过小,可能会导致模型无法跳出极小值点 。
Rocky这里总结了相关的SDXL学习率设置经验,分享给大家。如果我们总的Batch Size(单卡Batch Size x GPU数)小于10,可以设置学习率2e-6;如果我们总的Batch Size大于10小于100,可以设置学习率1e-7 。
【4】使用save_state和resume对SDXL模型训练的中断重启
在AI绘画领域,很多时候我们需要进行大规模数据的训练优化,数据量级在10万甚至100万以上,这时候整个训练周期需要一周甚至一个月,训练中可能会出现一些通讯/NCCL超时等问题,导致训练中断。
经典NCCL超时问题如下所示:
[ E ProcessGroupNCCL.cpp:828] [ Rank 0 ] Watchdog caught collective operation timeout: WorkNCCL( SeqNum= 213 , OpType = ALLREDUCE, Timeout( ms) = 1800000 ) ran for 1809831 milliseconds before timing out.
这些训练中断问题会导致我们的训练成本大大增加,为了解决这个问题,我们可以在config_file.toml中设置save_state = true,这样我们在训练模型时不单单保存模型权重,还会保存相关的optimizer states等训练状态。
接着,我们在config_file.toml中设置resume = “/本地路径/模型权重保存地址”,重新运行SDXL训练脚本,这时会直接调取训练中断前的模型权重与训练状态,接着继续训练。
4.4.4 SDXL模型训练
完成训练参数配置后,我们就可以运行训练脚本进行SDXL模型的全参微调训练了。
我们本次训练用的底模型选择了WeThinkIn_SDXL_二次元模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SDXL_二次元模型 ”获取模型资源链接。
我们打开SDXL_finetune.sh脚本,可以看到以下的代码:
accelerate launch
--config_file accelerate_config.yaml
--num_cpu_threads_per_process = 8
/本地路径/SDXL-Train/sdxl_train.py
--sample_prompts = "/本地路径/SDXL-Trian/train_config/XL_config/sample_prompt.toml"
--config_file = "/本地路径/SDXL-Trian/train_config/XL_config/config_file.toml"
我们把训练脚本封装在accelerate库里,这样就能启动我们一开始配置的训练环境了,同时我们将刚才配置好的config_file.toml和sample_prompt.toml参数传入训练脚本中。
接下来,就到了激动人心的时刻,我们只需在命令行输入以下命令,就能开始SDXL的全参微调训练啦:
cd SDXL-Trian
sh SDXL_finetune.sh
训练脚本启动后,会打印出以下的log,方便我们查看整个训练过程的节奏:
running training / 学習開始
num examples / サンプル数: 10240
num batches per epoch / 1epochのバッチ数: 640
num epochs / epoch数: 100
batch size per device / バッチサイズ: 2
gradient accumulation steps / 勾配を合計するステップ数 = 1
total optimization steps / 学習ステップ数: 64000
当我们设置1024分辨率+FP16精度+xformers加速时,SDXL模型进行Batch Size = 1的微调训练需要约24.7G的显存,进行Batch Size=14的微调训练需要约32.3G的显存 ,所以想要微调训练SDXL模型,最好配置一个32G以上的显卡,能让我们更加从容地进行训练。
到此为止,Rocky已经将SDXL全参微调训练的全流程都做了详细的拆解 ,等训练完成后,我们就可以获得属于自己的SDXL模型了!
4.4.5 加载自训练SDXL模型进行AI绘画
SDXL模型微调训练完成后,会将模型权重保存在我们之前设置的output_dir路径下。接下来,我们使用Stable Diffusion WebUI作为框架,加载SDXL二次元人物模型进行AI绘画 。
在本文3.3节零基础使用Stable Diffusion WebUI搭建Stable Diffusion XL推理流程中,Rocky已经详细讲解了如何搭建Stable Diffusion WebUI框架,未使用过的朋友可以按照这个流程快速搭建起Stable Diffusion WebUI。
要想使用SDXL模型进行AI绘画,首先我们需要将训练好的SDXL二次元人物模型放入Stable Diffusion WebUI的/models/Stable-diffusion文件夹下。
然后我们在Stable Diffusion WebUI中分别选用SDXL二次元人物模型即可: 完成上图中的操作后,我们就可以进行二次元人物图片的生成啦!
下面是使用本教程训练出来的SDXL二次元人物模型生成的图片:到这里,关于SDXL微调训练的全流程攻略就全部展示给大家了,大家如果觉得好,欢迎给Rocky的劳动点个赞,支持一下Rocky,谢谢大家!
如果大家对SDXL全参数微调训练还有想要了解的知识或者不懂的地方,欢迎在评论区留言,Rocky也会持续优化本文内容,能让大家都能快速了解SDXL训练知识,并训练自己的专属SDXL绘画模型!
4.5 基于SDXL训练LoRA模型
目前Stable Diffusion XL全参微调的训练成本是Stable Diffusion之前系列的2-3倍左右 ,而基于Stable Diffusion XL训练LoRA的成本与之前的系列相比并没有太多增加,故训练LoRA依旧是持续繁荣SDXL生态的高效选择 。
如果大家想要了解LoRA模型的核心基础知识,LoRA的优势,热门LoRA模型推荐等内容,可以阅读Rocky之前写的文章:
深入浅出完整解析LoRA(Low-Rank Adaptation)模型核心基础知识
在本节,Rocky将告诉大家从0到1使用SDXL模型训练对应的LoRA的全流程攻略 ,让我们一起来训练属于自己的SDXL LoRA模型吧!
4.5.1 SDXL LoRA数据集制作
首先,我们需要确定数据集主题,比如说人物,画风或者某个抽象概念等。本次我们选择用Rocky自己搜集的人物主题数据集——猫女数据集来进行SDXL LoRA模型的训练。
确定好数据集主题后,我们需要保证数据集的质量,Rocky总结了以下的SDXL LoRA训练数据集筛选要求 :
当我们训练人物主题 时,一般需要10-20张高质量数据;当我们训练画风主题 时,需要100-200张高质量数据;当我们训练抽象概念 时,则至少需要200张以上的数据。
不管是人物主题,画风主题还是抽象概念,一定要保证数据集中数据的多样性 (比如说猫女姿态,角度,全身半身的多样性)。
每个数据都要符合我们的审美和评判标准!每个数据都要符合我们的审美和评判标准!每个数据都要符合我们的审美和评判标准!
所以Rocky这次挑选的猫女数据集一共有22张图片,包含了猫女的不同姿态数据,并且每张图也符合Rocky的审美哈哈。
接下来,我们就可以按照本文4.3 Stable Diffusion XL数据集制作章节里的步骤 ,进行数据的清洗,自动标注,以及添加特殊tag——即触发词。在这里,我们要在标注文件的开头添加“catwomen”作为猫女的触发词 。
除了对数据进行标注,我们还需要对数据的标注进行清洗,删除一些概念与触发词重合的标签。为什么我们要进行数据标注的清洗呢?因为如果不对标注进行清洗,会导致训练时的tag污染 。
我们拿猫女数据集为例,我们想要让SDXL LoRA模型学习猫女的主要特征,包括脸部特征,服装特征(最具猫女特点的黑色皮衣和黑色眼罩 )等,我们想让“catwomen”学习到这些特征。但是自动标注会给数据打上一些描述脸部特征和服装特征的tag,导致猫女的主要特征被这些tag分走,从而导致tag污染。这样就会导致很多精细化的特征丢失在自动标注的tag中,使得SDXL LoRA在生成猫女图片时缺失黑色皮衣或者黑色眼罩等。
所以我们需要删除自动标注的脸部,服装等tag,从而使得保留下来的触发词等标签是SDXL LoRA模型着重需要学习的。
一张一张手动删除标签费时费力,Rocky这里推荐大家使用Stable Diffusion WebUI的一个数据标注处理插件:stable-diffusion-webui-dataset-tag-editor ,可以对标签进行批量处理,非常方便。
完成上述步骤,咱们的数据处理部分就告一段落了。为了方便大家使用猫女数据集进行后续的LoRA训练,Rocky这边已经将处理好的猫女数据集开源(包含原数据,标注文件,读取数据的json文件等) ,大家可以关注公众号WeThinkIn ,后台回复“猫女数据集 ”获取。
4.5.2 SDXL LoRA训练参数配置
大家可以在SDXL-Trian项目中train_config/XL_LoRA_config路径下找到SDXL LoRA的训练参数配置文件config_file.toml和sample_prompt.toml ,他们分别存储着SDXL_LoRA的训练超参数与训练中的验证prompt信息。
其中config_file.toml文件中的配置文件包含了sdxl_arguments,model_arguments,dataset_arguments,training_arguments,logging_arguments,sample_prompt_arguments,saving_arguments,optimizer_arguments以及additional_network_arguments九个个维度的参数信息。
训练SDXL_LoRA的参数配置与SDXL全参微调的训练配置有相同的部分(上述的前八个维度),也有LoRA的特定参数需要配置(additional_network_arguments)。
下面我们首先看看这些共同的维度中,有哪些需要注意的事项吧:
[ sdxl_arguments]
cache_text_encoder_outputs = true
no_half_vae = true
min_timestep = 0
max_timestep = 1000
shuffle_caption = false
[ model_arguments]
pretrained_model_name_or_path = "/本地路径/SDXL模型文件"
vae = "/本地路径/VAE模型文件"
[ dataset_arguments]
debug_dataset = false
in_json = "/本地路径/data_meta_lat.json"
train_data_dir = "/本地路径/训练集"
dataset_repeats = 1
keep_tokens = 0
resolution = "1024,1024"
color_aug = false
token_warmup_min = 1
token_warmup_step = 0
[ training_arguments]
output_dir = "/本地路径/模型权重保存地址"
output_name = "sdxl_lora_WeThinkIn"
save_precision = "fp16"
save_every_n_epochs = 1
train_batch_size = 4
max_token_length = 225
mem_eff_attn = false
sdpa = true
xformers = false
max_train_epochs = 100
max_data_loader_n_workers = 8
persistent_data_loader_workers = true
gradient_checkpointing = true
gradient_accumulation_steps = 1
mixed_precision = "fp16"
[ logging_arguments]
log_with = "tensorboard"
logging_dir = "/本地路径/logs"
log_prefix = "sdxl_lora_WeThinkIn"
[ sample_prompt_arguments]
sample_every_n_epochs = 1
sample_sampler = "euler_a"
[ saving_arguments]
save_model_as = "safetensors"
[ optimizer_arguments]
optimizer_type = "AdaFactor"
learning_rate = 1e-5
max_grad_norm = 0
optimizer_args = [ "scale_parameter=False" , "relative_step=False" , "warmup_init=False" ,]
lr_scheduler = "constant_with_warmup"
lr_warmup_steps = 100
除了上面的参数,训练SDXL_LoRA时还需要设置一些专属参数,这些参数非常关键,下面Rocky将给大家一一讲解:
[ additional_network_arguments]
no_metadata = false
network_module = "networks.lora"
network_dim = 32
network_alpha = 16
network_args = [ "conv_dim=32" , "conv_alpha=16" ,]
network_train_unet_only = true
no_metadata:保存模型权重时不附带Metadata数据,建议关闭,能够减少保存下来的LoRA大小。
network_module:选择训练的LoRA模型结构,可以从[“networks.lora”, “networks.dylora”, “lycoris.kohya”]中选择,最常用的LoRA结构默认选择”networks.lora” 。
network_dim:设置LoRA的RANK,设置的数值越大表示表现力越强,但同时需要更多的显存和时间来训练。
network_alpha:设置缩放权重,用于防止下溢并稳定训练的alpha值。
network_args:设置卷积的Rank与缩放权重。
下面表格中Rocky给出一些默认配置,大家可以作为参考:
network_category
network_dim
network_alpha
conv_dim
conv_alpha
LoRA
32
1
–
–
LoCon
16
8
8
1
LoHa
8
4
4
1
如果我们想要训练LoRA ,我们需要设置network_module = “networks.lora”,同时设置network_dim和network_alpha,和上面的配置一致。
如果我们想要训练LoCon ,我们需要设置network_module = “lycoris.kohya”和algo=“locon”,同时设置network_dim和network_alpha:
network_module = "lycoris.kohya"
algo = "locon"
network_dim = 32
network_alpha = 16
network_args = [ "conv_dim=32" , "conv_alpha=16" ,]
如果我们想要训练LoHa ,我们需要设置network_module = “lycoris.kohya”和algo=“loha”,同时设置network_dim和network_alpha:
network_module = "lycoris.kohya"
algo = "loha"
network_dim = 32
network_alpha = 16
network_args = [ "conv_dim=32" , "conv_alpha=16" ,]
network_train_unet_only:如果设置为true,那么只训练U-Net部分。
4.5.3 SDXL LoRA关键参数详解
【1】train_batch_size对SDXL LoRA模型训练的影响
和传统深度学习一样,train_batch_size即为训练时的batch size,表示一次性送入SDXL LoRA模型进行训练的图片数量。
一般来说,较大的batch size 往往每个epoch训练时间更短,但是显存占用会更大,并且收敛得慢 (需要更多epoch数)。较小的batch size 每个epoch训练时间长,但是显存占用会更小,并且收敛得快 (需要更少epoch数)。
但是有研究表明这个结论会在batch size大于8000的时候才会体现 ,所以在实际的训练时,如果GPU数不大于8卡的话,还是需要尽可能占满GPU显存为宜,比如64-96之间(理论上batch size = 时计算效率较高),训练一般都能取得不错效果。
上面的结论在训练SDXL大模型时是非常适用的,不过我们在训练SDXL LoRA模型时,一般来说数据量级是比较小的(10-300为主),所以在这种情况下,我们可以设置batch size为2-6即可。
【2】pretrained_model_name_or_path对SDXL LoRA模型训练的影响
pretrained_model_name_or_path参数中我们需要加载本地的SDXL模型作为训练底模型。
底模型的选择至关重要,SDXL LoRA的很多底层能力与基础概念的学习都来自于底模型的能力 。并且底模型的优秀能力需要与我们训练的主题,比如说人物,画风或者某个抽象概念相适配。如果我们要训练二次元LoRA,则需要选择二次元底模型,如果我们要训练三次元LoRA,则需要选择三次元底模型,以此类推。
【3】network_dim对SDXL LoRA模型训练的影响
network_dim即特征维度,越高表示模型的参数量越大,设置高维度有助于LoRA学习到更多细节特征,但模型收敛速度变慢,同时也更容易过拟合,需要的训练时间更长 。所以network_dim的设置需要根据任务主题去调整。
一般来说,在SDXL的1024*1024分辨率训练基础上,可以设置network_dimension = 128,此时SDXL LoRA大小约为686MB。
【4】network_alpha对SDXL LoRA模型训练的影响
network_alpha是一个缩放因子,用于缩放模型的训练权重
W
W
W ,
W
=
W
i
n
×
a
l
p
h
a
/
d
i
m
W = W_{in} times alpha / dim
W = W in × a lp ha / d im 。network_alpha设置的越高,LoRA模型能够学习更多的细节信息,同时学习速率也越快,推荐将其设置为network_dimension的一半。
4.5.4 SDXL LoRA模型训练
完成训练参数配置后,我们就可以运行训练脚本进行SDXL_LoRA模型的训练了。
我们本次训练用的底模型选择了WeThinkIn_SDXL_真人模型 ,大家可以关注Rocky的公众号WeThinkIn ,后台回复“SDXL_真人模型 ”获取模型资源链接。
我们打开SDXL_fintune_LoRA.sh脚本,可以看到以下的代码:
accelerate launch
--config_file accelerate_config.yaml
--num_cpu_threads_per_process = 8
/本地路径/SDXL-Train/sdxl_train_network.py
--sample_prompts = "/本地路径/SDXL-Train/train_config/XL_LoRA_config/sample_prompt.toml"
--config_file = "/本地路径/SDXL-Train/train_config/XL_LoRA_config/config_file.toml"
我们把训练脚本封装在accelerate库里,这样就能启动我们一开始配置的训练环境了,同时我们将刚才配置好的config_file.toml和sample_prompt.toml参数传入训练脚本中。
接下来,就到了激动人心的时刻,我们只需在命令行输入以下命令,就能开始SDXL_LoRA训练啦:
cd SDXL-Trian
sh SDXL_fintune_LoRA.sh
当我们基于SDXL训练SDXL LoRA模型时,我们设置分辨率为1024+FP16精度+xformers加速时,进行Batch Size = 1的微调训练需要约13.3G的显存,进行Batch Size=8的微调训练需要约18.4G的显存 ,所以想要微调训练SDXL LoRA模型,最好配置一个16G以上的显卡,能让我们更加从容地进行训练。
4.5.5 加载SDXL LoRA模型进行AI绘画
SDXL LoRA模型训练完成后,会将模型权重保存在我们之前设置的output_dir路径下。接下来,我们使用Stable Diffusion WebUI作为框架,加载SDXL LoRA模型进行AI绘画。
在本文3.3节零基础使用Stable Diffusion WebUI搭建Stable Diffusion XL推理流程中,Rocky已经详细讲解了如何搭建Stable Diffusion WebUI框架,未使用过的朋友可以按照这个流程快速搭建起Stable Diffusion WebUI。
要想使用SDXL LoRA进行AI绘画,首先我们需要将SDXL底模型和SDXL LoRA模型分别放入Stable Diffusion WebUI的/models/Stable-diffusion文件夹和/models/Lora文件夹下。
然后我们在Stable Diffusion WebUI中分别选用底模型与LoRA即可: 完成上图中的操作后,我们就可以进行猫女图片的生成啦!
【1】训练时的底模型+猫女LoRA
首先我们使用训练时的底模型作为测试底模型,应选用训练好的猫女LoRA,并将LoRA的权重设为1,看看我们生成的图片效果如何: 我们可以看到,生成的猫女图片的完成度还是非常好的,不管是整体质量还是细节都能展现出猫女该有的气质与魅力。并且在本次训练中猫女的手部特征也得到了较好的学习,优化了一直困扰AI绘画的手部问题 。
【2】设置LoRA的不同权重
接下来,我们设置LoRA的权重分别为[0.2, 0.4, 0.6, 0.8, 1],进行对比测试,看看不同SDXL LoRA权重下的图片生成效果如何: 从上图的对比中可以看出,当SDXL LoRA设置的权重越高时,训练集中的特征越能载生成图片中展现,比如说猫女的人物特征,猫女的服装特征以及生成的猫女有无面罩等。但LoRA的权重也不是越高越好,当设置权重为0.6-0.8之间,生成的图片会有更多的泛化性 。
【3】切换不同的底模型
完成了在单个底模型上的SDXL LoRA不同权重的效果测试,接下来我们切换不同的底模型,看看会生成的猫女图片会有什么变化吧。
首先,我们将底模型切换成SDXL Base模型,使用猫女LoRA并设置权重为1: 从上面的图中可以看出,使用SDXL Base模型作为底模型后,生成的猫女图片整体质感已经发生改变,背景也有了更多光影感 。
我们再使用SDXL的二次元模型作为底模型,同样使用猫女LoRA并设置权重为1: 可以看到,换用二次元模型作为底模型后,生成的猫女图片整体质感开始卡通化。但是由于训练数据集中全是三次元图片,所以二次元底模型+三次元LoRA生成的图片并没有完全的二次元化。
【4】使用不同提示词改变图片风格
最后,我们再尝试通过有添加提示词prompt,来改变生成的猫女图片的风格。
首先,我们在提示词prompt中加入赛博朋克风格“Cyberpunk style”,这是生成的猫女图片中就会加入赛博朋克元素了:到这里,关于SDXL LoRA的全流程攻略就全部展示给大家了,大家如果觉得好,欢迎给Rocky的劳动点个赞,支持一下Rocky,谢谢大家!
如果大家对SDXL LoRA还有想要了解的知识或者不懂的地方,欢迎在评论区留言,Rocky也会持续优化本文内容,能让大家都能快速了解SDXL LoRA知识,并训练自己的专属LoRA模型!
4.6 SDXL训练结果测试评估
之前的章节讲述了SDXL模型微调和SDXL LoRA模型训练后的效果测试评估流程,那么在本小节,Rocky向大家介绍一下AI绘画模型测试评估的一些通用流程与技巧。
在进行AI绘画时,我们需要输入正向提示词(positive prompts)和负向提示词(negative prompts)。
正向提示词一般需要输入我们想要生成的图片内容,包括我们训练好的特殊tag等。
不过在正向提示词的开头,一般都需要加上提高生成图片整体质量的修饰词,Rocky这里推荐一套“万金油”修饰词,方便大家使用:
( masterpiece,best quality,ultra_detailed,highres,absurdres:1.2)
负向提示词一般需要输入我们不想生成的内容,在这里Rocky再分享一套基于SDXL的“万金油”负向提示词,方便大家使用:
( worst quality, low quality, ugly:1.4) , poorly drawn hands, poorly drawn feet, poorly drawn face, out of frame, mutation, mutated, extra limbs, extra legs, extra arms, disfigured, deformed, cross-eye, blurry, ( bad art, bad anatomy:1.4) , blurred, text, watermark
当然的,我们也可以使用ChatGPT辅助生成提示词 ,在此基础上我们再加入训练好的特殊tag并对提示词进行修改润色。
在我们进行模型测试的时候,如果存在生成图片质量不好,生成图片样式单一或者生成图片崩坏的情况,就需要优化数据或者参数配置,重新训练了。
4.7 SDXL训练经验分享(持续更新!)
在本节中,Rocky将向大家持续分享关于SDXL和SDXL LoRA等模型的训练经验,大家有自己的经验,也欢迎在评论区补充,我们一起让AIGC和AI绘画领域更加繁荣!
数据质量标准 :图片的文件容量(占用的内存)越大越好,图像的分辨率越大越好,同时数据内容的是符合我们训练的领域的专业审美与标准的。
数据质量最为重要 :切勿在没有保证数据质量的前提下,盲目扩充数据数量,这样只会导致低质量数据污染整个数据集,从而导致模型训练后的图片生成效果不理想。
数据集中类别均衡 :确保数据集中每种风格、主题、概念等各种维度的类别有大致相同的数量。使用均衡的数据集训练出来的SDXL模型,具备多功能性,可以作为未来训练的基础SDXL模型。
细分类别精细化训练 :对整个数据集,我们进行统一的训练,整体上效果是可以保证的。但是可能会存在一些难类别/难样本/难细节等,在这些场景中模型的训练效果不好。这时可以针对这些bad case,补充庞大且高质量的素材进行优化训练(每个素材强化训练80-100步)。
数据标签质量 :每张图片都需要经过仔细的数据标注,能够较好的表达呈现图片中的内容,才算是一个好的标签。高质量的数据标签能够增强模型用最少的提示词生成高质量图片的能力和生成图片内容的准确性。
数据增强手段 :数据多尺寸处理、素材去水印、图像特殊部分(手部、服装等)mask处理等。
Rocky将持续把Stable Diffusion XL训练的经验与思考分享出来,大家先点赞收藏敬请期待!!!
5. 生成式模型的性能测评
到目前为止,AIGC领域的测评过程整体上还是比较主观。Stable Diffusion XL在性能测评时使用了FID(Fréchet inception distance),CLIP score以及人类视觉系统(HVS)评价这三个指标作为文生图的标价指标 ,其中人类视觉系统依旧是占据主导地位 。
下面,跟着Rocky一起来看看各个评价指标的意义与特点,以及在不同的实际场景中,该如何对生成式模型做出有效的评估。
5.1 FID(Fréchet inception distance)
FID(Fréchet inception distance) 表示生成图像与真实图像之间的相似性 ,即图像的真实度。FID表示的是生成图像的特征向量与真实图像的特征向量之间的距离,该距离越近(值越小),表明生成模型的效果越好 ,即图像的清晰度高,且多样性丰富。
FID是通过Inception模型进行计算的。主要流程是将生成图像和真实图像输入到Inception模型中,并提取倒数第二层的2048维向量进行输出,最后计算两者特征向量之间的距离。
由于Stable Diffusion XL模型是文生图模型,并不存在原本的真实图像,所以一般选用COCO验证集上的zero-shot FID-30K(选择30K的样本)与生成图像进行求FID操作,并将其中最小的FID用于不同模型之间的性能对比 。
但是有研究指出,FID对深入的文本理解,独特艺术风格之间的精细区分,以及明显的视觉美感等AIGC时代特有的特征不能很好的评估。同时也有研究表明,zero-shot FID-30K与视觉美学呈负相关 。
5.2 CLIP score
CLIP score 可以用于评估文生图/图生图中生成图像与输入Prompt文本以及生成图像与输入原图像的匹配度 。以文生图为例,我们使用CLIP模型将Prompt文本和生成图像分别转换为特征向量,然后计算它们之间的余弦相似度。当CLIP Score较高时,表示生成图像与输入Prompt文本之间的匹配度较高;当CLIP Score较低时,表示生成图像与输入Prompt文本之间的匹配度较低 。 从上表可以看出,SDXL在CLIP score上得分最高 ,由于使用了两个CLIP Text Encoder进行约束,SDXL对文本内容的控制力确实强了不少。但是SDXL在FID指标上也同步上升了 ,并且比之前的系列都要高,刚才在介绍FID指标的内容中,Rocky已经阐述过很多研究都表明FID在AIGC时代不能很好的作为美学评价指标,甚至与视觉美学呈负相关,在SDXL的论文中更加证实了这一点。所以在此基础上,最后又增加了人类视觉系统作为评价指标(同样的参数让SD系列的不同模型生成图像,并让人工评价出最好的图像),在人类评估者眼中,明显更加喜欢SDXL生成的图片 ,结果如下所示:
5.3 Aesthetics Scorer(美学评分)
除了上述提到的三种评价指标,我们还可以用Aesthetics Scorer(美学评分) 对Stable DIffusion系列模型生成的图片进行评分。Aesthetics Scorer背后的评价标准数据集是基于LAION-Aesthetics ,也就是Stable Diffusion系列训练时有用到的数据集,所以Aesthetics Scorer有一定的可靠性。
5.4 与Midjourney系列进行对比
完成和Stable Diffusion之前系列的对比之后,SDXL还与Midjourney v5.1和Midjourney v5.2进行了对比。
这里主要使用谷歌提出的文生图测试prompts:PartiPrompts(P2) 作为测试基准。Parti Prompts(P2)包含了1600多个英文prompts ,覆盖了不同的类别与复杂度,可以说是一个高价值基准。 在具体比较时,从PartiPrompts(P2)的每个类别中选择五个随机prompts,并由Midjourney v5.1和SDXL分别生成四张1024×1024分辨率的图像。然后将这些图像提交给AWS GroundTruth工作组,工作组根据图像与prompts的匹配度进行投票(Votes) 。投票结果如下图所示,总体而言,SDXL的生成效果略高于Midjourney v5.1(54.9%:45.1%):
除了Midjourney v5.1之外,SDXL还与DeepFloyd IF、DALLE-2、Bing Image Creator和Midjourney v5.2进行了定性比较,这些都是AIGC领域的高价值与强生态模型 ,对比结果已经在下图展示,大家可以对比了解一下:总的来说,不管是在传统深度学习时代还是在AIGC时代,生成式模型的生成效果一直存在难以量化和难以非常客观评价的问题,需要人类视觉系统去进行兜底与约束。
那么,在不同的实际场景中,我们该如何对SDXL等生成式模型做出务实的评价呢?
5.5 不同实际场景的务实评估
其实在不同的实际场景中,最务实有效的AIGC模型评估手段是判断模型是否具备价值 。
从投资视角看 ,价值是有产生类ChatGPT效应或者类妙鸭相机流量的潜在势能,比如在团队内部或者让潜在投资人产生了“哇塞时刻”。
从CEO角度看 ,价值是在ToB领域能解决客户的问题;在ToC领域能获得用户的好评并存在成为爆款的潜在可能性。
从CTO角度看 ,价值是能够在严谨的验证中发表论文;能够在顶级算法竞赛中斩获冠军;能够作为产品解决方案的一部分,让产品“焕然一新”。
由于模型本身是“黑盒”,无法量化分析模型结构本身,而评估模型生成的内容质量的指标又离不开人类视觉系统的支持。那就把模型融入到产品中,融入到算法解决方案中,在一次次的实际商业“厮杀”中,来反馈验证模型的性能。
6. SDXL Turbo模型核心基础内容完整讲解
2023年11月29日,StabilityAI官方发布了最新的快速文生图模型SDXL Turbo ,目前代码、模型和技术报告已经全部开源 。
6.1 SDXL Turbo整体架构初识
SDXL Turbo模型是在SDXL 1.0模型的基础上设计了全新的蒸馏训练方案(Adversarial Diffusion Distillation,ADD),经过蒸馏训练得到的。SDXL Turbo模型只需要1-4步就能够生成高质量图像,这接近实时的性能,无异让AI绘画领域的发展更具爆炸性,同时也为未来AI视频的爆发奠定坚实的基础。
SDXL Turbo模型本质上依旧是SDXL模型,其网络架构与SDXL一致,可以理解为一种经过蒸馏训练后的SDXL模型,优化的主要是生成图像时的采样步数。
不过SDXL Turbo模型并不包含Refiner部分,只包含U-Net(Base)、VAE和CLIP Text Encoder三个模块 。在FP16精度下SDXL Turbo模型大小6.94G(FP32:13.88G),其中U-Net(Base)大小5.14G,VAE模型大小167M以及两个CLIP Text Encoder:一大一小分别是1.39G和246M。
6.2 SDXL Turbo核心原理详解
既然我们已经知道SDXL Turbo模型结构本质上是和SDXL一致,那么其接近实时的图片生成性能主要还是得益于最新的Adversarial Diffusion Distillation(ADD)蒸馏方案 。
模型蒸馏技术在传统深度学习时代就应用广泛,只是传统深度学习的落地场景只局限于ToB,任务范围不大且目标定义明确,大家往往人工设计轻量型的目标检测、分割、分类小模型来满足实际应用需求,所以当时模型蒸馏技术显得有些尴尬。
但是到了AIGC时代,大模型成为“AI舞台“上最耀眼的明星,让模型蒸馏技术重新繁荣,应用于各个大模型的性能实时化中,Rocky相信模型蒸馏技术将在AIGC时代成为一个非常关键的AI技术工具 。
接下来,就让我们一起解析ADD蒸馏方案的核心知识吧。首先ADD蒸馏方案的整体架构如下图所示:
ADD蒸馏方案的核心流程包括:将预训练好的SDXL 1.0 Base模型作为学生模型(预训练好的网络能显著提高对抗性损失(adversarial loss)的训练效果 ),它接收经过forward diffusion process后的噪声图片,并输出去噪后的图片,然后用这个去噪后的图片与原图输入判别器中计算adversarial loss以及与教师模型(一个冻结权重的强力Diffusion Model)输出的去噪图片计算distillation loss。ADD蒸馏算法中主要通过优化这两个loss来训练得到SDXL Turbo模型:
adversarial loss :借鉴了GAN的思想,设计了Hinge loss(支持向量机SVM中常用的损失函数)作为SDXL Turbo模型的adversarial loss,通过一个Discriminator来辨别学生模型(SDXL 1.0 Base模型)生成的图像和真实的图像,以确保即使在一个或两个采样步数的低步数状态下也能有高图像保真度,同时避免了其他蒸馏方法中常见的失真或模糊问题 。
distillation loss :经典的蒸馏损失函数,让一个强力Diffusion Model作为教师模型并冻结参数,让学生模型(SDXL 1.0 Base模型)的输出和教师模型的输出尽量一致,具体计算方式使用的是机器学习中经典的L2损失 。
最后,ADD蒸馏训练中总的损失函数就是adversarial loss和distillation loss的加权和,如下图所示,其中权重
λ
lambda
λ =2.5:
6.3 SDXL Turbo效果测试
因为SDXL Turbo网络结构与SDXL一致,所以大家可以直接在Stable Diffusion WebUI上使用SDXL Turbo模型,我们只需按照本文3.3章中的教程使用Stable Diffusion WebUI即可。
同时ComfyUI也支持SDXL Turbo的使用:ComfyUI SDXL Turbo Examples ,然后我们按照本文3.1章的教程使用ComfyUI工作流即可运行SDXL Turbo。
当然的,diffusers库最早原生支持SDXL Turbo的使用运行,可以进行文生图和图生图的任务 ,相关代码和操作流程如下所示:
# 加载diffusers和torch依赖库
from diffusers import AutoPipelineForText2Image
import torch
# 构建SDXL Turbo模型的Pipeline,加载SDXL Turbo模型
pipe = AutoPipelineForText2Image.from_pretrained("/本地路径/sdxl-turbo", torch_dtype=torch.float16, variant="fp16")
# "/本地路径/sdxl-turbo"表示我们需要加载的SDXL Turbo模型,
# 大家可以关注Rocky的公众号WeThinkIn,后台回复:SDXL模型,即可获得资源链接,里面包含SDXL Turbo模型权重文件
# "fp16"代表启动fp16精度。比起fp32,fp16可以使模型显存占用减半。
# 使用GPU进行Pipeline的推理
pipe.to("cuda")
# 输入提示词
prompt = "A cinematic shot of a baby racoon wearing an intricate italian priest robe."
# Pipeline进行推理
image = pipe(prompt=prompt, num_inference_steps=1, guidance_scale=0.0).images[0]
# Pipeline生成的images包含在一个list中:[]
#所以需要使用images[0]来获取list中的PIL图像
运行上面的整个代码流程,我们就能生成一张小浣熊的图片了。这里要注意的是,SDXL Turbo模型在diffusers库中进行文生图操作时不需要使用guidance_scale和negative_prompt参数,所以我们设置guidance_scale=0.0 。
接下来,Rocky再带大家完成SDXL Turbo模型在diffusers中图生图的整个流程:
from diffusers import AutoPipelineForImage2Image
from diffusers.utils import load_image
pipe = AutoPipelineForImage2Image.from_pretrained("/本地路径/sdxl-turbo", torch_dtype=torch.float16, variant="fp16")
pipe.to("cuda")
init_image = load_image("/本地路径/用于图生图的原始图片").resize((913, 512))
prompt = "Miniature model, axis shifting, reality, clarity, details, panoramic view, suburban mountain range, game suburban mountain range, master work, ultra-high quality, bird's-eye view, best picture quality, 8K, higher quality, high details, ultra-high resolution, masterpiece, full of tension, realistic scene, top-level texture, top-level light and shadow, golden ratio point composition, full of creativity, color, future city, technology, smart city, aerial three-dimensional transportation, pedestrian and vehicle separation, green building, macaron color, gorgeous, bright"
image = pipe(prompt, image=init_image, num_inference_steps=2, strength=0.5, guidance_scale=0.0).images[0]
运行上面的整个代码流程,我们就能生成一张新的城郊山脉的图片。需要注意的是,当在diffusers中使用SDXL Turbo模型进行图生图操作时,需要确保num_inference_steps * strength大于或等于1。因为前向推理的步数等于int(num_inference_steps * strength)步 。比如上面的例子中,我们就使用SDXL-Turbo模型前向推理了0.5 * 2.0 = 1 步。
Stability AI官方发布的技术报告中表示SDXL Turbo和SDXL相比,在推理速度上有大幅的提升。在A100上,SDXL Turbo以207ms的速度生成一张512×512的图像(prompt encoding + a single denoising step + decoding, fp16),其中U-Net部分耗时占用了67ms 。
Rocky也测试了一下SDXL Turbo的图像生成效率,确实非常快,在V100上,4 steps生成512×512尺寸的图像基本可以做到实时响应(1.02秒,平均1 step仅需250ms) 。
在我们输入完最后一个prompt后,新生成的图像就能马上显示,推理速度确实超过了Midjourney、DALL·E 3以及之前的Stable Difusion系列模型,可谓是“天下武功,无坚不破,唯快不破”的典范。SDXL Turbo在生成速度快的同时,生成的图像质量也非常高,可以比较精准地还原prompt的描述 。
为了测试SDXL Turbo的性能,StabilityAI使用相同的文本提示,将SDXL Turbo与SDXL、LCM-XL等不同版本的文生图模型进行了比较。测试结果显示,在图像质量和Prompt对齐方面,SDXL Turbo只用1个step,就击败了LCM-XL用4个steps生成的图像,并且达到了SDXL 1.0 Base通过50个steps生成的图像效果 。
接着当我们将采样步数提高到4时,SDXL Turbo在图像质量和Prompt对齐方面都已经略微超过SDXL 1.0 Base模型:
论文里表示目前SDXL Turbo只能生成512×512像素的图片 ,Rocky推测当前开源的SDXL Turbo只在单一尺寸上进行了蒸馏训练,后续估计会有更多优化版本发布。Rocky也在512×512像素下测试了不同steps(1-8 steps)时SDXL Turbo的图片生成效果,对比结果如下所示:
可以看到当steps为1和4时,效果都非常好,并且4steps比1step效果更好 ,这是可以理解的。不过当steps大于4之后,生成的图像明显开始出现过拟合现象 。总的来说,如果是急速出图的场景,可以选择1 step;如果想要生成更高质量图像,推荐选择4 steps 。
同时Rocky测试了一下SDXL Turbo在不同尺寸(768×768,1024×1024,512×768,768×1024,768×512,1024×768共6中尺寸 )下的图像生成质量,可以看到除了1024×1024存在一定的图片特征不完善的情况,其余也具备一定的效果,但是整体上确实不如512×512的效果好。
SDXL Turbo的一个直接应用,就是与游戏相结合,获得2fps的风格迁移后的游戏画面:
SDXL Turbo的另外一个直接应用是成为SDXL的“化身” ,代替SDXL去快速验证各种AI绘画工作流的有效性,助力AI绘画领域的持续繁荣与高效发展。
SDXL Turbo发布后,未来AI绘画和AI视频领域有了更多的想象空间。一定程度上再次整合加速了AIGC领域的各种工作流应用,未来的潜力非常大。不过由于SDXL Turbo模型需要通过蒸馏训练获得,并且其中包含了GAN的对抗损失训练,在开源社区中像训练自定义的SDXL模型一样训练出特定SDXL Turbo模型,并且能保证出图的质量,目前来看是有一定难度的 。
SD Turbo模型介绍
SD Turbo模型是在Stable Diffusion V2.1的基础上,通过蒸馏训练得到的精简版本,其本质上还是一个Stable Diffusion V2.1模型,其网络架构不变。
比起SDXL Turbo,SD Turbo模型更小、速度更快,但是生成图像的质量和Prompt对齐方面不如前者。
但是在AI视频领域,SD Turbo模型有很大的想象空间,因为Stable Video Diffusion的基础模型是Stable Diffusion V2.1,所以未来SD Turbo模型在AI视频领域很可能成为AI视频加速生产的有力工具之一。
为了测试SD Turbo的性能,StabilityAI使用相同的文本提示,将SD Turbo与LCM-LoRA 1.5和LCM-LoRA XL等不同版本的文生图模型进行了比较。测试结果显示,在图像质量和Prompt对齐方面,SD Turbo只用1个step,就击败了LCM-LoRA 1.5和LCM-LoRA XL生成的图像。
diffusers库已经支持SDXL Turbo的使用运行了,可以进行文生图和图生图的任务 ,相关代码和操作流程如下所示:
from diffusers import AutoPipelineForText2Image
import torch
pipe = AutoPipelineForText2Image.from_pretrained("/本地路径/sd-turbo", torch_dtype=torch.float16, variant="fp16")
pipe.to("cuda")
prompt = "A cinematic shot of a baby racoon wearing an intricate italian priest robe."
image = pipe(prompt=prompt, num_inference_steps=1, guidance_scale=0.0).images[0]
这里要注意的是,SD Turbo模型在diffusers库中进行文生图操作时不需要使用guidance_scale和negative_prompt参数,所以我们设置guidance_scale=0.0 。
接下来,Rocky再带大家完成SD Turbo模型在diffusers中图生图的整个流程:
from diffusers import AutoPipelineForImage2Image
from diffusers.utils import load_image
import torch
pipe = AutoPipelineForImage2Image.from_pretrained("/本地路径/sd-turbo", torch_dtype=torch.float16, variant="fp16")
pipe.to("cuda")
init_image = load_image("/本地路径/test.png").resize((512, 512))
prompt = "cat wizard, gandalf, lord of the rings, detailed, fantasy, cute, adorable, Pixar, Disney, 8k"
image = pipe(prompt, image=init_image, num_inference_steps=2, strength=0.5, guidance_scale=0.0).images[0]
需要注意的是,当在diffusers中使用SD Turbo模型进行图生图操作时,需要确保num_inference_steps*strength大于或等于1。因为前向推理的步数等于int(num_inference_steps * strength)步。比如上面的例子中,我们就使用SD Turbo模型前向推理了0.5 * 2.0 = 1 步 。
7. Playground v2.5核心基础内容完整讲解
2024年2月28号,Playground发布了最新的文生图模型Playground v2.5,其是Playground v2.0模型的升级版本 。Playground v2.5在美学质量,颜色和对比度,多尺度生成以及以人为中心的细节处理 等方面有比较大的提升,使得Playground v2.5显著优于主流的开源模型(如SDXL、Playground v2和PixArt-⍺)和闭源模型(如Midjourney v5.2和DALL-E 3)。 下面,Rocky就和大家一起研究探讨Playground v2.5的优化方法。
7.1 Playground v2.5模型整体架构讲解
Playground v2.5的模型架构与SDXL的模型架构完全一致 ,在此基础上Playground v2.5设计了针对性的优化训练方法(增强颜色和对比度、改善多种长宽比的图像生成效果,以及改善以人为中心的细节 )来显著提升生成图片的质量。
总的来说,把Playground v2.5看作是SDXL的调优版本也不为过,这些优化训练的方法具备很强的兼容性,能在AI绘画领域的其他模型上进行迁移应用,非常有价值!
7.1.1 增强颜色和对比度
基于Latent Diffusion架构的AI绘画模型通常难以生成色彩鲜艳、对比度高的图像,这是SD 1.x系列以来就存在的问题。尽管SDXL在生成图片的美学质量上相比之前的版本有了显著的改进,但它的色彩和对比度依然较为柔和,有概率无法生成纯色图像或者无法将生成主体放置在纯色背景上。
这个问题源于扩散模型在扩散过程设置的noise schedule:Stable Diffusion的信噪比太高,即使在离散噪声水平达到最大时也是如此 。Offset Noise 和Zero Terminal SNR 等工作能够优化这个问题,因此SDXL在训练的最后阶段采用了Offset Noise,有一定的优化效果。
Playground v2.5模型则采取了更为直接的方法,从零开始使用EDM框架训练,而不是在SDXL的基础上进行微调训练 。EDM框架为Playground v2.5带来了显著的性能优势,EDM的noise schedule在最后的Timestep中展示出接近零的信噪比,我们可以不再使用offset noise的情况下增强AI绘画模型出图的颜色和对比度,同时能让模型在训练中更快的收敛。
下图是Playground v2.5模型和SDXL模型的生成图片效果对比,可以看到Playground v2.5模型生成的图片对比度更好: 下图是Playground v2.5模型生成图片的颜色与对比度质量:
7.1.2 改善多种长宽比的图像生成效果
在AI绘画领域中,生成多种长宽比(1:1、1:2、2:1、3:4、4:3、9:16、16:9等)尺寸的高质量图像是AI绘画模型能够在学术界、工业界、竞赛界以及用户侧受欢迎的重要能力。
目前很多主流的AI绘画模型在训练时一般只采用一种分辨率(比如通过随机或中心裁剪获得1:1尺寸)进行训练,虽然这些AI绘画模型中包含了卷积结构,卷积的平移不变性能一定程度上适应在推理时生成任何分辨率的图像,但是如果训练时只使用了一种尺寸,那么AI绘画模型大概率会过拟合在一个尺寸上,在其他不同尺寸上的出图效果会有问题(泛化性差、图像结构错误、内容缺失等) 。
为了解决这个问题,SDXL尝试了NovelAI提出的一种宽高比分桶策略,确实是有一定的效果。但是如果数据集的分辨率分布本身已经很不均衡了,这时SDXL仍然会学习到数据集里的长宽尺寸的不均衡偏见 。
Playground v2.5在SDXL的分桶策略基础上,设计了更加细分的数据Bucket管道,来确保一个更平衡的桶采样策略。新的分桶策略避免了AI绘画模型在训练时对尺寸的灾难性遗忘,并帮助AI绘画模型不会偏向某个特定的尺寸 。
7.1.3 改善以人为中心的细节
改善以人为中心的细节,即使AI绘画模型的输出结果与人类偏好对齐 。在AIGC时代,不管是AI绘画大模型还是AI对话大模型,都存在模型产生“幻觉”的情况。这在AI绘画领域的具体表现包括写实人物的人体特征崩坏(如手、脸、躯干等结构错误和特征缺失),这使得一张构图和风格都非常高质量的图片也可能存在“恐怖谷”效应。
为了缓解这个问题,Playground v2.5设计了一种类似于SFT(SFT是在LLM s中常用的策略,用于使模型与人类偏好对齐并减少错误 )的对齐策略,用于AI绘画模型。新的对齐策略使Playground v2.5在至少四个重要的以人为中心的类别上超越了SDXL的效果:
面部细节、清晰度和生动度
眼睛的形状和凝视状态
头发的纹理质地
整体的光照、颜色、饱和度和景深
7.2 Playground v2.5模型效果测试
Playground官方在AIGC时代引入了互联网产品思维 ,直接将Playground v2.5模型上线到产品中让用户进行测试评估(用户评估,User Evaluations)。Playground官方认为这是收集用户反馈、测评AI绘画模型的最佳环境与方式,并且是最严格的测试 ,能判断AI绘画模型是否真正为用户提供了有价值和收到用户喜爱,从而能够反哺整个AI绘画生态与社区。 我们首先来看一下Playground官方的模型测试评估效果。
首先将Playground v2.5与世界级的主流开源AI绘画模型SDXL(提高了4.8倍)、PixArt-α(提高了2.4倍)和Playground v2(提高了1.6倍),以及世界级的闭源模型Midjourney v5.2(提高了1.2倍)和DALL·E 3(提高了1.5倍)进行了对比测试,Playground v2.5的美学质量显著优于当前最先进的这些AI绘画模型。
接着,在9:16、2:3、3:4、1:1、4:3、3:2、16:9等多分辨率尺寸生成质量方面,Playground v2.5也远远超过了SDXL模型。
人像写实图像是AI绘画领域的生成主力军,能占到AI绘画生成总量的80%左右 。所以针对人像生成这块,官方将Playground v2.5与SDXL、RealStock v2两个模型进行测试对比,RealStock v2模型在SDXL的基础上针对人像场景进行了微调训练。从下图中可以看出,Playground v2.5在人像生成方面的美学质量远远超过了这两个模型。
最后,在MJHQ-30K评测上,Playground v2.5在总体FID和所有类别FID指标(所有FID指标都是在1024×1024的分辨率下计算的 )上都超过了Playground v2和SDXL,特别是在人物和时尚类别上。MJHQ-30K评测结果与用户评估的结果一致,这也表明人类偏好与MJHQ-30K基准的FID得分之间存在着相关性。 目前Playground v2.5模型可以在diffusers中直接使用,可以进行文生图和图生图的任务,生成1024×1024分辨率及以上的高质量图片 。相关代码和操作流程如下所示:
from diffusers import DiffusionPipeline
import torch
pipe = DiffusionPipeline. from_pretrained(
"/本地路径/playground-v2.5-1024px-aesthetic" ,
torch_dtype= torch. float16,
variant= "fp16" ,
) . to( "cuda" )
prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
image = pipe( prompt= prompt, num_inference_steps= 50 , guidance_scale= 3 ) . images[ 0 ]
我们在使用Playground v2.5模型时,推荐使用EDMDPMSolverMultistepScheduler调度器,能够生成更加清晰的图像,这时推荐设置guidance_scale = 3.0 。如果我们使用EDMEulerScheduler调度器,推荐设置guidance_scale = 5.0。
Playground官方认为SDXL系列模型架构还有很大的优化空间 ,主要方向包括:更好的文本-图像对齐效果、增强模型的泛化能力、增强Latent特征空间、更精确的图像编辑等。
8. AI绘画领域的未来发展
8.1 AI绘画的“数据工厂”
看完本文的从0到1进行Stable Diffusion XL模型训练章节内容,大家可能都有这样一种感觉,整个数据处理流程占据了整个SDXL模型开发流程的60-70%甚至更多的时间,并且在数据量级不断增大的情况下,数据产生的内容护城河开始显现 ,模型的“数据飞轮”效应会给产品带来极大的势能 。
可以看到,数据侧是如此重要,AIGC时代也需要像传统深度学习时代一样,设立“数据工厂”为AIGC模型的优化迭代提供强有力的数据支持 。
在传统深度学习时代,数据工厂能够将图片中的目标类别进行精准标注 ;而到了AIGC时代,数据工厂的标注内容就发生了变化,需要对图片进行理解,并且通过文字与关键词完整描述出图片中的内容 。
除此之外,数据工厂的数据收集、数据整理、数据供给等功能都是跨周期的需求 ,在传统深度学习时代已经证明,数据工厂能大大增强算法团队的工作效率,为整个AI算法解决方案和AI产品的开发、交付、迭代提供有力支持。
Rocky相信,未来AIGC时代的数据工厂会是一个非常大的机会点 ,作为AIGC领域的上游产业,不管是大厂自建数据工厂,还是专门的AIGC数据工厂公司,都会像在传统深度学习时代那样,成为AIGC产业链中不可或缺的关键一环 。
8.2 AI绘画的“工作流”产品
2022年是AIGC元年,各路大模型争先恐后的发布,“百模大战”一触即发 。
但是,市场真的需要这么多大模型吗?用户真的需要这么多大模型吗?
答案显而易见是否定的 。并且大模型并不是万能的,有着明显的能力边界,单个大模型不足以形成足够的技术护城河与产品普惠 。
历史不总是重复,但是会押韵。从AIGC之前的深度学习时代,也有非常多的公司迷信当时的人脸检测、人脸识别、目标检测、图像分割、图像分类算法。但时间告诉我们,深度学习时代的红利与价值,最后只赋能了互联网行业、安防行业、智慧城市行业以及智慧工业等强B端行业 。
那么,AIGC时代和深度学习时代的区别是什么呢?
也很简单,AIGC时代有类似移动互联网时代那样的ToC可能性 。因为不管是开源社区,还是AIGC时代的互联网大厂和AI公司,亦或者是绘画领域专业的个人,都开始尝试大模型+辅助工具的“工作流”产品,并且让这些产品触达每个用户 。像妙鸭相机等APP已经显现移动互联网时代独有的快速商业落地与流量闭环能力。
Rocky在这里再举一些热门AI绘画“工作流”产品例子:
Stable Diffusion + LoRA + ControlNet的“三巨头”组合。
Stable Diffusion + 其他生成式模型(ChatPT,GAN等)的组合。
Stable Diffusion + 深度学习模型(分类,分割,检测等)的组合。
Stable Diffusion + 视频模型的组合。
Stable Diffusion + 数字人模型的组合。
…
这些“工作流”式的AIGC产品,不管是对ToB还是ToC,都有很强的普惠性与优化迭代可能性。同时可以为工业界、学术界以及竞赛界的AI绘画未来 发展带来很多的势能与“灵感”,Rocky相信这会成为AI绘画行业未来持续繁荣的核心关键。
8.3 AI绘画模型未来需要突破的瓶颈
SDXL虽然是先进的开源AI绘画模型,但是其同样存在一些需要突破的瓶颈。
SDXL有时仍难以处理包含详细空间安排和详细描述的复杂提示词。同时手部生成依旧存在一定的问题,会出现多手指、少手指、鸡爪指、断指以及手部特征错乱等情况。除此之外,两个概念的互相渗透、互相混淆,或者是概念溢出等问题还是存在。
下图中展示了这些问题,左上角的图片展示了手部生成失败的例子;左下角和右下角的图片展示了概念渗透,互相混淆的例子;右上角的图片展示了对复杂描述与详细空间安排的提示词生成失败的例子: 客观来说,目前AI绘画领域的模型一定程度上都存在上述的瓶颈,既然有瓶颈,那么就有突破的方向与动力 。
SDXL论文中也给出了future work,向我们阐述了未来图像生成式模型的研究重点(科研界风向标 ):
Single stage(单阶段模型) :目前,SDX是二阶段的级联模型,使得显存占用和运算耗时都增大了。所以未来的一个价值点是想办法提出和SDXL有相似性能或者更强性能的单阶段模型。
Text synthesis(文本合成) :持续优化Text Encoder模型,提升模型对文本的理解能力。使用更加细粒度的文本编码器或者使用额外的约束增加文本与图像的一致性,或许是AI绘画领域的X因素。
Architecture(架构) :SDXL论文中简单地尝试了基于纯Transformer的架构,比如UViT和DiT,目前暂没有太大的进展。但是SDXL论文中认为通过精心的超参数研究,最终将能够扩展到以Transformer结构为主导的更高效的模型架构中。
Distillation(蒸馏) :通过指导性蒸馏、知识性蒸馏和逐步蒸馏等技术,来降低SDXL推理所需的计算量,并减少推理耗时。
New Model(新模型) :未来基于连续时间的EDM框架是非常有势能的候选扩散模型框架,因为它允许更大的采样灵活性,并且不需要噪声调度修正。
8.4 构建AI绘画产品的开发流程
就如同深度学习时代一样,构建AIGC时代算法产品与算法解决方案的开发流程是每个AIGC公司的必修课。
与传统深度学习时代作类比的话,我们可以发现AIGC时代中的算法产品开发流程有很多与之相似的地方。
下面是Rocky在AIGC时代积累的算法产品开发流程方法论,大家可以参考:
产品需求定义(与传统深度学习类似)
数据收集、筛选、标注(与传统深度学习不同,需要细分领域的专家对数据进行评估)
模型选择(与传统深度学习无脑选择的YOLO,ResNet,U-Net不同,AIGC时代对模型的选择也需要根据细分领域进行评估)
模型训练(与传统深度学习类似)
模型测试评估(与传统深度学习不同,需要细分领域的专家通过Prompt工程挖掘评估模型能力 )
前处理与后处理(与传统深度学习类似)
工程化部署(与传统深度学习类似,在传统深度学习只能ToB的基础上,多了ToC可能性,既能端侧部署,也能上线部署)
8.5 AI绘画的多模态发展
在2023年OpenAI的开发者大会上,GPTs这个重量级产品正式发布,让人感到惊艳的同时,其生态快速繁荣。
如果说2023年年初是“百模大战”的话,那么2023年的年末就是“千GPTs大战” 。
如此强的ToC普惠是传统深度学习时代未曾出现的,就连移动互联网时代在如此的势能面前都稍逊一筹,然而AIGC时代才刚刚开始 。
所以Rocky认为AIGC时代的AI产品与应用会以AI绘画+AI视频+AI对话+AI语音+AI大模型+数字人等多模态的形式呈现 ,AI绘画会成为AI应用的关键一环,发挥重要作用。多模态的AI产品形态,会极大增强AI产品的ToC/ToB的普惠势能,也是AIGC时代发展的必经之路 。
8.6 AI绘画的轻量化与端侧部署
在传统深度学习时代,AI模型的轻量化和端侧部署为ToB的可能性打下了坚实的基础,在端侧快速高效的使用目标检测、图像分割、图像分类、目标跟踪等算法,能够为智慧城市、智慧交通、智慧工业能领域创造非常大的价值。
历史不会重复,但会押韵 。在AIGC时代中,AI绘画模型的轻量化和端侧部署依旧在ToC和ToB领域有着巨大的势能与市场,在可预见的未来,如果每个人都能方便快速的在端侧设备中使用AI绘画模型生成内容,这将大大推动各行各业的变革与重构。
同时,实时高效的生成AIGC内容,将是未来的元宇宙时代的“核心基建” 。
更多思考与感悟,Rocky会持续补充,大家敬请期待!码字确实不易,希望大家能一键三连,多多点赞!
9. 推荐阅读
Rocky会持续分享AIGC的干货文章、实用教程、商业应用/变现案例以及对AIGC行业的深度思考与分析 ,欢迎大家多多点赞、喜欢、收藏和转发 ,给Rocky的义务劳动多一些动力吧,谢谢各位!
9.1 深入浅出完整解析Stable Diffusion(SD)核心基础知识
Rocky也对Stable Diffusion 1.x-2.x系列模型的核心基础知识 做了全面系统的梳理与解析:
深入浅出完整解析Stable Diffusion(SD)核心基础知识
9.2 深入浅出完整解析Stable Diffusion中U-Net的前世今生与核心知识
Rocky对Stable Diffusion中最为关键的U-Net结构 进行了深入浅出的全面解析,包括其在传统深度学习中的价值和在AIGC中的价值:
深入浅出完整解析Stable Diffusion中U-Net的前世今生与核心知识
9.3 深入浅出完整解析LoRA(Low-Rank Adaptation)模型核心基础知识
对于AIGC时代中的**“ResNet”——LoRA模型**,Rocky也进行了深入浅出的全面讲解:
深入浅出完整解析LoRA(Low-Rank Adaptation)模型核心基础知识
9.4 深入浅出完整解析ControlNet核心基础知识
AI绘画作为AIGC时代的一个核心方向,开源社区已经形成以Stable Difffusion为核心,ConrtolNet和LoRA作为首要AI绘画辅助工具的变化万千的AI绘画工作流。
ControlNet正是让AI绘画社区无比繁荣的关键一环,它让AI绘画生成过程更加的可控,更有助于广泛地将AI绘画应用到各行各业中 :
深入浅出完整解析ControlNet核心基础知识
9.5 深入浅出完整解析主流AI绘画框架核心基础知识
AI绘画框架正是AI绘画“工作流”的运行载体,目前主流的AI绘画框架有Stable Diffusion WebUI、ComfyUI以及Fooocus等 。在传统深度学习时代,PyTorch、TensorFlow以及Caffe是传统深度学习模型的基础运行框架,到了AIGC时代,Rocky相信Stable Diffusion WebUI就是AI绘画领域的“PyTorch”、ComfyUI就是AI绘画领域的“TensorFlow”、Fooocus就是AI绘画领域的“Caffe” :
深入浅出完整解析主流AI绘画框架(Stable Diffusion WebUI、ComfyUI、Fooocus)核心基础知识
9.6 手把手教你成为AIGC算法工程师,斩获AIGC算法offer!
在AIGC时代中,如何快速转身,入局AIGC产业?如何成为AIGC算法工程师?如何在学校中系统性学习AIGC知识,斩获心仪的AIGC算法offer?
Don‘t worry,Rocky为大家总结整理了全面的AIGC算法工程师成长秘籍 ,为大家答疑解惑,希望能给大家带来帮助:
手把手教你成为AIGC算法工程师,斩获AIGC算法offer!(持续更新)
9.7 AIGC产业的深度思考与分析
2023年3月21日,微软创始人比尔·盖茨在其博客文章《The Age of AI has begun》中表示,自从1980年首次看到图形用户界面(graphical user interface)以来,以OpenAI为代表的科技公司发布的AIGC模型是他所见过的最具革命性的技术进步。
Rocky也认为,AIGC及其生态,会成为AI行业重大变革的主导力量。AIGC会带来一个全新的红利期,未来随着AIGC的全面落地和深度商用,会深刻改变我们的工作、生活、学习以及交流方式,各行各业都将被重新定义,过程会非常有趣。
那么,在此基础上,我们该如何更好的审视AIGC的未来?我们该如何更好地拥抱AIGC引领的革新?Rocky准备从技术、产品、商业模式、长期主义等维度持续分享一些个人的核心思考与观点,希望能帮助各位读者对AIGC有一个全面的了解 :
2023年“疯狂三月”之后,深入浅出全面分析AIGC的核心价值 (持续更新)
9.8 算法工程师的独孤九剑秘籍
为了方便大家实习、校招以及社招的面试 准备,同时帮助大家提升扩展技术基本面 ,Rocky将符合大厂和AI独角兽价值的算法高频面试知识点撰写总结成**《三年面试五年模拟之独孤九剑秘籍》,并制作成 pdf版本**,大家可在公众号WeThinkIn 后台**【精华干货】菜单**或者回复关键词“三年面试五年模拟 ”进行取用:
【三年面试五年模拟】算法工程师的求职面试秘籍
【三年面试五年模拟】算法工程师的求职面试“独孤九剑”秘籍(持续更新中)
9.9 深入浅出完整解析AIGC时代中GAN系列模型的前世今生与核心知识
GAN网络作为传统深度学习时代的最热门生成式Al模型,在AIGC时代继续繁荣,作为Stable Diffusion系列模型的“得力助手”,广泛活跃于Al绘画的产品与工作流中:
深入浅出完整解析AIGC时代中GAN系列模型的前世今生与核心知识
Rocky一直在运营技术交流群 (WeThinkIn-技术交流群),这个群的初心主要聚焦于AI行业话题的讨论与研究,包括但不限于算法、开发、竞赛、科研以及工作求职等。群里有很多AI行业的大牛,欢迎大家入群一起交流探讨~(请备注来意,添加小助手微信Jarvis8866,邀请大家进群~)
文章来源于互联网:深入浅出完整解析Stable Diffusion XL(SDXL)核心基础知识
上一篇AIGC全面介绍
下一篇文心一言赋能问卷生成,打造高效问卷调研工具