DLAI-扩散模型工作原理笔记-全-
DLAI 扩散模型工作原理笔记(全)
001:课程介绍 🎬


在本节课中,我们将要学习扩散模型的基本概念、课程目标以及你将通过本课程掌握的核心技能。扩散模型是当前生成式人工智能领域的重要基石,理解其工作原理对于掌握前沿技术至关重要。
我很高兴向大家介绍这个由Sharon Jo主讲的关于扩散模型的短期课程。
Midjourney、Stable Diffusion、DALL-E等模型能够仅根据一段文字提示就生成图像,有时甚至是精美的图像。这些算法是如何工作的?你可能听说过一个模糊的描述:这些算法通过学习“减去”噪声来生成图像。但在这个短期课程中,Sharon将引导你完成一个使用扩散模型生成图像的具体实现,以便你准确理解其技术细节。
谢谢,Andrew。在本课程中,你将了解当前扩散模型的发展现状和能力。
你将首先理解采样过程:从纯噪声开始,逐步细化以得到最终美观的图像。
你将建立必要的编程技能,以有效地训练一个扩散模型。
你将学习如何构建一个能够预测图像中噪声的神经网络。
你将学习为模型添加上下文,以便控制你想要生成的内容。
最后,通过实现高级算法,你将学习如何将采样过程加速10倍。
这是一个中级到高级的课程。我们假设你熟悉Python和基本的神经网络训练。例如,我们假设你知道什么是反向传播。我们将全程使用PyTorch,但如果你熟悉其他机器学习框架(如TensorFlow),你也应该能够顺利跟上。
本短期课程将使用的运行示例是生成16x16像素的精灵图,就像电子游戏中的那些小角色。我们选择这个示例是为了让你不仅能够浏览代码,还能自己运行它们,在Jupyter笔记本中亲自生成可爱的精灵图。
扩散模型正在成为生命科学和其他领域前沿研究的基础。例如,用于药物发现的分子生成。因此,当你理解了扩散模型的技术细节后,你也将能更好地理解并可能亲自应用这些模型。
许多人共同构建了这个短期课程。我要感谢Eric Lu和Meme Gura Ogod的重要贡献,以及DeepLearning.AI团队的Jeff Ludwig和Eddie Shu。
那么,现在让我把时间交给Sharon,希望你享受这门课程。好的,我们开始吧。


本节课中,我们一起学习了本课程的目标、结构以及你将通过实践掌握的核心技术。我们了解到,扩散模型通过一个从噪声到清晰图像的逐步去噪过程来工作,并且本课程将通过一个具体的编程示例带你深入理解这一过程。
002:扩散模型基础直觉

在本节课中,我们将学习扩散模型的基本目标和工作原理。我们将首先明确扩散模型的目标,然后探讨如何通过添加噪声使训练数据对模型有用,最后介绍如何基于这些数据训练模型本身。

扩散模型的目标 🎯
你拥有大量训练数据,例如下方这些视频游戏角色的精灵图像。这是你的训练数据集。你的目标是获得更多训练数据中未出现的新精灵图像。你可以使用一个遵循扩散模型流程的神经网络,为你生成更多此类精灵。
如何使图像对神经网络有用? 🧠
你希望神经网络学习“精灵”这一概念的普遍特征。这包括精细细节,例如精灵的发色、是否佩戴扣子或腰带;也包括整体轮廓,例如其头部、身体以及介于两者之间的所有特征。
一种处理数据并强调精细细节或整体轮廓的方法是添加不同程度的噪声。这个过程被称为“加噪过程”,其灵感来源于物理学。你可以想象一滴墨水滴入一杯水中:起初你确切知道墨水滴落的位置,但随着时间的推移,你会看到它扩散到水中直至消失。这里的原理相同:你从精灵Bob开始,随着添加噪声,它会逐渐消失,直到你完全无法辨认它原本是哪个精灵。
神经网络在不同噪声水平下的任务 🤔
那么,当你逐步向图像添加更多噪声时,神经网络在各个噪声水平下应该思考什么?
- 当图像是精灵Bob时,你希望神经网络确认:“是的,那是精灵Bob”,并保持Bob的原样。
- 当图像很可能是Bob时,你希望神经网络说:“图像上有一些噪声”,并建议可能的细节使其看起来更像精灵Bob。
- 当图像只是一个精灵的轮廓时,你只能感觉到这可能是一个精灵人物,但它可能是Bob、Fred,甚至可能是Nancy。此时,你希望为可能出现的精灵建议更通用的细节,例如基于此轮廓为Bob或Fred建议一些细节。
- 最后,即使图像看起来完全不像任何东西,你仍然希望它看起来更像一个精灵。你希望神经网络说:“我将把这个完全充满噪声的图像,通过提出一个精灵可能具有的轮廓,转变为稍微更像精灵的东西。”
加噪过程可视化 🌊
现在,让我们看看这个加噪过程,即随时间逐步添加噪声的过程。最终,就像一滴墨水完全扩散在一杯水中。
训练神经网络 🏋️

上一节我们介绍了加噪过程,本节中我们来看看如何训练神经网络。你的目标是训练神经网络学会将不同的噪声图像变回精灵。其实现方式是:神经网络学习移除你添加的噪声。这个过程从“完全无概念”的纯噪声水平开始,逐渐呈现出“可能有人物在里面”的迹象,然后看起来像Fred,最后变成一个看起来像Fred的精灵。

需要特别指出的是,“完全无概念”的噪声水平非常重要,因为它是正态分布的。这意味着每个像素值都是从正态分布(也称为高斯分布或钟形曲线)中采样得到的。
因此,当你希望神经网络生成一个新精灵(例如这里的Fred)时,你可以从那个正态分布中采样噪声,然后使用神经网络逐步移除该噪声,从而得到一个全新的精灵。
至此,你已达成目标:你可以获得比所有训练数据更多的精灵图像。
在下一视频中,我们将介绍采样过程。
总结 📝

本节课中我们一起学习了扩散模型的基本直觉。我们明确了模型的目标是生成新的数据样本。通过向训练图像逐步添加噪声(加噪过程),我们使神经网络能够在不同噪声水平下学习精灵的特征,从精细细节到整体轮廓。训练的核心是让神经网络学会逆向移除噪声,从纯噪声开始逐步重建出清晰的精灵图像。最终,通过从正态分布采样噪声并让网络去噪,我们就能生成全新的、不在训练集中的精灵。
003:采样过程详解 🧪



在本节课中,我们将要学习扩散模型在训练完成后,如何通过一个称为“采样”的过程,从纯噪声生成高质量的图像。我们将详细拆解采样算法的每一步,并通过代码示例直观地展示其工作原理。
上一节我们介绍了扩散模型的基本概念,本节中我们来看看模型训练后如何生成图像,即采样过程。

采样过程的核心是反向去噪。想象一下,我们有一张被墨滴完全扩散污染的图像(纯噪声)。我们的目标是逆向这个过程,一步步地将噪声移除,最终还原出清晰的图像。训练好的神经网络在这一过程中扮演着关键角色:它负责预测当前图像中的噪声。
以下是采样过程的核心步骤:
- 初始化:首先,我们从一个完全随机的噪声样本开始。这对应于扩散过程的最终状态。
- 反向迭代:我们从最大的时间步(例如 T=500)开始,逐步向时间步 1 倒退。每一步,我们都执行以下操作:
- 将当前噪声图像输入训练好的神经网络。
- 神经网络预测出图像中的噪声成分。
- 根据 DDPM 采样算法,从当前图像中减去预测的噪声。
- 关键步骤:在进入下一步之前,我们会添加少量经过特定缩放的额外噪声。这有助于稳定采样过程,防止结果退化。
经过多次这样的“预测噪声 -> 减去噪声 -> 添加微量新噪声”的迭代后,初始的随机噪声就会逐渐转变为我们期望的目标图像(例如一个精灵图案)。
现在,让我们通过代码来具体实现这个过程。我们将使用 PyTorch 框架。
首先,我们需要导入必要的库并设置一些辅助函数。


import torch
import torch.nn as nn
import torch.nn.functional as F
# 导入其他必要的工具和自定义辅助函数

接下来,我们定义神经网络模型的结构。这里我们暂时不深入其内部细节,只需知道它将用于预测噪声。


# 实例化噪声预测模型
model = SimpleUnet()
print("模型加载完毕。")
然后,我们设置采样过程所需的超参数。这包括总时间步数、图像尺寸以及 DDPM 算法中用于控制噪声添加和移除的缩放系数(由噪声调度表定义)。
# 定义超参数
T = 500 # 总时间步数
img_size = 16 # 图像尺寸为16x16
beta1, beta2 = 1e-4, 0.02 # DDPM 算法的超参数
# 定义噪声调度表 (Noise Schedule)
# 该表根据时间步t计算噪声添加的强度系数
def get_noise_schedule(T, beta1, beta2):
betas = torch.linspace(beta1, beta2, T)
alphas = 1. - betas
alphas_cumprod = torch.cumprod(alphas, dim=0)
sqrt_alphas_cumprod = torch.sqrt(alphas_cumprod)
sqrt_one_minus_alphas_cumprod = torch.sqrt(1. - alphas_cumprod)
return sqrt_alphas_cumprod, sqrt_one_minus_alphas_cumprod



sqrt_alphas_cumprod, sqrt_one_minus_alphas_cumprod = get_noise_schedule(T, beta1, beta2)


以下是采样算法的核心函数 denoise_add_noise。它完成了单步的去噪和噪声添加操作。

def denoise_add_noise(x, t, pred_noise, z=None):
"""
单步采样函数。
x: 当前噪声图像
t: 当前时间步
pred_noise: 模型预测的噪声
z: 额外添加的随机噪声(若为None则随机生成)
"""
# 根据DDPM公式计算去噪后的图像均值
sqrt_alpha_cumprod_t = sqrt_alphas_cumprod[t]
sqrt_one_minus_alpha_cumprod_t = sqrt_one_minus_alphas_cumprod[t]
# 减去预测的噪声
x_denoised = (x - pred_noise * sqrt_one_minus_alpha_cumprod_t) / sqrt_alpha_cumprod_t
# 添加额外噪声z,并应用缩放
if z is None:
z = torch.randn_like(x)
# 根据时间步计算添加噪声的方差
sigma_t = torch.sqrt((1 - alphas_cumprod[t-1]) / (1 - alphas_cumprod[t]) * betas[t]) if t > 0 else 0
x_next = x_denoised + sigma_t * z
return x_next


现在,我们执行完整的采样循环。我们从随机噪声开始,循环 T 次,逐步生成图像。

# 加载预训练好的模型权重
model.load_state_dict(torch.load('pretrained_model.pth'))
model.eval()

# 开始采样
sample = torch.randn(1, 3, img_size, img_size) # 生成初始随机噪声
for t in reversed(range(T)): # 从T到1反向循环
t_tensor = torch.tensor([t])
with torch.no_grad():
pred_noise = model(sample, t_tensor) # 模型预测噪声
sample = denoise_add_noise(sample, t_tensor, pred_noise) # 去噪并添加新噪声

# 最终得到的sample即为生成的图像
final_image = sample
运行上述代码,我们将观察到噪声图像如何随着迭代一步步变得清晰,最终形成一个精灵图案。这个过程可能需要几分钟,具体取决于硬件性能。
关于“添加额外噪声”的深入探讨

你可能会问,为什么在减去预测噪声后,还要添加新的噪声?这是因为,经过一步去噪后,图像的分布已经偏离了神经网络训练时所见的“标准噪声分布”。直接将其输入下一步可能会导致模型表现不稳定,使生成结果模糊或趋于数据平均值(即产生毫无特征的“平均精灵”)。

通过添加一个经过精心缩放(由噪声调度表和当前时间步决定)的微量随机噪声 z,我们可以将图像“推回”到模型期望的分布附近。这极大地提高了采样的稳定性和生成图像的质量与多样性。

以下是对比实验:如果我们不添加额外噪声(即在 denoise_add_noise 函数中设置 z=0),结果会怎样?

# 不添加额外噪声的错误采样方式
sample_bad = torch.randn(1, 3, img_size, img_size)
for t in reversed(range(T)):
t_tensor = torch.tensor([t])
with torch.no_grad():
pred_noise = model(sample_bad, t_tensor)
# 将z强制设为0
sample_bad = denoise_add_noise(sample_bad, t_tensor, pred_noise, z=torch.zeros_like(sample_bad))

运行这段代码,生成的图像很可能是一团模糊、缺乏细节的色块,而不是清晰的精灵。这证明了添加步骤噪声对于生成高质量样本至关重要。



本节课中我们一起学习了扩散模型的采样过程。我们了解到,采样是一个从噪声开始、通过神经网络迭代预测并减去噪声的反向过程。其中,在每一步减去预测噪声后,添加适量缩放的新噪声是保证生成效果清晰、多样的关键技巧。下一节,我们将深入探讨用于预测噪声的神经网络本身是如何构建的。
004:神经网络架构 🧠


在本节课中,我们将学习扩散模型所使用的神经网络架构,并了解如何将额外信息整合到网络中。
上一节我们介绍了扩散模型的基本概念,本节中我们来看看其核心组件——U-Net神经网络。
神经网络架构概述
扩散模型使用的神经网络架构是U-Net。关于U-Net,最重要的一点是:它以图像作为输入,并输出一个与输入图像尺寸相同的预测结果。在本例中,其任务是预测添加到图像中的噪声。
U-Net自2015年就已存在,最初用于图像分割任务,例如在自动驾驶研究中将图像分割为行人或汽车区域。U-Net的特殊之处在于其输入和输出尺寸相同。它的工作原理是:首先通过一系列卷积层对输入信息进行下采样,将其压缩到一个低维嵌入空间中;然后,再通过相同数量的上采样块,将信息恢复并输出,以完成其特定任务。
以下是U-Net处理流程的简化表示:
# 伪代码表示U-Net的前向传播过程
def forward(x):
# 下采样路径:压缩信息
down1 = down_block_1(x)
down2 = down_block_2(down1)
# ... 更多下采样层
bottleneck = bottleneck_block(downN)
# 上采样路径:恢复信息并预测噪声
up1 = up_block_1(bottleneck, downN)
up2 = up_block_2(up1, downN-1)
# ... 更多上采样层
predicted_noise = output_layer(upN)
return predicted_noise
整合额外信息
U-Net的一个优点是能够接收额外信息。除了压缩图像以理解其内容外,它还可以整合其他关键信息。
以下是两种重要的嵌入信息:
时间嵌入
时间嵌入对于扩散模型至关重要。它告知模型当前处于哪个时间步,从而判断所需的噪声水平。实现时,只需将时间步编码为一个向量,并将其添加到上采样块中。
上下文嵌入
上下文嵌入有助于控制模型的生成内容。例如,它可以是一个文本描述(如“生成一张鲍勃的照片”),或某种控制因子(如“图像需为特定颜色”)。我们将在后续课程中详细讨论这一点。对于上下文嵌入,通常将其与上采样块进行乘法运算来整合。
在代码中,整合过程如下所示:
# 在U-Net的上采样块中整合嵌入信息
def up_block_with_embeddings(x, context_emb, time_emb):
# 将上下文嵌入通过乘法整合
x = x * context_emb
# 将时间嵌入通过加法整合
x = x + time_emb
# ... 后续卷积等操作
return x
代码结构解析

在笔记本代码的前向传播函数中,可以清晰地看到这些下采样块和上采样块。每个上采样块都接收上下文嵌入和时间嵌入。下采样块和上采样块的定义可以在模型的初始化部分找到。


下采样块本质上是一系列卷积层,用于逐步压缩图像尺寸并提取特征。其结构可以概括为:
下采样块 = 卷积层 + 激活函数 + 可能的下采样操作(如池化)

总结


本节课中,我们一起学习了扩散模型的核心神经网络——U-Net。我们了解到U-Net是一种输入输出同尺寸的网络,通过下采样压缩信息再上采样恢复信息来预测噪声。更重要的是,我们探讨了如何将时间嵌入和上下文嵌入这两种关键信息整合到U-Net中,以指导模型的生成过程。在下一节视频中,我们将学习如何训练这个神经网络。
005:训练扩散模型 🧠



在本节课中,我们将要学习如何训练一个U-Net神经网络,使其能够预测噪声。我们将详细讲解训练过程、损失计算以及如何通过代码实现训练循环。
概述
扩散模型的核心在于训练一个神经网络,使其能够从加噪的图像中预测出所添加的噪声。通过这个过程,模型不仅学会了识别噪声,也学会了识别图像中“非噪声”的部分,即图像本身的特征。本节将深入解析这一训练机制。
训练目标与原理
神经网络的目标是预测噪声。更准确地说,它学习的是图像上噪声的分布,同时也学习图像本身的特征(即“精灵”的样貌)。
训练方法如下:
- 从训练数据中取出一张精灵图像。
- 向这张图像添加噪声。
- 将加噪后的图像输入神经网络,并要求其预测所添加的噪声。
- 将神经网络预测的噪声与真实添加的噪声进行比较,以此计算损失。
- 通过反向传播更新神经网络参数,使其能更好地预测噪声。
时间步与噪声采样策略
你可能会问,如何确定添加的噪声量?理论上可以按时间顺序逐步增加噪声,但在实际训练中,我们不希望神经网络一直看同一张图像。
为了使训练更稳定、更均匀,我们采用随机采样的策略:
- 我们随机采样一个时间步
t。 - 根据这个时间步
t获取对应的噪声水平,并将其添加到当前图像中。 - 让神经网络进行预测。
- 接着,我们取训练数据中的下一张图像。
- 再次随机采样一个(可能完全不同的)时间步,添加噪声,并让网络预测。

这种随机采样时间步的方法能带来更稳定的训练效果。

训练过程可视化
以下是训练过程的直观展示。我们以一个巫师帽精灵为例:
- 初始阶段(第0轮训练):神经网络尚未理解精灵的样貌。它预测的噪声与输入图像差异不大,减去预测噪声后,输出结果与输入非常相似。
- 后期阶段(第31轮训练):神经网络对精灵的样貌有了更好的理解。它预测的噪声被从加噪输入中减去后,能生成一个看起来很像原始巫师帽精灵的图像。
这种进步不仅体现在单个样本上。观察多个不同精灵在多轮训练中的变化,可以看到:
- 在第一轮训练时,生成结果与精灵相去甚远。
- 到了第32轮训练,生成的结果已经非常像一个个小电子游戏角色了。
代码实现训练算法

上一节我们介绍了训练的原理,本节中我们来看看如何用代码实现它。以下是训练循环的核心步骤:
首先,需要准备数据并设置循环。
# 假设 data_loader 是包含所有训练图像的数据加载器
for x in data_loader: # x 是一个训练图像
# 训练循环在此进行


在循环内部,我们执行以下关键操作:

- 随机采样时间步:采样一个时间步
t,它决定了噪声的水平。我们并非遍历所有时间步,而是每次随机采样。 - 生成并添加噪声:采样一个噪声
ε,并根据时间步t将其添加到图像x中。 - 神经网络预测:将加噪后的图像以及时间步
t(用于时间嵌入)输入神经网络,神经网络输出预测的噪声。 - 计算损失:使用均方误差(MSE)比较预测的噪声与真实添加的噪声。
- 反向传播与优化:根据损失进行反向传播,更新模型参数。通过这个过程,模型逐渐学会区分噪声和精灵特征。

损失函数可以表示为:
Loss = MSE(ε_predicted, ε_true)
实战训练演示
现在,我们进入训练笔记本的实战部分。超参数设置如下:批量大小为100,共训练32轮,并设置了学习率。

以下是训练的关键代码块:

- 数据加载:我们加载16x16像素的精灵数据集到数据加载器中。
- 优化器设置:配置优化器(如Adam)。
- 加噪函数:定义一个函数
perturb_input,它接收图像和时间步t,添加相应水平的噪声,然后返回加噪图像。
由于在CPU上进行完整训练需要数小时,我们在此不逐步运行。但强烈建议你亲自运行代码,这正是我们刚才一起分析过的代码。




为了展示训练效果,我们提供了在不同训练轮次(如第0、4、8、31轮)保存的模型检查点。你可以加载这些模型,并使用上一节课学到的DDPM采样方法进行图像生成,直观观察模型随训练轮次增加而进步的过程:


- 第0轮:生成结果仍有些模糊,但已开始理解精灵的大致轮廓,不再是纯噪声。
- 第4轮:生成结果更像精灵了。
- 第8轮:可以看到更多细节(例如一些书本形状)。
- 第31/32轮:生成结果已经非常接近精灵,可以看到剑、巫师帽、药水瓶等形状。当然,其中仍夹杂着一些模糊的团块,表明模型仍有改进空间。
总结

本节课中我们一起学习了扩散模型的训练过程。我们了解到,训练的核心是让U-Net神经网络学习从加噪图像中预测噪声。通过随机采样时间步、添加相应噪声、计算预测噪声与真实噪声的均方误差损失,并利用反向传播进行优化,模型逐渐掌握了从噪声中重建图像(精灵)特征的能力。代码实战部分展示了这一流程的具体实现,以及模型随着训练轮次增加而生成的图像质量提升。在下一节课中,我们将学习如何控制生成过程,例如指定生成物体或人物。
006:控制扩散模型生成内容 🎮



在本节课中,我们将学习如何控制扩散模型,使其根据我们的指令生成特定内容。这是最令人兴奋的部分,因为你可以告诉模型你想要什么,而模型会为你想象出来。
理解上下文嵌入
上一节我们介绍了扩散模型的基本工作原理,本节中我们来看看如何通过“上下文”来控制模型的生成内容。控制这些模型的关键在于使用“嵌入”。
嵌入是能够捕捉含义的向量(即一组数字)。例如,对于扩散模型,一个句子“棕熊经常互相碰撞”的含义可以被编码成一个嵌入向量。嵌入的特殊之处在于,语义相似的文本会拥有相似的向量。更神奇的是,你几乎可以对嵌入进行向量运算,例如:巴黎向量 - 法国向量 + 英国向量 ≈ 伦敦向量。
那么,在训练过程中,这些嵌入如何成为模型的上下文呢?
- 你有一张牛油果图片和一个描述它的标题“一个成熟的牛油果”。
- 你可以将标题转换为嵌入向量,并将其输入到神经网络中。
- 神经网络的任务仍然是预测添加到这张牛油果图片中的噪声,并计算损失。
- 这个过程可以在大量带标题的图片上重复进行,例如一张“舒适的扶手椅”图片。
这个环节的魔力在于:虽然你从互联网上抓取的训练图片是牛油果和扶手椅,但在采样生成时,你可以让模型生成它从未见过的东西,比如一个“牛油果扶手椅”。这是因为你可以将“牛油果扶手椅”这个词组嵌入到一个向量中,这个向量既包含一点牛油果的特征,也包含一点扶手椅的特征。将这个向量输入神经网络,让它预测噪声,减去噪声后,你就能得到一个牛油果扶手椅的图像。
上下文的多种形式
更广泛地说,上下文是一个可以控制生成的向量。它可以是像“牛油果扶手椅”这样较长的文本嵌入,但上下文也可以很短,比如长度为5的分类向量。
以下是几种上下文类型的例子:

- 英雄/非英雄:例如火球、蘑菇等物体。
- 食物:例如苹果、橙子、西瓜。
- 法术和武器:例如弓箭、蜡烛。
- 精灵朝向:例如侧面朝向或非侧面朝向。
动手实验:为模型添加上下文
现在,让我们在接下来的实验中看看如何为模型添加上下文。
首先,我们运行设置代码,这与之前的实验相同。


# 设置代码(与之前相同)
然后,在上下文部分,我们再次实例化神经网络。请注意,我们不会在此训练模型,但会指出几个添加上下文的关键位置。
- 加载数据时:我们现在同时遍历数据点及其关联的上下文因子。在我们的例子中,上下文是经过独热编码的向量,代表“英雄/非英雄”、“食物”、“法术/武器”、“侧面朝向”等类别。
- 创建上下文掩码:这里重要的是,我们会以一定的随机概率将上下文完全掩蔽(置零)。这样做的目的是让模型既能学习特定上下文下的生成,也能学习生成一个通用的精灵图像。这在扩散模型中很常见。
- 调用神经网络时:我们在调用神经网络时添加上下文。
接下来,我们加载一个已经使用上下文训练好的模型检查点。
# 加载预训练模型
model.load_state_dict(torch.load('context_model.pth'))

再次运行我们的采样代码。在默认情况下,这段代码会为每个样本选择完全随机的上下文,因此你会看到各种不同类型的输出,包括不同的物体和人物。

控制生成内容


现在,我们可以开始控制生成内容了。你可以在这里定义具体的上下文。

例如,我定义了以下上下文:
- 前两个样本是“英雄”。
- 接下来两个样本是“侧面朝向”(即独热编码向量的最后一个值为1)。
- 再接下来两个是“非英雄”(看起来像野兽)。
- 最后两个是“食物”(一个像苹果,一个像梨)。
进入“牛油果扶手椅”的混合模式,我们实际上可以混合匹配这些特征。虽然模型是在独热编码向量上训练的,但我们也可以提供0到1之间的浮点数来获得混合特征。
- 第二个样本是“英雄”并混合了部分“食物”特征,因此它看起来像一个“土豆人”。
- 第三个样本混合了部分“食物”和部分“法术”特征,因此它看起来像一瓶“药水”。
你可以自己尝试,甚至可以输入一些看似矛盾的特征组合,比如既是“英雄”又是“侧面朝向”(同时包含正面和侧面特征)。这非常有趣,请随时暂停视频,自己尝试修改这些值。
课程总结
本节课中,我们一起学习了如何通过上下文嵌入来控制扩散模型的生成内容。我们了解了嵌入如何捕捉语义信息,并作为额外的条件输入引导模型生成特定或混合特征的图像。通过动手实验,我们实践了如何定义和修改上下文向量,从而创造出“英雄”、“食物”甚至“土豆人”等多样化的生成结果。



现在你已经可以创建并控制这些样本了。在下一视频中,你将探索如何加速采样过程,这样你就不需要等待那么长时间了。
007:DDIM加速采样 🚀



在本节课中,我们将学习一种名为DDIM(去噪扩散隐式模型)的新采样方法。该方法比我们目前使用的DDPM采样方法效率高出10倍以上。我们将了解其工作原理,并通过代码示例直观地对比其速度优势。
概述:为何需要更快的采样?
上一节我们介绍了DDPM的标准采样过程。本节中我们来看看其面临的主要挑战:采样速度慢。这是因为DDPM采样通常需要经历数百个时间步,且每一步都依赖于前一步,形成一个马尔可夫链过程。为了获得更多、更快的图像生成结果,研究者们开发了多种新的采样器,其中DDIM便是非常流行的一种。
DDIM的核心思想:打破马尔可夫链
DDIM之所以更快,是因为它能够跳过时间步。它不再需要从时间步500、499、498……这样顺序执行。其关键在于移除了采样过程中的所有随机性,使其成为一个确定性的过程。本质上,DDIM首先预测最终输出的一个粗略草图,然后通过去噪过程对其进行细化。

以下是DDIM与DDPM采样过程的直观对比:
- DDPM(左侧):遵循标准的马尔可夫链,逐步去噪,过程较慢。
- DDIM(右侧):可以跳过大量中间步骤,快速形成图像轮廓并细化。


代码实现与对比

以下是DDIM采样算法的关键部分。请注意,其中涉及一个步长参数,它决定了我们跳过的步数。
# DDIM采样函数示例(关键参数)
n_steps = 20 # 总采样步数,远小于DDPM的500步
step_size = max(1, total_timesteps // n_steps) # 计算跳过的步长



在实验中,我们设置n_steps=20,这意味着采样过程大约只执行了原来的1/25(500/20)。运行后可以观察到,DDIM的采样速度极快,几乎瞬间就能看到图像的基本形态。


速度与质量的权衡


使用这种更快的采样方法时,并不总能获得与运行完整DDPM采样(如500步)相同水平的图像质量。但经验表明,对于一个在500步上训练的模型:
- 如果采样500步,DDPM通常表现更好。
- 如果采样步数少于500步,DDIM的表现则要优秀得多。

因此,DDIM在追求速度的场景下具有巨大优势。


性能对比测试


我们可以使用timeit等工具来量化比较DDIM与DDPM的采样速度。在典型的测试中,DDIM能带来数量级级别的加速。建议你在自己的笔记本中运行代码,亲身体验这种速度差异。


总结



本节课中我们一起学习了DDIM加速采样方法。我们了解到DDIM通过跳过时间步和采用确定性采样过程,打破了DDPM的马尔可夫链假设,从而实现了十倍以上的采样加速。虽然在高步数采样下DDPM的质量可能更优,但在低步数采样中,DDIM在速度和质量上提供了更佳的平衡。这为扩散模型的实际应用打开了新的大门。
008:课程总结 🎉
在本节课中,我们将对扩散模型的核心知识进行总结,回顾从训练到采样的完整流程,并展望其未来的发展方向。
课程回顾
上一节我们介绍了模型架构与上下文控制,本节中我们将对整个课程内容进行梳理与总结。
恭喜你学习了扩散模型的基础知识。现在,让我们将所有内容整合起来。

你已能够训练一个扩散模型来预测噪声,并通过从纯噪声中迭代减去预测的噪声来获得高质量的图像。

你也能使用一个名为DDIM的更高效采样器,从训练好的神经网络中快速采样生成图像。
你学习了模型架构——U-Net。你将上下文信息输入模型,从而可以决定生成食物、咒语、英雄精灵图像,或介于其间的一些奇特内容。
最后,你探索并运行了实现所有这些功能的代码。
未来探索方向
现在,你可以创建自己的数据集并尝试生成新事物。

扩散模型的应用不仅限于图像,这只是它们目前最流行的领域。
以下是扩散模型的其他应用方向:
- 音乐生成:输入任何提示词即可生成音乐。
- 药物发现:用于提出新分子以加速药物研发。
- 尝试更大规模的数据集。
- 尝试新的采样器。实际上存在大量比DDIM更快、更好的采样器。
你还可以利用这些模型做更多事情,例如:
- 图像修复:让扩散模型在你已有的图像周围进行绘制填充。
- 文本反转:仅用几张样本图像,就能让模型学习一个全新的文本概念。
进阶发展与展望
你在这里学习的是基础和原理。该领域还有其他重要的发展。
例如,Stable Diffusion使用了一种名为潜在扩散的方法,其公式可简化为在潜在空间而非像素空间进行操作:z = Encoder(x), x' = Decoder(z)。这直接处理图像嵌入而非原始图像,使过程更加高效。
其他值得关注的技术还包括交叉注意力文本条件化以及无分类器引导。
研究社区仍在致力于开发更快的采样方法,因为在推理阶段,扩散模型的速度仍然比其他生成模型慢。
总而言之,随着扩散模型和整个生成式模型的不断改进及其应用日益广泛,现在是一个极其令人兴奋的时代。

非常感谢你加入本课程的学习,我期待看到你的创作成果。😊

浙公网安备 33010602011771号