最近在学习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()
除此外,代码还有无其他问题