国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion

這篇具有很好參考價(jià)值的文章主要介紹了【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。


Stable Diffusion是一個(gè)強(qiáng)大的文本條件隱式擴(kuò)散模型(text-conditioned latent diffusion model),它具有根據(jù)文字描述生成精美圖片的能力。它不僅是一個(gè)完全開(kāi)源的模型(代碼,數(shù)據(jù),模型全部開(kāi)源),而且是它的參數(shù)量只有 1B左右,大部分人可以在普通的顯卡上進(jìn)行推理甚至精調(diào)模型。毫不夸張的說(shuō),Stable Diffusion的出現(xiàn)和開(kāi)源對(duì)AIGC的火熱和發(fā)展是有巨大推動(dòng)作用的,因?yàn)樗尭嗟娜四芸斓厣鲜諥I作畫(huà)。本文將基于Hugging Face的diffusers庫(kù)深入講解Stable Diffusion的技術(shù)原理以及部分的實(shí)現(xiàn)細(xì)節(jié),然后也會(huì)介紹Stable Diffusion的常用功能。

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成

1. Stable Diffusion簡(jiǎn)介

Stable Diffusion是CompVis、Stability AI和LAION等公司研發(fā)的一個(gè)文生圖模型,它的模型和代碼是開(kāi)源的,而且訓(xùn)練數(shù)據(jù)LAION-5B也是開(kāi)源的。

Stable Diffusion是一個(gè)基于Latent的擴(kuò)散模型,它在UNet中引入text condition來(lái)實(shí)現(xiàn)基于文本生成圖像。Stable Diffusion的核心來(lái)源于Latent Diffusion這個(gè)工作,常規(guī)的擴(kuò)散模型是基于Pixel(像素)的生成模型,而Latent Diffusion是基于Latent的生成模型,它先采用一個(gè)autoencoder將圖像壓縮到Latent空間,然后用擴(kuò)散模型來(lái)生成圖像的Latents,最后送入autoencoder的decoder模塊就可以得到生成的圖像。
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
Stable Diffusion模型的主體結(jié)構(gòu)如下圖所示,主要包括三個(gè)模型:

  • AutoEncoder:Encoder將圖像壓縮到Latent空間,而Decoder將Latent解碼為圖像;
  • CLIP text encoder:提取輸入text的text embeddings,通過(guò)cross attention方式送入擴(kuò)散模型的UNet中作為condition;
  • UNet:擴(kuò)散模型的主體,用來(lái)實(shí)現(xiàn)文本引導(dǎo)下的Latent生成。

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
對(duì)于Stable Diffusion模型,其Autoencoder模型參數(shù)大小為84M,CLIP text encoder模型大小為123M,而UNet參數(shù)大小為860M,所以Stable Diffusion模型的總參數(shù)量約為1B。

基于Latent的擴(kuò)散模型的優(yōu)勢(shì)在于計(jì)算效率更高效,因?yàn)閳D像的Latent空間要比圖像Pixel空間要小,這也是Stable Diffusion的核心優(yōu)勢(shì)。文生圖模型往往參數(shù)量比較大,基于Pixel的方法往往限于算力只生成64x64大小的圖像,比如OpenAI的DALL-E2和谷歌的Imagen,然后再通過(guò)超分辨模型將圖像分辨率提升至256x256和1024x1024;而基于Latent的SD是在Latent空間操作的,它可以直接生成256x256和512x512甚至更高分辨率的圖像。

1.1 基本概念

  • 隱式擴(kuò)散使用VAE(Variational Auto-Encoder)將圖片映射到一個(gè)較小的隱式表征,再將其映射到原始圖片,通過(guò)在隱式表征上進(jìn)行擴(kuò)散,可以使用更少的內(nèi)存,減少UNet層數(shù)并加速圖片的生成。還可以將結(jié)果輸入VAE解碼器中,得到高分辨率圖像。Stable Diffusion中的VAE能夠接收一張三通道圖片作為輸入,從而生成一個(gè)四通道的隱式表征,同時(shí)每一個(gè)空間維度都將減少為原來(lái)的八分之一。

  • 以文本為生成條件:在推理階段,輸入期望圖像的文本描述,將純?cè)肼晹?shù)據(jù)作為起點(diǎn),然后模型對(duì)噪聲輸入進(jìn)行“去噪”,生成能匹配文本描述的圖像。為此,Stable Diffusion使用了一個(gè)名為CLIP的預(yù)訓(xùn)練Transformer模型。

    1. CLIP的文本編碼器將文本描述轉(zhuǎn)換為特征向量,該特征向量用于與圖像特征向量進(jìn)行相似度比較
    2. 輸入的文本提示語(yǔ)進(jìn)行分詞(也就是基于一個(gè)很大的詞匯庫(kù),將句子中的詞語(yǔ)或短語(yǔ)轉(zhuǎn)換為一個(gè)一個(gè)的token),然后被輸入CLIP的文本編碼器。
    3. 使用交叉注意力機(jī)制(cross attention),交叉注意力貫穿整個(gè)UNet結(jié)構(gòu),UNet中的每個(gè)空間位置都可以“注意”到文字條件中不同的token,以便從文本提示語(yǔ)中獲取不同位置的相互關(guān)聯(lián)信息。
      下圖展示了文本條件信息(以及基于時(shí)間步的條件)是如何在不同位置被輸入的。
      【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
      文本條件信息通過(guò)交叉注意力被輸入到各個(gè)模塊,時(shí)間步信息通過(guò)時(shí)間嵌入的映射被輸入到各個(gè)模塊。
  • 無(wú)分類(lèi)器引導(dǎo)(Classifier-Free Guidance, CFG):主要解決可能得到與文字描述根本不相關(guān)的圖片,具體方法如下:

    1. 訓(xùn)練階段,強(qiáng)制模型學(xué)習(xí)在無(wú)文字信息的情況下對(duì)圖片“去噪”(無(wú)條件生成)。
    2. 推理階段,進(jìn)行有文字條件預(yù)測(cè)vs無(wú)文字條件預(yù)測(cè),利用兩者的差異來(lái)建立一個(gè)最終結(jié)合版的預(yù)測(cè)。

1.2 主體結(jié)構(gòu)

(1)AutoEncoder
AutoEncoder是一個(gè)基于encoder-decoder架構(gòu)的圖像壓縮模型,對(duì)于一個(gè)大小為 H × W × 3 H\times W\times 3 H×W×3的輸入圖像,encoder模塊將其編碼為一個(gè)大小為 h × w × c h\times w\times c h×w×c的Latent,其中 f = H / h = W / h f=H/h=W/h f=H/h=W/h為下采樣率(downsampling factor)。

在訓(xùn)練AutoEncoder過(guò)程中,除了采用L1重建損失外,還增加了感知損失(Perceptual Loss,即LPIPS,具體見(jiàn)論文The Unreasonable Effectiveness of Deep Features as a Perceptual Metric)以及基于Patch的對(duì)抗訓(xùn)練

輔助Loss主要是為了確保重建的圖像局部真實(shí)性以及避免模糊,具體損失函數(shù)見(jiàn)Latent Diffusion的Loss部分。同時(shí)為了防止得到的latent的標(biāo)準(zhǔn)差過(guò)大,采用了兩種正則化方法

  • 第一種是KL-reg,類(lèi)似VAE增加一個(gè)latent和標(biāo)準(zhǔn)正態(tài)分布的KL loss,不過(guò)這里為了保證重建效果,采用比較小的權(quán)重(~10e-6);
  • 第二種是VQ-reg,引入一個(gè)VQ (vector quantization)layer,此時(shí)的模型可以看成是一個(gè)VQ-GAN,不過(guò)VQ層是在decoder模塊中,這里VQ的codebook采樣較高的維度(8192)來(lái)降低正則化對(duì)重建效果的影響。

Stable Diffusion采用基于KL-reg的autoencoder,其中下采樣率 f = 8 f=8 f=8,特征維度為 c = 4 c=4 c=4,當(dāng)輸入圖像為512x512大小時(shí)將得到64x64x4大小的Latent。AutoEncoder模型時(shí)在OpenImages數(shù)據(jù)集上基于256x256大小訓(xùn)練的,但是由于AutoEncoder的模型是全卷積結(jié)構(gòu)的(基于ResnetBlock),所以它可以擴(kuò)展應(yīng)用在尺寸>256的圖像上。

下面給出使用diffusers庫(kù)來(lái)加載AutoEncoder模型,并使用AutoEncoder來(lái)實(shí)現(xiàn)圖像的壓縮和重建的代碼:

import torch
import numpy as np
from diffusers.models import AutoencoderKL
from diffusers import StableDiffusionPipeline
from PIL import Image

# 加載模型
autoencoder = AutoencoderKL.from_pretrained("runwayml/stable-diffusion-v1-5", subfolder="vae")
autoencoder.to("cuda", dtype=torch.float16)

# 讀取圖像并預(yù)處理
raw_image = Image.open("boy.jpg").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)
# 壓縮圖像為L(zhǎng)atent并重建
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

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
由于Stable Diffusion采用的AutoEncoder是基于KL-reg的,所以這個(gè)AutoEncoder在編碼圖像時(shí)其實(shí)得到的是一個(gè)高斯分布DiagonalGaussianDistribution(分布的均值和標(biāo)準(zhǔn)差),然后通過(guò)調(diào)用sample方法來(lái)采樣一個(gè)具體的Latent(調(diào)用mode方法可以得到均值)。

由于KL-reg的權(quán)重系數(shù)非常小,實(shí)際得到Latent的標(biāo)準(zhǔn)差還是比較大的,Latent diffusion論文中提出了一種rescaling方法:首先計(jì)算出第一個(gè)batch數(shù)據(jù)中的latent的標(biāo)準(zhǔn)差 σ ^ \hat{\sigma} σ^,然后采用 1 / σ ^ 1/\hat{\sigma} 1/σ^的系數(shù)來(lái)rescale latent,這樣就盡量保證latent的標(biāo)準(zhǔn)差接近1(防止擴(kuò)散過(guò)程的SNR較高,影響生成效果),然后擴(kuò)散模型也是應(yīng)用在rescaling的latent上,在解碼時(shí)只需要將生成的latent除以 1 / σ ^ 1/\hat{\sigma} 1/σ^,然后再送入autoencoder的decoder即可。對(duì)于SD所使用的autoencoder,這個(gè)rescaling系數(shù)為0.18215。

(2)CLIP text encoder
Stable Diffusion采用CLIP text encoder來(lái)對(duì)輸入text提取text embeddings,具體的是采用目前OpenAI所開(kāi)源的最大CLIP模型:clip-vit-large-patch14,這個(gè)CLIP的text encoder是一個(gè)transformer模型(只有encoder模塊):層數(shù)為12,特征維度為768,模型參數(shù)大小是123M。

對(duì)于輸入text,送入CLIP text encoder后得到最后的hidden states(即最后一個(gè)transformer block得到的特征),其特征維度大小為77x768(77是token的數(shù)量),這個(gè)細(xì)粒度的text embeddings將以cross attention的方式送入U(xiǎn)Net中。在transofmers庫(kù)中,可以如下使用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")

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

# 對(duì)輸入的text進(jìn)行tokenize,得到對(duì)應(yīng)的token ids
prompt = "a photograph of an astronaut riding a horse"
text_input_ids = text_tokenizer(
    prompt,
    padding="max_length",
    max_length=text_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]

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
值得注意的是,這里的text_tokenizer最大長(zhǎng)度為77(CLIP訓(xùn)練時(shí)所采用的設(shè)置),當(dāng)輸入text的tokens數(shù)量超過(guò)77后,將進(jìn)行截?cái)?/strong>,如果不足則進(jìn)行paddings,這樣將保證無(wú)論輸入任何長(zhǎng)度的文本(甚至是空文本)都得到77x768大小的特征。而且在訓(xùn)練Stable Diffusion的過(guò)程中,CLIP text encoder模型是凍結(jié)的。


補(bǔ)充
在早期的工作中,比如OpenAI的GLIDElatent diffusion中的LDM均采用一個(gè)隨機(jī)初始化的tranformer模型來(lái)提取text的特征,但是最新的工作都是采用預(yù)訓(xùn)練好的text model。比如谷歌的Imagen采用純文本模型T5 encoder來(lái)提出文本特征,而Stable Diffusion則采用CLIP text encoder,預(yù)訓(xùn)練好的模型往往已經(jīng)在大規(guī)模數(shù)據(jù)集上進(jìn)行了訓(xùn)練,它們要比直接采用一個(gè)從零訓(xùn)練好的模型要好。


(3)UNet
Stable Diffusion的擴(kuò)散模型是一個(gè)860M的UNet,其主要結(jié)構(gòu)如下圖所示(這里以輸入的Latent為64x64x4維度為例),
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
其中encoder部分包括3個(gè)CrossAttnDownBlock2D模塊和1個(gè)DownBlock2D模塊,而decoder部分包括1個(gè)UpBlock2D模塊和3個(gè)CrossAttnUpBlock2D模塊,中間還有一個(gè)UNetMidBlock2DCrossAttn模塊。encoder和decoder兩個(gè)部分是完全對(duì)應(yīng)的,中間存在skip connection。注意3個(gè)CrossAttnDownBlock2D模塊最后均有一個(gè)2x的downsample操作,而DownBlock2D模塊是不包含下采樣的。

其中CrossAttnDownBlock2D模塊的主要結(jié)構(gòu)如下圖所示,text condition將通過(guò)CrossAttention模塊嵌入進(jìn)來(lái),此時(shí)Attention的query是UNet的中間特征,而key和value則是text embeddings
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
Stable Diffusion和DDPM一樣采用預(yù)測(cè)noise的方法來(lái)訓(xùn)練UNet,其訓(xùn)練損失也和DDPM一樣:
L s i m p l e = E x 0 , ? ~ N ( 0 , I ) , t [ ∣ ∣ ? ? ? θ ( α ˉ t x 0 + 1 ? α ˉ t ? , t , c ) ∣ ∣ 2 ] L^{simple}=\mathbb{E}_{x_0,\epsilon \sim \mathcal{N}(0,\mathrm{I}),t}[||\epsilon -\epsilon _{\theta }(\sqrt{\bar{\alpha }_t}\mathrm{x}_0+\sqrt{1-\bar{\alpha }_t}\epsilon,t,\mathrm{c})||^2] Lsimple=Ex0?,?N(0,I),t?[∣∣???θ?(αˉt? ?x0?+1?αˉt? ??,t,c)2]
這里的 c c c為text embeddings,此時(shí)的模型是一個(gè)條件擴(kuò)散模型。

在訓(xùn)練條件擴(kuò)散模型時(shí),往往會(huì)采用Classifier-Free Guidance(簡(jiǎn)稱(chēng)為CFG),所謂的CFG簡(jiǎn)單來(lái)說(shuō)就是在訓(xùn)練條件擴(kuò)散模型的同時(shí)也訓(xùn)練一個(gè)無(wú)條件的擴(kuò)散模型,同時(shí)在采樣階段將條件控制下預(yù)測(cè)的噪音和無(wú)條件下的預(yù)測(cè)噪音組合在一起來(lái)確定最終的噪音,具體的計(jì)算公式如下所示:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
這里的 w w wguidance scale,當(dāng) w w w越大時(shí),condition起的作用越大,即生成的圖像其更和輸入文本一致。CFG的具體實(shí)現(xiàn)非常簡(jiǎn)單,在訓(xùn)練過(guò)程中,我們只需要以一定的概率(比如10%)隨機(jī)drop掉text即可,這里我們可以將text置為空字符串(前面說(shuō)過(guò)此時(shí)依然能夠提取text embeddings)。

1.3 訓(xùn)練細(xì)節(jié)

Stable Diffusion的訓(xùn)練主要包括訓(xùn)練數(shù)據(jù)訓(xùn)練資源,這方面也是在Stable Diffusion的Model Card上有說(shuō)明。首先是訓(xùn)練數(shù)據(jù),Stable Diffusion在laion2B-en數(shù)據(jù)集上訓(xùn)練的,它是laion-5b數(shù)據(jù)集的一個(gè)子集,更具體的說(shuō)它是laion-5b中的英文(文本為英文)數(shù)據(jù)集。laion-5b數(shù)據(jù)集是從網(wǎng)頁(yè)數(shù)據(jù)Common Crawl中篩選出來(lái)的圖像-文本對(duì)數(shù)據(jù)集,它包含5.85B的圖像-文本對(duì),其中文本為英文的數(shù)據(jù)量為2.32B,這就是laion2B-en數(shù)據(jù)集。
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
下面是laion2B-en數(shù)據(jù)集的元信息(圖片width和height,以及文本長(zhǎng)度)統(tǒng)計(jì)分析:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
其中圖片的width和height均在256以上的樣本量為1324M,在512以上的樣本量為488M,而在1024以上的樣本為76M;文本的平均長(zhǎng)度為67。Laion數(shù)據(jù)集中除了圖片(下載URL,圖像width和height)和文本(描述文本)的元信息外,還包含以下信息:

  • similarity:使用CLIP ViT-B/32計(jì)算出來(lái)的圖像和文本余弦相似度
  • pwatermark:使用一個(gè)圖片水印檢測(cè)器檢測(cè)的概率值,表示圖片含有水印的概率;
  • punsafe圖片是否安全,或者圖片是不是NSFW,使用基于CLIP的檢測(cè)器來(lái)估計(jì);
  • AESTHETIC_SCORE:圖片的美學(xué)評(píng)分(1-10),這個(gè)是后來(lái)追加的,首先選擇一小部分圖片數(shù)據(jù)集讓人對(duì)圖片的美學(xué)打分,然后基于這個(gè)標(biāo)注數(shù)據(jù)集來(lái)訓(xùn)練一個(gè)打分模型,并對(duì)所有樣本計(jì)算估計(jì)的美學(xué)評(píng)分。

上面是Laion數(shù)據(jù)集的情況,下面介紹Stable Diffusion訓(xùn)練數(shù)據(jù)集的具體情況,Stable Diffusion的訓(xùn)練是多階段的(先在256x256尺寸上預(yù)訓(xùn)練,然后在512x512尺寸上精調(diào)),不同的階段產(chǎn)生了不同的版本:

  • SD v1.1:在Laion2B-en數(shù)據(jù)集上以256x256大小訓(xùn)練237,000步,如上所述,laion2B-en數(shù)據(jù)集中256以上的樣本量共1324M;然后在Laion5B的高分辨率數(shù)據(jù)集以512x512尺寸訓(xùn)練194,000步,這里的高分辨率數(shù)據(jù)集是圖像尺寸在1024x1024以上,共170M樣本。
  • SD v1.2:以SD v1.1為初始權(quán)重,在improved_aesthetics_5plus數(shù)據(jù)集上以512x512尺寸訓(xùn)練515,000步數(shù),這個(gè)improved_aesthetics_5plus數(shù)據(jù)集上laion2B-en數(shù)據(jù)集中美學(xué)評(píng)分在5分以上的子集(共約600M樣本),注意這里過(guò)濾了含有水印的圖片(pwatermark>0.5)以及圖片尺寸在512x512以下的樣本。
  • SD v1.3:以SD v1.2為初始權(quán)重,在improved_aesthetics_5plus數(shù)據(jù)集上繼續(xù)以512x512尺寸訓(xùn)練195,000步數(shù),不過(guò)這里采用了CFG(以10%的概率隨機(jī)drop掉text)。
  • SD v1.4:以SD v1.2為初始權(quán)重,在improved_aesthetics_5plus數(shù)據(jù)集上采用CFG以512x512尺寸訓(xùn)練225,000步數(shù)。
  • SD v1.5:以SD v1.2為初始權(quán)重,在improved_aesthetics_5plus數(shù)據(jù)集上采用CFG以512x512尺寸訓(xùn)練595,000步數(shù)。

可以看到SD v1.3、SD v1.4和SD v1.5其實(shí)是以SD v1.2為起點(diǎn)在improved_aesthetics_5plus數(shù)據(jù)集上采用CFG訓(xùn)練過(guò)程中的不同checkpoints,目前最常用的版本是SD v1.4和SD v1.5。SD的訓(xùn)練是采用了32臺(tái)8卡的A100機(jī)器(32 x 8 x A100_40GB GPUs),所需要的訓(xùn)練硬件還是比較多的??梢院?jiǎn)單計(jì)算一下,單卡的訓(xùn)練batch size為2,并采用gradient accumulation,其中g(shù)radient accumulation steps=2,那么訓(xùn)練的總batch size就是32x8x2x2=2048。訓(xùn)練優(yōu)化器采用AdamW,訓(xùn)練采用warmup,在初始10,000步后學(xué)習(xí)速率升到0.0001,后面保持不變。至于訓(xùn)練時(shí)間,文檔上只說(shuō)了用了150,000小時(shí),這個(gè)應(yīng)該是A100卡時(shí),如果按照256卡A100來(lái)算的話,那么大約需要訓(xùn)練25天左右。

1.4 模型評(píng)測(cè)

對(duì)于文生圖模型,目前常采用的定量指標(biāo)是FID(Fréchet inception distance)和CLIP score,其中FID可以衡量生成圖像的逼真度(image fidelity),而CLIP score評(píng)測(cè)的是生成的圖像與輸入文本的一致性,其中FID越低越好,而CLIP score是越大越好。當(dāng)CFG的gudiance scale參數(shù)設(shè)置不同時(shí),F(xiàn)ID和CLIP score會(huì)發(fā)生變化,下圖為不同的gudiance scale參數(shù)下,SD模型在COCO2017驗(yàn)證集上的評(píng)測(cè)結(jié)果,注意這里是zero-shot評(píng)測(cè),即SD模型并沒(méi)有在COCO訓(xùn)練數(shù)據(jù)集上精調(diào)。
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
可以看到當(dāng)gudiance scale=3時(shí),F(xiàn)ID最低;而當(dāng)gudiance scale越大時(shí),CLIP score越大,但是FID同時(shí)也變大。在實(shí)際應(yīng)用時(shí),往往會(huì)采用較大的gudiance scale,比如SD模型默認(rèn)采用7.5,此時(shí)生成的圖像和文本有較好的一致性。

從不同版本的對(duì)比曲線上看,Stable Diffusion的采用CFG訓(xùn)練后三個(gè)版本其實(shí)差別并沒(méi)有那么大,其中SD v1.5相對(duì)好一點(diǎn),但是明顯要未采用CFG訓(xùn)練的版本要好的多,這說(shuō)明CFG訓(xùn)練是比較關(guān)鍵的。

但是FID有很大的局限性,它并不能很好地衡量生成圖像的質(zhì)量,也是因?yàn)檫@個(gè)原因,谷歌的Imagen引入了人工評(píng)價(jià),先建立一個(gè)評(píng)測(cè)數(shù)據(jù)集DrawBench(包含200個(gè)不同類(lèi)型的text),然后用不同的模型來(lái)生成圖像,讓人去評(píng)價(jià)同一個(gè)text下不同模型生成的圖像,這種評(píng)測(cè)方式比較直接,但是可能也受一些主觀因素的影響。

1.5 模型應(yīng)用

(1)文生圖
根據(jù)文本生成圖像這是文生圖的最核心的功能,下圖為Stable Diffusion的文生圖的推理流程圖:

  1. 首先,根據(jù)輸入text用text encoder提取text embeddings,同時(shí)初始化一個(gè)隨機(jī)噪音noise(latent上的,512x512圖像對(duì)應(yīng)的noise維度為64x64x4),
  2. 然后,將text embeddings和noise送入擴(kuò)散模型UNet中生成去噪后的latent
  3. 最后,送入autoencoder的decoder模塊得到生成的圖像

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
使用diffusers庫(kù),可以直接調(diào)用StableDiffusionPipeline來(lái)實(shí)現(xiàn)文生圖:

import torch
from diffusers import StableDiffusionPipeline
from PIL import Image

# 判斷當(dāng)前的設(shè)備
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(f'Using device: {device}')

# 組合圖像,生成grid
def image_grid(imgs, rows, cols):
	assert len(imgs) == rows*cols

  	w, h = imgs[0].size
  	grid = Image.new('RGB', size=(cols*w, rows*h))
  	grid_w, grid_h = grid.size
    
  	for i, img in enumerate(imgs):
    	grid.paste(img, box=(i%cols*w, i//cols*h))
  	return grid

# 加載文生圖pipeline
pipe = StableDiffusionPipeline.from_pretrained(
    "runwayml/stable-diffusion-v1-5", # 或者使用 SD v1.4: "CompVis/stable-diffusion-v1-4"
    torch_dtype=torch.float16
).to(device)

# 輸入text,這里text又稱(chēng)為prompt
prompts = [
    "a photograph of an astronaut riding a horse",
    "A cute otter in a rainbow whirlpool holding shells, watercolor",
    "An avocado armchair",
    "A white dog wearing sunglasses"
]
# 定義隨機(jī)seed,保證可重復(fù)性
generator = torch.Generator(device).manual_seed(42) 

# 執(zhí)行推理
images = pipe(
    prompts,
    height=512,
    width=512,
    num_inference_steps=50,
    guidance_scale=7.5,
    negative_prompt=None,
    num_images_per_prompt=1,
    generator=generator
).images

grid = image_grid(images, rows=1, cols=4)
grid

生成的圖像效果如下所示:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
可以通過(guò)指定widthheight來(lái)決定生成圖像的大小,前面提到Stable Diffusion最后是在512x512尺度上訓(xùn)練的,所以生成512x512尺寸效果是最好的,但是實(shí)際上Stable Diffusion可以生成任意尺寸的圖片:一方面AutoEncoder支持任意尺寸的圖片的編碼和解碼,另外一方面擴(kuò)散模型UNet也是支持任意尺寸的latents生成的(UNet是卷積+attention的混合結(jié)構(gòu))。

但是注意生成低分辨率圖像時(shí),圖像的質(zhì)量會(huì)大幅度下降,這是因?yàn)?strong>訓(xùn)練是在固定尺寸上(512x512)進(jìn)行的,生成其它尺寸圖像還是會(huì)存在一定的問(wèn)題。解決這個(gè)問(wèn)題的相對(duì)比較簡(jiǎn)單,就是采用多尺度策略訓(xùn)練,比如NovelAI提出采用Aspect Ratio Bucketing策略來(lái)在二次元數(shù)據(jù)集上精調(diào)模型,這樣得到的模型就很大程度上避免Stable Diffusion的這個(gè)問(wèn)題,目前大部分開(kāi)源的基于Stable Diffusion的精調(diào)模型往往都采用類(lèi)似的多尺度策略來(lái)精調(diào)。

這里的另一個(gè)比較重要的參數(shù)是num_inference_steps,它是指推理過(guò)程中的去噪步數(shù)或者采樣步數(shù)。Stable Diffusion在訓(xùn)練過(guò)程采用的是步數(shù)為1000的noise scheduler,但是在推理時(shí)往往采用速度更快的scheduler:只需要少量的采樣步數(shù)就能生成不錯(cuò)的圖像,比如Stable Diffusion默認(rèn)采用PNDM scheduler,它只需要采樣50步就可以出圖。當(dāng)然我們也可以換用其它類(lèi)型的scheduler,比如DDIM schedulerDPM-Solver scheduler

可以在diffusers中直接替換scheduler,比如使用DDIM:

from diffusers import DDIMScheduler

# 注意這里的clip_sample要關(guān)閉,否則生成圖像存在問(wèn)題,因?yàn)椴荒軐?duì)latent進(jìn)行clip
pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config, clip_sample=False)

換成DDIM后,同樣的采樣步數(shù)生成的圖像如下所示,在部分細(xì)節(jié)上和PNDM有差異:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
當(dāng)然采樣步數(shù)越大,生成的圖像質(zhì)量越好,但是相應(yīng)的推理時(shí)間也更久

第三個(gè)要討論的參數(shù)是guidance_scale,當(dāng)CFG的guidance_scale越大時(shí),生成的圖像應(yīng)該會(huì)和輸入文本更一致,但是過(guò)大的guidance_scale會(huì)出現(xiàn)問(wèn)題,這主要是由于訓(xùn)練和測(cè)試的不一致,過(guò)大的guidance_scale會(huì)導(dǎo)致生成的樣本超出范圍。谷歌的Imagen論文提出一種dynamic thresholding策略來(lái)解決這個(gè)問(wèn)題,所謂的dynamic thresholding是相對(duì)于原來(lái)的static thresholding

  • static thresholding策略是直接將生成的樣本clip到[-1, 1]范圍內(nèi)(Imagen是基于pixel的擴(kuò)散模型,這里是將圖像像素值歸一化到-1到1之間),但是會(huì)在過(guò)大的guidance_scale時(shí)產(chǎn)生很多的飽含像素點(diǎn)。
  • dynamic thresholding策略先計(jì)算樣本在某個(gè)百分位下(比如99%)的像素絕對(duì)值 s s s,然后如果它超過(guò)1時(shí)就采用 s s s來(lái)進(jìn)行clip,這樣就可以大大減少過(guò)飽和的像素。

這兩種策略的具體代碼如下:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
dynamic thresholding策略對(duì)于Imagen是比較關(guān)鍵的,它使得Imagen可以采用較大的guidance_scale來(lái)生成更自然的圖像。

另一個(gè)比較容易忽略的參數(shù)是negative_prompt,這個(gè)參數(shù)和CFG有關(guān),前面說(shuō)過(guò)Stable Diffusion采用了CFG來(lái)提升生成圖像的質(zhì)量。使用CFG,去噪過(guò)程的噪音預(yù)測(cè)不僅僅依賴(lài)條件擴(kuò)散模型,也依賴(lài)無(wú)條件擴(kuò)散模型
KaTeX parse error: Expected 'EOF', got '_' at position 11: \text{pred_?noise}=w\epsilo…
這里的negative_prompt為無(wú)條件擴(kuò)散模型的text輸入,上文說(shuō)到訓(xùn)練過(guò)程中將text置為空字符串來(lái)實(shí)現(xiàn)無(wú)條件擴(kuò)散模型,即negative_prompt = None = ""。但是有時(shí)候可以使用不為空的negative_prompt來(lái)避免模型生成的圖像包含不想要的東西,因?yàn)閺纳鲜龉娇梢钥吹竭@里的無(wú)條件擴(kuò)散模型是想遠(yuǎn)離的部分

合理使用negative prompt能夠幫助去除不想要的東西來(lái)提升圖像生成效果。 一般情況下,輸入的text或者prompt我們稱(chēng)之為“正向提示詞”,而negative prompt稱(chēng)之為“反向提示詞”,想要生成的好的圖像,不僅要選擇好的正向提示詞,也需要好的反向提示詞,這和文本生成模型也比較類(lèi)似:都需要好的prompt。

一個(gè)對(duì)正向prompt優(yōu)化的例子:

  • 原始prompt為"A rabbit is wearing a space suit",直接生成的效果:
    【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成

  • 將prompt改為"A rabbit is wearing a space suit, digital Art, Greg rutkowski, Trending cinematographic artstation",其生成的效果就大大提升:
    【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
    (2)圖生圖
    圖生圖(image2image)是對(duì)文生圖功能的一個(gè)擴(kuò)展,其核心思路也非常簡(jiǎn)單:給定一個(gè)筆畫(huà)的色塊圖像,可以先給它加一定的高斯噪音(執(zhí)行擴(kuò)散過(guò)程)得到噪音圖像,然后基于擴(kuò)散模型對(duì)這個(gè)噪音圖像進(jìn)行去噪,就可以生成新的圖像,但是這個(gè)圖像在結(jié)構(gòu)和布局和輸入圖像基本一致。
    【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
    對(duì)于Stable Diffusion來(lái)說(shuō),圖生圖的流程圖如下所示,相比文生圖流程來(lái)說(shuō),這里的
    初始latent不再是一個(gè)隨機(jī)噪音,而是由初始圖像經(jīng)過(guò)autoencoder編碼之后的latent加高斯噪音得到
    ,這里的加噪過(guò)程就是擴(kuò)散過(guò)程。要注意的是,去噪過(guò)程的步數(shù)要和加噪過(guò)程的步數(shù)一致,就是說(shuō)你加了多少噪音,就應(yīng)該去掉多少噪音,這樣才能生成想要的無(wú)噪音圖像。
    【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
    在diffusers中,可以使用StableDiffusionImg2ImgPipeline來(lái)實(shí)現(xiàn)文生圖,具體代碼如下:

import torch
from diffusers import StableDiffusionImg2ImgPipeline
from PIL import Image

# 加載圖生圖pipeline
model_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionImg2ImgPipeline.from_pretrained(model_id, torch_dtype=torch.float32).to(device)

# 讀取初始圖片
init_image = Image.open("boy.jpg").convert("RGB")

# 推理
prompt = "A fantasy landscape, trending on artstation"
generator = torch.Generator(device=device).manual_seed(2023)

image = pipe(
    prompt=prompt,
    image=init_image,
    strength=0.8,
    guidance_scale=7.5,
    generator=generator
).images[0]
image


相比文生圖的pipeline,圖生圖的pipeline還多了一個(gè)參數(shù)strength,這個(gè)參數(shù)介于0-1之間,表示對(duì)輸入圖片加噪音的程度,這個(gè)值越大加的噪音越多,對(duì)原始圖片的破壞也就越大,當(dāng)strength=1時(shí),其實(shí)就變成了一個(gè)隨機(jī)噪音,此時(shí)就相當(dāng)于純粹的文生圖pipeline了。

總結(jié)來(lái)看,圖生圖其實(shí)核心也是依賴(lài)了文生圖的能力,其中strength這個(gè)參數(shù)需要靈活調(diào)節(jié)來(lái)得到滿(mǎn)意的圖像。

(3)圖像修補(bǔ)
圖像修補(bǔ),image inpainting,它和圖生圖一樣也是文生圖功能的一個(gè)擴(kuò)展。Stable Diffusion的圖像inpainting不是用在圖像修復(fù)上,而是主要用在圖像編輯上給定一個(gè)輸入圖像和想要編輯的區(qū)域mask,通過(guò)文生圖來(lái)編輯mask區(qū)域的內(nèi)容。Stable Diffusion的圖像inpainting原理圖如下所示:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
和圖生圖一樣:首先將輸入圖像通過(guò)autoencoder編碼為latent,然后加入一定的高斯噪音生成noisy latent,再進(jìn)行去噪生成圖像,但是這里為了保證mask以外的區(qū)域不發(fā)生變化,在去噪過(guò)程的每一步,都將擴(kuò)散模型預(yù)測(cè)的noisy latent用真實(shí)圖像同level的nosiy latent替換。

在diffusers中,使用StableDiffusionInpaintPipelineLegacy可以實(shí)現(xiàn)文本引導(dǎo)下的圖像inpainting,具體代碼如下所示:

import torch
from diffusers import StableDiffusionInpaintPipelineLegacy
from PIL import Image

# 加載inpainting pipeline
model_id = "runwayml/stable-diffusion-v1-5"
pipe = StableDiffusionInpaintPipelineLegacy.from_pretrained(model_id, torch_dtype=torch.float16).to("cuda")

# 讀取輸入圖像和輸入mask
input_image = Image.open("overture-creations-5sI6fQgYIuo.png").resize((512, 512))
input_mask = Image.open("overture-creations-5sI6fQgYIuo_mask.png").resize((512, 512))

# 執(zhí)行推理
prompt = ["a mecha robot sitting on a bench", "a cat sitting on a bench"]
generator = torch.Generator("cuda").manual_seed(0)

with torch.autocast("cuda"):
    images = pipe(
        prompt=prompt,
        image=input_image,
        mask_image=input_mask,
        num_inference_steps=50,
        strength=0.75,
        guidance_scale=7.5,
        num_images_per_prompt=1,
        generator=generator,
    ).images

下面是一個(gè)具體的生成效果,這里我們將輸入圖像的dog換成了mecha robot或者cat,從而實(shí)現(xiàn)了圖像編輯。
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
要注意的是這里的參數(shù)guidance_scale也和圖生圖一樣比較重要,要生成好的圖像,需要選擇合適的guidance_scale。如果guidance_scale=0.5時(shí),生成的圖像由于過(guò)于受到原圖干擾而產(chǎn)生一些不協(xié)調(diào)。

無(wú)論是上面的圖生圖還是這里的圖像inpainting,其實(shí)并沒(méi)有去finetune Stable Diffusion模型,只是擴(kuò)展了它的能力,但是這兩樣功能就需要精確調(diào)整參數(shù)才能得到滿(mǎn)意的生成效果。 這里也給出StableDiffusionInpaintPipelineLegacy這個(gè)pipeline內(nèi)部的核心代碼:

import PIL
import numpy as np
import torch
from diffusers import AutoencoderKL, UNet2DConditionModel, DDIMScheduler
from transformers import CLIPTextModel, CLIPTokenizer
from tqdm.auto import tqdm

def preprocess_mask(mask):
    mask = mask.convert("L")
    w, h = mask.size
    w, h = map(lambda x: x - x % 32, (w, h))  # resize to integer multiple of 32
    mask = mask.resize((w // 8, h // 8), resample=PIL.Image.NEAREST)
    mask = np.array(mask).astype(np.float32) / 255.0
    mask = np.tile(mask, (4, 1, 1))
    mask = mask[None].transpose(0, 1, 2, 3)  # what does this step do?
    mask = 1 - mask  # repaint white, keep black
    mask = torch.from_numpy(mask)
    return mask

def preprocess(image):
    w, h = image.size
    w, h = map(lambda x: x - x % 32, (w, h))  # resize to integer multiple of 32
    image = image.resize((w, h), resample=PIL.Image.LANCZOS)
    image = np.array(image).astype(np.float32) / 255.0
    image = image[None].transpose(0, 3, 1, 2)
    image = torch.from_numpy(image)
    return 2.0 * image - 1.0

model_id = "runwayml/stable-diffusion-v1-5"
# 1. 加載autoencoder
vae = AutoencoderKL.from_pretrained(model_id, subfolder="vae")
# 2. 加載tokenizer和text encoder 
tokenizer = CLIPTokenizer.from_pretrained(model_id, subfolder="tokenizer")
text_encoder = CLIPTextModel.from_pretrained(model_id, subfolder="text_encoder")
# 3. 加載擴(kuò)散模型UNet
unet = UNet2DConditionModel.from_pretrained(model_id, subfolder="unet")
# 4. 定義noise scheduler
noise_scheduler = DDIMScheduler(
    num_train_timesteps=1000,
    beta_start=0.00085,
    beta_end=0.012,
    beta_schedule="scaled_linear",
    clip_sample=False, # don't clip sample, the x0 in stable diffusion not in range [-1, 1]
    set_alpha_to_one=False,
)

# 將模型復(fù)制到GPU上
device = "cuda"
vae.to(device, dtype=torch.float16)
text_encoder.to(device, dtype=torch.float16)
unet = unet.to(device, dtype=torch.float16)

prompt = "a mecha robot sitting on a bench"
strength = 0.75
guidance_scale = 7.5
batch_size = 1
num_inference_steps = 50
negative_prompt = ""
generator = torch.Generator(device).manual_seed(0)

with torch.no_grad():
    # 獲取prompt的text_embeddings
    text_input = tokenizer(prompt, padding="max_length", max_length=tokenizer.model_max_length, truncation=True, return_tensors="pt")
    text_embeddings = text_encoder(text_input.input_ids.to(device))[0]
    # 獲取unconditional text embeddings
    max_length = text_input.input_ids.shape[-1]
    uncond_input = tokenizer(
        [negative_prompt] * batch_size, padding="max_length", max_length=max_length, return_tensors="pt"
    )
    uncond_embeddings = text_encoder(uncond_input.input_ids.to(device))[0]
    # 拼接batch
    text_embeddings = torch.cat([uncond_embeddings, text_embeddings])

    # 設(shè)置采樣步數(shù)
    noise_scheduler.set_timesteps(num_inference_steps, device=device)
    # 根據(jù)strength計(jì)算timesteps
    init_timestep = min(int(num_inference_steps * strength), num_inference_steps)
    t_start = max(num_inference_steps - init_timestep, 0)
    timesteps = noise_scheduler.timesteps[t_start:]


    # 預(yù)處理init_image
    init_input = preprocess(input_image)
    init_latents = vae.encode(init_input.to(device, dtype=torch.float16)).latent_dist.sample(generator)
    init_latents = 0.18215 * init_latents
    init_latents = torch.cat([init_latents] * batch_size, dim=0)
    init_latents_orig = init_latents
    # 處理mask
    mask_image = preprocess_mask(input_mask)
    mask_image = mask_image.to(device=device, dtype=init_latents.dtype)
    mask = torch.cat([mask_image] * batch_size)
    
    # 給init_latents加噪音
    noise = torch.randn(init_latents.shape, generator=generator, device=device, dtype=init_latents.dtype)
    init_latents = noise_scheduler.add_noise(init_latents, noise, timesteps[:1])
    latents = init_latents # 作為初始latents


    # Do denoise steps
    for t in tqdm(timesteps):
        # 這里latens擴(kuò)展2份,是為了同時(shí)計(jì)算unconditional prediction
        latent_model_input = torch.cat([latents] * 2)
        latent_model_input = noise_scheduler.scale_model_input(latent_model_input, t) # for DDIM, do nothing

        # 預(yù)測(cè)噪音
        noise_pred = unet(latent_model_input, t, encoder_hidden_states=text_embeddings).sample

        # CFG
        noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
        noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)

        # 計(jì)算上一步的noisy latents:x_t -> x_t-1
        latents = noise_scheduler.step(noise_pred, t, latents).prev_sample
        
        # 將unmask區(qū)域替換原始圖像的nosiy latents
        init_latents_proper = noise_scheduler.add_noise(init_latents_orig, noise, torch.tensor([t]))
        latents = (init_latents_proper * mask) + (latents * (1 - mask))

    # 注意要對(duì)latents進(jìn)行scale
    latents = 1 / 0.18215 * latents
    image = vae.decode(latents).sample

另外,runwayml在發(fā)布SD 1.5版本的同時(shí)還發(fā)布了一個(gè)inpainting模型:runwayml/stable-diffusion-inpainting,與前面所講不同的是,這是一個(gè)在SD 1.2上finetune的模型。原來(lái)Stable Diffusion的UNet的輸入是64x64x4,為了實(shí)現(xiàn)inpainting,現(xiàn)在給UNet的第一個(gè)卷積層增加5個(gè)channels,分別為masked圖像的latents(經(jīng)過(guò)autoencoder編碼,64x64x4)和mask圖像(直接下采樣8x,64x64x1),增加的權(quán)重填零初始化。

在diffusers中,可以使用StableDiffusionInpaintPipeline來(lái)調(diào)用這個(gè)模型,具體代碼如下:

import torch
from diffusers import StableDiffusionInpaintPipeline
from PIL import Image
from tqdm.auto import tqdm
import PIL

# Load pipeline
model_id = "runwayml/stable-diffusion-inpainting/"
pipe = StableDiffusionInpaintPipeline.from_pretrained(model_id, torch_dtype=torch.float16).to("cuda")

prompt = ["a mecha robot sitting on a bench", "a dog sitting on a bench", "a bench"]

generator = torch.Generator("cuda").manual_seed(2023)

input_image = Image.open("overture-creations-5sI6fQgYIuo.png").resize((512, 512))
input_mask = Image.open("overture-creations-5sI6fQgYIuo_mask.png").resize((512, 512))

images = pipe(
    prompt=prompt,
    image=input_image,
    mask_image=input_mask,
    num_inference_steps=50,
    generator=generator,
    ).images

其生成的效果圖如下所示:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
經(jīng)過(guò)finetune的inpainting在生成細(xì)節(jié)上可能會(huì)更好,但是有可能會(huì)喪失部分文生圖的能力,而且也比較難遷移其它finetune的Stable Diffusion模型。

1.6 模型版本

(1)Stable Diffusion V2
Stability AI公司在2022年11月(stable-diffusion-v2-release)放出了SD 2.0版本,SD 2.0相比SD 1.x版本的主要變動(dòng)在于模型結(jié)構(gòu)訓(xùn)練數(shù)據(jù)兩個(gè)部分。

首先是模型結(jié)構(gòu),SD 1.x版本的text encoder采用的是OpenAI的CLIP ViT-L/14模型,其模型參數(shù)量為123.65M;而SD 2.0采用了更大的text encoder:基于OpenCLIP在laion-2b數(shù)據(jù)集上訓(xùn)練的CLIP ViT-H/14模型,其參數(shù)量為354.03M,相比原來(lái)的text encoder模型大了約3倍。

然后是訓(xùn)練數(shù)據(jù),前面說(shuō)過(guò)SD 1.x版本其實(shí)最后主要采用Laion-2B中美學(xué)評(píng)分為5以上的子集來(lái)訓(xùn)練,而SD 2.0版本采用評(píng)分在4.5以上的子集,相當(dāng)于擴(kuò)大了訓(xùn)練數(shù)據(jù)集,具體的訓(xùn)練細(xì)節(jié)見(jiàn)model card。 另外SD 2.0除了512x512版本的模型,還包括768x768版本的模型(https://huggingface.co/stabilityai/stable-diffusion-2),所謂的768x768模型是在512x512模型基礎(chǔ)上用圖像分辨率大于768x768的子集繼續(xù)訓(xùn)練的,不過(guò)優(yōu)化目標(biāo)不再是noise_prediction,而是采用Progressive Distillation for Fast Sampling of Diffusion Models論文中所提出的 v-objective。

Stability AI在發(fā)布SD 2.0的同時(shí),還發(fā)布了另外3個(gè)模型:stable-diffusion-x4-upscaler,stable-diffusion-2-inpaintingstable-diffusion-2-depth。

在diffusers庫(kù)中,可以如下使用這個(gè)超分模型(這里的noise level是指推理時(shí)對(duì)低分辨率圖像加入噪音的程度):

import requests
from PIL import Image
from io import BytesIO
from diffusers import StableDiffusionUpscalePipeline
import torch

# load model and scheduler
model_id = "stabilityai/stable-diffusion-x4-upscaler"
pipeline = StableDiffusionUpscalePipeline.from_pretrained(model_id, torch_dtype=torch.float16)
pipeline = pipeline.to("cuda")

# let's download an  image
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=20).images[0]
upscaled_image.save("upsampled_cat.png")

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
stable-diffusion-2-depth是也是在SD 2.0的512x512版本上finetune的模型,它是額外增加了圖像的深度圖作為condition,這里是直接將深度圖下采樣8x,然后和nosiy latent拼接在一起送入U(xiǎn)Net模型中。深度圖可以作為一種結(jié)構(gòu)控制,下圖展示了加入深度圖后生成的圖像效果:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
原圖如下:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
可以調(diào)用diffusers庫(kù)中的StableDiffusionDepth2ImgPipeline來(lái)實(shí)現(xiàn)基于深度圖控制的文生圖:

import torch
import requests
from PIL import Image
from diffusers import StableDiffusionDepth2ImgPipeline

pipe = StableDiffusionDepth2ImgPipeline.from_pretrained(
   "stabilityai/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]

除此之外,Stability AI公司還開(kāi)源了兩個(gè)加強(qiáng)版的autoencoder:ft-EMAft-MSE(前者使用L1 loss后者使用MSE loss),它們是在LAION數(shù)據(jù)集繼續(xù)finetune decoder來(lái)增強(qiáng)重建效果。

(2)Stable Diffusion V2.1
在SD 2.0版本發(fā)布幾周后,Stability AI又發(fā)布了SD 2.1。SD 2.0在訓(xùn)練過(guò)程中采用NSFW檢測(cè)器過(guò)濾掉了可能包含色情的圖像(punsafe=0.1),但是也同時(shí)過(guò)濾了很多人像圖片,這導(dǎo)致SD 2.0在人像生成上效果可能較差,所以SD 2.1是在SD 2.0的基礎(chǔ)上放開(kāi)了限制(punsafe=0.98)繼續(xù)finetune,所以增強(qiáng)了人像的生成效果。

(3)Stable Diffusion unclip
Stability AI在2023年3月份,又放出了基于Stable Diffusion的另外一個(gè)模型:stable-diffusion-reimagine,它可以實(shí)現(xiàn)單個(gè)圖像的變換,即image variations,目前該模型已經(jīng)在在huggingface上開(kāi)源:stable-diffusion-2-1-unclip。

這個(gè)模型是借鑒了OpenAI的DALLE2(又稱(chēng)unCLIP),unCLIP是基于CLIP的image encoder提取的image embeddings作為condition來(lái)實(shí)現(xiàn)圖像的生成。
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
Stable Diffusion unCLIP是在原來(lái)的Stable Diffusion模型的基礎(chǔ)上增加了CLIP的image encoder的nosiy image embeddings作為condition。具體來(lái)說(shuō),它在訓(xùn)練過(guò)程中是對(duì)提取的image embeddings施加一定的高斯噪音(也是通過(guò)擴(kuò)散過(guò)程),然后將noise level對(duì)應(yīng)的time embeddings和image embeddings拼接在一起,最后再以class labels的方式送入U(xiǎn)Net。

在diffusers中,可以調(diào)用StableUnCLIPImg2ImgPipeline來(lái)實(shí)現(xiàn)圖像的變換:

import requests
import torch
from PIL import Image
from io import BytesIO

from diffusers import StableUnCLIPImg2ImgPipeline

#Start the StableUnCLIP Image variations pipeline
pipe = StableUnCLIPImg2ImgPipeline.from_pretrained(
    "stabilityai/stable-diffusion-2-1-unclip", torch_dtype=torch.float16, variation="fp16"
)
pipe = pipe.to("cuda")

#Get image from URL
url = "https://huggingface.co/datasets/hf-internal-testing/diffusers-images/resolve/main/stable_unclip/tarsila_do_amaral.png"
response = requests.get(url)
init_image = Image.open(BytesIO(response.content)).convert("RGB")

#Pipe to make the variation
images = pipe(init_image).images
images[0].save("tarsila_variation.png")

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
其實(shí)在Stable Diffusion unCLIP之前,已經(jīng)有Lambda Labs開(kāi)源的sd-image-variations-diffusers,它是在SD 1.4的基礎(chǔ)上finetune的模型,不過(guò)實(shí)現(xiàn)方式是直接將text embeddings替換為image embeddings,這樣也同樣可以實(shí)現(xiàn)圖像的變換。
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
這里Stable Diffusion unCLIP有兩個(gè)版本:sd21-unclip-lsd21-unclip-h,兩者分別是采用OpenAI CLIP-LOpenCLIP-H模型的image embeddings作為condition。如果要實(shí)現(xiàn)文生圖,還需要像DALLE2那樣訓(xùn)練一個(gè)prior模型,它可以實(shí)現(xiàn)基于文本來(lái)預(yù)測(cè)對(duì)應(yīng)的image embeddings,將prior模型和SD unCLIP接在一起就可以實(shí)現(xiàn)文生圖了。

1.7 其他類(lèi)型的條件生成模型

  1. Img2Img
    Img2Img是圖片到圖片的轉(zhuǎn)換,包括多種類(lèi)型,如風(fēng)格轉(zhuǎn)換(從照片風(fēng)格轉(zhuǎn)換為動(dòng)漫風(fēng)格)和圖片超分辨率(給定一張低分辨率圖片作為條件,讓模型生成對(duì)應(yīng)的高分辨率圖片,類(lèi)似于Stable Diffusion Upscaler)。

  2. Inpainting
    Inpainting又稱(chēng)為圖片修復(fù),它是圖片的部分掩膜到圖片的轉(zhuǎn)換,模型會(huì)根據(jù)掩膜的區(qū)域信息和掩膜之外的全局結(jié)構(gòu)信息,用掩膜區(qū)域生成連貫的圖片,而掩膜區(qū)域之外則與原圖保持一致。

  3. Depth2Img
    Depth2Img采用圖片的深度圖作為條件,模型會(huì)生成與深度圖本身相似的具有全局結(jié)構(gòu)的圖片。

1.8 使用DreamBooth進(jìn)行微調(diào)

DreamBooth是一種個(gè)性化訓(xùn)練一個(gè)文本到圖像模型的方法,只需要提供一個(gè)主題的3~5張圖像,就能教會(huì)模型有關(guān)這個(gè)主題的各種概念,從而在不同的場(chǎng)景和視圖中生成這個(gè)主題的相關(guān)圖像。

2. 實(shí)戰(zhàn)Stable Diffusion

2.1 環(huán)境準(zhǔn)備

!pip install -Uq diffusers fifty accelerate transformers

查看GPU:

import torch

device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(f'Using device: {device}')

下載圖像:

import torch
import requests
from PIL import Image
from io import BytesIO
from matplotlib import pyplot as plt

from diffusers import (
    StableDiffusionPipeline, 
    StableDiffusionImg2ImgPipeline,
    StableDiffusionInpaintPipeline, 
    StableDiffusionDepth2ImgPipeline
    )       

def download_image(url):
    response = requests.get(url)
    return Image.open(BytesIO(response.content)).convert("RGB")

img_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo.png"
mask_url = "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo_mask.png"

init_image = download_image(img_url).resize((512, 512))
mask_image = download_image(mask_url).resize((512, 512))

device =  "cuda" if torch.cuda.is_available() else "cpu"

2.2 從文本生成圖像

載入管線:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
如果GPU顯存不足,可以嘗試通過(guò)如下方法減少對(duì)GPU顯存的使用:

  • 載入FP16精度版本(并非所有系統(tǒng)都支持),此時(shí)需要保證所有張量都是torch.float16精度:
pipe = StableDiffusionPipeline.from_pretrained(model_id, revision="fp16", torch_dtype=torch.float16).to(device)
  • 開(kāi)啟注意力切分功能,旨在通過(guò)降低速度來(lái)減少GPU顯存的使用,代碼如下:
pipe.enable_attention_slicing()
  • 減少所生成圖片的尺寸。

管線加載完畢后,通過(guò)如下代碼,利用文本提示語(yǔ)生成圖片:

# 給生成器設(shè)置一個(gè)隨機(jī)種子
generator = torch.Generator(device=device).manual_seed(42)

pipe_output = pipe(
    prompt="Palette knife painting of an autumn cityscape", # 提示語(yǔ):哪里要生成
    negative_prompt="Oversaturated, blurry, low quality", # 提示語(yǔ):哪里不需要生成
    height=480, width=640,     # 圖片大小
    guidance_scale=8,        # 提示文字的影響程度
    num_inference_steps=35,     # 推理步數(shù)
    generator=generator       # 設(shè)置隨機(jī)種子生成器
)

pipe_output.images[0]

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
主要的調(diào)節(jié)參數(shù)如下:

  • width和height用于指定所生成圖片的尺寸,注意它們必須是能被8整除的數(shù)字,只有這樣,VAE才能正常工作。
  • 步數(shù)num_inference_steps也會(huì)影響所生成圖片的質(zhì)量,采用默認(rèn)設(shè)置50即可,也可以嘗試將其設(shè)置為20并觀察結(jié)果。
  • negative_prompt用于強(qiáng)調(diào)不希望生成的內(nèi)容,這個(gè)參數(shù)一般在無(wú)分類(lèi)器引導(dǎo)的情況下使用。這種添加額外控制的方式特別有效:列出一些不想要的特征,有助于生成更好的結(jié)果。
  • guidance_scale決定了無(wú)分類(lèi)器引導(dǎo)的影響強(qiáng)度。增大這個(gè)參數(shù)可以使生成的內(nèi)容更接近給出的文本提示語(yǔ);但如果該參數(shù)過(guò)大,則可能導(dǎo)致結(jié)果過(guò)于飽和,不美觀。

以下代碼能加大guidance_scale參數(shù)的作用:

# 對(duì)比不同的guidance_scale效果(該參數(shù)決定了無(wú)分類(lèi)器引導(dǎo)的影響強(qiáng)度)
cfg_scales = [1.1, 8, 12] 
prompt = "A collie with a pink hat" 
fig, axs = plt.subplots(1, len(cfg_scales), figsize=(16, 5))
for i, ax in enumerate(axs):
    im = pipe(prompt, height=480, width=480,
        guidance_scale=cfg_scales[i], num_inference_steps=35,
        generator=torch.Generator(device=device).manual_seed(42)).images[0]
    ax.imshow(im); ax.set_title(f'CFG Scale {cfg_scales[i]}');

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成

2.3 Stable Diffusion Pipeline

查看Stable Diffusion Pipeline的組成部分:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成

2.3.1

可變分自編碼器(VAE)是一種模型,VAE可以對(duì)輸入圖像進(jìn)行編碼,得到“壓縮過(guò)”的信息,之后再解碼“隱式的”壓縮信息,得到接近輸入的輸出。
UNet的輸入不是完整的圖片,而是縮小版的特征,這樣可以極大地減少對(duì)計(jì)算資源的使用。

# 創(chuàng)建區(qū)間為(-1, 1)的偽數(shù)據(jù)
images = torch.rand(1, 3, 512, 512).to(device) * 2 - 1 
print("Input images shape:", images.shape)

# 編碼到隱空間
with torch.no_grad():
    latents = 0.18215 * pipe.vae.encode(images).latent_dist.mean
print("Encoded latents shape:", latents.shape)

# 解碼
with torch.no_grad():
    decoded_images = pipe.vae.decode(latents / 0.18215).sample
print("Decoded images shape:", decoded_images.shape)

代碼輸出內(nèi)容:

Input images shape: torch.Size([1, 3, 512, 512])
Encoded latents shape: torch.Size([1, 4, 64, 64])
Decoded images shape: torch.Size([1, 3, 512, 512])

2.3.2 分詞器和文本編碼器

文本編碼器的作用是將輸入的字符串(文本提示語(yǔ))轉(zhuǎn)換成數(shù)值表示形式,這樣才能將其輸入U(xiǎn)Net作為條件。文本則被管線中的分詞器(tokenizer)轉(zhuǎn)換成一系列的token(分詞)。文本編碼器是一個(gè)Transformer模型,它被訓(xùn)練用于CLIP。

下面首先手動(dòng)分詞,并將分詞結(jié)果輸入文本編碼器,然后使用管線的_encode_prompt方法調(diào)用這個(gè)編碼過(guò)程,其間補(bǔ)全或截?cái)喾衷~串的長(zhǎng)度;最后使得分詞串的長(zhǎng)度等于最大長(zhǎng)度7。
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
接下來(lái),獲取最終的文本特征:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
文本嵌入(text embedding)是指文本編碼器中最后一個(gè)Transformer模塊的“隱狀態(tài)”(hidden state),它們將作為UNet中的forward函數(shù)的一個(gè)額外輸入。

2.3.3 UNet

在擴(kuò)散模型中,UNet的作用是接收“帶噪”的輸入并預(yù)測(cè)噪聲,以實(shí)現(xiàn)“去噪”。此處輸入模型的并非圖片,而是圖片的隱式表示形式,此外,除了將用于暗示“帶噪”程度的時(shí)間步作為條件輸入U(xiǎn)Net之外,模型還將文本提示語(yǔ)和文本嵌入也作為UNet的輸入。

首先使用偽輸入嘗試讓模型進(jìn)行預(yù)測(cè)。注意在此過(guò)程中各個(gè)輸入輸出的形狀和大小:

# 創(chuàng)建偽輸入
timestep = pipe.scheduler.timesteps[0]
latents = torch.randn(1, 4, 64, 64).to(device)
text_embeddings = torch.randn(1, 77, 1024).to(device)

# 模型預(yù)測(cè)
with torch.no_grad():
    unet_output = pipe.unet(latents, timestep, text_embeddings).sample
print('UNet output shape:', unet_output.shape)  # UNet output shape: torch.Size([1, 4, 64, 64])

2.3.4 調(diào)度器

調(diào)度器保存了關(guān)于如何添加噪聲的信息,并管理如何基于模型的預(yù)測(cè)更新“帶噪”樣本。默認(rèn)的調(diào)度器是PNDMScheduler。

可以通過(guò)繪制圖片來(lái)觀察在添加噪聲的過(guò)程中噪聲水平(基于參數(shù) α ˉ \bar{\alpha} αˉ)隨時(shí)間步增加的變化趨勢(shì):

plt.plot(pipe.scheduler.alphas_cumprod, label=r'$\bar{\alpha}$')
plt.xlabel('Timestep (high noise to low noise ->)')
plt.title('Noise schedule')
plt.legend();

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
嘗試不同的調(diào)度器:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
生成的圖片:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成

2.3.5 DIY采樣循環(huán)

將管線的不同組成部分組裝在一起,復(fù)現(xiàn)整個(gè)管線的功能:

guidance_scale = 8 
num_inference_steps=30 
prompt = "Beautiful picture of a wave breaking" 
negative_prompt = "zoomed in, blurry, oversaturated, warped" 

# 對(duì)提示文字進(jìn)行編碼
text_embeddings = pipe._encode_prompt(prompt, device, 1, True, negative_prompt)

# 創(chuàng)建隨機(jī)噪聲作為起點(diǎn)
latents = torch.randn((1, 4, 64, 64), device=device, generator=generator)
latents *= pipe.scheduler.init_noise_sigma

# 設(shè)置調(diào)度器
pipe.scheduler.set_timesteps(num_inference_steps, device=device)

# 循環(huán)采樣
for i, t in enumerate(pipe.scheduler.timesteps):
    latent_model_input = torch.cat([latents] * 2)
    latent_model_input = pipe.scheduler.scale_model_input(latent_model_input, t)
    with torch.no_grad():
        noise_pred = pipe.unet(latent_model_input, t, text_embeddings).sample
    noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
    noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)

    # compute the previous noisy sample x_t -> x_t-1
    latents = pipe.scheduler.step(noise_pred, t, latents).prev_sample

# 將隱變量映射到圖片
with torch.no_grad():
    image = pipe.decode_latents(latents.detach())
pipe.numpy_to_pil(image)[0]

生成的結(jié)果:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成

2.4 其他管線應(yīng)用

2.4.1 Img2Img

Img2Img首先會(huì)對(duì)一張已有的圖片進(jìn)行編碼,得到隱變量后添加隨機(jī)噪聲,并以此作為起點(diǎn)。噪聲的數(shù)量和“去噪”所需步數(shù)決定了Img2Img過(guò)程的“強(qiáng)度”.

Img2Img管線不需要任何特殊的模型,而只需要與文字到圖像模型相同的模型ID,無(wú)需下載新文件。

首先載入Img2Img管線:

model_id = "stabilityai/stable-diffusion-2-1-base"
img2img_pipe = StableDiffusionImg2ImgPipeline.from_pretrained(model_id, revision="fp16", torch_dtype=torch.float16).to(device)

Img2Img管線代碼:

result_image = img2img_pipe(
    prompt="An oil painting of a man on a bench",
    image = init_image,
    strength = 0.6, # 強(qiáng)度:0表示完全不起作用,1表示作用強(qiáng)度最大
).images[0]


fig, axs = plt.subplots(1, 2, figsize=(12, 5))
axs[0].imshow(init_image);axs[0].set_title('Input Image')
axs[1].imshow(result_image);axs[1].set_title('Result');

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成

2.4.2 Inpainting

關(guān)于Inpainting的內(nèi)容上文已經(jīng)詳細(xì)說(shuō)明了,這里回顧以下。Stable Diffusion模型接收一張掩模圖片作為額外條件輸入,該掩模圖片與輸入圖片的尺寸一致,白色區(qū)域表示要替換的部分,黑色區(qū)域表示要保留的部分。

以下代碼展示了如何載入StableDiffusionInpaintPipelineLegacy管線并將其應(yīng)用于前面輸入的示例圖片和掩膜圖片:

pipe = StableDiffusionInpaintPipeline.from_pretrained("runwayml/stable-diffusion-inpainting", revision="fp16", torch_dtype=torch.float16)
pipe = pipe.to(device)

prompt = "A small robot, high resolution, sitting on a park bench"
image = pipe(prompt=prompt, image=init_image, mask_image=mask_image).images[0]

fig, axs = plt.subplots(1, 3, figsize=(16, 5))
axs[0].imshow(init_image);axs[0].set_title('Input Image')
axs[1].imshow(mask_image);axs[1].set_title('Mask')
axs[2].imshow(image);axs[2].set_title('Result');

【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
Hugging Face Spaces上的一個(gè)示例Space應(yīng)用就使用了一個(gè)名為CLIPSeg的模型,旨在根據(jù)文字描述自動(dòng)地通過(guò)掩膜去掉一個(gè)物體。

2.4.3 Depth2Image

Depth2Image采用深度預(yù)測(cè)模型來(lái)預(yù)測(cè)一個(gè)深度圖,該深度圖被輸入微調(diào)過(guò)的UNet以生成圖片。希望生成的圖片既能保留原始圖片的深度信息和總體結(jié)構(gòu),同時(shí)又能在相關(guān)部分填入全新的內(nèi)容:

pipe = StableDiffusionDepth2ImgPipeline.from_pretrained("stabilityai/stable-diffusion-2-depth",revision="fp16", torch_dtype=torch.float16)
pipe = pipe.to(device)

prompt = "An oil painting of a man on a bench"
image = pipe(prompt=prompt, image=init_image).images[0]

fig, axs = plt.subplots(1, 2, figsize=(16, 5))
axs[0].imshow(init_image);axs[0].set_title('Input Image')
axs[1].imshow(image);axs[1].set_title('Result');

Depth2Img管線的生成結(jié)果:
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成

3. Stable Diffusion的特色應(yīng)用

3.1 個(gè)性化生成

個(gè)性化生成是指的生成特定的角色或者風(fēng)格,比如給定自己幾張肖像來(lái)利用SD來(lái)生成個(gè)性化頭像。在個(gè)性化生成方面,比較重要的兩個(gè)工作是英偉達(dá)的Textual Inversion和谷歌的DreamBooth。

  • Textual Inversion這個(gè)工作的核心思路是基于用戶(hù)提供的3~5張?zhí)囟ǜ拍睿ㄎ矬w或者風(fēng)格)的圖像來(lái)學(xué)習(xí)一個(gè)特定的text embeddings,實(shí)際上只用一個(gè)word embedding就足夠了。Textual Inversion不需要finetune UNet,而且由于text embeddings較小,存儲(chǔ)成本很低。目前diffusers庫(kù)已經(jīng)支持textual_inversion的訓(xùn)練。
  • DreamBooth原本是谷歌提出的應(yīng)用在Imagen上的個(gè)性化生成,但是它實(shí)際上也可以擴(kuò)展到Stable Diffusion上。DreamBooth首先為特定的概念尋找一個(gè)特定的描述詞[V],這個(gè)特定的描述詞只要是稀有的就可以,然后與Textual Inversion不同的是DreamBooth需要finetune UNet,這里為了防止過(guò)擬合,增加了一個(gè)class-specific prior preservation loss(基于SD生成同class圖像加入batch里面訓(xùn)練)來(lái)進(jìn)行正則化。
    【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
    由于finetune了UNet,DreamBooth往往比Textual Inversion要表現(xiàn)的要好,但是DreamBooth的存儲(chǔ)成本較高。目前diffusers庫(kù)已經(jīng)支持dreambooth訓(xùn)練,也可以在sd-dreambooth-library中找到其他人上傳的模型。

還有很多其它的研究工作,比如Adobe提出的Custom Diffusion,相比DreamBooth,它只finetune了UNet的attention模塊的KV權(quán)重矩陣,同時(shí)優(yōu)化一個(gè)新概念的token。
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成

3.2 風(fēng)格化finetune模型

Stable Diffusion的另外一大應(yīng)用是采用特定風(fēng)格的數(shù)據(jù)集進(jìn)行finetune,這使得模型“過(guò)擬合”在特定的風(fēng)格上。之前比較火的novelai就是基于二次元數(shù)據(jù)在Stable Diffusion上finetune的模型,雖然它失去了生成其它風(fēng)格圖像的能力,但是它在二次元圖像的生成效果上比原來(lái)的Stable Diffusion要好很多。
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
目前已經(jīng)有很多風(fēng)格化的模型在huggingface上開(kāi)源,這里也列出一些:

  • andite/anything-v4.0:二次元或者動(dòng)漫風(fēng)格圖像
  • dreamlike-art/dreamlike-diffusion-1.0:藝術(shù)風(fēng)格圖像
  • prompthero/openjourney:mdjrny-v4風(fēng)格圖像

值得說(shuō)明的一點(diǎn)是,目前finetune Stable Diffusion模型的方法主要有兩種:一種是直接finetune了UNet,但是容易過(guò)擬合,而且存儲(chǔ)成本;另外一種低成本的方法是基于微軟的LoRA,LoRA本來(lái)是用于finetune語(yǔ)言模型的,但是現(xiàn)在已經(jīng)可以用來(lái)finetune Stable Diffusion模型了

3.3 圖像編輯

圖像編輯也是Stable Diffusion比較火的應(yīng)用方向,這里所說(shuō)的圖像編輯是指的是使用Stable Diffusion來(lái)實(shí)現(xiàn)對(duì)圖片的局部編輯。這里列舉兩個(gè)比較好的工作:谷歌的prompt-to-prompt和加州伯克利的instruct-pix2pix。

  • 谷歌的prompt-to-prompt的核心是基于UNet的cross attention maps來(lái)實(shí)現(xiàn)對(duì)圖像的編輯,它的好處是不需要finetune模型,但是主要用在編輯用Stable Diffusion生成的圖像。
  • 伯克利的instruct-pix2pix這個(gè)工作基于GPT-3和prompt-to-prompt構(gòu)建了pair的數(shù)據(jù)集,然后在Stable Diffusion上進(jìn)行finetune,它可以輸入text instruct對(duì)圖像進(jìn)行編輯

3.4 可控生成

可控生成是Stable Diffusion最近比較火的應(yīng)用,這主要?dú)w功于ControlNet,基于ControlNet可以實(shí)現(xiàn)對(duì)很多種類(lèi)的可控生成,比如邊緣,人體關(guān)鍵點(diǎn),草圖和深度圖等等。
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成
其實(shí)在ControlNet之前,也有一些可控生成的工作,比如stable-diffusion-2-depth也屬于可控生成,但是沒(méi)有太火。

與ControlNet同期的工作還有騰訊的T2I-Adapter以及阿里的composer-page
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成

3.5 Stable-Diffusion-WebUI

最后要介紹的一個(gè)比較火的應(yīng)用stable-diffusion-webui其實(shí)是用來(lái)支持Stable Diffusion出圖的一個(gè)web工具,它算是基于gradio框架實(shí)現(xiàn)了Stable Diffusion的快速部署,不僅支持Stable Diffusion的最基礎(chǔ)的文生圖、圖生圖以及圖像inpainting功能,還支持Stable Diffusion的其它拓展功能,很多基于Stable Diffusion的拓展應(yīng)用可以用插件的方式安裝在webui上。
【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion,生成式AI與擴(kuò)散模型,stable diffusion,DDPM,Img2Img,Depth2Image,Inpainting,無(wú)分類(lèi)器引導(dǎo),條件生成文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-814606.html

參考資料

  1. stability.ai
  2. dreamstudio.ai
  3. 硬核解讀Stable Diffusion(系列一)
  4. OpenAI/CLIP
  5. CLIP: Connecting text and images
  6. 十分鐘讀懂Stable Diffusion運(yùn)行原理
  7. 硬核解讀Stable Diffusion(系列二)
  8. 硬核解讀Stable Diffusion(系列三)

到了這里,關(guān)于【擴(kuò)散模型】萬(wàn)字長(zhǎng)文全面理解與應(yīng)用Stable Diffusion的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • stable diffusion原理解讀通俗易懂,史詩(shī)級(jí)萬(wàn)字爆肝長(zhǎng)文!

    stable diffusion原理解讀通俗易懂,史詩(shī)級(jí)萬(wàn)字爆肝長(zhǎng)文!

    hello,大家好我是 Tian-Feng,今天介紹一些stable diffusion的原理,內(nèi)容通俗易懂,因?yàn)槲移綍r(shí)也玩Ai繪畫(huà)嘛,所以就像寫(xiě)一篇文章說(shuō)明它的原理,這篇文章寫(xiě)了真滴挺久的,如果對(duì)你有用的話,希望點(diǎn)個(gè)贊,謝謝。 stable diffusion作為Stability-AI開(kāi)源圖像生成模型,其出現(xiàn)也是不遜于

    2024年04月28日
    瀏覽(25)
  • 【stable diffusion原理解讀通俗易懂,史詩(shī)級(jí)萬(wàn)字爆肝長(zhǎng)文,喂到你嘴里】

    【stable diffusion原理解讀通俗易懂,史詩(shī)級(jí)萬(wàn)字爆肝長(zhǎng)文,喂到你嘴里】

    個(gè)人網(wǎng)站 hello,大家好我是 Tian-Feng,今天介紹一些stable diffusion的原理,內(nèi)容通俗易懂,因?yàn)槲移綍r(shí)也玩Ai繪畫(huà)嘛,所以就像寫(xiě)一篇文章說(shuō)明它的原理,這篇文章寫(xiě)了真滴挺久的,如果對(duì)你有用的話,希望點(diǎn)個(gè)贊,謝謝。 stable diffusion作為Stability-AI開(kāi)源圖像生成模型,其出現(xiàn)也

    2024年02月07日
    瀏覽(28)
  • 【AI繪畫(huà)】萬(wàn)字長(zhǎng)文——(超詳細(xì))ControlNet的詳細(xì)介紹&使用Stable Diffusion的藝術(shù)二維碼完全生成攻略

    【AI繪畫(huà)】萬(wàn)字長(zhǎng)文——(超詳細(xì))ControlNet的詳細(xì)介紹&使用Stable Diffusion的藝術(shù)二維碼完全生成攻略

    詳細(xì)介紹ControlNet的各個(gè)部分,相關(guān)案例,以及使用二維碼作為ControlNet模型的輸入的Stable Diffusion生成的圖像,使二維碼轉(zhuǎn)變?yōu)樗囆g(shù)圖像 Stable Diffusion :是StabilityAI于2022年8月22日發(fā)布的文本到圖像模型。它類(lèi)似于OpenAI的DALL·E 2和Midjourney等其他圖像生成模型,但有一個(gè)很大的不同

    2024年02月05日
    瀏覽(34)
  • 番外篇Diffusion&Stable Diffusion擴(kuò)散模型與穩(wěn)定擴(kuò)散模型

    番外篇Diffusion&Stable Diffusion擴(kuò)散模型與穩(wěn)定擴(kuò)散模型

    本篇文章為閱讀筆記,,主要內(nèi)容圍繞擴(kuò)散模型和穩(wěn)定擴(kuò)散模型展開(kāi),介紹了kl loss、vae模型的損失函數(shù)以及變分下限作為擴(kuò)展部分。擴(kuò)散模型是一種生成模型,定義了一個(gè)逐漸擴(kuò)散的馬爾科夫鏈,逐漸項(xiàng)數(shù)據(jù)添加噪聲,然后學(xué)習(xí)逆擴(kuò)散過(guò)程,從噪聲中構(gòu)建所需的數(shù)據(jù)樣本。穩(wěn)

    2024年02月03日
    瀏覽(27)
  • 擴(kuò)散模型 - Stable Diffusion

    擴(kuò)散模型 - Stable Diffusion

    ? Stable Diffusion 是由 Stability AI 開(kāi)發(fā)的 開(kāi)源 擴(kuò)散模型。Stable Diffusion 可以完成多模態(tài)任務(wù),包括:文字生成圖像(text2img)、圖像生成圖像(img2img)等。 4.1 Stable Diffusion 的組成部分 ? Stable Diffusion 由兩部分 組成 : 文本編碼器:提取文本 prompt 的信息 圖像生成器:根據(jù)文本

    2024年02月11日
    瀏覽(24)
  • Stable diffusion擴(kuò)散模型相關(guān)

    Stable diffusion擴(kuò)散模型相關(guān)

    時(shí)隔兩年半(2年4個(gè)月),我又回來(lái)研究生成技術(shù)了。以前學(xué)習(xí)研究GAN沒(méi)結(jié)果,不管是技術(shù)上,還是應(yīng)用產(chǎn)品上,結(jié)果就放棄了,現(xiàn)在基于diffusion的技術(shù)又把生成技術(shù)帶上了一個(gè)新的高度?,F(xiàn)在自己又來(lái)研究學(xué)習(xí)這方面的東西了?,F(xiàn)在看來(lái),以前還是自己自我定位不清晰,想

    2024年01月17日
    瀏覽(30)
  • 【CV】穩(wěn)定擴(kuò)散模型(Stable Diffusion)

    【CV】穩(wěn)定擴(kuò)散模型(Stable Diffusion)

    ????大家好,我是Sonhhxg_柒,希望你看完之后,能對(duì)你有所幫助,不足請(qǐng)指正!共同學(xué)習(xí)交流?? ??個(gè)人主頁(yè)-Sonhhxg_柒的博客_CSDN博客??? ??歡迎各位→點(diǎn)贊?? + 收藏?? + 留言??? ??系列專(zhuān)欄 - 機(jī)器學(xué)習(xí)【ML】?自然語(yǔ)言處理【NLP】? 深度學(xué)習(xí)【DL】 ?? ???foreword

    2024年02月09日
    瀏覽(42)
  • Stable Diffusion擴(kuò)散模型 + Consistency一致性模型

    Stable Diffusion擴(kuò)散模型 + Consistency一致性模型

    通過(guò)估計(jì)數(shù)據(jù)分布梯度進(jìn)行生成建模 一文解釋 Diffusion Model (一) DDPM 理論推導(dǎo) 隨著人工智能在圖像生成,文本生成以及多模態(tài)生成等 生成領(lǐng)域 的技術(shù)不斷累積,生成對(duì)抗網(wǎng)絡(luò)(GAN)、變微分自動(dòng)編碼器(VAE)、normalizing flow models、自回歸模型(AR)、energy-based models以及近年來(lái)

    2024年02月09日
    瀏覽(20)
  • 理解擴(kuò)散模型:Diffusion Models & DDPM

    理解擴(kuò)散模型:Diffusion Models & DDPM

    在前面的博客中,我們討論了生成模型VAE和GAN,近年來(lái),新的生成模型——擴(kuò)散模型受到越來(lái)越多的關(guān)注,因此值得好好去研究一番。擴(kuò)散模型(Diffusion Models)最早由 [2] 于2015年提出,但直到2020年論文 [3] 發(fā)表之后才得到關(guān)注,本文詳細(xì)梳理了 [3] 中的公式推導(dǎo)部分,幫助大

    2023年04月08日
    瀏覽(32)
  • 全面理解Stable Diffusion采樣器

    全面理解Stable Diffusion采樣器

    原文:Stable Diffusion Samplers: A Comprehensive Guide 在 AUTOMATIC1111 的 SD webui 中,有許多采樣器(sampler),如 Euler a,Heun,DDIM,… 什么是采樣器?他們?nèi)绾喂ぷ鳎克麄冎g的區(qū)別是什么?我們應(yīng)該用哪種采樣器?本文將帶給你答案。 在生成圖片時(shí),Stable Diffusion 會(huì)先在隱層空間(l

    2024年02月04日
    瀏覽(16)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包