【AI绘画】硬核解读Stable Diffusion(完整版) 小白必收藏!!!

news2024/11/28 8:30:43

手把手教你入门绘图超强的AI绘画,用户只需要输入一段图片的文字描述,即可生成精美的绘画。给大家带来了全新保姆级教程资料包 (文末可获取)

2022年可谓是AIGC(AI Generated Content)元年,上半年有文生图大模型DALL-E2Stable Diffusion,下半年有OpenAI的文本对话大模型ChatGPT问世,这让冷却的AI又沸腾起来了,因为AIGC能让更多的人真真切切感受到AI的力量。这篇文章将介绍比较火的文生图模型Stable Diffusion(简称SD),Stable Diffusion不仅是一个完全开源的模型(代码,数据,模型全部开源),而且是它的参数量只有1B左右,大部分人可以在普通的显卡上进行推理甚至精调模型。毫不夸张的说,Stable Diffusion的出现和开源对AIGC的火热和发展是有巨大推动作用的,因为它让更多的人能快地上手AI作画。这里将基于Hugging Face的diffusers库深入讲解SD的技术原理以及部分的实现细节,然后也会介绍SD的常用功能,注意本文主要以SD V1.5版本为例,在最后也会简单介绍 SD 2.0版本以及基于SD的扩展应用。

SD模型原理

SD是CompVis、Stability AI和LAION等公司研发的一个文生图模型,它的模型和代码是开源的,而且训练数据LAION-5B也是开源的。SD在开源90天github仓库就收获了33K的stars,可见这个模型是多受欢迎。

SD是一个基于latent的扩散模型,它在UNet中引入text condition来实现基于文本生成图像。SD的核心来源于Latent Diffusion这个工作,常规的扩散模型是基于pixel的生成模型,而Latent Diffusion是基于latent的生成模型,它先采用一个autoencoder将图像压缩到latent空间,然后用扩散模型来生成图像的latents,最后送入autoencoder的decoder模块就可以得到生成的图像。基于latent的扩散模型的优势在于计算效率更高效,因为图像的latent空间要比图像pixel空间要小,这也是SD的核心优势。文生图模型往往参数量比较大,基于pixel的方法往往限于算力只生成64x64大小的图像,比如OpenAI的DALL-E2和谷歌的Imagen,然后再通过超分辨模型将图像分辨率提升至256x256和1024x1024;而基于latent的SD是在latent空间操作的,它可以直接生成256x256和512x512甚至更高分辨率的图像。

SD模型的主体结构如下图所示,主要包括三个模型:

  • autoencoder:encoder将图像压缩到latent空间,而decoder将latent解码为图像;

  • CLIP text encoder:提取输入text的text embeddings,通过cross attention方式送入扩散模型的UNet中作为condition;

  • UNet:扩散模型的主体,用来实现文本引导下的latent生成。

对于SD模型,其autoencoder模型参数大小为84M,CLIP text encoder模型大小为123M,而UNet参数大小为860M,所以SD模型的总参数量约为1B

autoencoder

autoencoder是一个基于encoder-decoder架构的图像压缩模型,对于一个大小为的输入图像,encoder模块将其编码为一个大小为的latent,其中为下采样率(downsampling factor)。在训练autoencoder过程中,除了采用L1重建损失外,还增加了感知损失(perceptual loss,即LPIPS,具体见论文The Unreasonable Effectiveness of Deep Features as a Perceptual Metric)以及基于patch的对抗训练。辅助loss主要是为了确保重建的图像局部真实性以及避免模糊,具体损失函数见latent diffusion的loss部分。同时为了防止得到的latent的标准差过大,采用了两种正则化方法:第一种是KL-reg,类似VAE增加一个latent和标准正态分布的KL loss,不过这里为了保证重建效果,采用比较小的权重(~10e-6);第二种是VQ-reg,引入一个VQ (vector quantization)layer,此时的模型可以看成是一个VQ-GAN,不过VQ层是在decoder模块中,这里VQ的codebook采样较高的维度(8192)来降低正则化对重建效果的影响。latent diffusion论文中实验了不同参数下的autoencoder模型,如下表所示,可以看到当较小和较大时,重建效果越好(PSNR越大),这也比较符合预期,毕竟此时压缩率小。

论文进一步将不同的autoencoder在扩散模型上进行实验,在ImageNet数据集上训练同样的步数(2M steps),其训练过程的生成质量如下所示,可以看到过小的(比如1和2)下收敛速度慢,此时图像的感知压缩率较小,扩散模型需要较长的学习;而过大的其生成质量较差,此时压缩损失过大。

当在4~16时,可以取得相对好的效果。SD采用基于KL-reg的autoencoder,其中下采样率,特征维度为,当输入图像为512x512大小时将得到64x64x4大小的latent。autoencoder模型时在OpenImages数据集上基于256x256大小训练的,但是由于autoencoder的模型是全卷积结构的(基于ResnetBlock),所以它可以扩展应用在尺寸>256的图像上。下面我们给出使用diffusers库来加载autoencoder模型,并使用autoencoder来实现图像的压缩和重建,代码如下所示:

import torch
from diffusers import AutoencoderKL
import numpy as np
from PIL import Image

#加载模型: autoencoder可以通过SD权重指定subfolder来单独加载
autoencoder = AutoencoderKL.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="vae")
autoencoder.to("cuda", dtype=torch.float16)

# 读取图像并预处理
raw_image = Image.open("boy.png").convert("RGB").resize((256, 256))
image = np.array(raw_image).astype(np.float32) / 127.5 - 1.0
image = image[None].transpose(0, 3, 1, 2)
image = torch.from_numpy(image)

# 压缩图像为latent并重建
with torch.inference_mode():
    latent = autoencoder.encode(image.to("cuda", dtype=torch.float16)).latent_dist.sample()
    rec_image = autoencoder.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 = Image.fromarray(rec_image[0])
rec_image

这里我们给出了两张图片在256x256和512x512下的重建效果对比,如下所示,第一列为原始图片,第二列为512x512尺寸下的重建图,第三列为256x256尺寸下的重建图。对比可以看出,autoencoder将图片压缩到latent后再重建其实是有损的,比如会出现文字和人脸的畸变,在256x256分辨率下是比较明显的,512x512下效果会好很多。

这种有损压缩肯定是对SD的生成图像质量是有一定影响的,不过好在SD模型基本上是在512x512以上分辨率下使用的。为了改善这种畸变,stabilityai在发布SD 2.0时同时发布了两个在LAION子数据集上精调的autoencoder,注意这里只精调autoencoder的decoder部分,SD的UNet在训练过程只需要encoder部分,所以这样精调后的autoencoder可以直接用在先前训练好的UNet上(这种技巧还是比较通用的,比如谷歌的Parti也是在训练好后自回归生成模型后,扩大并精调ViT-VQGAN的decoder模块来提升生成质量)。我们也可以直接在diffusers中使用这些autoencoder,比如mse版本(采用mse损失来finetune的模型):

autoencoder = AutoencoderKL.from_pretrained("stabilityai/sd-vae-ft-mse/")

对于同样的两张图,这个mse版本的重建效果如下所示,可以看到相比原始版本的autoencoder,畸变是有一定改善的。

由于SD采用的autoencoder是基于KL-reg的,所以这个autoencoder在编码图像时其实得到的是一个高斯分布DiagonalGaussianDistribution(分布的均值和标准差),然后通过调用sample方法来采样一个具体的latent(调用mode方法可以得到均值)。由于KL-reg的权重系数非常小,实际得到latent的标准差还是比较大的,latent diffusion论文中提出了一种rescaling方法:首先计算出第一个batch数据中的latent的标准差,然后采用的系数来rescale latent,这样就尽量保证latent的标准差接近1(防止扩散过程的SNR较高,影响生成效果,具体见latent diffusion论文的D1部分讨论),然后扩散模型也是应用在rescaling的latent上,在解码时只需要将生成的latent除以,然后再送入autoencoder的decoder即可。对于SD所使用的autoencoder,这个rescaling系数为0.18215。

CLIP text encoder

SD采用CLIP text encoder来对输入text提取text embeddings,具体的是采用目前OpenAI所开源的最大CLIP模型:clip-vit-large-patch14,这个CLIP的text encoder是一个transformer模型(只有encoder模块):层数为12,特征维度为768,模型参数大小是123M。对于输入text,送入CLIP text encoder后得到最后的hidden states(即最后一个transformer block得到的特征),其特征维度大小为77x768(77是token的数量),这个细粒度的text embeddings将以cross attention的方式送入UNet中。在transofmers库中,可以如下使用CLIP text encoder:

from transformers import CLIPTextModel, CLIPTokenizer

text_encoder = CLIPTextModel.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="text_encoder").to("cuda")
# text_encoder = CLIPTextModel.from_pretrained("openai/clip-vit-large-patch14").to("cuda")
tokenizer = CLIPTokenizer.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="tokenizer")
# tokenizer = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14")

# 对输入的text进行tokenize,得到对应的token ids
prompt = "a photograph of an astronaut riding a horse"
text_input_ids = text_tokenizer(
    prompt,
    padding="max_length",
    max_length=tokenizer.model_max_length,
    truncation=True,
    return_tensors="pt"
).input_ids

# 将token ids送入text model得到77x768的特征
text_embeddings = text_encoder(text_input_ids.to("cuda"))[0]

值得注意的是,这里的tokenizer最大长度为77(CLIP训练时所采用的设置),当输入text的tokens数量超过77后,将进行截断,如果不足则进行paddings,这样将保证无论输入任何长度的文本(甚至是空文本)都得到77x768大小的特征。在训练SD的过程中,CLIP text encoder模型是冻结的。在早期的工作中,比如OpenAI的GLIDE和latent diffusion中的LDM均采用一个随机初始化的tranformer模型来提取text的特征,但是最新的工作都是采用预训练好的text model。比如谷歌的Imagen采用纯文本模型T5 encoder来提出文本特征,而SD则采用CLIP text encoder,预训练好的模型往往已经在大规模数据集上进行了训练,它们要比直接采用一个从零训练好的模型要好。

UNet

SD的扩散模型是一个860M的UNet,其主要结构如下图所示(这里以输入的latent为64x64x4维度为例),其中encoder部分包括3个CrossAttnDownBlock2D模块和1个DownBlock2D模块,而decoder部分包括1个UpBlock2D模块和3个CrossAttnUpBlock2D模块,中间还有一个UNetMidBlock2DCrossAttn模块。encoder和decoder两个部分是完全对应的,中间存在skip connection。注意3个CrossAttnDownBlock2D模块最后均有一个2x的downsample操作,而DownBlock2D模块是不包含下采样的。

其中CrossAttnDownBlock2D模块的主要结构如下图所示,text condition将通过CrossAttention模块嵌入进来,此时Attention的query是UNet的中间特征,而key和value则是text embeddings。SD和DDPM一样采用预测noise的方法来训练UNet,其训练损失也和DDPM一样:这里的为text embeddings,此时的模型是一个条件扩散模型。基于diffusers库,我们可以很快实现SD的训练,其核心代码如下所示(这里参考diffusers库下examples中的finetune代码):

import torch
from diffusers import AutoencoderKL, UNet2DConditionModel, DDPMScheduler
from transformers import CLIPTextModel, CLIPTokenizer
import torch.nn.functional as F

# 加载autoencoder
vae = AutoencoderKL.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="vae")
# 加载text encoder
text_encoder = CLIPTextModel.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="text_encoder")
tokenizer = CLIPTokenizer.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="tokenizer")
# 初始化UNet
unet = UNet2DConditionModel(**model_config) # model_config为模型参数配置
# 定义scheduler
noise_scheduler = DDPMScheduler(
    beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", num_train_timesteps=1000
)

# 冻结vae和text_encoder
vae.requires_grad_(False)
text_encoder.requires_grad_(False)

opt = torch.optim.AdamW(unet.parameters(), lr=1e-4)

for step, batch in enumerate(train_dataloader):
    with torch.no_grad():
        # 将image转到latent空间
        latents = vae.encode(batch["image"]).latent_dist.sample()
        latents = latents * vae.config.scaling_factor # rescaling latents
        # 提取text embeddings
        text_input_ids = text_tokenizer(
            batch["text"],
            padding="max_length",
            max_length=tokenizer.model_max_length,
            truncation=True,
            return_tensors="pt"
  ).input_ids
  text_embeddings = text_encoder(text_input_ids)[0]
    
    # 随机采样噪音
    noise = torch.ra

AI绘画所有方向的学习路线思维导图

这里为大家提供了总的路线图。它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。如果下面这个学习路线能帮助大家将AI利用到自身工作上去,那么我的使命也就完成了:
在这里插入图片描述

👉stable diffusion新手0基础入门PDF👈

在这里插入图片描述

👉AI绘画必备工具👈

在这里插入图片描述

温馨提示:篇幅有限,已打包文件夹,获取方式在:文末

👉AI绘画基础+速成+进阶使用教程👈

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

在这里插入图片描述

👉12000+AI关键词大合集👈

在这里插入图片描述
这份完整版的AI绘画资料我已经打包好,戳下方蓝色字体,即可免费领取!CSDN大礼包:《全套AI绘画基础学习资源包》免费分享

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1450556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# CAD SelectionFilter下TypedValue数组

SelectionFilter是用于过滤AutoCAD实体的类,在AutoCAD中,可以使用它来选择具有特定属性的实体。构造SelectionFilter对象时,需要传入一个TypedValue数组,它用于定义选择规则。 在TypedValue数组中,每个元素表示一个选…

【制作100个unity游戏之25】3D背包、库存、制作、快捷栏、存储系统、砍伐树木获取资源、随机战利品宝箱7(附带项目源码)

效果演示 文章目录 效果演示系列目录前言新增简单的泛型单例消耗品源码完结 系列目录 前言 欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第25篇中,我们将探索如何用unity制作一个3D背包、库存、…

HTML5+CSS3+JS小实例:锥形渐变彩虹按钮

实例:锥形渐变彩虹按钮 技术栈:HTML+CSS+JS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge" /…

无人机导航技术,无人机导航理论基础,无人机导航技术应用发展详解

惯性/卫星定位组合是一种比较理想的组合导航系统。在无人机导航领域&#xff0c;多年来惯性/卫星定位组合导航系统的研究一直受到普遍的关注&#xff0c;大量的理论研究成果得到实际应用。 常见的几类导航系统 单一导航 卫星导航系统 、多普勒导航、惯性导航系统(INS) 、图形…

【知识整理】产研中心岗位评定标准之大数据岗位

为贯彻执行集团数字化转型的需要,该知识库将公示集团组织内各产研团队不同角色成员的职务“职级”岗位的评定标准; 一、定级定档目的 通过对公司现有岗位及相应岗位员工的工作能力、工作水平进行客观公正评定,确定各岗位的等级及同等级岗位员工对应的档级,从而为员工以后的晋升…

【Cocos入门】物理检测

目录 一、物理检测的概念二、点测试三、矩形测试四、射线测试 一、物理检测的概念 CoCos中&#xff0c;物理检测也是物理系统的一部分&#xff0c;它不是用于检测物体的物理特性的&#xff0c;而是用来查询物体的(比如某个地方是否存在物理碰撞体)。其又分成&#xff1a;点检测…

Mysql运维篇(四) Xtarbackup--备份与恢复练习

一路走来&#xff0c;所有遇到的人&#xff0c;帮助过我的、伤害过我的都是朋友&#xff0c;没有一个是敌人。如有侵权&#xff0c;请留言&#xff0c;我及时删除&#xff01; 前言 xtrabackup是Percona公司CTO Vadim参与开发的一款基于InnoDB的在线热备工具&#xff0c;具有…

【PyQt】11-QTextEdit、QPushButton

文章目录 前言一、文本输入-QTextEdit1.1 代码1.2 运行结果 二、QPushButton2.1.1 按钮上添加文本2.1.2 按键的弹跳效果2.1.3 两个信号可以绑定一个槽。2.1.4 带图标的按键运行结果 2.1.5 按键不可用以及回车默认完整代码2.2 单选按键控件运行结果 2.3 复选框&#xff08;多选框…

free pascal:fpwebview 组件通过 JSBridge 调用本机TTS

从 https://github.com/PierceNg/fpwebview 下载 fpwebview-master.zip 简单易用。 先请看 \fpwebview-master\README.md cd \lazarus\projects\fpwebview-master\demo\js_bidir 学习 js_bidir.lpr &#xff0c;编写 js_bind_speak.lpr 如下&#xff0c;通过 JSBridge 调用本…

shumei 滑块 qd参数仿写记录

在对qd参数进行仿写的过程中&#xff0c;由于缺失很多js的基础知识&#xff0c;导致进展一度非常的缓慢&#xff0c;并且不知道自己的方向是不是正确的方向。在不知道自己的方向是否正确的时候&#xff0c;这个时候自己的投入的努力都是畏首畏尾。大概是一种&#xff0c;不知道…

RabbitMQ如何保证可靠

0. RabbitMQ不可靠原因 消息从生产者到消费者的每一步都可能导致消息丢失&#xff1a; 发送消息时丢失&#xff1a; 生产者发送消息时连接MQ失败生产者发送消息到达MQ后未找到Exchange生产者发送消息到达MQ的Exchange后&#xff0c;未找到合适的Queue消息到达MQ后&#xff0c;…

【Deep Learning 1】神经网络的搭建

&#x1f31e;欢迎来到PyTorch的世界 &#x1f308;博客主页&#xff1a;卿云阁 &#x1f48c;欢迎关注&#x1f389;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f31f;本文由卿云阁原创&#xff01; &#x1f4c6;首发时间&#xff1a;&#x1f339;2024年2月16日&a…

Flutter Android开发 梳理Google Material Design颜色体系

前言 做安卓开发&#xff08;Kotlin语言&#xff09;&#xff0c;Flutter开发的人员应该都听说过谷歌一直推崇的Material Design&#xff0c;而Material Design Color是其推崇的颜色体系&#xff0c;具体来说&#xff0c;Material Design Color是一套旨在帮助设计师和开发者创…

问题:单层工业厂房柱子吊装时,其校正的内容包括( )。 #微信#经验分享#知识分享

问题&#xff1a;单层工业厂房柱子吊装时&#xff0c;其校正的内容包括(  )。 A、截面尺寸偏差 B、平面位置 C、标高 D、垂直度 E、柱的长度 参考答案如图所示

重磅更新!谷歌发布Gemini 1.5 Pro!多模态,1000K上下文!附Waitlist链接!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

[OPEN SQL] 修改数据

MODIFY语句用于修改数据库表中的数据 MODIFY拥有INSERT和UPDATE的操作&#xff0c;如果数据库表中不存在符合条件的数据则会添加该条新数据&#xff0c;反之数据库表中存在符合条件的数据则会更新该条数据 本次操作使用的数据库表为SCUSTOM&#xff0c;其字段内容如下所示 航…

【计算机网络】多路复用和多路分解

多路分解 demultiplexing 数据到达接收主机时&#xff0c;需要指定对应的套接字&#xff0c;所以在运输层报文段中放置了一些字段用于套接字的识别&#xff0c;从而将报文段定向到套接字&#xff0c;将运输层报文段数据交付到正确套接字的工作就是多路分解。多路复用 multiple…

day42 一个极简动画效果(复习相关属性)

<!DOCTYPE html> <html><head><title>动画页面</title><style>body {font-family: Arial, sans-serif;background-color: #f2f2f2;margin: 0;padding: 0;}.container {max-width: 800px;margin: 0 auto;margin-top: 100px;padding: 20px;b…

(N-144)基于微信小程序在线订餐系统

开发工具&#xff1a;IDEA、微信小程序 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 前端技术&#xff1a;vue、ElementUI、 Vant Weapp 服务端技术&#xff1a;springbootmybatisredis 本系统分微信小程序和…

ChatGPT重大升级:能自动记住用户的习惯和喜好,用户有权决定是否共享数据给OpenAI

OpenAI刚刚宣布了ChatGPT的一项激动人心的更新&#xff01; OpenAI在ChatGPT中新加了记忆功能和用户控制选项&#xff0c;这意味着GPT能够在与用户的互动中记住之前的对话内容&#xff0c;并利用这些信息在后续的交谈中提供更加相关和定制化的回答。 这一功能目前正处于测试阶…