可随意转载!Update2023.12.02

前言

Diffusion作为GAN的后起之秀,以简洁的数学推导,强大的文/图生图的能力,把GAN赶下了神坛,而Stable Diffusion作为其中开源的版本在社区广泛流传。其中Stable Diffusion WebUI更是让广大非科技工作者也体验到了二次元涩图的乐趣。

一、扩散模型发展历程

1.1 2020年论文《Denoising Diffusion Probabilistic Models》

UC伯克利的大神Jonathan Ho(后来加入了Google)构建了一个离散步骤的马尔可夫链,不断加入随机噪声直至其成为无法辨识的纯噪声为止的前向过程。这个过程对应着分子热动力学里的扩散过程。而模型学习的则是如何从噪声分布里出发,逐渐去除噪声将图片还原至原始的数据分布中。如下图所示:

经过推导从时间步0到任意时间步t的扩散(diffusion)过程公式如下:

因为XT 是符合正态分布的噪声图,所以参数取值因满足下面条件:

从上面公式可以看出扩散(diffusion)就是:从x0开始加连乘噪声z(标准正态分布),很容易理解。

训练过程是输入图片x0,t,噪声ε ,最小化ε θ(Unet神经网络)生成的噪声(Z飘)和输入噪声 ε 的loss,迭代优化得到最优Unet网络

去噪(denoise)过程理论上只需要把上面公式做简单转换即可,但是实验结果表明直接从xt去噪到x0生成图片太模糊,实际上去噪过程是一步步进行的,也就是从xT,xT-1, xt, xt-1,x0 分多步来做的。去噪(denoising)公式如下:

xt-1跟xt与Z飘的关系,其中 xt 是已知噪声图,Z飘是通过Unet神经网络计算,Z是标准正态分布,α、β都是常量

从上面公式可以看出去噪(denoising)就是:用Xt减去扩散过程加的噪声Z飘,重复迭代到X0。另外加了扰动z(标准正态分布)帮助神经网络做梯度下降,很容易理解。

从噪声XT,for循环执行去噪公式,其中 ε θ是上一步训练出的Unet用来生成Z飘,最后得到一张清晰图x0。其中1-αt = βt,且t=1时不加扰动噪声z

1.2 2021年论文《Diffusion Models Beat GANs on Image Synthesis》

微软旗下的OpenAI也不甘示弱,通过扎实的理论和丰富的消融实验论证了扩散模型优于GAN系列模型。受到GAN算法的启发,首次引入classifier,通过权重控制在生成“威尔士柯基狗”例子上取得了很好的效果。

它的贡献是首次提出了分类(classifier),实现了用分类方法控制扩散模型输出。

1.3 文/图生图

2021年论文《More Control for Free! Image Synthesis with Semantic Diffusion Guidance》和论文《DiffusionCLIP: Text-Guided Diffusion Models for Robust Image Manipulation》等,引入了”文生图”,突破了GAN的局限性(文生图是out domain,GAN+CLIP的效果比较差,比如用手遮住一部分脸,GAN就很难生成那只手),扩散模型这方面明显强过GAN系列模型,大大提升了这个科技领域的上限。

GAN算法是无法reconstruct这只手

这篇文章的意义是论证了扩展模型强于GANs,此文之后学术界再无GANs。

1.4 Classifier-Free 引导的文/图生图

2022年大神Jonathan Ho入职google后发表论文《Classifier-Free Diffusion Guidance》(简称CFG)提出不管是引入classifier或者用文字、图片等形式去引导扩散模型,都需要给扩散模型增加额外的网络,不利于扩散模型做得更大。Classifier-Free模型的好处是不需要训练额外的Classifier网络,而且对原始的无条件扩散网络改动极小,只需要在训练代码中增加随机dropout条件,在sampling代码中混合条件和无条件的score estimates。

这篇论文非常重要。这条路线诞生了三个著名的扩散模型:Google的Imagen,OpenAI的GLIDE模型,开源的Stable Diffusion。

OpenA动用大量算力做出了产品GLIDE。使用自家的CLIP来替代外部模型的classifier,直接输入扩散模型做训练。

Google还以颜色,做出了Imagen。使用了T5系列的文本编码,作为控制条件直接输入扩散模型做训练。使用了cross-attention关联文本编码和图片编码。

开源社区不甘示弱,研发出了Stable Diffusion,把图片缩小48倍,在latent space中实现了更节约和高效的扩展算法,同时使用了openClip。在这个开源模型的基础上,还出现了更多算法:

  • 基于SD的微调算法HyperNetwork劫持CrossAttention插入Style
  • 从大语言模型引入的LoRA算法修改CrossAttention权重,实现SD模型特性化微调

SD中的重要步骤VAE处理图片域到latent space转换,研究者发现SD的细节(例如人脸)恢复存在问题。2023年11月,openAI承认是它训练的VAE预训练模型导致的这些问题,并提出了新的VAE模型

1.5 能指定人/物体的生成算法DreamBooth

2022年的谷歌论文《DreamBooth: Fine Tuning Text-to-Image Diffusion Models for Subject-Driven Generation》提出了定义一个概念/物体X,通过微调让扩散模型理解X并在生成的时候可以根据提示词+种类词生成对应的X’。

dreambooth算法的根本问题是需要对每个人/物体做训练,因此无法大规模应用。

1.6 控制生成模型ControlNet

ControlNet来自论文《Adding Conditional Control to Text-to-Image Diffusion Models》,通过小数据、小算力的训练就可以给LDM增加控制模型(注意:它是一系列针对不同用途的模型,不是算法),在执行DDIM生成的时候,可以做到条件控制。例如:pose,canny,inpaint等等。最新版本是V1.1。

它的创新点是使用了zero inited layer,使得可以不动预训练模型,复制一份原模型部分网络结构做旁路训练,结合预训练模型和旁路模型实现生成控制。

1.7 GLIGEN算法

这个算法来自微软的实习生,主要作用是可以结合开放集合的定位算法,实现对图片中的某一个位置的替换。它的代码思路不错,有很好的借鉴价值。

1.8 T2I-Adapter算法

作者认为sd的生成能力没有问题,但是控制能力有问题,所以训练若干个adapter来做控制。

https://huggingface.co/docs/diffusers/main/en/api/pipelines/stable_diffusion/adapter

1.9 Custom Diffusion

来自Adobe公司的论文《Multi-Concept Customization of Text-to-Image Diffusion》,又名custom diffusion,代码地址:Custom Diffusion。它的性能优于dreambooth和textual Inversion

此项目已经被diffusers实现,文档路径分别是:

https://huggingface.co/docs/diffusers/main/en/training/custom_diffusion

训练Custom Diffusion

  1. 用脚本去网址https://knn.laion.ai/knn-service从laion_400m数据集中搜索并下载了200张对应的类别(class)用来做正则化。

2. RTX3090需要开xformers,否则会内存溢出。关联pytorth 1.13.1+cu117只能用conda安装,因为pip目前只有cu118和cu121两个版本。每个物体都需要训练时间3-4分钟。

python train_custom_diffusion.py \
  --pretrained_model_name_or_path=$MODEL_NAME  \
  --instance_data_dir=$INSTANCE_DIR \
  --output_dir=$OUTPUT_DIR \
  --class_data_dir=./real_reg/samples_cat/ \
  --with_prior_preservation --real_prior --prior_loss_weight=1.0 \
  --class_prompt="cat" --num_class_images=200 \
  --instance_prompt="photo of a skssks cat"  \
  --resolution=512  \
  --enable_xformers_memory_efficient_attention \
  --train_batch_size=2  \
  --learning_rate=1e-5  \
  --lr_warmup_steps=0 \
  --max_train_steps=250 \
  --scale_lr --hflip  \
  --modifier_token "skssks" 

二、Stable Diffusion WebUI软件安装

  1. 打开科学上网工具
  2. 安装Python(版本号3.10.6)并勾选“Add Python To Path”
  3. 安装git
  4. Github网址拖最新源码
  5. 去抱抱脸网站下载stable diffusion 1.5的模型文件,大约4G。放到目录C:\AlexOuyang\app\SD\models\Stable-diffusion
  6. 运行webui-user.bat,下载很多依赖后,打开浏览器访问http://127.0.0.1:7860就可以使用了。

三、仿写Stable Diffusion WebUI

3.1 各模型支持的提示词权重

在modules中有个文件叫sd_samplers.py,里面会调用prompt_parser.py。这个文件包含了stable-diffusion-webui的特殊提示词语法,例如:“((best quality))”会被处理成[‘best quality’, 1.21]最终传递给Text Encoder做tokenize。

实际上根据测试,语法(())本身在stable diffusion上就是支持的,请看下面代码

import torch
from PIL import Image
from diffusers import StableDiffusionPipeline, UniPCMultistepScheduler

prompts = ["a red cat playing with a ball","a red cat playing with a (ball)","a red cat playing with a ((ball))",
            "a red cat playing with a (((ball)))","a red cat playing with a ['ball',1.1]"]

def concat_images(images):
    """Generate composite of all supplied images."""
    # Get the widest width.
    width = max(image.width for image in images)
    # Add up all the heights.
    height = sum(image.height for image in images)
    composite = Image.new('RGB', (width, height))
    # Paste each image below the one before it.
    y = 0
    for image in images:
        composite.paste(image, (0, y))
        y += image.height
    return composite

pipe = StableDiffusionPipeline.from_pretrained("CompVis/stable-diffusion-v1-4")
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
pipe.to("cuda")
pipe.enable_xformers_memory_efficient_attention()
generator = torch.Generator(device="cuda").manual_seed(13)
print(prompts)
images = pipe(prompts, generator=generator, num_inference_steps=20).images
concat_image = concat_images(images)
concat_image.save('prompt_weighting_test.jpg')

3.2 中文提示词

AltDiffusion支持中文提示词

四、使用Dreambooth for SD插件

从LV牌官网找几张包包各个角度的图片,生成一张全新的此包包的图片。

4.1 安装插件

4.2 创建空模型(create)

其中source checkpoint选择sd1.5模型,第一次使用会下载一些依赖包,之后每次创建模型大约2分钟左右。

4.3 准备数据

4.4 参数设置(settings)

设置学习率为0.00001,设置高级–>8bit Adam和fp16

4.5 配置物品参数(concepts)

点击“Training Wizard (Object/Style)”,这时候Settings会自动调节为Object/Style默认值。插件tip建议训练物体不需要用prior-preservation。

点击上方菜单“Train”开始训练

4.6 合成ckpt文件

训练完成后,点击Generate Ckpt按钮合成一个大的ckpt文件。

4.7 测试效果

切换到txt2img

五、使用ControlNet For SD插件

找一张模特的姿势图片,生成同样姿势的另外一个模特的图片。

5.1 安装插件

5.2 下载pose模型

从抱抱脸网站下载control_any3_openpose.pth,下载后复制到文件夹C:\AlexOuyang\app\SD\extensions\sd-webui-controlnet\models,大约有5.3G,请耐心等待。

5.3 准备数据

从商业测试数据选取456号模特中的任意一张图作为姿势引导图

5.4 配置参数

在文生图页签中选中ControlNet,配置如下:

5.5 点击生成

六、源码理解

stable-diffusion-webui分为几个部分:

  • launch.py : prepare_environment() 安装依赖库,下载github源码
  • webui.py : 安装好一次后就可以跳过前面步骤,直接从这个文件启动程序。它分为两种模式:api_only()和webui()。
  • 如果使用了webui模式会使用框架gradio,它定义了call_queue.py做异步,分离了前端网页和后台算法,保证用户不会卡死。下面以文生图为例介绍:
  • txt2img.py : 从队列中取任务并调用processing.py中的process_images
  • processing.py : 它的方法process_images_inner是文生图和图生图都要用的。

process_images_inner关键流程:

  1. 通过p.scripts.process(p)调用alwayson脚本(包含插件里面的脚本);
  2. 通过extra_networks.parse_prompts和p.scripts.process_batch(p, batch_number=n, prompts=prompts, seeds=seeds, subseeds=subseeds)处理扩展网络;
  3. 通过samples_ddim = p.sample(xxxx)执行生成过程,得到张量samples_ddim;
  4. 执行p.scripts.postprocess_batch(p, x_samples_ddim, batch_number=n)后处理x_samples_ddim;
  5. 迭代x_sample执行p.scripts.postprocess_image(p, pp)后处理image最后得到生成结果

如下流程图所示:

附录

huggingface 实现Lora

主流调优sd模型的方法:

从DDPM到GLIDE:基于扩散模型的图像生成算法进展

Q1:xformers没有被安装

请打开webui-user.bat,修改下面一行

set COMMANDLINE_ARGS=--xformers

Q2:报错Repo id must use alphanumeric chars or ‘-‘, ”, ‘.’, ‘–‘ and ‘..’ are forbidden, ‘-‘ and ‘.’ cannot start or end the name, max length is 96_

请把项目根目录改名叫SD(或者任何不含特殊字符的名字)

Q3: TypeError: ‘NoneType’ object is not subscriptable | Error verifying pickled file from C:\AlexOuyang\app\SD\models\Codeformer\

下载Codeformer未完成,删掉models/Codeformer/里面的对应模型,重新下载。

测试用图

参考资料

生成扩散模型基础(外链)

生成扩散模型和autoencoder(外链)

生成扩散模型改进(外链)

提示词教程(外链)

fastapi教程

stable diffusion图文关系可解释性(diffusion attentive attribution maps)

stable diffusion 详解(外链)