前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >变分自编码器 VAE

变分自编码器 VAE

作者头像
为为为什么
发布2022-09-27 15:17:22
1.5K0
发布2022-09-27 15:17:22
举报
文章被收录于专栏:又见苍岚

变分自编码器 (Variational Auto-Encoders, VAE) 属于生成模型家族。VAE 的生成器能够利用连续潜在空间的矢量产生有意义的输出,它是包含隐变量的一种模型,通过潜在矢量探索解码器输出的可能属性。

简介

简单来讲,变分自编码器是可以和GAN相媲美的生成网络。我们可以输入一个低维空间的Z,映射到高维空间的真实数据。比如,生成不同样的数字,人脸等等。

什么是 VAE
  • 变分自动编码器(AEV)就是用于生成模型,结合了深度模型以及静态推理。简单来说就是通过映射学习将一个高位数据,例如一幅图片映射到低维空间Z。与标准自动编码器不同的是,X和Z是随机变量。所以可以这么理解,尝试从P(X|Z)中去采样出x,所以利用这个可以生成人脸,数字以及语句的生成。

VAE 使用了类似 AE (Auto Encoder) 的结构,和最早出现的生成模型完成类似的任务,所以和二者有着千丝万缕的联系

与 GAN 的关系
  • 变分自编码器与对抗生成网络类似,均是为了解决数据生成问题而生的。在 GAN 中,重点在于如何得出近似输入分布的模型。 VAE 尝试对可解耦的连续潜在空间中的输入分布进行建模。
  • 变分自编码器同样的以特定分布的随机样本作为输入,并且可以生成相应的图像,从此方面来看其与对抗生成网络目标是相似的。但是变分自编码器不需要判别器,而是使用编码器来估计特定分布。总体结构来看与自编码器结构类似,但是中间传递向量为特定分布的随机向量。
  • 假设,给定一系列猫的照片,我希望你能够对应我随机输入的一个n维向量,生成一张新的猫的照片,你需要怎么去做?对于GAN就是典型的深度学习时代的逻辑,你不清楚这个n维向量与猫的图片之间的关系,没关系,我直接拟合出来猫的图片对于n维向量的分布,通过对抗学习的方式获得较好的模型效果,这个方法虽然很暴力,但是却是有效的。
  • VAE则不同,他通过说我希望生成一张新的猫脸,那么这个n维向量代表的就是n个决定最终猫脸模样的隐形因素。对于每个因素,都对应产生一种分布,从这些分布关系中进行采样,那么我就可以通过一个深度网络恢复出最终的猫脸。
与 AE 的关系
  • 在自编码器(Auto Encoder)结构中,通常需要一个输入数据,而且所生成的数据与输入数据是相同的。但是通常希望生成的数据具有一定程度的不同,这需要输入随机向量并且模型能够学习生成图像的风格化特点,因此在后续研究中以随机化向量作为输入生成特定样本的对抗生成网络结构便产生了。
  • 在结构上,VAE 与自编码器相似。它也由编码器(也称为识别或推理模型)和解码器(也称为生成模型)组成。 VAE 和自编码器都试图在学习潜矢量的同时重建输入数据。但是,与自编码器不同,VAE 的潜在空间是连续的,并且解码器本身被用作生成模型。
  • VAE即在AE的基础上引入变分的思想,使其能够进行数据生成。VAE建模着重考虑 x^=g(z) 过程的有效性,其中 z 为隐变量特征的分布。

  • AE的主要作用为特征提取或数据降维,即寻找合适的抽象特征z,可以使其代表x,如上图左侧,当我们微调z时,无法生成有效的月亮图片;而右侧的VAE过程,此时z为抽象特征的分布,当微调时,可以得到有效的月亮图片。

Auto-Encoder

  • Auto encoder 是一种无监督算法,主要用于特征提取或数据降维。其思想非常简单,即输入特征 x 经过 encoder 后抽象为 hidden layer z,再将 z 经过 decoder 过程重新预测为 x^ 。其中encoder和decoder 的过程可以是 MLP/CNN/LSTM 等简单的神经网络。

VAE原理

VAE 结构

VAE 确定方向的原因

  • 考虑所有可能的属性,最终得到描述输入的分布。在人脸数据中,利用包含面部表情,发型,头发颜色和性别在内的特征,可以恢复描述人脸数据的分布。
  • 问题在于该方程式没有解析形式或有效的估计量。因此,通过神经网络进行优化是不可行的。
  • 使用贝叶斯定理,可以找到方程式 2 的替代表达式:

VAE 推导过程

  • 整体计算流程:

代码语言:javascript
复制
class VAE(nn.Module):
    """Implementation of VAE(Variational Auto-Encoder)"""
    def __init__(self):
        super(VAE, self).__init__()
        self.fc1 = nn.Linear(784, 200)
        self.fc2_mu = nn.Linear(200, 10)
        self.fc2_log_std = nn.Linear(200, 10)
        self.fc3 = nn.Linear(10, 200)
        self.fc4 = nn.Linear(200, 784)
    def encode(self, x):
        h1 = F.relu(self.fc1(x))
        mu = self.fc2_mu(h1)
        log_std = self.fc2_log_std(h1)
        return mu, log_std
    def decode(self, z):
        h3 = F.relu(self.fc3(z))
        recon = torch.sigmoid(self.fc4(h3))  # use sigmoid because the input image's pixel is between 0-1
        return recon
    def reparametrize(self, mu, log_std):
        std = torch.exp(log_std)
        eps = torch.randn_like(std)  # simple from standard normal distribution
        z = mu + eps * std
        return z
    def forward(self, x):
        mu, log_std = self.encode(x)
        z = self.reparametrize(mu, log_std)
        recon = self.decode(z)
        return recon, mu, log_std
    def loss_function(self, recon, x, mu, log_std) -> torch.Tensor:
        recon_loss = F.mse_loss(recon, x, reduction="sum")  # use "mean" may have a bad effect on gradients
        kl_loss = -0.5 * (1 + 2*log_std - mu.pow(2) - torch.exp(2*log_std))
        kl_loss = torch.sum(kl_loss)
        loss = recon_loss + kl_loss
        return loss
  • 训练流程

实验结果
  • 论文中基于 MNIST 和 Frey Face 做了实验
  • 网络结构包含三个部分:
  1. 先验网络 pθ(z∣X),如下图(b)所示_
  2. Recognition 网络 qϕ(z∣X,Y), 如下图©所示
  3. Decoder网络 pθ(Y∣X,Z),如下图(b)所示

代码语言:javascript
复制
class CVAE(nn.Module):
    """Implementation of CVAE(Conditional Variational Auto-Encoder)"""
    def __init__(self, feature_size, class_size, latent_size):
        super(CVAE, self).__init__()
        self.fc1 = nn.Linear(feature_size + class_size, 200)
        self.fc2_mu = nn.Linear(200, latent_size)
        self.fc2_log_std = nn.Linear(200, latent_size)
        self.fc3 = nn.Linear(latent_size + class_size, 200)
        self.fc4 = nn.Linear(200, feature_size)
    def encode(self, x, y):
        h1 = F.relu(self.fc1(torch.cat([x, y], dim=1)))  # concat features and labels
        mu = self.fc2_mu(h1)
        log_std = self.fc2_log_std(h1)
        return mu, log_std
    def decode(self, z, y):
        h3 = F.relu(self.fc3(torch.cat([z, y], dim=1)))  # concat latents and labels
        recon = torch.sigmoid(self.fc4(h3))  # use sigmoid because the input image's pixel is between 0-1
        return recon
    def reparametrize(self, mu, log_std):
        std = torch.exp(log_std)
        eps = torch.randn_like(std)  # simple from standard normal distribution
        z = mu + eps * std
        return z
    def forward(self, x, y):
        mu, log_std = self.encode(x, y)
        z = self.reparametrize(mu, log_std)
        recon = self.decode(z, y)
        return recon, mu, log_std
    def loss_function(self, recon, x, mu, log_std) -> torch.Tensor:
        recon_loss = F.mse_loss(recon, x, reduction="sum")  # use "mean" may have a bad effect on gradients
        kl_loss = -0.5 * (1 + 2*log_std - mu.pow(2) - torch.exp(2*log_std))
        kl_loss = torch.sum(kl_loss)
        loss = recon_loss + kl_loss
        return loss

原始论文

file:///C:/Users/issuser/Downloads/202208271254675.pdf

参考资料

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年8月25日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简介
    • 什么是 VAE
      • 与 GAN 的关系
        • 与 AE 的关系
        • Auto-Encoder
        • VAE原理
        • VAE 结构
        • VAE 确定方向的原因
        • VAE 推导过程
          • 实验结果
          • 原始论文
          • 参考资料
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档