1. 引言
这是我关于StableDiffusion
学习系列的第二篇文章,如果第一篇你还没有阅读,强烈推荐大家翻看前篇内容。在本文中,我们将学习构成StableDiffusion
的各个基础组件,并针对每个组件的功能进行阐述。
闲话少说,我们直接开始吧!
2. 概览
正如前文所述,扩散模型主要用来生成高质量的图像。稳定扩散模型(StableDiffusion)
可以视为一种特殊的扩散模型,学术上叫做潜在扩散模型(Latent Diffusion model)
,相关概念来自于论文《 High-Resolution Image Synthesis with Latent Diffusion Models》
。简单来说,原始的扩散模型通常会消耗更多的内存,因此创建了潜在扩散模型,可以在被称为潜在低维度特征空间进行扩散过程。更进一步,扩散模型是机器学习模型,它被训练来在带有高斯噪声的图像上逐步进行去噪,以获得高质量图像。而潜在扩散模型被训练成在低纬度的特征空间上进行同样的过程。
一般来说,潜在扩散模型含有三个组件:
- a text encoder 文本编码器,这里主要指基于
CLIP
的文本编码器 - an autoencoder 自编码器,这里主要指
Variational Auto Encoder
,也被简称为VAE
- A Unet 扩散模型
本文先从最基础的text encoder
讲起,主要介绍其在扩散过程中的用途。
3. CLIP Text Encoder作用
CLIP text Encoder
以文本作为输入,并在潜在特征空间中生成文本嵌入(text embeddings)
;我们也可以通过CLIP模型对图像进行特征编码一样。
任何机器学习模型都无法直接理解原始文本输入数据。在机器学习领域,我们通常都需要将文本转换为包含文本含义的数字表示,称为嵌入(embedding)
。将文本转换为数字表示的过程可以分为两部分:
-
Tokenizer
- 将文本输入拆分为各个子单词,然后使用查找表将每个子单词转换为数字 -
Token_To_Embedding Encoder
- 将每个子单词的数字表示转换为包含该文本语义信息的特征表示
4. 代码实践之Tokenizer
只看文字讲解还是不够直观,让我们不妨通过代码来进一步了解它。我们将从导入相关库开始:
import torch,logging
from transformers import CLIPTextModel,CLIPTokenizer
clip_path = "/media/stable_diffusion/clip-vit-large-patch14"
tokenizer = CLIPTokenizer.from_pretrained(clip_path,
local_files_only=True,
torch_dtype=torch.float16)
让我们初始化一个文本提示,并将其token
化,代码如下:
prompt = [ 'a dog wearing hat' ]
tok = tokenizer(prompt,padding="max_length",
max_length=tokenizer.model_max_length,
truncation=True,
return_tensors="pt")
print(tok.input_ids.shape)
print(tok)
输出结果如下:
观察上述输出,tokenizer
返回包含以下两个对象的字典:
●input_ids
- 表示一个文本提示被转化为一个1X77的tensor
,其中49406表示start token
, 而320表示对应单词“a”的token
,1929对应单词“dog”,3309对应单词“wearing”,3801对应单词“hat”,49407表示end token,后面重复的多个49407为了padding至固定长度77
● attention_mask
- 这里的1表示对应有效的embeded
值,0表示对应的为padding
进一步,我们可以使用一下代码来将input_ids
表示的单词依次打印出来:
for token in list(tok.input_ids[0,:7]):
print(f"{token}:{tokenizer.convert_ids_to_tokens(int(token))}")
得到结果如下:
5. 代码实践之Text Encoder
这一节我们来介绍基于CLIP
的Text Encoder
,首先我们利用以下代码来进行初始化操作:
text_encoder = CLIPTextModel.from_pretrained(clip_path,
local_files_only=True,
torch_dtype=torch.float16).to('cuda')
接着我们利用text_encoder
来将由tokenizer
生成的input_ids
转化为对应的文本嵌入表示,代码如下:
emb = text_encoder(tok.input_ids.to("cuda"))[0].half()
print(f"shape of embedding: {emb.shape}")
print(emb)
得到结果如下:
如上所述,大小为1x77
的每个token化后的输入现在已被转换为1x77x768
嵌入(embedding)
。因此,每个单词都被表示在768维的潜在特征空间中。
6. Text encoder在SD中的用途
事实上,Stable Diffusion
仅仅使用训练好的CLIP模型来实现将文本转化为嵌入表示,这种嵌入表示作为扩散模型UNet
的输入之一。
一般来说,CLIP使用文本编码器和图像编码器来在潜在空间进行特征嵌入,通过对比学习来将文本和图像语义接近的在特征空间进行距离拉近。关于CLIP更多的信息,大家可以访问OpenAI的关于CLIP介绍的文章,链接见附录;也可以翻看我之前的博客。
7. 总结
本文重点介绍了SD模型中的文本编码器text encoder
的相关功能和具体实现原理,并详细介绍了其两个具体操作步骤,并给出了相应的代码示例。
您学废了嘛!
8. 参考链接
本文涉及的相关参考链接如下:
LDM论文: 戳我
CLIP介绍: 戳我