缘起:在玩 SD 的时候,总会遇到构图上的偏差,好奇宝宝上线。
Diffusion Model
核心:两条马尔可夫链,一条加噪训练、一条预测去噪。
前向扩散(加噪,用于生成训练数据)
将数据 ( 图像 ) 出发,通过 T 步逐步添加高斯噪声,最终将数据变为纯噪声数据,转移分布如下:
反向去噪(去噪,用于生成目标图片):
从噪声 ( 图像 ) 出发,通过神经网络经 K 步逐步预测并移除噪声,最终恢复数据,转移分布如下:
采样训练
DDPM
DDIM
CLIP -- Contrastive Language-Image Pre-training
核心:将文本和图像映射到同一语义空间:
如图所示:让图中蓝色部分距离相近、白色部分距离向远 ( 如计算余弦相似度,越大相似度越高,最大化该值 ),代码示例如下:
# Numpy-like pseudocode for the core of an implementation of CLIP
# image_encoder - ResNet or Vision Transformer
# text_encoder - CBOW or Text Transformer
# I[n, h, w, c] - minibatch of aligned images
# T[n, l] - minibatch of aligned texts
# W_i[d_i, d_e] - learned proj of image to embed
# W_t[d_t, d_e] - learned proj of text to embed
# t - learned temperature parameter
# extract feature representations of each modality
I_f = image_encoder(I) #[n, d_i]
T_f = text_encoder(T) #[n, d_t]
# joint multimodal embedding [n, d_e]
I_e = l2_normalize(np.dot(I_f, W_i), axis=1)
T_e = l2_normalize(np.dot(T_f, W_t), axis=1)
# scaled pairwise cosine similarities [n, n]
logits = np.dot(I_e, T_e.T) * np.exp(t)
# symmetric loss function
labels = np.arange(n)
loss_i = cross_entropy_loss(logits, labels, axis=0)
loss_t = cross_entropy_loss(logits, labels, axis=1)
loss = (loss_i + loss_t)/2
VAE -- Variational AutoEncoder
核心:学习概率分布,将高维压缩至低维 ( 编码器 ),以减少计算量,再从低维重建到高维 ( 解码器 )。
U-Net + Transformer
核心:使用多层卷积核逐步提取特征/还原细节,encoder 用于提取特征、decoder 用于还原细节。U-Net 之所以能够使用在噪音预测上,核心还是特征提取上。
Diffusion Transformer
核心:使用 Transformer 代替 U-Net。
Stable Diffusion
核心:SD = VAE + Diffusion Model ( Scheduler ) + U-Net ( + Transformer ) / DiT + CLIP Text Encoder
左侧是 VAE 压缩和重构,中间是 Diffusion 训练和生成,右侧是 CLIP 文本语义理解;上半部分是加噪训练,下半部分是去噪生成。
构图
self-attention:理解元素的空间关系和层次关系。
cross-attention:文本引导方向,其余随机生成。
流程
[ 你的提示语 "一只戴礼帽的橘猫..." ]
|
v
[文本编码器 (如 CLIP)]
|
v
[ 文本嵌入向量 (高维语义表示) ]
|
| +---------------------------+
| | |
v v |
[随机噪声潜在表示] --> [U-Net: 去噪核心] <-- [当前步骤编号]
| | |
| | [交叉注意力] <--- 文本嵌入向量 (文本引导)
| | |
| | [自注意力] (内部构图协调)
| |
| v
| [预测的噪声]
| |
v |
[更新后的潜在表示] (噪声更少)
|
| (循环迭代 20-50 步)
v
[干净的潜在表示]
|
v
[VAE 解码器]
|
v
[最终生成的图片 (512x512)]
Self-Attention & Cross-Attention
| 特性 | Self-Attention (自注意力) | Cross-Attention (交叉注意力) |
|---|---|---|
| 核心功能 | 在单个序列内部建立元素之间的关系。关注序列中不同位置元素之间的依赖性和重要性。 | 在两个不同序列之间建立关系。允许一个序列(目标序列)的元素基于另一个序列(源序列)的信息进行聚焦。 |
| 输入 | Query (Q), Key (K), Value (V) 都来自同一个输入序列 (X)。 Q = K = V = X | Query (Q) 来自一个序列 (通常是目标序列,如解码器输出)。 Key (K), Value (V) 来自另一个序列 (通常是源序列,如编码器输出)。 Q = Target, K = V = Source |
| 计算过程 | 1. 计算序列中每个元素 Q 与序列中所有元素 K 的相似度得分。 2. 对得分进行缩放和 Softmax 归一化得到权重。 3. 用权重对序列中所有元素的 V 进行加权求和,得到该元素的输出。 | 1. 计算目标序列中一个元素 Q 与源序列中所有元素 K 的相似度得分。 2. 对得分进行缩放和 Softmax 归一化得到权重。 3. 用权重对源序列中所有元素的 V 进行加权求和,得到该目标元素的输出(融合了源信息)。 |
| 目的 | 捕捉序列内部的上下文信息。理解序列中每个元素相对于序列中其他元素的重要性。 | 整合来自另一个序列的相关信息。让目标序列的元素能够“查询”并“关注”源序列中最相关的部分。 |
| 典型应用位置 | Transformer ****编码器:处理输入序列。 Transformer 解码器:处理目标序列(通常会结合 Mask,防止关注未来信息)。 | Transformer ****解码器:连接编码器和解码器。解码器的自注意力层输出作为 Q,编码器的输出作为 K 和 V。 |
| 是否因果 掩码 | 在 解码器 中需要:防止当前位置关注未来位置的信息(用于自回归生成)。 在编码器中不需要:可以关注序列的所有位置。 | 通常不需要:目标序列的当前位置 Q 可以关注源序列的所有位置(无论过去或“未来”),因为源序列通常是已完全生成的(如编码器输出)。 |
| 可视化意义 | 序列内部元素之间画连线(🔄),表示它们相互关注和影响的程度。 | 从目标序列的一个元素指向源序列的多个元素(↔️),表示目标元素关注了源序列的哪些部分。 |
| 类比 | 阅读一个句子时,思考句子中哪个词对理解当前词最重要。 | 翻译时,看着源语言句子(如英文),思考它的哪个部分对生成当前的目标语言词(如中文)最重要。 |