风峪 2023-09-18 18:16 采纳率: 0%
浏览 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进行比较,计算生成器的损失值。这样就可以纠正该错误并正常训练生成器。

    评论
  • CSDN-Ada助手 CSDN-AI 官方账号 2023-09-18 20:24
    关注
    获得0.75元问题酬金

    【以下回答由 GPT 生成】

    你的代码中有几处问题需要修复。

    首先,关于生成器定义和在GPU上运行的问题,在下面的代码中加入了注释来解释每一步的作用,并进行了一些修改:

    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__()
            self.z_dim = z_dim
            self.hidden_dim = hidden_dim
            self.fc1 = nn.Linear(z_dim, hidden_dim)
            self.fc2 = nn.Linear(hidden_dim, 7 * 7 * 256)
            self.deconv1 = nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1)
            self.deconv2 = nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1)
            self.deconv3 = nn.ConvTranspose2d(64, 1, kernel_size=4, stride=2, padding=1)  # 输出通道数应该是1,因为MNIST是单通道的
    
        def forward(self, z):
            x = self.fc1(z)
            x = F.leaky_relu(x, 0.2)  # 使用 torch.nn.functional 的时候需要加上前缀 F.
            x = x.view(-1, 256, 7, 7)
            x = self.deconv1(x)
            x = F.leaky_relu(x, 0.2)
            x = self.deconv2(x)
            x = F.leaky_relu(x, 0.2)
            x = self.deconv3(x)
            x = torch.tanh(x)
            return x
    
    # 创建生成器实例并将其移动到GPU上
    generator = Generator().to(device)
    

    另外,还需要对数据集进行一些处理。在 MNIST 数据集中,图像是单通道的,所以在生成器中将输出通道数设置为 1,同时标签的范围应该在 -1 到 1 之间。根据代码,你已经处理了图像的归一化,在数据加载处需要对标签进行处理:

    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)
    
    # 为了使生成器的输出和标签一致,这里对标签进行了处理
    label_transform = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize(mean=0.5, std=0.5)
    ])
    
    mnist_data.targets = label_transform(mnist_data.targets.unsqueeze(1)).squeeze(1)
    
    data_loader = torch.utils.data.DataLoader(mnist_data,
                                              batch_size=128,
                                              shuffle=True,
                                              drop_last=True,
                                              num_workers=6)
    

    请尝试以上修改后的代码,看是否能够解决你的问题。如果还有其他问题,请随时提问。



    【相关推荐】



    如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^
    评论
  • 太极-彼岸 2023-09-18 20:47
    关注
    获得0.45元问题酬金
    
    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__()
            self.z_dim = z_dim
            self.hidden_dim = hidden_dim
            self.fc1 = nn.Linear(z_dim, hidden_dim)
            self.fc2 = nn.Linear(hidden_dim, 7 * 7 * 256)
            self.deconv1 = nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1)
            self.deconv2 = nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1)
            self.deconv3 = nn.ConvTranspose2d(64, 1, kernel_size=4, stride=2, padding=1)  # 输出通道数应该是1,因为MNIST是单通道的
        def forward(self, z):
            x = self.fc1(z)
            x = F.leaky_relu(x, 0.2)  # 使用 torch.nn.functional 的时候需要加上前缀 F.
            x = x.view(-1, 256, 7, 7)
            x = self.deconv1(x)
            x = F.leaky_relu(x, 0.2)
            x = self.deconv2(x)
            x = F.leaky_relu(x, 0.2)
            x = self.deconv3(x)
            x = torch.tanh(x)
            return x
    # 创建生成器实例并将其移动到GPU上
    generator = Generator().to(device)
    
    
    评论
  • 玥轩_521 2023-09-18 21:05
    关注
    获得0.45元问题酬金

    援引讯飞星火:
    代码中存在一个问题,即在定义生成器和判别器的全连接层时,输入维度不正确。生成器的全连接层输入维度应为 z_dim * 256 * 7 * 7,判别器的全连接层输入维度应为 1024 * 7 * 7。请参考以下修改后的代码:

    # 定义生成器
    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, 28, 28, 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,stride 为 2,padding 为 1
            self.conv2 = nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1) # 卷积层,输入为 64 维,输出为 128 维,kernel_size 为 4,stride 为 2,padding 为 1
            self.conv3 = nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1) # 卷积层,输入为 128 维,输出为 256 维,kernel_size 为 4,stride 为 2,padding 为 1
            self.conv4 = nn.Conv2d(256, 512, kernel_size=4, stride=2, padding=1) # 卷积层,输入为 256 维,输出为 512 维,kernel_size 为 4,stride 为 2,padding 为 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
    

    其他部分代码看起来没有问题。

    评论
  • Leodong. 2023-09-18 21:19
    关注
    获得0.45元问题酬金

    该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
    代码中存在一个问题,即在定义生成器和判别器的全连接层时,输入维度不正确。生成器的最后一层全连接层的输入维度应为 7 * 7 * 256,而不是 512 * 4 * 4。同样,判别器的第一层全连接层的输入维度应为 100 * 28 * 28,而不是 512 * 4 * 4。请参考以下修改后的代码:

    # 定义生成器
    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) # 全连接层,输入为 hidden_dim 维,输出为 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, 28, 28, 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.fc1 = nn.Linear(hidden_dim, 100 * 28 * 28) # 全连接层,输入为 hidden_dim 维,输出为 100*28*28 的图像
            self.fc2 = nn.Linear(100 * 28 * 28, 1) # 只有一个输出,表示输入是否是真实的图像
        def forward(self, x):
            x = F.leaky_relu(self.fc1(x), 0.2) # 在全连接层中应用 LeakyReLU 激活函数
            x = F.leaky_relu(self.fc2(x), 0.2) # 在全连接层中应用 LeakyReLU 激活函数
            x = torch.sigmoid(x) # 将输出值映射到 [0, 1] 的范围,表示输入是否是真实图像的概率
            return x
    

    其他部分看起来没有问题。


    如果以上回答对您有所帮助,点击一下采纳该答案~谢谢

    评论
  • 数据大魔王 2023-09-19 10:38
    关注
    获得0.45元问题酬金

    1.在判别器(Discriminator)的 forward 方法中,不再建议使用 nn.functional.sigmoid 来进行 sigmoid 操作。PyTorch 1.6 版本之后,您应该使用 torch.sigmoid。因此,将这一行代码:

    x = nn.functional.sigmoid(x) # 将输出值映射到 [0, 1] 的范围,表示输入是否是真实图像的概率
    

    更改为:

    x = torch.sigmoid(x) # 将输出值映射到 [0, 1] 的范围,表示输入是否是真实图像的概率
    

    2.在生成器(Generator)的 forward 方法中,使用 F.tanh 来映射输出到 [-1, 1] 的范围是正确的,但请注意,从 PyTorch 1.6 版本开始,建议使用 torch.tanh 代替 F.tanh。因此,将这一行代码:

    x = F.tanh(self.deconv3(x)) # 将输出值映射到 [-1, 1] 的范围
    

    更改为:

    x = torch.tanh(self.deconv3(x)) # 将输出值映射到 [-1, 1] 的范围
    

    3.在训练循环中,您使用了 criterion 计算损失值。要在代码的顶部导入了损失函数 nn.BCELoss,否则会出现 NameError。

    评论
  • coder_small_bell 2023-09-19 21:39
    关注
    获得0.30元问题酬金

    传递的shape不对奥

    评论
  • yy64ll826 2023-09-20 16:51
    关注
    获得0.30元问题酬金
    评论
  • 心梓知识 2023-09-21 02:16
    关注
    获得0.45元问题酬金

    结合GPT给出回答如下请题主参考
    以下是一个使用GAN模型训练MNIST数据集的示例代码,包括全连接层和卷积层:

    import torch
    import torch.nn as nn
    import torch.optim as optim
    from torchvision import datasets, transforms
    from torch.utils.data import DataLoader
    from torch.autograd import Variable
    
    # 定义生成器
    class Generator(nn.Module):
        def __init__(self):
            super(Generator, self).__init__()
            self.fc1 = nn.Linear(100, 256)
            self.conv1 = nn.ConvTranspose2d(64, 32, 4, 2, 1)
            self.conv2 = nn.ConvTranspose2d(32, 1, 4, 2, 1)
    
        def forward(self, x):
            x = self.fc1(x)
            x = x.view(-1, 64, 2, 2)
            x = nn.functional.relu(self.conv1(x))
            x = nn.functional.sigmoid(self.conv2(x))
            return x
    
    # 定义判别器
    class Discriminator(nn.Module):
        def __init__(self):
            super(Discriminator, self).__init__()
            self.conv1 = nn.Conv2d(1, 32, 5, stride=2, padding=2)
            self.conv2 = nn.Conv2d(32, 64, 5, stride=2, padding=2)
            self.fc1 = nn.Linear(7 * 7 * 64, 1)
    
        def forward(self, x):
            x = nn.functional.relu(self.conv1(x))
            x = nn.functional.relu(self.conv2(x))
            x = x.view(-1, 7 * 7 * 64)
            x = nn.functional.sigmoid(self.fc1(x))
            return x
    
    # 定义是否使用GPU
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    
    # 加载数据集
    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=100, shuffle=True)
    
    # 实例化生成器和判别器
    generator = Generator().to(device)
    discriminator = Discriminator().to(device)
    
    # 定义损失函数和优化器
    criterion = nn.BCELoss()
    optimizer_g = optim.Adam(generator.parameters(), lr=0.0002, betas=(0.5, 0.999))
    optimizer_d = optim.Adam(discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999))
    
    # 训练模型
    for epoch in range(200):
        for i, (data, _) in enumerate(train_loader):
            # 训练判别器
            discriminator.zero_grad()
            real_data = Variable(data.to(device))
            real_label = Variable(torch.ones(data.size(0)).to(device))
            fake_label = Variable(torch.zeros(data.size(0)).to(device))
            # 真实数据的损失
            output = discriminator(real_data).view(-1)
            loss_d_real = criterion(output, real_label)
            # 生成数据的损失
            noise = Variable(torch.randn(data.size(0), 100).to(device))
            fake_data = generator(noise)
            output = discriminator(fake_data.detach()).view(-1)
            loss_d_fake = criterion(output, fake_label)
            # 计算总损失
            loss_d = loss_d_real + loss_d_fake
            loss_d.backward()
            optimizer_d.step()
    
            # 训练生成器
            generator.zero_grad()
            label = Variable(torch.ones(data.size(0)).to(device))
            output = discriminator(fake_data).view(-1)
            loss_g = criterion(output, label)
            loss_g.backward()
            optimizer_g.step()
    
            # 打印损失
            if i % 100 == 0:
                print('Epoch [%d/%d], Step[%d/%d], Loss_D: %.4f, Loss_G: %.4f'
                      % (epoch, 200, i, len(train_dataset) // 100, loss_d.item(), loss_g.item()))
    
    # 保存模型
    torch.save(generator.state_dict(), './generator.pth')
    

    这个代码中,生成器采用了全连接层和卷积层的结合,判别器采用了卷积层。在训练过程中,先训练判别器,再训练生成器。打印出损失,以便检查模型的训练状态。最后,保存生成器的模型参数。你可以根据你的需要修改代码以满足你的任务需求。

    评论
  • bug菌¹ Java领域优质创作者 2023-09-24 21:22
    关注
    获得0.75元问题酬金

    该回答引用ChatGPT,希望对题主有所帮助,如有帮助,还望采纳。


    在生成器的 forward() 函数中,应该使用 F.leaky_relu() 函数代替 nn.functional.leaky_relu() 函数进行 LeakyReLU 激活操作。修改后的代码如下:

    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 = F.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 = torch.tanh(self.deconv3(x)) # 将输出值映射到 [-1, 1] 的范围
            return x.view(-1, 1, 28, 28) # 将输出展平成图片张量形式
    

    除此之外,代码没有其他问题。但需要注意的是,本代码在运行时可能会出现一些警告或错误提示,如使用 sigmoid() 函数时的警告。这些问题可以通过查看 PyTorch 文档或相关论文进行解决。同时,建议在训练时使用 GPU,以加速训练过程。

    评论
  • 代码调试大神 2023-09-25 14:57
    关注
    获得0.15元问题酬金

    在训练GAN模型时,生成器和判别器的损失函数通常不同。在您的代码中,您没有定义生成器和判别器的损失函数。您可以使用二进制交叉熵损失函数(torch.nn.BCELoss)来计算生成器和判别器的损失

    评论
  • Minuw 2023-09-25 17:37
    关注
    获得0.45元问题酬金

    参考gpt

    1. 缺少导入语句:在代码的开头,您导入了torch和transforms模块,但没有导入nn和F模块。请添加以下导入语句:
    import torch.nn as nn
    import torch.nn.functional as F
    
    1. 生成器的最后一层激活函数问题:在生成器的forward方法中,您使用了tanh作为最后一层的激活函数。然而,tanh的输出范围是[-1, 1],而MNIST图像的像素值范围是[0, 1]。因此,您可以将最后一层的激活函数改为sigmoid,将输出范围映射到[0, 1]。修改代码如下:
    x = torch.sigmoid(self.deconv3(x))
    
    1. 生成器的输出形状问题:在生成器的forward方法中,最后一行的返回语句将输出展平为形状为(-1, 1, 28, 28)的张量。然而,MNIST图像的通道数为1,而不是3。因此,您可以将返回语句修改为以下形式:
    return x.view(-1, 1, 28, 28)
    
    评论
  • GIS工具开发 2023-09-25 19:40
    关注
    获得0.45元问题酬金

    传递的值不对呀

    评论
  • 会跑的小鹿 2023-09-25 21:24
    关注
    获得0.15元问题酬金

    BCELoss函数计算损失值出现问题

    评论
  • 全栈项目讲解 2023-09-25 22:06
    关注
    获得0.45元问题酬金

    生成器和判别器的全连接层时参数有误,主要是输入维度不正确可以仔细看看

    评论

报告相同问题?

问题事件

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

悬赏问题

  • ¥60 关于海信电视聚好看安装应用的问题
  • ¥15 vue引入sdk后的回调问题
  • ¥15 求一个智能家居控制的代码
  • ¥15 ad软件 pcb布线pcb规则约束编辑器where the object matpcb布线pcb规则约束编辑器where the object matchs怎么没有+15v只有no net
  • ¥15 虚拟机vmnet8 nat模式可以ping通主机,主机也能ping通虚拟机,但是vmnet8一直未识别怎么解决,其次诊断结果就是默认网关不可用
  • ¥20 求各位能用我能理解的话回答超级简单的一些问题
  • ¥15 yolov5双目识别输出坐标代码报错
  • ¥15 这个代码有什么语法错误
  • ¥15 给予STM32按键中断与串口通信
  • ¥15 使用QT实现can通信