Stable Diffusion原理详解(附代码实现)

[复制链接]
发表于 2026-2-8 11:26:32 | 显示全部楼层 |阅读模式
一、媒介

回顾AI绘画的汗青,GAN(Generative Adversarial Nets)是比力出众的一个。GAN的出现让AI绘画成为大概,当时GAN给AI绘画提供了一种新的思绪,现在回顾当时的绘画可以算是相当粗糙。

gan-results.jpg
初代GAN出现后,出现了大量GAN的变种,好比StyleGAN、CycleGAN、DCGAN等。而StyleGAN已经可以天生非常传神的图像了,下面是StyleGAN的一些结果。

stylegan-results.jpg
GAN提出已经已往十年,AI绘画也得到了颠覆性的进步。Diffusion Model(DM)徐徐取代了GAN在AI绘画范畴的职位。在此底子上,AI绘画范畴还融合了别的深度学习方法,好比Controlnet、LoRA等。现在,AI绘画到达了以假乱真的地步,同时给与用户极高的可控性,对资源的要求也徐徐低沉,每个人都可以在本身的电脑上运行AI绘画模子。
本日我们的主角是Stable Diffusion,它是现在最盛行的开源DM。基于Stable Diffusion,开源社区涌现了繁多的开源项目和模子。好比Stable Diffusion Webui、Comfyui、Fooocus等集成应用;分享模子的Civitai网站;HuggingFace提供的Diffusers模块。
本日我们将先容Stable Diffusion的团体架构,分解每个部件,末了借助Diffusers模块实现AI绘画。
二、网络布局

Stable Diffusion由多个子网络构成,包罗文本编码器、UNet和VAE三大部门。组合在一起可以看做一个吸收文本输入,输出图像的模子。下面我们将从团体出发,而后拆分每个部件。
2.1 团体架构

Stable Diffusion的架构如图所示:

stable-diffusion-structure.jpg
团体上看是一个吸收文本输入,并输出图像的模子。Stable Diffusion处理处罚的过程如下:

  • 输入文本,利用CLIP模子对文本举行编码,得到文本Embedding
  • 从潜空间天生噪声Latent
  • 将文本Embedding和Latent输入UNet模子,推测Latent中的噪声
  • 将去除Latent中的噪声,去除噪声后的结果重新赋值为Latent
  • 重复步调3、4
  • 将Latent传入VAE解码器,得到终极图片
模子的核心是一个UNet噪声推测网络。差别于GAN直接从噪声中天生图片,Stable Diffusion会举行多次推测噪声并降噪,终极天生图片。
2.2 文本编码器

Stable Diffusion是一种带条件的图像天生模子,可以根据输入的文本天生与文本符合的图片。我们可以直接利用训练良好的Bert模子作为文本编码器,但是如许天生的文本向量和图像的关系不太密切,为了图像天生能更遵照文本条件,Stable Diffusion利用了CLIP模子。
CLIP模子的提出是为了更好的办理视觉使命,CLIP可以在zero-shot的情况下在ImageNet上与ResNet50有划一的表现。
下面是OpenAI提供的CLIP工作图:

clip-training-steps.jpg
从布局上来看,CLIP模子由两个Encoder构成,分别是用来编码文本的TextEncoder和用来编码图片的ImageEncoder。CLIP的训练数据是一堆“图片-文本”对情势,其工作模式如下:

  • 训练TextEncoder和ImageEncoder,最大化ItTt(图片向量与相应的文本向量相似度)
  • 利用分类标签天生句子,“a photo of a {object}”
  • 输入图片得到It,找到最相似的句子向量Tk,改句子对应的标签就是图片标签 在完成训练后就可以得到比力精彩的文本编码器,而后两步则是为图像分类做准备。
2.3 VAE模子

VAE模子在Diffusion Model内里并非须要的,VAE在Stable Diffusion中作为一种有用利用资源的方法,镌汰了图片天生的资源需求。下图是VAE的布局,此中c是一个可选的条件。

vae-structure.png
VAE由Encoder和Decoder两个部门构成,起首必要输入x,颠末Encoder编码后,得到(μ,σ),分别表现均值和方差,这两个变量可以确定一个分布,然后在当前分布中采样出样本z。z通常是一个比x维度更低的向量。
采样出来的z输入Decoder,我们盼望Decoder的输出与输入的x越靠近越好。如许我们就到达了图像压缩的结果。
在训练Stable Diffusion时,我们会把图片输入VAE的Encoder,然后再拿来训练UNet,如许我们就可以在更低的维度空间训练图像天生模子,如许就可以镌汰资源的斲丧。
2.4 UNet模子

UNet模子布局与VAE非常相似,也是Encoder-Decoder架构。在Stable Diffusion中,UNet作为一个噪声推测网络,在绘画过程中必要多次推理。我们先不思量VAE的到场,来看看UNet在Stable Diffusion中的作用。
现实上UNet在Stable Diffusion中充当噪声推测的功能。UNet吸收一张带有噪声的图片,输出图片中的噪声,根据带噪声的图片和噪声我们可以得到加噪前的图片。这个降噪的过程通常会重复数十遍。
知道UNet的作用后,我们就必要创建数据集了。我们只必要图片即可,拿到图片对该图片举行n次加噪,直到原图变成完全噪声。而加噪前的图片可以作为输入,加噪后的数据可以作为输出。如图所示:

noising_step.jpg
在加噪的过程中,噪声徐徐增大。因此在降噪的过程中,我们必要有噪声图片,以及当前加噪的step。下图是噪声推测部门的布局:

noise-predicter.jpg
末了图像天生的步调就是不绝降噪的步调:

denoising-step.jpg
末了,我们再参加VAE。我们加噪和推测噪声的步调不再是作用在原图上,而是作用在VAE Encoder的输出上面,如许我们就可以在较小的图像上完成UNet的训练,极大镌汰资源的斲丧。

unet-vae.png
现在只必要在UNet的输入中再参加文本变量就是完备的Stable Diffusion了。
三、Diffusers模块

现在我们已经知道Stable Diffusion的原理,为了加深明确,下面利用Diffusers模块实现Stable Diffusion的全过程。下面的代码必要利用到pytorch、transformers和diffusers模块。
3.1 利用pipeline

HuggingFace中的模块提供了许多pipeline用于各种使命,而Stable Diffusion则是Text-to-image范例的使命,我们可以利用下面几句代码完成文生图:
  1. from diffusers import AutoPipelineForText2Image
  2. import torch
  3. pipeline = AutoPipelineForText2Image.from_pretrained(
  4. "runwayml/stable-diffusion-v1-5", torch_dtype=torch.float16, variant="fp16"
  5. ).to("cuda")
  6. image = pipeline(
  7. "stained glass of darth vader, backlight, centered composition, masterpiece, photorealistic, 8k"
  8. ).images[0]
  9. image
复制代码
天生图像如下:

generated01.PNG
上面是一种简朴的调用方式,下面我们加载各个部件,手动完成图像天生的过程。
3.2 加载各个部件

除了pipeline直接加载,我们还可以分部件加载,分别加载CLIP、UNet和VAE,代码如下:
  1. from tqdm.auto import tqdm
  2. from PIL import Image  
  3. import torch  
  4. from transformers import CLIPTextModel, CLIPTokenizer  
  5. from diffusers import AutoencoderKL, UNet2DConditionModel, DDPMScheduler  
  6.   
  7. # 加载模型  
  8. model_path = "runwayml/stable-diffusion-v1-5"  
  9. vae = AutoencoderKL.from_pretrained(model_path, subfolder="vae")  
  10. tokenizer = CLIPTokenizer.from_pretrained(model_path, subfolder="tokenizer")  
  11. text_encoder = CLIPTextModel.from_pretrained(  
  12. model_path, subfolder="text_encoder"  
  13. )  
  14. unet = UNet2DConditionModel.from_pretrained(  
  15. model_path, subfolder="unet"  
  16. )  
  17. scheduler = DDPMScheduler.from_pretrained(model_path, subfolder="scheduler")
  18. # 使用gpu加速  
  19. torch_device = "cuda"  
  20. vae.to(torch_device)  
  21. text_encoder.to(torch_device)  
  22. unet.to(torch_device)
复制代码
在这里我们还加载了Scheduler,后续会利用Scheduler管理降噪的步调。
3.3 对文本举行编码

下面我们利用CLIP模子对文本举行编码,这里要利用到tokenizer和text_encoder:
  1. # 对文本进行编码  
  2. prompt = ["a photograph of an astronaut riding a horse"]  
  3. height = 512 # default height of Stable Diffusion  
  4. width = 512 # default width of Stable Diffusion  
  5. num_inference_steps = 25 # Number of denoising steps  
  6. guidance_scale = 7.5 # Scale for classifier-free guidance  
  7. batch_size = len(prompt)  
  8. text_input = tokenizer(  
  9. prompt, padding="max_length", max_length=tokenizer.model_max_length, truncation=True, return_tensors="pt"  
  10. )  
  11. with torch.no_grad():  
  12. text_embeddings = text_encoder(text_input.input_ids.to(torch_device))[0]
复制代码
此中text_embeddings就是文本编码结果。
3.4 获取潜变量

在训练过程中潜变量Latent是由VAE的Encoder得到的,而在天生过程中,Latent则是符合肯定分别的随机噪声。代码如下:
  1. # 获取latent  
  2. latents = torch.randn(  
  3. (batch_size, unet.config.in_channels, height // 8, width // 8),  
  4. device=torch_device,  
  5. )  
  6. latents = latents * scheduler.init_noise_sigma
复制代码
torch.randn可以得到方差为1的噪声,而latents * scheduler.init_noise_sigma则把方差修改为scheduler.init_noise_sigma。
3.5 降噪

接下来就是重复多次UNet推理,得到降噪后的Latent:
  1. # 降噪  
  2. scheduler.set_timesteps(num_inference_steps)  
  3. for t in tqdm(scheduler.timesteps):  
  4. latent_model_input = latents  
  5. latent_model_input = scheduler.scale_model_input(latent_model_input, timestep=t)  
  6. with torch.no_grad():  
  7.   # 预测噪声
  8.   noise_pred = unet(
  9.    latent_model_input,
  10.    t,
  11.    encoder_hidden_states=text_embeddings
  12.   ).sample
  13. # 降噪
  14. latents = scheduler.step(noise_pred, t, latents).prev_sample
复制代码
末了得到的latents变量就是降噪后的结果,在训练过程中对应VAE Encoder的输出,因此我们还必要利用VAE Decoder还原出图片。
3.6 VAE解码

下面就是利用VAE Decoder解码出原图:
  1. # 使用vae解码  
  2. latents = 1 / 0.18215 * latents  
  3. with torch.no_grad():  
  4. image = vae.decode(latents).sample  
  5. image = (image / 2 + 0.5).clamp(0, 1).squeeze()  
  6. image = (image.permute(1, 2, 0) * 255).to(torch.uint8).cpu().numpy()  
  7. images = (image * 255).round().astype("uint8")  
  8. image = Image.fromarray(image)  
  9. image.show()
复制代码
末了天生如下图片:

generated02.PNG
四、总结

本日我们以GAN开始,先容了AI绘画范畴的一些模子,并把Stable Diffusion作为本日的主角,详解先容了Stable Diffusion的实现原理。
我们还利用Diffusers模块实现了Stable Diffusion天生图像的代码。在Stable Diffusion中,尚有诸如LoRA、Controlnet等干系技能,在本文没有详细提到。而这些东西在AI绘画中却非常紧张,也让AI绘画可以应用在更多范畴。
我们可以利用Stable Diffusion Webui等工具利用LoRA和Controlnet等工具,我们还可以在Diffusers中利用这些根据。后续我们将先容Diffusers模块怎样加载LoRA等附加网络。
感爱好的小同伴,赠予全套AIGC学习资料,包罗AI绘画、AI人工智能等前沿科技教程和软件工具,详细看这里。


AIGC技能的将来发展远景广阔,随着人工智能技能的不绝发展,AIGC技能也将不绝进步。将来,AIGC技能将在游戏和盘算范畴得到更广泛的应用,使游戏和盘算体系具有更高效、更智能、更机动的特性。同时,AIGC技能也将与人工智能技能细密团结,在更多的范畴得到广泛应用,对步伐员来说影响至关紧张。将来,AIGC技能将继承得到进步,同时也将与人工智能技能细密团结,在更多的范畴得到广泛应用。


一、AIGC全部方向的学习门路
AIGC全部方向的技能点做的整理,形成各个范畴的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,包管本身学得较为全面。


二、AIGC必备工具
工具都帮各人整理好了,安装就可直接上手!

三、最新AIGC学习条记
当我学到肯定底子,有本身的明确本领的时间,会去阅读一些先辈整理的册本大概手写的条记资料,这些条记详细记录了他们对一些技能点的明确,这些明确是比力独到,可以学到不一样的思绪。


四、AIGC视频教程合集
观看全面零底子学习视频,看视频学习是最快捷也是最有结果的方式,跟着视频中老师的思绪,从底子到深入,还是很容易入门的。

五、实战案例
纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才气将本身的所学运用到现实当中去,这时间可以搞点实战案例来学习。

如有侵权,请接洽删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表