1.GAN主要又生成器和鉴别器组成。
2.其流程主要有以下:
初始化生成器和鉴别器
重复:
固定生成器,升级鉴别器
固定鉴别器,升级生成器
链接:https://pan.baidu.com/s/1ZbANCQ58p42lzmcpc2r2-A?pwd=ttmf
提取码:ttmf
此处我们也来实现一个经典的二次元头像生成器,上面是数据集。
我们使用深度卷积神经网络来作为鉴别器,使用反卷积神经网络作为生成器,DCGAN。
补充一下:
-
迭代次数(Iteration):迭代次数指的是模型在训练过程中参数更新的次数。在每次迭代中,模型会通过反向传播算法计算梯度并更新参数,这样模型就逐渐优化和学习。一次迭代通常是指模型使用一个 mini-batch(小批量)数据进行前向传播、计算损失、反向传播和参数更新的过程。
-
Epoch:Epoch 是指整个数据集通过神经网络的前向传播和反向传播的总次数。当我们将整个数据集通过模型训练一轮(将数据集中的每个样本都经过一次前向传播和反向传播)时,就称为完成了一个 epoch。在实际训练中,一个 epoch 包含多个迭代过程。
举个例子,假设数据集有 1000 个样本,如果我们将 mini-batch 大小设置为 100,那么在完成一个 epoch 时,模型会执行 10 次迭代(1000个样本 / 100个样本 = 10 次迭代)。
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
from torchvision import datasets,transforms,models
import matplotlib.pyplot as plt
import os
# 图片预处理与图像加载
data_transform = transforms.Compose([
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
trainset = datasets.ImageFolder('faces', data_transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=5, shuffle=True, num_workers=0)
def imshow(inputs, picname):
plt.ion()
inputs = inputs / 2 + 0.5
inputs = inputs.numpy().transpose((1, 2, 0))
plt.imshow(inputs)
plt.pause(0.01)
plt.savefig(picname + ".jpg")
plt.close()
# 从名为trainloader的数据加载器中获取下一个批次的数据,并将其中的第一个元素赋值给变量inputs。
# 通常这种代码用在深度学习的场景中,用于迭代数据加载器以获取训练数据的批次。
inputs,_ = next(iter(trainloader))
imshow(torchvision.utils.make_grid(inputs), "RealDataSample")
# 定义一个鉴别器
class D(nn.Module):
def __init__(self,nc,ndf):
super(D, self).__init__()
# nc代表输入图片的通道数(例如,RGB图像的通道数为3)。
# ndf代表模型中特征的数量,在这里用作卷积层中的特征维度倍增系数。
# 例如,在第一层卷积之后,特征图的通道数为ndf,第二层卷积后的特征图通道数为ndf*2,依此类推
self.layer1 = nn.Sequential(nn.Conv2d(nc, ndf, kernel_size=4, stride=2, padding=1),
nn.BatchNorm2d(ndf), nn.LeakyReLU(0.2, inplace=True))
self.layer2 = nn.Sequential(nn.Conv2d(ndf, ndf * 2, kernel_size=4, stride=2, padding=1),
nn.BatchNorm2d(ndf*2), nn.LeakyReLU(0.2, inplace=True))
self.layer3 = nn.Sequential(nn.Conv2d(ndf * 2, ndf * 4, kernel_size=4, stride=2, padding=1),
nn.BatchNorm2d(ndf * 4), nn.LeakyReLU(0.2, inplace=True))
self.layer4 = nn.Sequential(nn.Conv2d(ndf * 4, ndf * 8, kernel_size=4, stride=2, padding=1),
nn.BatchNorm2d(ndf * 8), nn.LeakyReLU(0.2, inplace=True))
self.fc = nn.Sequential(nn.Linear(256*6*6, 1), nn.Sigmoid())
def forward(self,x):
out = self.layer1(x)
out = self.layer2(out)
out = self.layer3(out)
out = self.layer4(out)
out = out.view(-1, 256*6*6)
out = self.fc(out)
return out
class G(nn.Module):
def __init__(self, nc, ngf, nz, feature_size):
super(G, self).__init__()
self.prj = nn.Linear(feature_size, nz*6*6)
self.layer1 = nn.Sequential(nn.ConvTranspose2d(nz, ngf * 4, kernel_size=4, stride=2, padding=1),
nn.BatchNorm2d(ngf*4), nn.ReLU())
self.layer2 = nn.Sequential(nn.ConvTranspose2d(ngf * 4, ngf * 2, kernel_size=4, stride=2, padding=1),
nn.BatchNorm2d(ngf * 2), nn.ReLU())
self.layer3 = nn.Sequential(nn.ConvTranspose2d(ngf * 2, ngf, kernel_size=4, stride=2, padding=1),
nn.BatchNorm2d(ngf), nn.ReLU())
self.layer4 = nn.Sequential(nn.ConvTranspose2d(ngf, nc, kernel_size=4, stride=2, padding=1),
nn.Tanh())
def forward(self,x):
out = self.prj(x)
out = out.view(-1, 1024, 6, 6)
out = self.layer1(out)
out = self.layer2(out)
out = self.layer3(out)
out = self.layer4(out)
return out
# d = D(3, 32):创建了一个判别器对象d,将输入图像的通道数设为3(通常表示RGB图像),
# ndf参数设为32,用于定义模型中特征的数量。
# 这意味着判别器的第一层卷积输出的特征图通道数为32,之后逐层增加。
# g = G(3, 128, 1024, 100):创建了一个生成器对象g,将输入图像的通道数设为3(通常表示RGB图像),
# ngf参数设为128作为模型中特征的数量,nz设为1024表示噪声向量的维度,
# feature_size设为100表示生成器前向传播时的特征参数大小。
d = D(3, 32)
g = G(3, 128, 1024, 100)
criterion = nn.BCELoss()
d_optimizer = torch.optim.Adam(d.parameters(), lr=3e-4)
g_optimizer = torch.optim.Adam(g.parameters(), lr=3e-4)
def train(d, g, criterion, d_optimizer, g_optimizer,epochs=1, show_every=1000, print_every=10):
iter_count = 0
for epoch in range(epochs):
for inputs,_ in trainloader:
# 训练判别器(D):
# 计算真实图像通过判别器后的输出。将真实标签设为1,计算判别器对真实图像的损失d_loss_real。
# 计算生成图像通过判别器后的输出。将生成标签设为0,计算判别器对生成图像的损失d_loss_fake。
# 将两者的损失相加得到总的判别器损失d_loss。
# 对判别器的参数进行梯度清零、反向传播、更新参数过程。
# 训练生成器(G):
# 重新生成一组噪声数据fake_inputs。
# 将生成的假图像通过判别器,得到输出。
# 将生成标签设为1,计算生成器的损失g_loss。
# 对生成器的参数进行梯度清零、反向传播、更新参数过程
real_inputs = inputs
# 重新生成噪声数据 fake_inputs
fake_inputs = g(torch.randn(5,100))
real_labels = torch.ones(real_inputs.size(0), 1)
fake_labels = torch.zeros(5, 1)
# 将 real_inputs 输入到判别器 d 中,得到判别器对真实数据的输出 real_outputs。
real_outputs = d(real_inputs)
d_loss_real = criterion(real_outputs, real_labels)
real_scores = real_outputs
fake_outputs = d(fake_inputs)
d_loss_fake = criterion(fake_outputs, fake_labels)
fake_score = fake_outputs
d_loss = d_loss_real + d_loss_fake
d_optimizer.zero_grad()
d_loss.backward()
d_optimizer.step()
fake_inputs = g(torch.randn(5, 100))
outputs = d(fake_inputs)
real_labels = torch.ones(outputs.size(0), 1)
g_loss = criterion(outputs, real_labels)
g_optimizer.zero_grad()
g_loss.backward()
g_optimizer.step()
if iter_count % show_every == 0:
print('Epoch: {},Iter: {},D: {:.4}, G: {:.4}'.format(
epoch, iter_count, d_loss.item(), g_loss.item()))
picname = "Epoch_" + str(epoch) + "Iter_" + str(iter_count)
imshow(torchvision.utils.make_grid(fake_inputs.data),picname)
if iter_count % print_every == 0:
print('Epoch: {},Iter: {},D: {:.4}, G: {:.4}'.format(
epoch, iter_count, d_loss.item(), g_loss.item()))
iter_count += 1
print("Finished")
train(d, g, criterion, d_optimizer, g_optimizer, epochs=300)