pytorch实现变分自编码器

变分自编码器(Variational Autoencoder, VAE)是一种生成模型,属于深度学习中的无监督学习方法。它通过学习输入数据的潜在分布(Latent Distribution),生成与输入数据相似的新样本。VAE 可以用于数据生成、降维、异常检测等任务。

VAE 的关键思想是在传统的自编码器(Autoencoder)的基础上,引入了变分推断(Variational Inference)和概率模型,使得网络能够学习到数据的潜在分布,而不仅仅是数据的映射。

VAE 的结构:

  1. 编码器(Encoder):将输入数据映射到潜在空间的分布。不同于传统的自编码器直接将数据映射到一个固定的潜在向量,VAE 通过输出潜在变量的均值和方差来描述一个概率分布,这样潜在空间中的每个点都有一个概率分布。
  2. 潜在空间(Latent Space):表示数据的潜在特征。在 VAE 中,潜在空间的表示是一个分布而不是固定的值。通常,采用正态分布来作为潜在空间的先验分布。
  3. 解码器(Decoder):从潜在空间的样本中重构输入数据。解码器通过将潜在空间的点映射回数据空间来生成样本。

VAE 的目标函数:

VAE 的目标是最大化变分下界(Variational Lower Bound,简称 ELBO),即通过优化以下两部分的加权和:

  • 重构误差(Reconstruction Loss):衡量生成的数据和输入数据之间的差异,通常使用均方误差(MSE)或交叉熵(Cross-Entropy)。
  • KL 散度(KL Divergence):衡量潜在空间的分布与先验分布(通常是标准正态分布)之间的差异。

其最终的目标是使生成的数据尽可能接近真实数据,同时使潜在空间的分布接近先验分布。

优点:

  • VAE 能够生成具有多样性的样本,尤其适用于图像、音频等数据的生成。
  • 潜在空间通常具有良好的结构,可以进行插值、样本生成等操作。

应用:

  • 生成任务:如图像生成、文本生成等。

  • 数据重构:如去噪、自编码等。

  • 半监督学习:VAE 可以结合有标签和无标签的数据进行训练,提升模型的泛化能力。

    import torch
    import torch.nn as nn
    import torch.optim as optim
    from torch.utils.data import Dataset, DataLoader
    import matplotlib.pyplot as plt

    生成圆形图像的函数(使用PyTorch)

    def generate_circle_image(size=64):
    image = torch.zeros((1, size, size)) # 使用 PyTorch 创建空白图像
    center = size // 2
    radius = size // 4
    for y in range(size):
    for x in range(size):
    if (x - center) ** 2 + (y - center) ** 2 <= radius ** 2:
    image[0, y, x] = 1 # 在圆内的点设置为白色
    return image

    生成方形图像的函数(使用PyTorch)

    def generate_square_image(size=64):
    image = torch.zeros((1, size, size)) # 使用 PyTorch 创建空白图像
    padding = size // 4
    image[0, padding:size - padding, padding:size - padding] = 1 # 设置方形区域为白色
    return image

    自定义数据集:圆形和方形图像

    class ShapeDataset(Dataset):
    def init(self, num_samples=1000, size=64):
    self.num_samples = num_samples
    self.size = size
    self.data = []
    # 生成数据:一半是圆形图像,一半是方形图像
    for i in range(num_samples // 2):
    self.data.append(generate_circle_image(size))
    self.data.append(generate_square_image(size))

      def __len__(self):
          return len(self.data)
    
      def __getitem__(self, idx):
          return self.data[idx].float()  # 直接返回 PyTorch Tensor 格式的数据
    

    VAE模型定义

    class VAE(nn.Module):
    def init(self, latent_dim=2):
    super(VAE, self).init()
    self.latent_dim = latent_dim

          # 编码器
          self.fc1 = nn.Linear(64 * 64, 400)
          self.fc21 = nn.Linear(400, latent_dim)  # 均值
          self.fc22 = nn.Linear(400, latent_dim)  # 方差
    
          # 解码器
          self.fc3 = nn.Linear(latent_dim, 400)
          self.fc4 = nn.Linear(400, 64 * 64)
    
      def encode(self, x):
          h1 = torch.relu(self.fc1(x.view(-1, 64 * 64)))
          return self.fc21(h1), self.fc22(h1)  # 返回均值和方差
    
      def reparameterize(self, mu, logvar):
          std = torch.exp(0.5 * logvar)
          eps = torch.randn_like(std)
          return mu + eps * std
    
      def decode(self, z):
          h3 = torch.relu(self.fc3(z))
          return torch.sigmoid(self.fc4(h3)).view(-1, 1, 64, 64)  # 重构图像
    
      def forward(self, x):
          mu, logvar = self.encode(x)
          z = self.reparameterize(mu, logvar)
          return self.decode(z), mu, logvar
    

    损失函数:重构误差 + KL 散度

    def loss_function(recon_x, x, mu, logvar):
    BCE = nn.functional.binary_cross_entropy(recon_x.view(-1, 64 * 64), x.view(-1, 64 * 64), reduction='sum')
    # KL 散度
    return BCE + 0.5 * torch.sum(torch.exp(logvar) + mu ** 2 - 1 - logvar)

    设置超参数

    batch_size = 128
    epochs = 10
    latent_dim = 2
    learning_rate = 1e-3

    数据加载

    train_loader = DataLoader(ShapeDataset(num_samples=2000), batch_size=batch_size, shuffle=True)

    创建模型和优化器

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    model = VAE(latent_dim).to(device)
    optimizer = optim.Adam(model.parameters(), lr=learning_rate)

    训练模型

    def train(epoch):
    model.train()
    train_loss = 0
    for batch_idx, data in enumerate(train_loader):
    data = data.to(device)
    optimizer.zero_grad()
    recon_batch, mu, logvar = model(data)
    loss = loss_function(recon_batch, data, mu, logvar)
    loss.backward()
    train_loss += loss.item()
    optimizer.step()

          if batch_idx % 100 == 0:
              print(
                  f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)}] Loss: {loss.item() / len(data):.6f}')
    
      print(f'Train Epoch: {epoch} Average loss: {train_loss / len(train_loader.dataset):.4f}')
    

    测试并显示一些真实图像和生成的图像

    def test():
    model.eval()
    with torch.no_grad():
    # 获取一批真实的图像(原始图像)
    real_images = next(iter(train_loader))[:64] # 只取前64个图像
    real_images = real_images.cpu().numpy()

          # 从潜在空间随机生成一些样本
          sample = torch.randn(64, latent_dim).to(device)
          generated_images = model.decode(sample).cpu().numpy()
    
          # 显示真实图像和生成的图像,分别标明
          fig, axes = plt.subplots(8, 8, figsize=(8, 8))
          axes = axes.flatten()
    
          for i in range(64):
              if i < 32:  # 前32个显示真实图像
                  axes[i].imshow(real_images[i].squeeze(), cmap='gray')
                  axes[i].set_title('Real', fontsize=8)
              else:  # 后32个显示生成图像
                  axes[i].imshow(generated_images[i - 32].squeeze(), cmap='gray')
                  axes[i].set_title('Generated', fontsize=8)
    
              axes[i].axis('off')
    
          plt.tight_layout()
          plt.show()
    

    训练模型

    for epoch in range(1, epochs + 1):
    train(epoch)

    训练完成后,显示生成的图像

    test()

解释:

  1. 真实图像 (real_images) :我们通过 next(iter(train_loader)) 获取一批真实图像,并将其转换为 NumPy 数组,以便 matplotlib 显示。
  2. 生成图像 (generated_images) :通过模型生成的图像,使用 decode() 方法生成潜在空间的样本。
  3. 图像展示 :前 32 张图像展示真实图像,后 32 张图像展示生成的图像。每个图像上方都有 RealGenerated 标注。

结果:

  • 前32个图像 :显示真实图像,并标注为 Real
  • 后32个图像 :显示通过训练后的 VAE 生成的图像,并标注为 Generated
相关推荐
Bruce_Liuxiaowei28 分钟前
基于阿里云百炼大模型Sensevoice-1的语音识别与文本保存工具开发
人工智能·阿里云·语音识别·xcode
说私域35 分钟前
对顾客行为的数据分析:融入2+1链动模式、AI智能名片与S2B2C商城小程序的新视角
人工智能·小程序·数据分析·开源
字节全栈_mMD1 小时前
Flask框架基础入门教程_ezflaskapp
后端·python·flask
Bran_Liu1 小时前
【LeetCode 刷题】二叉树-修改与构造
数据结构·python·算法·leetcode
游王子1 小时前
Python NumPy(10):NumPy 统计函数
开发语言·python·numpy
仇辉攻防2 小时前
【AI】DeepSeek 概念/影响/使用/部署
人工智能·网络安全·ai·语言模型·chatgpt·ddos
叫我DPT2 小时前
Python 类型注解
python
sirius123451232 小时前
自定义数据集 使用paddlepaddle框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测
人工智能·逻辑回归·paddlepaddle
Luzem03192 小时前
使用PaddlePaddle实现逻辑回归:从训练到模型保存与加载
人工智能·逻辑回归·paddlepaddle
广药门徒2 小时前
Anaconda使用教程 如何conda配置多版本Python环境
开发语言·python·conda