深度生成网络模型介绍:VAE GAN VAE-GAN 附pytorch 代码

摘要

本文主要介绍了VAE,GAN以及对论文 Autoencoding beyond pixels using a learned similarity metric here自己的一些理解,并用代码实现了VAE,GAN 以及两种结构的VAE-GAN .

VAE介绍

在介绍VAE之前,首先要介绍它的前身自动编码器,自动编码器的结构如下:由一个Encoder和Decoder组成,Encoder将图像编码成隐藏向量,Decoder将图像解码,通过训练,可以使模型生成与训练图像相同类型的图像。
自动编码器的结构如下:

自动编码器有一个缺点是我们不知道隐藏向量的分布形式,不能生成任意的图片
变分自动编码器(VAE)很好的解决了这个问题,它通过将隐藏向量重参数化使其服从一个高斯分布,这样我们只需要给一个服从高斯分布的隐藏向量我们就可以生成想要的图片了
VAE结构如下:
在这里插入图片描述

VAE的loss由两部分组成:首先是要保证生成的图片与原图片具有一定的相似性(均方损失函数),其次要保证隐藏向量服从高斯分布(KL散度)。

GAN

GAN全称是生成对抗网络,这个网络由生成网络和对抗网络两部分组成,生成网络生成假的图片,判别网络要将真的图片判真,假的图片判假,最后希望生成器生成的图片能够以假乱真骗过判别网络。
GAN的网络结构如下:在这里插入图片描述
VAE的隐藏向量服从高斯分布,而GAN的输入是D维的噪声向量。
GAN的loss也由两部分组成:对与生成网络来说,它要让它生成的假图片能够以假乱真骗过判别器,而对于判别网络来说它要将真的图片判真,假的图片判假。

VAE-GAN

了解了VAE和GAN之后很自然的想到是否可以将VAE作为GAN的生成器,这样的网络即具有了VAE的可控制图片生成的特性又有了GAN优良的生成图片的性能。
VAE-GAN 的网络结构如下:
在这里插入图片描述
由结构图可以看出,这个网络前半部分就是一个完整的VAE,后面是一个GAN,其中VAE和GAN共享一个Decoder。
对于VAE-GAN网络来说他在生成上综合了VAE和GAN的优点,可以实现可控图片的生成。这也是这个网络最大的特点.
如何生成具有指定特征的图片呢?
在VAE-GAN的代码里,判别器返回两个值,一个值代表了图片的真假值,另一个值代表了图片的特征值,在计算网络损失时除了一般的前面提到的VAE损失和GAN损失外,该网络还加上了一个特征损失,即生成图片与原图片的特征损失,该损失旨在让网络生成具有和原图片具有相同特征的图片。即在实验中你可以控制网络生成图片的特征.
论文中给出的效果如下:
在这里插入图片描述
由图可以看出,生成的图片都具有某种特征。
这里有个问题,我们怎么让网络知道你要生成具有哪种特征的图片呢?
我们要想生成具有某种特征的图片首先要提取该特征的特征向量,然后将该该特征向量加到网络的隐藏向量中,这样生成的图片就都具有该特征了。
图片特征向量的提取过程:将一系列具有该特特征的图片的隐藏向量与不具有该特征的图片隐藏向量的平均差向量作为该特征的向量。

我对论文的理解

下面我想说说我在实现VAE-GAN的过程中遇到的问题
首先我没有看论文之前,先了解了VAE又了解了GAN看了看它们的代码感觉好简单,然后又知道VAE-GAN就是将VAE作为GAN的生成器,于是就自己构建了一种VAE-GAN的网络结构:在这里插入图片描述
大家可以看到这个网络结构与论文中的网络结构相比就是少了一个噪声向量Zp.由于计算能力有限我所有的代码的数据集都是minist数据集,这两个网络的生成性能都不错,但是VAE-GAN真正好的是它能生成具有特定特征的图片,在这一点上这个网络结构就不行了,这个作者在论文中也提到过了,(我当时看论文时看到作者也考虑过这个网络结构,感觉自己也能和作者想到一起去,真的是很兴奋)论文中说:在实践中,这个网络结构遇到了一些极难处理的事,于是出于实际的考虑,它们采用了之前那个网络结构.
我想这两个网络结构不同之处就在这个Zp上,由论文给的代码中我发现这个Zp的作用就是用来训练GAN的,而为什么要专门加上一个噪声向量来训练GAN呢?我的猜想是:由结构图可以看出这个网络很好地实现了VAE的结构但是对与GAN来说它的输入是VAE的隐藏向量,这个隐藏向量是服从高斯分布的,然而GAN的输入是一个随机的噪声向量,此外这个网络的x和作为GAN输入的z是有联系的,这也是我猜GAN不能很好训练的原因。

代码

github 地址 here

  • 20
    点赞
  • 149
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
下面是一个简单的pytorch实现VAEGAN代码,仅供参考: ```python import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader # 定义VAEGAN生成器 class Generator(nn.Module): def __init__(self, latent_size): super(Generator, self).__init__() self.latent_size = latent_size self.fc1 = nn.Linear(latent_size, 128) self.fc2 = nn.Linear(128, 256) self.fc3 = nn.Linear(256, 512) self.fc4 = nn.Linear(512, 28*28) self.relu = nn.ReLU() self.sigmoid = nn.Sigmoid() def forward(self, x): x = self.relu(self.fc1(x)) x = self.relu(self.fc2(x)) x = self.relu(self.fc3(x)) x = self.sigmoid(self.fc4(x)) return x.view(-1, 1, 28, 28) # 定义VAEGAN的判别器 class Discriminator(nn.Module): def __init__(self): super(Discriminator, self).__init__() self.conv1 = nn.Conv2d(1, 16, 3, stride=2, padding=1) self.conv2 = nn.Conv2d(16, 32, 3, stride=2, padding=1) self.conv3 = nn.Conv2d(32, 64, 3, stride=2, padding=1) self.fc = nn.Linear(64*4*4, 1) self.relu = nn.ReLU() self.sigmoid = nn.Sigmoid() def forward(self, x): x = self.relu(self.conv1(x)) x = self.relu(self.conv2(x)) x = self.relu(self.conv3(x)) x = x.view(-1, 64*4*4) x = self.sigmoid(self.fc(x)) return x # 定义VAEGAN的损失函数 class VAEGANLoss(nn.Module): def __init__(self): super(VAEGANLoss, self).__init__() self.mse_loss = nn.MSELoss() def forward(self, x, target, output, discriminator_output): recon_loss = self.mse_loss(output, target) adv_loss = -torch.log(discriminator_output + 1e-8).mean() return recon_loss + adv_loss # 定义训练函数 def train_vae_gan(generator, discriminator, train_loader, lr, latent_size, num_epochs): device = torch.device("cuda" if torch.cuda.is_available() else "cpu") generator.to(device) discriminator.to(device) optimizer_g = optim.Adam(generator.parameters(), lr=lr) optimizer_d = optim.Adam(discriminator.parameters(), lr=lr) loss_fn = VAEGANLoss() for epoch in range(num_epochs): for batch_idx, (data, _) in enumerate(train_loader): data = data.to(device) batch_size = data.size(0) # 训练判别器 z = torch.randn(batch_size, latent_size).to(device) fake_data = generator(z) real_output = discriminator(data) fake_output = discriminator(fake_data.detach()) d_loss = loss_fn(data, data, fake_data, fake_output) optimizer_d.zero_grad() d_loss.backward() optimizer_d.step() # 训练生成器 z = torch.randn(batch_size, latent_size).to(device) fake_data = generator(z) fake_output = discriminator(fake_data) g_loss = loss_fn(fake_data, data, fake_data, fake_output) optimizer_g.zero_grad() g_loss.backward() optimizer_g.step() print('Epoch [{}/{}], d_loss: {:.4f}, g_loss: {:.4f}' .format(epoch+1, num_epochs, d_loss.item(), g_loss.item())) # 加载MNIST数据集 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True) train_loader = DataLoader(train_dataset, batch_size=128, shuffle=True) # 定义超参数 lr = 0.0002 latent_size = 100 num_epochs = 50 # 创建VAEGAN模型并训练 generator = Generator(latent_size) discriminator = Discriminator() train_vae_gan(generator, discriminator, train_loader, lr, latent_size, num_epochs) # 生成新的数据 z = torch.randn(10, latent_size).to(device) fake_data = generator(z) ``` 以上代码仅供参考,实际实现过程中还需要针对具体问题进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值