当前位置:   article > 正文

VAE——重构数字(Pytorch+mnist)

VAE——重构数字(Pytorch+mnist)

1、简介

  • VAE(变分自编码器)由编码器和解码器组成,但与AE不同的是,VAE通过引入隐变量并利用概率分布来学习潜在表示。
  • 本文利用VAE,输入数字图像。训练后,输入测试数字图像,重构生成新的数字图像。
    • 【注】本文案例需要输入才能生成输出,目标是重构,而不是生成。
  • 【注】输出的16张数字图像是输入的测试图像的第一批次。

2、代码

    1. import torch
    2. import torch.nn as nn
    3. import torch.optim as optim
    4. import torchvision
    5. import torch.nn.functional as F
    6. from torchvision.utils import save_image
    7. import matplotlib.pyplot as plt
    8. # 变分自编码器
    9. class VAE(nn.Module):
    10. def __init__(self):
    11. super(VAE, self).__init__()
    12. # 编码器层
    13. self.fc1 = nn.Linear(input_size, 512) # 编码器输入层
    14. self.fc2 = nn.Linear(512, latent_size)
    15. self.fc3 = nn.Linear(512, latent_size)
    16. # 解码器层
    17. self.fc4 = nn.Linear(latent_size, 512) # 解码器输入层
    18. self.fc5 = nn.Linear(512, input_size) # 解码器输出层
    19. # 编码器部分
    20. def encode(self, x):
    21. x = F.relu(self.fc1(x)) # 编码器的隐藏表示
    22. mu = self.fc2(x) # 潜在空间均值
    23. log_var = self.fc3(x) # 潜在空间对数方差
    24. return mu, log_var
    25. # 重参数化技巧
    26. def reparameterize(self, mu, log_var): # 从编码器输出的均值和对数方差中采样得到潜在变量z
    27. std = torch.exp(0.5 * log_var) # 计算标准差
    28. eps = torch.randn_like(std) # 从标准正态分布中采样得到随机噪声
    29. return mu + eps * std # 根据重参数化公式计算潜在变量z
    30. # 解码器部分
    31. def decode(self, z):
    32. z = F.relu(self.fc4(z)) # 将潜在变量 z 解码为重构图像
    33. return torch.sigmoid(self.fc5(z)) # 将隐藏表示映射回输入图像大小,并应用 sigmoid 激活函数,以产生重构图像
    34. # 前向传播
    35. def forward(self, x): # 输入图像 x 通过编码器和解码器,得到重构图像和潜在变量的均值和对数方差
    36. mu, log_var = self.encode(x.view(-1, input_size))
    37. z = self.reparameterize(mu, log_var)
    38. return self.decode(z), mu, log_var
    39. # 使用重构损失和 KL 散度作为损失函数
    40. def loss_function(recon_x, x, mu, log_var): # 参数:重构的图像、原始图像、潜在变量的均值、潜在变量的对数方差
    41. MSE = F.mse_loss(recon_x, x.view(-1, input_size), reduction='sum') # 计算重构图像 recon_x 和原始图像 x 之间的均方误差
    42. KLD = -0.5 * torch.sum(1 + log_var - mu.pow(2) - log_var.exp()) # 计算潜在变量的KL散度
    43. return MSE + KLD # 返回二进制交叉熵损失和 KLD 损失的总和作为最终的损失值
    44. if __name__ == '__main__':
    45. batch_size = 512 # 批次大小
    46. epochs = 30 # 学习周期
    47. sample_interval = 10 # 保存结果的周期
    48. learning_rate = 0.001 # 学习率
    49. input_size = 784 # 输入大小
    50. latent_size = 64 # 潜在空间大小
    51. # 载入 MNIST 数据集中的图片进行训练
    52. transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor()]) # 将图像转换为张量
    53. train_dataset = torchvision.datasets.MNIST(
    54. root="~/torch_datasets", train=True, transform=transform, download=True
    55. ) # 加载 MNIST 数据集的训练集,设置路径、转换和下载为 True
    56. train_loader = torch.utils.data.DataLoader(
    57. train_dataset, batch_size=batch_size, shuffle=True
    58. ) # 创建一个数据加载器,用于加载训练数据,设置批处理大小和是否随机打乱数据
    59. # 在使用定义的 AE 类之前,有以下事情要做:
    60. # 配置要在哪个设备上运行
    61. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    62. # 建立 VAE 模型并载入到 CPU 设备
    63. model = VAE().to(device)
    64. # Adam 优化器,学习率
    65. optimizer = optim.Adam(model.parameters(), lr=learning_rate)
    66. # 训练
    67. for epoch in range(epochs):
    68. train_loss = 0
    69. for batch_idx, (data, _) in enumerate(train_loader):
    70. data = data.to(device) # 将输入数据移动到设备(GPU 或 CPU)上
    71. optimizer.zero_grad() # 进行反向传播之前,需要将优化器中的梯度清零,以避免梯度的累积
    72. # 重构图像 recon_batch、潜在变量的均值 mu 和对数方差 log_var
    73. recon_batch, mu, log_var = model(data)
    74. loss = loss_function(recon_batch, data, mu, log_var) # 计算损失
    75. loss.backward() # 计算损失相对于模型参数的梯度
    76. train_loss += loss.item()
    77. optimizer.step() # 更新模型参数
    78. train_loss = train_loss / len(train_loader) # # 计算每个周期的训练损失
    79. print('Epoch [{}/{}], Loss: {:.3f}'.format(epoch + 1, epochs, train_loss))
    80. # 用训练过的自编码器提取一些测试用例来重构
    81. test_dataset = torchvision.datasets.MNIST(
    82. root="~/torch_datasets", train=False, transform=transform, download=True
    83. ) # 加载 MNIST 测试数据集
    84. test_loader = torch.utils.data.DataLoader(
    85. test_dataset, batch_size=16, shuffle=False
    86. ) # 创建一个测试数据加载器
    87. test_examples = None
    88. # 通过循环遍历测试数据加载器,获取一个批次的图像数据
    89. with torch.no_grad(): # 使用 torch.no_grad() 上下文管理器,确保在该上下文中不会进行梯度计算
    90. for batch_features in test_loader: # 历测试数据加载器中的每个批次的图像数据
    91. batch_features = batch_features[0] # 获取当前批次的图像数据
    92. test_examples = batch_features.view(-1, 784).to(
    93. device) # 将当前批次的图像数据转换为大小为 (批大小, 784) 的张量,并加载到指定的设备(CPU 或 GPU)上
    94. reconstruction, _, _ = model(test_examples) # 使用训练好的自编码器模型对测试数据进行重构,即生成重构的图像
    95. break
    96. # 试着用训练过的自编码器重建一些测试图像
    97. with torch.no_grad():
    98. number = 16 # 设置要显示的图像数量
    99. plt.figure(figsize=(60, 10)) # 创建一个新的 Matplotlib 图形,设置图形大小为 (16, 16)
    100. for index in range(number): # 遍历要显示的图像数量
    101. # 显示原始图
    102. ax = plt.subplot(2, number, index + 1) # 行 列 位置
    103. plt.imshow(test_examples[index].cpu().numpy().reshape(28, 28))
    104. plt.gray()
    105. plt.axis('off')
    106. # 显示重构图
    107. ax = plt.subplot(2, number, index + 1 + number)
    108. plt.imshow(reconstruction[index].cpu().numpy().reshape(28, 28))
    109. plt.gray()
    110. plt.axis('off')
    111. plt.savefig('reconstruction_results.png') # 保存图像
    112. plt.show()
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/344579
推荐阅读
相关标签
  

闽ICP备14008679号