PyTorch生成式人工智能(17)——变分自编码器详解与实现
PyTorch生成式人工智能(17)——变分自编码器详解与实现
- 0. 前言
- 1. 潜空间运算
- 2. 变分自编码器
- 2.1 自编码器与变分自编码器对比
- 2.2 模型训练流程
- 3. 构建变分自编码器
- 3.1 模型构建
- 3.2 模型训练
- 3.3 生成图像
- 4. 向量运算
- 小结
- 系列链接
0. 前言
虽然自编码器 (AutoEncoder, AE) 在重建输入数据方面表现良好,但通常在生成训练集中不存在的新样本时表现不佳。更重要的是,自编码器在输入插值方面同样表现不佳,无法生成两个输入数据点之间的中间表示。这就引出了变分自编码器 (Variational Auto-Encoder
, VAE
)。
本节将从零开始构建和训练一个 VAE
,用于生成人脸图像,使用 eyeglasses
数据集训练 VAE
。VAE
的编码器将大小为 3 × 256 × 256 = 196,608
个像素的图像压缩成一个 100
维的概率向量,每个维度遵循正态分布,解码器则根据这个概率向量重建图像。训练好的 VAE
不仅能够复制训练集中的人脸,还能够生成新的面孔。
1. 潜空间运算
使用变分自编码器 (Variational Auto-Encoder
, VAE
) 可以进行向量运算和输入插值。操作不同输入的编码表示(潜向量),以在解码时实现特定的结果(例如,图像中是否具有某些特征)。潜向量控制解码图像中的不同特征,如性别、图像中是否有眼镜等。例如,可以首先获得戴眼镜的男性的潜向量 (z1
)、戴眼镜的女性的潜向量 (z2
) 和不戴眼镜的女性的潜向量 (z3
)。然后,计算一个新的潜向量 z4 = z1 – z2 + z3
。由于 z1
和 z2
解码后都会出现眼镜,z1 – z2
会在结果图像中去除眼镜特征。类似地,由于 z2
和 z3
都会解码为女性面孔,z3 – z2
会去除结果图像中的女性特征。因此,如果使用训练好的 VAE
解码 z4
将得到一张没有不戴眼镜的男性图像。
通过调整潜向量 z1
和 z2
的权重,创建一系列从戴眼镜的女性过渡到不戴眼镜的女性的图像,展示了 VAE
在生成模型领域的多样性和创造潜力。
与生成对抗网络 (Generative Adversarial Network, GAN)相比,VAE
具有更简单的架构,且更容易构建。此外,VAE
在训练时通常比 GAN
更容易且更稳定。然而,与 GAN
生成的图像相比,VAE
生成的图像往往更加模糊。GAN
在生成高质量、逼真的图像方面表现出色,但面临训练困难和资源消耗大的问题。选择 GAN
还是 VAE
很大程度上取决于任务的具体要求,包括输出图像的质量、可用的计算资源以及训练过程的稳定性。
VAE
在现实世界中有广泛的实际应用。例如,假设一家眼镜店成功地推出了一款新的男士眼镜款式,我们希望将同款眼镜推广给女性市场,但没有戴眼镜的女性图像,这时,使用 VAE
就可以将现有的戴眼镜男士图像与没有眼镜的男性、女性图像结合。通过这种方式,可以通过向量运算,创建出戴同款眼镜的女性图像。
在另一种场景中,假设商店提供黑框和白框眼镜,这两种都很受欢迎,我们想推出一个中间选项,框架是中间色调。通过使用 VAE
和输入插值的方法,可以生成一系列平滑过渡的图像。这些图像将从深色到浅色框眼镜不等,为客户提供视觉上的选择范围。
VAE
的应用不止于此,它几乎可以扩展到任何产品类别,无论是服装、家具还是食品,为可视化和营销产品提供了一个富有创意且具有成本效益的解决方案。除图像生成外,VAE
也可以应用于许多其他类型的数据,包括音乐和文本。
2. 变分自编码器
虽然自编码器 (AutoEncoder, AE) 擅长重建原始图像,但它们在生成训练集中没有出现的新图像方面表现不佳。此外,自编码器通常无法将相似的输入映射到潜空间中的相邻点。因此,AE
的潜空间既不连续,也不容易解释。例如,无法通过插值两个输入数据点来生成有意义的中间表示。基于这些原因,我们将学习自编码器的改进模型,变分自编码器 (Variational Auto-Encoder
, VAE
)。
在本节中,将首先学习 AE
和 VAE
之间的区别,以及为何后者能够生成训练集中未出现但逼真的图像。然后,将学习训练 VAE
的一般步骤,训练一个生成高分辨率人脸图像的 VAE
。
2.1 自编码器与变分自编码器对比
变分自编码器 (Variational Auto-Encoder
, VAE
) 是自编码器 (AutoEncoder
, AE
) 的一种变体。与 AE
类似,VAE
也包含两个主要部分:编码器和解码器。但 AE
和 VAE
之间存在两个关键区别。
首先,AE
中的潜空间是确定性的。每个输入都会被映射到潜空间中的一个固定点。而 VAE
中的潜空间是概率性的,VAE
并不是将输入编码为潜空间中的确定向量,而是将输入编码为一组可能值的分布。例如,将把一张彩色图像编码为一个 100
维的概率向量。此外,我们假设这个向量中的每个元素都服从独立的正态分布。由于定义正态分布只需要均值 (μ\muμ) 和标准差 (σ\sigmaσ),因此100维的概率向量中的每个元素都将由这两个参数来表征。为了重建图像,从该这个分布中采样一个向量,并进行解码。VAE
的独特性在于,每次从分布中采样都会产生一个略微不同的输出。
从统计学角度来看,VAE
中的编码器试图学习训练数据 xxx 的真实分布 p(x∣θ)p(x|\theta)p(x∣θ),其中 θ\thetaθ 是定义分布的参数。为了简化计算,通常假设潜变量的分布是正态分布。因为只需要均值 (μ\muμ) 和标准差 (σ\sigmaσ) 来定义正态分布,所以可以将真实分布重写为 p(x∣θ)=p(x∣μ,σ)p(x|\theta)=p(x|\mu, \sigma)p(x∣θ)=p(x∣μ,σ)。VAE
中的解码器基于编码器学习到的分布生成样本。也就是说,解码器根据分布 p(x∣μ,σ)p(x|\mu, \sigma)p(x∣μ,σ) 以概率方式生成一个实例。
AE
和 VAE
之间的第二个关键区别在于损失函数。在训练 AE
时,我们通过最小化重建损失来使重建图像尽可能接近原始图像。而在 VAE
中,损失函数由两部分组成:重建损失和 KL
(Kullback-Leibler
) 散度。KL
散度是衡量一个概率分布与期望概率分布之间差异的指标。在 VAE
中,KL
散度用于通过惩罚学习到的分布(编码器的输出)与先验分布(标准正态分布)之间的偏差来正则化编码器。鼓励编码器学习出有意义且可泛化的潜表示,通过惩罚那些与先验分布偏差过大的分布,KL
散度有助于避免过拟合。
由于我们假设分布是正态的,KL
散度计算公式如下(如果是非正态分布,公式会有所不同):
KL=∑n=1100(σn22+μn22−log(σn2)−12)KL = \sum_{n=1}^{100}(\frac {\sigma^2_n}2+\frac {\mu^2_n}2-log(\sigma_n^2)-\frac 12) KL=n=1∑100(2σn2+2μn2−log(σn2)−21)
求和是对潜空间中 100
个维度上进行的。当编码器将图像压缩到潜空间中的标准正态分布时(即 σ=0\sigma=0σ=0,μ=1\mu=1μ=1),KL
散度为 0
,当编码器成功将图像压缩到潜空间中的标准正态分布时,KL
散度最小化。
2.2 模型训练流程
在本节中,我们将从零开始构建并训练一个 VAE
,以生成彩色的人脸图像。训练好的模型可以生成在训练集中未出现的图像。此外,还可以通过对输入进行插值,生成介于两个输入数据点之间的中间表示的新图像。VAE
架构以及训练 VAE
生成人脸图像的步骤如下图所示。
在上图中,可以看到 VAE
包含两个部分:编码器和解码器。由于需要生成高分辨率彩色图像,我们将使用卷积神经网络 (Convolutional Neural Network, CNN) 构建 VAE
。高分辨率彩色图像包含的像素数量远大于低分辨率灰度图像。如果仅使用全连接层,模型中的参数数量将非常庞大,从而导致学习过程缓慢且效果不佳。与类似规模的全连接网络相比,CNN
所需的参数较少,从而能够更快、更有效地学习。使用 eyeglasses
数据集训练 VAE
流程如下:
- 输入图像 (
3 × 256 × 256
) 经编码器压缩为100
维潜变量(含均值和标准差,假设服从正态分布) - 从潜变量分布采样,输入解码器重建图像
- 损失函数为像素级重建损失与
KL
散度(约束潜空间接近标准正态分布)之和 - 反向传播优化编码器/解码器参数,使潜表示更具泛化性,重建更接近原始图像
模型训练完成后,将人脸图像输入编码器,并获取编码。然后,将编码结果输入解码器以获得重建图像。我们可以丢弃编码器,随机从潜空间中抽取潜编码,并将其输入训练好的解码器,以生成训练集中未出现过的人脸图像。此外,还可以操控不同输入的编码表示,解码后达到特定的效果。还可以通过调整两个编码之间的权重,生成从一个实例过渡到另一个实例的序列图像。
3. 构建变分自编码器
本节将按照上一小节中介绍的步骤,从零开始创建并训练一个 VAE
,以生成人脸图像。在 VAE
的编码器和解码器中使用卷积神经网络 (Convolutional Neural Network, CNN),因为高分辨率彩色图像包含更多的像素。作为将图像压缩成潜空间中服从正态分布的向量的一部分,在编码每个图像时,我们将生成一个均值向量和一个标准差向量。从编码后的正态分布中进行采样获取编码,随后将其解码以生成图像。需要注意的是,每次从该分布中采样时,重建图像都会略有不同,这就是 VAE 生成新图像能力的来源。
3.1 模型构建
(1) 我们将使用与条件生成对抗网络一节中相同的 eyeglasses
数据集训练 VAE
,把图像调整为 256 × 256
像素,像素值范围为 0
到 1
。接下来,创建一个批处理迭代器,每个批次包含 16
张图像:
import torchvision
import torchvision.transforms as T
import torch
import torch.nn.functional as F
from torch import nndevice="cuda" if torch.cuda.is_available() else "cpu"transform = T.Compose([T.Resize(256), # 将图像大小调整为 256 × 256 像素T.ToTensor(), # 将图像转换为值在 0 和 1 之间的张量])
# 加载图像并应用转换
data = torchvision.datasets.ImageFolder(root="files/glasses",transform=transform)
batch_size=16
# 创建数据加载器
loader = torch.utils.data.DataLoader(data,batch_size=batch_size,shuffle=True)
(2) 创建包含卷积层和转置卷积层的 VAE
。首先定义一个 Encoder()
类:
# 潜空间的维度为 100
latent_dims=100
class Encoder(nn.Module):def __init__(self, latent_dims=100): super().__init__()self.conv1 = nn.Conv2d(3, 8, 3, stride=2, padding=1)self.conv2 = nn.Conv2d(8, 16, 3, stride=2, padding=1)self.batch2 = nn.BatchNorm2d(16)self.conv3 = nn.Conv2d(16, 32, 3, stride=2, padding=0) self.linear1 = nn.Linear(31*31*32, 1024)self.linear2 = nn.Linear(1024, latent_dims)self.linear3 = nn.Linear(1024, latent_dims)self.N = torch.distributions.Normal(0, 1)self.N.loc = self.N.loc.cuda() self.N.scale = self.N.scale.cuda()def forward(self, x):x = x.to(device)x = F.relu(self.conv1(x))x = F.relu(self.batch2(self.conv2(x)))x = F.relu(self.conv3(x))x = torch.flatten(x, start_dim=1)x = F.relu(self.linear1(x))# 编码分布的均值mu = self.linear2(x)# 编码分布的标准差std = torch.exp(self.linear3(x))# 编码向量表示z = mu + std*self.N.sample(mu.shape)return mu, std, z
编码器网络由多个卷积层组成,用于提取输入图像的空间特征。编码器将输入压缩成向量表示 z
,该向量服从均值为 mu
、标准差为 std
的正态分布。编码器的输出包含三个张量:mu
、std
和 z
。其中,mu
和 std
分别表示概率向量的均值和标准差,而 z
是从该分布中采样得到的一个实例。
(3) 定义 Decoder()
类表示 VAE
中的解码器,逐渐将潜空间中的编码转换回高分辨率彩色图像:
class Decoder(nn.Module): def __init__(self, latent_dims=100):super().__init__()self.decoder_lin = nn.Sequential(nn.Linear(latent_dims, 1024), # 潜编码首先通过两个全连接层nn.ReLU(True),nn.Linear(1024, 31*31*32),nn.ReLU(True))# 将潜编码重塑为多维对象self.unflatten = nn.Unflatten(dim=1, unflattened_size=(32,31,31))# 潜编码通过三个转置卷积层self.decoder_conv = nn.Sequential(nn.ConvTranspose2d(32,16,3,stride=2,output_padding=1),nn.BatchNorm2d(16),nn.ReLU(True),nn.ConvTranspose2d(16, 8, 3, stride=2, padding=1, output_padding=1),nn.BatchNorm2d(8),nn.ReLU(True),nn.ConvTranspose2d(8, 3, 3, stride=2,padding=1, output_padding=1))def forward(self, x):x = self.decoder_lin(x)x = self.unflatten(x)x = self.decoder_conv(x)# 将输出压缩为 0 和 1 之间x = torch.sigmoid(x)return x
(4) 将编码器与解码器结合起来,创建 VAE
:
class VAE(nn.Module):def __init__(self, latent_dims=100):super().__init__()# 通过实例化 Encoder() 类创建编码器self.encoder = Encoder(latent_dims)# 通过实例化 Decoder() 类创建解码器self.decoder = Decoder(latent_dims)def forward(self, x):x = x.to(device)# 将输入通过编码器传递以获得潜编码mu, std, z = self.encoder(x)# 返回潜编码的均值和标准差,以及重建的图像return mu, std, self.decoder(z)
VAE
由一个编码器和一个解码器组成,这两个组件分别由 Encoder()
和 Decoder()
类定义。当我们将图像传递给 VAE
时,输出由三个张量组成:编码的均值、标准差和重建图像。
(5) 接下来,通过实例化 VAE()
类创建 VAE
,并为模型定义优化器:
vae=VAE().to(device)
lr=1e-4
optimizer=torch.optim.Adam(vae.parameters(),lr=lr,weight_decay=1e-5)
3.2 模型训练
(1) 定义 train_epoch()
函数,用于在一个训练 epoch
内训练模型:
def train_epoch(epoch):vae.train()epoch_loss = 0.0for imgs, _ in loader: imgs = imgs.to(device)mu, std, out = vae(imgs)# 计算重建损失reconstruction_loss = ((imgs-out)**2).sum() # 计算 KL 损失kl = ((std**2)/2 + (mu**2)/2 - torch.log(std) - 0.5).sum()# 总损失loss = reconstruction_loss + kl# 反向传播optimizer.zero_grad()loss.backward()optimizer.step()epoch_loss+=loss.item()print(f'at epoch {epoch}, loss is {epoch_loss}')
遍历训练集中的所有批次。将图像输入 VAE
以获得重建图像,总损失是重建损失和 KL
散度之和。模型的参数在每次迭代中调整,以最小化总损失。
(2) 定义 plot_epoch()
函数,用于可视化 VAE
生成的图像:
import numpy as np
import matplotlib.pyplot as pltdef plot_epoch():with torch.no_grad():noise = torch.randn(18,latent_dims).to(device)imgs = vae.decoder(noise).cpu()imgs = torchvision.utils.make_grid(imgs,6,3).numpy()fig, ax = plt.subplots(figsize=(6,3),dpi=100)plt.imshow(np.transpose(imgs, (1, 2, 0)))plt.axis("off")plt.show()
一个训练良好的 VAE
能够将相似的输入映射到潜空间中的邻近点,从而形成更连续且可解释的潜空间。
(3) 训练 VAE
,训练完成后保存模型权重:
for epoch in range(1,11):train_epoch(epoch)plot_epoch()
torch.save(vae.state_dict(),"files/VAEglasses.pth")
3.3 生成图像
(1) VAE
训练完成后,可以用它来生成图像。首先,加载保存在本地文件夹中的训练模型权重:
vae.eval()
vae.load_state_dict(torch.load('files/VAEglasses.pth',map_location=device))
(2) 检查 VAE
重建图像的能力,并查看它们与原始图像的相似度,输出结果如下所示:
imgs,_=next(iter(loader))
imgs = imgs.to(device)
mu, std, out = vae(imgs)
images=torch.cat([imgs,out],dim=0).detach().cpu()
images = torchvision.utils.make_grid(images,8,4)
fig, ax = plt.subplots(figsize=(8,4),dpi=100)
plt.imshow(np.transpose(images, (1, 2, 0)))
plt.axis("off")
plt.show()
(3) 调用 plot_epoch()
函数,测试 VAE
生成训练集中未出现的新图像的能力:
plot_epoch()
以上图像在训练集中并不存在:编码是从潜空间中随机抽取的,而不是通过将训练集中的图像传入编码器得到的编码向量。这是因为 VAE
的潜空间是连续且可解释的,潜空间中新编码可以被有效地解码为与训练集中的图像相似但又有所不同的图像。
4. 向量运算
VAE
在其损失函数中包含一个正则化项 (KL
散度),用于鼓励潜空间接近正态分布。这个正则化确保潜变量不仅仅记住训练数据,而是捕捉到数据的潜分布。它有助于形成一个结构良好的潜空间,在这个空间中,类似的数据点会映射在相近位置,使得空间连续且可解释。因此,我们可以操控编码来实现新的结果。
(1) 编码运算使我们能够生成具有特定特征的图像。为了说明在 VAE
中编码运算的工作原理,首先手动采样以下四组图像,每组三张:戴眼镜的男性、未戴眼镜的男性、戴眼镜的女性和未戴眼镜的女性:
glasses=[]
for i in range(25):img,label=data[i]glasses.append(img)plt.subplot(5,5,i+1)plt.imshow(img.numpy().transpose((1,2,0)))plt.axis("off")
plt.show()
# 选择三张带眼镜的男性图像
men_g=[glasses[0],glasses[3],glasses[14]]
# 选择三张带眼镜的女性图像
women_g=[glasses[9],glasses[15],glasses[21]] noglasses=[]
for i in range(25):img,label=data[-i-1]noglasses.append(img)plt.subplot(5,5,i+1)plt.imshow(img.numpy().transpose((1,2,0)))plt.axis("off")
plt.show()
# 选择三张不带眼镜的男性图像
men_ng=[noglasses[1],noglasses[7],noglasses[22]]
# 选择三张不带眼镜的女性图像
women_ng=[noglasses[4],noglasses[9],noglasses[19]]
每组图像包含三张图像,以便在进行编码运算时,可以计算同一组中多张图像的平均编码。VAE
的设计目的是学习输入数据在潜空间中的分布。通过对多张图像的编码进行平均,我们可以有效地平滑该空间中的表示。这有助于找到一个平均表示,捕捉组内不同样本之间的共同特征。
(2) 将三张戴眼镜的男性图像输入训练好的 VAE
,以获得它们在潜空间中的编码。然后,计算这三张图像的平均编码,并用它来获得一张戴眼镜的男性重建图像,然后对其他三组图像进行相同的操作:
# 创建一批戴眼镜的男性图像
men_g_batch = torch.cat((men_g[0].unsqueeze(0),men_g[1].unsqueeze(0),men_g[2].unsqueeze(0)), dim=0).to(device)
_,_,men_g_encodings=vae.encoder(men_g_batch)
# 获取戴眼镜男性的平均潜编码
men_g_encoding=men_g_encodings.mean(dim=0)
# 解码戴眼镜男性的平均潜编码
men_g_recon=vae.decoder(men_g_encoding.unsqueeze(0))women_g_batch = torch.cat((women_g[0].unsqueeze(0),women_g[1].unsqueeze(0),women_g[2].unsqueeze(0)), dim=0).to(device)
men_ng_batch = torch.cat((men_ng[0].unsqueeze(0),men_ng[1].unsqueeze(0),men_ng[2].unsqueeze(0)), dim=0).to(device)
women_ng_batch = torch.cat((women_ng[0].unsqueeze(0),women_ng[1].unsqueeze(0),women_ng[2].unsqueeze(0)), dim=0).to(device)
# 获取其他三组的平均潜编码
_,_,women_g_encodings=vae.encoder(women_g_batch)
women_g_encoding=women_g_encodings.mean(dim=0)
_,_,men_ng_encodings=vae.encoder(men_ng_batch)
men_ng_encoding=men_ng_encodings.mean(dim=0)
_,_,women_ng_encodings=vae.encoder(women_ng_batch)
women_ng_encoding=women_ng_encodings.mean(dim=0)
# 解码其他三组的平均潜编码
women_g_recon=vae.decoder(women_g_encoding.unsqueeze(0))
men_ng_recon=vae.decoder(men_ng_encoding.unsqueeze(0))
women_ng_recon=vae.decoder(women_ng_encoding.unsqueeze(0))
(3) 以上四组图像的平均编码分别为 men_g_encoding
、women_g_encoding
、men_ng_encoding
和 women_ng_encoding
,其中 g
代表戴眼镜,ng
代表不戴眼镜。四组解码图像分别为 men_g_recon
、women_g_recon
、men_ng_recon
和 women_ng_recon
。绘制这四个图像如下所示:
imgs=torch.cat((men_g_recon,women_g_recon,men_ng_recon,women_ng_recon),dim=0)
imgs=torchvision.utils.make_grid(imgs,4,1).cpu().numpy()
imgs=np.transpose(imgs,(1,2,0))
fig, ax = plt.subplots(figsize=(8,2),dpi=100)
plt.imshow(imgs)
plt.axis("off")
plt.show()
(4) 操作编码,创建一个新的编码,然后使用训练好的 VAE
解码器对新的编码进行解码。例如,我们可以从戴眼镜的男性的平均编码中减去戴眼镜女性的平均编码,再加上不戴眼镜女性的平均编码。然后,我们将结果输入解码器并查看输出:
# 将 z 定义为戴眼镜的男性潜编码 + 不戴眼镜的女性潜编码
z=men_g_encoding-women_g_encoding+women_ng_encoding
# 解码 z 以生成图像
out=vae.decoder(z.unsqueeze(0))
imgs=torch.cat((men_g_recon,women_g_recon,women_ng_recon,out),dim=0)
imgs=torchvision.utils.make_grid(imgs,4,1).cpu().numpy()
imgs=np.transpose(imgs,(1,2,0))
fig, ax = plt.subplots(figsize=(8,2),dpi=100)
# 可视化图像
plt.imshow(imgs)
plt.title("man with glasses - woman \
with glasses + woman without \
glasses = man without glasses ",fontsize=10,c="r")
plt.axis("off")
plt.show()
(5) 此外,我们还可以通过为两个编码分配不同的权重,在潜空间中对它们进行插值,创建一个新的编码。然后,可以解码这个新的编码,生成一个合成图像。通过选择不同的权重,我们创建一系列从一个图像过渡到另一个图像的中间图像。以戴眼镜和不戴眼镜的女性的编码为例。定义一个新的编码 z
为 w * women_ng_encoding + (1 - w) * women_g_encoding
,其中 w
是对 women_ng_encoding
分配的权重, w
从 0
逐步增大到 1
,每次增加 0.2
。然后,解码这些编码并展示生成的六张图像:
results=[]
for w in [0, 0.2, 0.4, 0.6, 0.8, 1.0]:z=w*women_ng_encoding+(1-w)*women_g_encodingout=vae.decoder(z.unsqueeze(0))results.append(out)
imgs=torch.cat((results[0],results[1],results[2],results[3],results[4],results[5]),dim=0)
imgs=torchvision.utils.make_grid(imgs,6,1).cpu().numpy()
imgs=np.transpose(imgs,(1,2,0))
fig, ax = plt.subplots(dpi=100)
plt.imshow(imgs)
plt.axis("off")
plt.show()
结果表明,潜空间中的编码是连续的、可解释的,并且可以进行插值操作。
小结
- 变分自编码器 (
Variational Auto-Encoder
,VAE
) 与自编码器 (AutoEncoder, AE) 相比,VAE
在两个关键方面有所不同。首先,AE
将每个输入编码为潜空间中的一个特定点,而VAE
将其编码为该空间中的一个概率分布。其次,AE
仅专注于最小化重建误差,而VAE
学习潜变量的概率分布的参数,最小化包含重建损失和正则化项(KL
散度)的损失函数 - 在训练
VAE
时,损失函数中的KL
散度确保潜变量的分布接近正态分布。这鼓励编码器学习连续、有意义且具有可泛化性的潜表示 - 训练良好的
VAE
可以将相似的输入映射到潜空间中的相邻点,从而得到更连续和可解释的潜空间。因此,VAE
可以将潜空间中的随机向量解码为有意义的输出,生成训练集未出现的图像 VAE
中的潜空间是连续且可解释的,不同于AE
中的潜空间。因此,我们可以操作编码来获取新的结果。我们还可以通过在潜空间中对两个编码施加不同的权重,创建从一个实例过渡到另一个实例的序列图像
系列链接
PyTorch生成式人工智能实战:从零打造创意引擎
PyTorch生成式人工智能(1)——神经网络与模型训练过程详解
PyTorch生成式人工智能(2)——PyTorch基础
PyTorch生成式人工智能(3)——使用PyTorch构建神经网络
PyTorch生成式人工智能(4)——卷积神经网络详解
PyTorch生成式人工智能(5)——分类任务详解
PyTorch生成式人工智能(6)——生成模型(Generative Model)详解
PyTorch生成式人工智能(7)——生成对抗网络实践详解
PyTorch生成式人工智能(8)——深度卷积生成对抗网络
PyTorch生成式人工智能(9)——Pix2Pix详解与实现
PyTorch生成式人工智能(10)——CyclelGAN详解与实现
PyTorch生成式人工智能(11)——神经风格迁移
PyTorch生成式人工智能(12)——StyleGAN详解与实现
PyTorch生成式人工智能(13)——WGAN详解与实现
PyTorch生成式人工智能(14)——条件生成对抗网络(conditional GAN,cGAN)
PyTorch生成式人工智能(15)——自注意力生成对抗网络(Self-Attention GAN, SAGAN)
PyTorch生成式人工智能(16)——自编码器(AutoEncoder)详解