风峪 2023-09-18 18:16 采纳率: 50%
浏览 9
已结题

GAN模型训练MINIST问题代码错误问题

最近在学习gan模型,基于pytorch在使用gan训练minist时,将全连接层增加了卷积层,但是代码一直有问题,寻求解答


import torch
from torchvision import datasets, transforms


device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')


transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=0.5,std=0.5)
])
mnist_data = datasets.MNIST(root='D:/data/FashionMNIST', train=True, transform=transform, download=True)
data_loader = torch.utils.data.DataLoader(mnist_data, batch_size=128, shuffle=True, drop_last=True, num_workers=6)
import torch
import torch.nn as nn
import torch.nn.functional as F

# 定义生成器
class Generator(nn.Module):
    def __init__(self, z_dim=100, hidden_dim=128):
        super(Generator, self).__init__() # 继承 nn.Module 类并初始化
        self.z_dim = z_dim # 输入向量的维度
        self.hidden_dim = hidden_dim # 隐藏层维度
        self.fc1 = nn.Linear(z_dim, hidden_dim) # 全连接层,输入为 z_dim 维,输出为 hidden_dim 维
        self.fc2 = nn.Linear(hidden_dim, 7 * 7 * 256) # 全连接层,将隐藏层映射到 7*7*256 的图像
        self.deconv1 = nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1) # 上采样层,输入为 7*7*256,输出为 14*14*128
        self.deconv2 = nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1) # 上采样层,输入为 14*14*128,输出为 28*28*64
        self.deconv3 = nn.ConvTranspose2d(64, 3, kernel_size=4, stride=2, padding=1) # 上采样层,输入为 28*28*64,输出为 28*28*3
    def forward(self, z):
        x = self.fc1(z) # 输入 z,通过全连接层 fc1 得到隐藏层向量 x
        x = nn.functional.leaky_relu(x, 0.2) # 在隐藏层中应用 LeakyReLU 激活函数
        x = self.fc2(x) # 将隐藏层映射到 7*7*256 的图像
        x = x.view(-1, 256, 7, 7) # 将输出展平成图片张量形式
        x = F.relu(self.deconv1(x)) # 在上采样层中应用 ReLU 激活函数
        x = F.relu(self.deconv2(x)) # 在上采样层中应用 ReLU 激活函数
        x = F.tanh(self.deconv3(x)) # 将输出值映射到 [-1, 1] 的范围
        return x.view(-1, 1, 28, 28) # 将输出展平成图片张量形式

# 定义判别器
class Discriminator(nn.Module):
    def __init__(self, hidden_dim=128):
        super(Discriminator, self).__init__() # 继承 nn.Module 类并初始化
        self.hidden_dim = hidden_dim # 隐藏层维度
        self.conv1 = nn.Conv2d(1, 64, kernel_size=4, stride=2, padding=1) # 卷积层,输入为 1 维,输出为 64 维,kernel_size=4 表示卷积核大小为 4*4,stride=2 表示步幅为 2,padding=1 表示填充 1 个像素
        self.conv2 = nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1) # 卷积层,输入为 64 维,输出为 128 维,kernel_size=4 表示卷积核大小为 4*4,stride=2 表示步幅为 2,padding=1 表示填充 1 个像素
        self.conv3 = nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1) # 卷积层,输入为 128 维,输出为 256 维,kernel_size=4 表示卷积核大小为 4*4,stride=2 表示步幅为 2,padding=1 表示填充 1 个像素
        self.conv4 = nn.Conv2d(256, 512, kernel_size=4, stride=2, padding=1) # 卷积层,输入为 256 维,输出为 512 维,kernel_size=4 表示卷积核大小为 4*4,stride=2 表示步幅为 2,padding=1 表示填充 1 个像素
        self.fc1 = nn.Linear(512 * 4 * 4, hidden_dim) # 全连接层,输入为 512*4*4 维,输出为 hidden_dim 维
        self.fc2 = nn.Linear(hidden_dim, 1) # 只有一个输出,表示输入是否是真实的图像。

    def forward(self, x):
        x = F.leaky_relu(self.conv1(x), 0.2) # 在卷积层中应用 LeakyReLU 激活函数
        x = F.leaky_relu(self.conv2(x), 0.2) # 在卷积层中应用 LeakyReLU 激活函数
        x = F.leaky_relu(self.conv3(x), 0.2) # 在卷积层中应用 LeakyReLU 激活函数
        x = F.leaky_relu(self.conv4(x), 0.2) # 在卷积层中应用 LeakyReLU 激活函数
        x = x.view(-1, 512 * 4 * 4) # 将输入展平成向量
        x = F.leaky_relu(self.fc1(x), 0.2) # 在全连接层中应用 LeakyReLU 激活函数
        x = self.fc2(x) # 将隐藏层输出映射到单个输出值
        x = nn.functional.sigmoid(x) # 将输出值映射到 [0, 1] 的范围,表示输入是否是真实图像的概率
        return x
# 定义超参数
lr = 0.0004
z_dim = 100
num_epochs = 100

generator = Generator(z_dim).to(device)
discriminator = Discriminator().to(device)

# 定义优化器和损失函数
optimizer_G = torch.optim.Adam(generator.parameters(), lr=lr)
optimizer_D = torch.optim.Adam(discriminator.parameters(), lr=lr)

criterion = nn.BCELoss()
# 训练网络,使用给定的 epoch 数量
for epoch in range(num_epochs):
    # 遍历数据集的 mini-batches
    for i, (real_images, _) in enumerate(data_loader):
        # 将真实图像传递给设备
        real_images = real_images.to(device)
        real_labels = torch.ones(real_images.size(0), 1).to(device)
        fake_labels = torch.zeros(real_images.size(0), 1).to(device)
 # 训练生成器
        # 生成随机的噪音 z
        z = torch.randn(real_images.size(0), z_dim).to(device)
        fake_images = generator(z)
        fake_output = discriminator(fake_images)

        # 计算生成器的损失值 loss_G
        # 需要将 fake_output 与真实标签 real_labels 进行比较
        loss_G = criterion(fake_output, real_labels)
        optimizer_G.zero_grad()
        # 计算 generator 的梯度
        loss_G.backward()
        # 更新 generator 参数,使用优化器 optimizer_G
        optimizer_G.step()

 # 训练判别器
        real_output = discriminator(real_images)

        # 计算判别器对真实图像的损失值 loss_D_real
        # 需要将 real_output 与真实标签 real_labels 进行比较
        loss_D_real = criterion(real_output, real_labels)

        # 计算判别器对生成器生成的 fake_images 的损失值 loss_D_fake
        # 需要将 fake_output 与假的标签 fake_labels 进行比较
        fake_output = discriminator(fake_images.detach())
        loss_D_fake = criterion(fake_output, fake_labels)
        loss_D = loss_D_real + loss_D_fake
        optimizer_D.zero_grad()
        # 计算 discriminator 的梯度
        loss_D.backward()

        # 更新 discriminator 参数,使用优化器 optimizer_D
        optimizer_D.step()

        # 输出损失值 每100次迭代输出一次
        if (i + 1) % 100 == 0:
            print('Epoch [{}/{}], Step [{}/{}], d_loss: {:.4f}, g_loss: {:.4f}'
                  .format(epoch+1, num_epochs, i+1, len(data_loader), loss_D.item(), loss_G.item()))
from matplotlib import pyplot as plt
# 生成一些测试数据
# 随机生成一些长度为 z_dim 的、位于设备上的向量 z
z = torch.randn(16, z_dim).to(device)

# 使用生成器从 z 中生成一些假的图片
fake_images = generator(z).detach().cpu()

# 显示生成的图像
# 创建一个图形对象,大小为 4x4 英寸
fig = plt.figure(figsize=(4, 4))

# 在图形对象中创建4x4的网格,以显示输出的16张假图像
for i in range(16):
    plt.subplot(4, 4, i+1)
    plt.imshow(fake_images[i][0], cmap='gray')
    plt.axis('off')

# 显示绘制的图形
plt.show()

img

除此外,代码还有无其他问题

  • 写回答

15条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2023-09-18 18:20
    关注
    获得0.45元问题酬金

    引用 皆我百晓生 小程序回复内容作答:
    在代码中,训练生成器时计算生成器的损失值时出现了错误。错误的原因是在使用BCELoss函数计算损失值时,纠正真实和生成图像的标签出现了问题。

    在生成图像的标签生成代码中,使用了错误的标签张量。可以修改代码如下:

    fake_labels = torch.ones(fake_images.size(0), 1).to(device)
    

    将上述代码放置在以下代码段的前面:

    # 训练生成器
    # 生成随机的噪音 z
    z = torch.randn(real_images.size(0), z_dim).to(device)
    fake_images = generator(z)
    fake_output = discriminator(fake_images)
    

    修改后的代码片段如下:

    # 训练生成器
    # 生成随机的噪音 z
    z = torch.randn(real_images.size(0), z_dim).to(device)
    fake_images = generator(z)
    fake_output = discriminator(fake_images)
    
    # 计算生成器的损失值 loss_G
    # 需要将 fake_output 与真实标签 fake_labels 进行比较
    loss_G = criterion(fake_output, fake_labels)
    optimizer_G.zero_grad()
    # 计算 generator 的梯度
    loss_G.backward()
    # 更新 generator 参数,使用优化器 optimizer_G
    optimizer_G.step()
    

    通过将真实图像和生成图像的标签分别与真实标签real_labels和假标签fake_labels进行比较,计算生成器的损失值。这样就可以纠正该错误并正常训练生成器。

    评论

报告相同问题?

问题事件

  • 系统已结题 9月26日
  • 创建了问题 9月18日

悬赏问题

  • ¥50 深度学习运行代码直接中断
  • ¥15 关于#单片机#的问题,请各位专家解答!
  • ¥15 关于#单片机#的问题,请各位专家解答!
  • ¥20 需要完整的共散射点成像代码
  • ¥15 编写vba代码实现数据录入工作
  • ¥15 做过TCL海信电视小米电视相关影视会员软件私我
  • ¥15 Mapreduce是正常的,在运行其他jar包时并没有任何问题,只是在做LogCount.jar 时出的问题。如图所示
  • ¥15 ImportError: DLL load failed while importing _iterative: 找不到指定的模块。
  • ¥15 如何通过交互分析得出某高危患者对放疗获益更多
  • ¥15 相关性分析中,p<0.05, r=0.29,怎么评价相关性呢