DCGAN(Deep Convolutional Generative Adversarial Networks)是一种生成对抗网络,用于生成逼真的图像。它结合了卷积神经网络和生成对抗网络的思想。
代码如下:
需要导入的相关库:
import os
import random
import numpy as np
import torch
import torch.nn as nn
import torchvision.datasets as dset
import torchvision.transforms as transforms
from torchvision.utils import save_image
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import torchvision.utils as vutils
创建文件夹用于保存图片,设置随机数。
os.makedirs("./images/", exist_ok=True)
manualSeed = 111
random.seed = manualSeed
torch.manual_seed(manualSeed)
图片的地址和网络的相关超参数:
dataroot = 'E:/神经网络学习/DCGAN/cartoon_face'
batch_size = 128
image_size = 64
nz = 100
ngf = 64
ndf = 64
lr = 0.0002
betal = 0.5
num_epochs = 100
将图片转成tensor格式,并且使用显卡来进行训练网络。这里还展示了图片内容:
dataset = dset.ImageFolder(root=dataroot,
transform=transforms.Compose([
transforms.Resize(image_size),
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5),
(0.5, 0.5, 0.5))
]))
dataloader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=True
)
device = torch.device('cuda:0' if (torch.cuda.is_available()) else 'cpu')
print('使用的设备是', device)
real_batch = next(iter(dataloader))
plt.figure(figsize=(8, 8))
plt.axis('off')
plt.title('Training image')
plt.imshow(np.transpose(vutils.make_grid(real_batch[0].to(device)[:24],
padding=2,
normalize=True).cpu(), (1, 2, 0)))
plt.show()
接下的代码主要是用于初始化神经网络权重的函数:
def weight_init(m):
classname = m.__class__.__name__
if classname.find('Conv') != -1:
nn.init.normal_(m.weight.data, 0.0, 0.02)
elif classname.find('BatchNorm') != -1:
nn.init.normal_(m.weight.data, 1.0, 0.02)
nn.init.constant_(m.bias.data, 0)
接下来的代码是生成器的代码,这里使用的是反卷积来生成图片的。注意里面的尺寸大小,计算方式如下的公式,这里输入的噪声的尺寸为1×1,经过网络后最终得到的图片尺寸为64×64。
class Generate(nn.Module):
def __init__(self):
super(Generate, self).__init__()
self.main = nn.Sequential(
nn.ConvTranspose2d(nz, ngf * 8, 4, 1, 0, bias=False),
nn.BatchNorm2d(ngf * 8),
nn.ReLU(True),
nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
nn.BatchNorm2d(ngf*4),
nn.ReLU(True),
nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1, bias=False),
nn.BatchNorm2d(ngf * 2),
nn.ReLU(True),
nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1, bias=False),
nn.BatchNorm2d(ngf),
nn.ReLU(True),
nn.ConvTranspose2d(ngf, 3, 4, 2, 1, bias=False),
nn.Tanh()
)
def forward(self, input):
return self.main(input)
net_G = Generate().to(device)
net_G.apply(weight_init)
print(net_G)
接下来就是判别器的代码,判别器的代码比较简单,类似于普通卷积神经网络在做分类任务,只不过这里就是一个简单的二分类任务。
class Discriminator(nn.Module):
def __init__(self):
super(Discriminator, self).__init__()
self.main = nn.Sequential(
nn.Conv2d(3, ndf, 4, 2, 1, bias=False),
nn.LeakyReLU(0.2, True),
nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
nn.BatchNorm2d(ndf * 2),
nn.LeakyReLU(0.2, True),
nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
nn.BatchNorm2d(ndf * 4),
nn.LeakyReLU(0.2, True),
nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),
nn.BatchNorm2d(ndf * 8),
nn.LeakyReLU(0.2, True),
nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
nn.Sigmoid()
)
def forward(self, input):
return self.main(input)
net_D = Discriminator().to(device)
net_D.apply(weight_init)
print(net_D)
接下来就是设置了GAN训练所需的损失函数、固定的噪声输入、真实与生成样本的标签,以及用于优化判别器和生成器的Adam优化器。这些步骤是GAN训练中常见的初始化和设置步骤,用于确保模型在训练过程中能够正确地更新参数和计算损失。
criterion = nn.BCELoss().to(device)
fix_noise = torch.randn(64, nz, 1, 1, device=device)
real_label = 1
fake_label = 0
optimizerD = torch.optim.Adam(net_D.parameters(), lr=lr, betas=(betal, 0.999))
optimizerG = torch.optim.Adam(net_G.parameters(), lr=lr, betas=(betal, 0.999))
下面这段代码就是训练了:
for epoch in range(num_epochs):
for i, data in enumerate(dataloader, 0):
net_D.zero_grad()
real_cpu = data[0].to(device)
b_size = real_cpu.size(0)
label = torch.full((b_size,), real_label, dtype=torch.float, device=device)
output = net_D(real_cpu).view(-1)
errD_real = criterion(output, label)
errD_real.backward()
D_x = output.mean().item()
optimizerD.step()
noise = torch.randn(b_size, nz, 1, 1, device=device)
fake = net_G(noise)
label.fill_(fake_label)
output = net_D(fake.detach()).view(-1)
errD_fake = criterion(output, label)
errD_fake.backward()
D_G_z1 = output.mean().item()
errD = errD_fake + errD_real
optimizerD.step()
net_G.zero_grad()
label.fill_(real_label)
output = net_D(fake).view(-1)
errG = criterion(output, label)
errG.backward()
D_G_z2 = output.mean().item()
optimizerG.step()
if i % 400 == 0:
print('[%d/%d][%d/%d]\tLoss_D: %.4f\tLoss_G: %.4f\tD(x): %.4f\tD(G(z)): %.4f / %.4f'
% (epoch, num_epochs, i, len(dataloader),
errD.item(), errG.item(), D_x, D_G_z1, D_G_z2))
G_loss.append(errG.item())
D_loss.append(errD.item())
if (iters % 500 == 0) or ((epoch == num_epochs - 1) and (i == len(dataloader) - 1)):
with torch.no_grad():
fake = net_G(fix_noise).detach().cpu()
save_image(fake, './images/%d.png' % iters)
iters += 1
这里列举训练结果:
这里这要问题是生成器的功能还不够强大,以至于生成的图片不能满足要求,接下来就需要对生成器网络进行改进。