赞
踩
参考:HuggingFace
参考:https://jalammar.github.io/illustrated-stable-diffusion/
Stable Diffusion 这个模型架构是由 Stability AI 公司推于2022年8月由 CompVis、Stability AI 和 LAION 的研究人员在 Latent Diffusion Model 的基础上创建并推出的。
其原型是(Latent Diffusion Model),一般的扩散模型都需要直接在像素空间训练和运行,训练可能需要上百个 GPUs,在测试推理的时候也需要很多硬件支持。所以就有了 LDM 这个模型的提出,通过平衡【降低复杂度】和【保持图像细节】,能在保持保真度的同时实现模型的加速。
Stable Diffusion 是什么:
Stable Diffusion 和 Midjourney 的对比:
当图片尺寸变大时,需要的计算能力也随之增加。这种现象在自注意力机制(self-attention)这种操作的影响下尤为突出,因为操作数随着输入量的增大呈平方地增加。一个 128px 的正方形图片有着四倍于 64px 正方形图片的像素数量,所以在自注意力层就需要16倍的内存和计算量。这是高分辨率图片生成任务的普遍问题。
隐式扩散致力于克服这一难题,它使用一个独立的模型 Variational Auto-Encoder(VAE)压缩图片到一个更小的空间维度。这背后的原理是,图片通场都包含了大量的冗余信息。因此,我们可以训练一个 VAE,并通过大量足够的图片数据训练,使得它可以将图片映射到一个较小的隐式空间,并将这个较小的特征映射回原图片。SD 模型中的 VAE 接收一个三通道图片输入,生成出一个四通道的隐式表征,同时每一个空间维度上都减少为原来的八分之一。比如,一个 512px 的正方形图片将会被压缩到一个 4×64×64 的隐式表征上。
通过在隐式表征上(而不是完整图像上)进行扩散过程,我们可以使用更少内存、减少 UNet 层数、加速生成。同时我们仍能把结果输入 VAE 的解码器,解码得到高分辨率图片。这一创新点极大地降低了训练和推理成本。
这里再回顾一下基础模型 LDM:
Stable Diffusion模型中使用变分自编码器(VAE)作为编码器的原因主要有以下几点:
生成模型:VAE是一种生成模型,能够学习数据的潜在表示,并且可以从这个潜在空间中抽样来生成新的数据。这与Stable Diffusion的目标,即学习复杂数据分布并从中抽样,非常契合。
变分推理:VAE利用变分推理进行参数估计和优化。这使得它能够有效地处理大规模和高维度的数据,这对于许多实际应用(如图像和文本)来说是非常重要的。
损失函数:VAE具有结构化的损失函数,包括重构损失和KL散度。这使得我们可以明确地控制重构质量与潜在表示之间的平衡。
鲁棒性:由于其随机性质,VAE通常比确定性方法更鲁棒,在面对噪声或缺失值时表现更好。
连续潜在空间:VAE假设一个连续的潜在空间,并试图将输入映射到此空间上。连续性使得我们可以通过插值和外推等操作来探索未知区域,并可能帮助改善生成结果的质量。
VAE 是什么:
是一种生成模型,它使用深度学习技术来提供数据的紧凑连续潜在表示。VAE由编码器和解码器两部分组成。
编码器:编码器将输入数据(例如图像)映射到一个潜在空间。每个输入都被映射为该空间中的一个点,或者更准确地说,是一个分布。这个分布通常假设为高斯分布,由均值和方差定义。
解码器:解码器则执行相反的操作,它从潜在空间中取样,并将这些样本映射回原始数据空间(例如生成图像)。解码过程也是随机的,在给定潜在变量的情况下,输出是原始数据空间上的一个条件分布。
VAE通过最大化下界(ELBO, Evidence Lower BOund)进行训练。ELBO包含两部分:
总结一句话就是, VAE 是一种利用深度神经网络进行参数化并利用变分推理进行训练以学习复杂数据集隐含结构并能从中生成新样本 的生成模型。
Diffusers 库如何使用:
git clone https://github.com/huggingface/diffusers.git
#可以使用 diffusers 这个 image 起容器
nvcr.io/nvidia/pytorch:22.08-py3
# 然后在容器中安装,为了更方便看内部,我使用了 -e . 的安装方式,每次调用库都会进入我自己的 diffusers 库
cd diffusers
pip install -e .
Diffusers 库是什么:
扩散模型的主要步骤:
一个简单的示例如下:
# Dataloader (you can mess with batch size)
batch_size = 128
train_dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
# How many runs through the data should we do?
n_epochs = 3
# Create the network
net = BasicUNet()
net.to(device)
# Our loss finction
loss_fn = nn.MSELoss()
# The optimizer
opt = torch.optim.Adam(net.parameters(), lr=1e-3)
# Keeping a record of the losses for later viewing
losses = []
# The training loop
for epoch in range(n_epochs):
for x, y in train_dataloader:
# Get some data and prepare the corrupted version
x = x.to(device) # Data on the GPU
noise_amount = torch.rand(x.shape[0]).to(device) # Pick random noise amounts
noisy_x = corrupt(x, noise_amount) # Create our noisy x
# Get the model prediction
pred = net(noisy_x)
# Calculate the loss
loss = loss_fn(pred, x) # How close is the output to the true 'clean' x?
# Backprop and update the params:
opt.zero_grad()
loss.backward()
opt.step()
# Store the loss for later
losses.append(loss.item())
# Print our the average of the loss values for this epoch:
avg_loss = sum(losses[-len(train_dataloader):])/len(train_dataloader)
print(f'Finished epoch {epoch}. Average loss for this epoch: {avg_loss:05f}')
# View the loss curve
plt.plot(losses)
plt.ylim(0, 0.1);
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。