实验要求与基本流程
实验要求
- 结合理论课内容,深入理解GAN(Generative Adversarial Networks,生成对抗网络)的原理与训练过程.了解GAN网络结构的演变过程与几个基本的GAN的原理(如DCGAN,wGAN等.)
- 阅读实验指导书的实验内容,按照提示运行以及补充实验代码,或者简要回答问题.提交作业时,保留实验结果.
实验流程
- GAN的网络结构与训练
- DCGAN
- LSGAN
- WGAN
- WGAN-GP
GAN(Generative Adversarial Networks)
让我们先来看一个只是用线性层的生成对抗网络(GAN),来简单了解一下GAN的基本网络结构与训练过程.
这个GAN网络结构分为两部分,生成器网络Generator和判别器网络Discriminator.
- 生成器Generator将随机生成的噪声z通过多个线性层生成图片,注意生成器的最后一层是Tanh,所以我们生成的图片的取值范围为[-1,1],同理,我们会将真实图片归一化(normalize)到[-1,1].
- 而判别器Discriminator是一个二分类器,通过多个线性层得到一个概率值来判别图片是"真实"或者是"生成"的,所以在Discriminator的最后是一个sigmoid,来得到图片是"真实"的概率.
在所有的网络结构中我们都使用了LeakyReLU作为激活函数,除了G与D的最后一层,同时,我们在层与层之间我们还加入了BatchNormalization.
import torch
import numpy as np
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
from utils import show
%matplotlib inline
class Generator(nn.Module):
def __init__(self, image_size=32, latent_dim=100, output_channel=1):
"""
image_size: image with and height
latent dim: the dimension of random noise z
output_channel: the channel of generated image, for example, 1 for gray image, 3 for RGB image
"""
super(Generator, self).__init__()
self.latent_dim = latent_dim
self.output_channel = output_channel
self.image_size = image_size
# Linear layer: latent_dim -> 128 -> 256 -> 512 -> 1024 -> output_channel * image_size * image_size -> Tanh
self.model = nn.Sequential(
nn.Linear(latent_dim, 128),
nn.BatchNorm1d(128),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(128, 256),
nn.BatchNorm1d(256),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(256, 512),
nn.BatchNorm1d(512),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(512, 1024),
nn.BatchNorm1d(1024),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(1024, output_channel * image_size * image_size),
nn.Tanh()
)
def forward(self, z):
img = self.model(z)
img = img.view(img.size(0), self.output_channel, self.image_size, self.image_size)
return img
class Discriminator(nn.Module):
def __init__(self, image_size=32, input_channel=1):
"""
image_size: image with and height
input_channel: the channel of input image, for example, 1 for gray image, 3 for RGB image
"""
super(Discriminator, self).__init__()
self.image_size = image_size
self.input_channel = input_channel
# Linear layer: input_channel * image_size * image_size -> 1024 -> 512 -> 256 -> 1 -> Sigmoid
self.model = nn.Sequential(
nn.Linear(input_channel * image_size * image_size, 1024),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(1024, 512),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(512, 256),
nn.LeakyReLU(0.2, inplace=True),
nn.Linear(256, 1),
nn.Sigmoid(),
)
def forward(self, img):
img_flat = img.view(img.size(0), -1)
out = self.model(img_flat)
return out
数据集
在训练我们的GAN网络之前, 先介绍一下本次实验可训练GAN的数据集,我们提供了两个数据集来供大家进行尝试数据集.
- MNIST手写体3类数据集,这里为了加快我们的训练速度,我们提供了一个简化版本的只包含数字0,2的2类MNIST数据集,每类各1000张.图片为28*28的单通道灰度图(我们将其resize到32*32),对于GAN而言,我们不需要测试集.我们本次实验主要使用该数据集作为主要的训练数据集.
- 室内家具数据集.为了加快我们的训练速度,我们将其做了删减处理,仅包含chair等一个类,共500张.图片为32*32的3通道彩色图片.
下面是两个加载数据集的函数.注意我们将所有图片normalize到了[-1,1]之间.
def load_mnist_data():
"""
load mnist(0,1,2) dataset
"""
transform = torchvision.transforms.Compose([
# transform to 1-channel gray image since we reading image in RGB mode
transforms.Grayscale(1),
# resize image from 28 * 28 to 32 * 32
transforms.Resize(32),
transforms.ToTensor(),
# normalize with mean=0.5 std=0.5
transforms.Normalize(mean=(0.5, ),
std=(0.5, ))
])
train_dataset = torchvision.datasets.ImageFolder(root='./data/mnist', transform=transform)
return train_dataset
def load_furniture_data():
"""
load furniture dataset
"""
transform = torchvision.transforms.Compose([
transforms.ToTensor(),
# normalize with mean=0.5 std=0.5
transforms.Normalize(mean=(0.5, 0.5, 0.5),
std=(0.5, 0.5, 0.5))
])
train_dataset = torchvision.datasets.ImageFolder(root='./data/household_furniture', transform=transform)
return train_dataset
(无需阅读理解)运行下面2个cell的代码来查看两个数据集中的20张随机真实图片.
def denorm(x):
# denormalize
out = (x + 1) / 2
return out.clamp(0, 1)
from utils import show
"""
you can pass code in this cell
"""
# show mnist real data
train_dataset = load_mnist_data()
trainloader = torch.utils.data.DataLoader(train_dataset, batch_size=20, shuffle=True)
show(torchvision.utils.make_grid(denorm(next(iter(trainloader))[0]), nrow=5))
# show furniture real data
train_dataset = load_furniture_data()
trainloader = torch.utils.data.DataLoader(train_dataset, batch_size=20, shuffle=True)
show(torchvision.utils.make_grid(denorm(next(iter(trainloader))[0]), nrow=5))
下面代码实现GAN在一个epoch内的训练过程.
大体而言,GAN的训练过程分为两步,首先将随机噪声z喂给G,生成图片,然后将真实图片和G生成的图片喂给D,然后使用对应的loss函数反向传播优化D.然后再次使用G生成图片,并喂给D,并使用对应的loss函数反向传播优化G.
下面的图片是普通的GAN在G和D上的优化目标:
值得注意的是,上述图片描述的是G和D的优化目标,而在具体实现过程中,我们实现loss函数来达到优化目标.对于上图中D与G的优化目标我们可以使用Binary Cross Entroy损失函数来实现:
, 分别是模型的预测值与图片的真实标签(1为真,0为假).因此,对于D,最大化其优化目标可以通过最小化一个BCEloss来实现,其真实图片的标签设置为1,而生成图片的标签设置为0.我们可以看到这样的损失函数相当于对D的优化目标加上负号.
而对于G,也通过最小化一个BCEloss来实现,即将生成图片的标签设置为1即可,我们可以看到这样的损失函数与其优化目标是一致的.
def train(trainloader, G, D, G_optimizer, D_optimizer, loss_func, device, z_dim):
"""
train a GAN with model G and D in one epoch
Args:
trainloader: data loader to train
G: model Generator
D: model Discriminator
G_optimizer: optimizer of G(etc. Adam, SGD)
D_optimizer: optimizer of D(etc. Adam, SGD)
loss_func: loss function to train G and D. For example, Binary Cross Entropy(BCE) loss function
device: cpu or cuda device
z_dim: the dimension of random noise z
"""
# set train mode
D.train()
G.train()
D_total_loss = 0
G_total_loss = 0
for i, (x, _) in enumerate(trainloader):
# real label and fake label
y_real = torch.ones(x.size(0), 1).to(device)
y_fake = torch.zeros(x.size(0), 1).to(device)
x = x.to(device)
z = torch.rand(x.size(0), z_dim).to(device)
# update D network
# D optimizer zero grads
D_optimizer.zero_grad()
# D real loss from real images
d_real = D(x)
d_real_loss = loss_func(d_real, y_real)
# D fake loss from fake images generated by G
g_z = G(z)
d_fake = D(g_z)
d_fake_loss = loss_func(d_fake, y_fake)
# D backward and step
d_loss = d_real_loss + d_fake_loss
d_loss.backward()
D_optimizer.step()
# update G network
# G optimizer zero grads
G_optimizer.zero_grad()
# G loss
g_z = G(z)
d_fake = D(g_z)
g_loss = loss_func(d_fake, y_real)
# G backward and step
g_loss.backward()
G_optimizer.step()
D_total_loss += d_loss.item()
G_total_loss += g_loss.item()
return D_total_loss / len(trainloader), G_total_loss / len(trainloader)
当模型训练后,我们需要查看此时G生成的图片效果,下面的visualize_results代码便实现了这块内容.注意,我们生成的图片都在[-1,1],因此,我们需要将图片反向归一化(denorm)到[0,1].
def visualize_results(G, device, z_dim, result_size=20):
G.eval()
z = torch.rand(result_size, z_dim).to(device)
g_z = G(z)
show(torchvision.utils.make_grid(denorm(g_z.detach().cpu()), nrow=5))
万事具备,接下来让我们来尝试这训练一个基本的GAN网络吧.这里实现run_gan函数来调用train以及visualize_results来训练我们的GAN.
def run_gan(trainloader, G, D, G_optimizer, D_optimizer, loss_func, n_epochs, device, latent_dim):
d_loss_hist = []
g_loss_hist = []
for epoch in range(n_epochs):
d_loss, g_loss = train(trainloader, G, D, G_optimizer, D_optimizer, loss_func, device,
z_dim=latent_dim)
print('Epoch {}: Train D loss: {:.4f}, G loss: {:.4f}'.format(epoch, d_loss, g_loss))
d_loss_hist.append(d_loss)
g_loss_hist.append(g_loss)
if epoch == 0 or (epoch + 1) % 10 == 0:
visualize_results(G, device, latent_dim)
return d_loss_hist, g_loss_hist
设置好超参数就可以开始训练!让我们尝试用它来训练2类的mnist数据集
# hyper params
# z dim
latent_dim = 100
# image size and channel
image_size=32
image_channel=1
# Adam lr and betas
learning_rate = 0.0002
betas = (0.5, 0.999)
# epochs and batch size
n_epochs = 100
batch_size = 32
# device : cpu or cuda:0/1/2/3
device = torch.device('cuda:0')
# mnist dataset and dataloader
train_dataset = load_mnist_data()
trainloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
# use BCELoss as loss function
bceloss = nn.BCELoss().to(device)
# G and D model
G = Generator(image_size=image_size, latent_dim=latent_dim, output_channel=image_channel).to(device)
D = Discriminator(image_size=image_size, input_channel=image_channel).to(device)
# G and D optimizer, use Adam or SGD
G_optimizer = optim.Adam(G.parameters(), lr=learning_rate, betas=betas)
D_optimizer = optim.Adam(D.parameters(), lr=learning_rate, betas=betas)
d_loss_hist, g_loss_hist = run_gan(trainloader, G, D, G_optimizer, D_optimizer, bceloss,
n_epochs, device, latent_dim)
Epoch 0: Train D loss: 1.1649, G loss: 0.7650
Epoch 1: Train D loss: 1.2279, G loss: 0.9637
Epoch 2: Train D loss: 1.2282, G loss: 1.0666
Epoch 3: Train D loss: 1.1667, G loss: 1.1114
Epoch 4: Train D loss: 1.1309, G loss: 1.1353
Epoch 5: Train D loss: 1.0876, G loss: 1.1348
Epoch 6: Train D loss: 1.0184, G loss: 1.2990
Epoch 7: Train D loss: 1.1157, G loss: 1.2255
Epoch 8: Train D loss: 1.0693, G loss: 1.2365
Epoch 9: Train D loss: 1.0913, G loss: 1.2913
Epoch 10: Train D loss: 1.0821, G loss: 1.3000
Epoch 11: Train D loss: 1.0513, G loss: 1.3288
Epoch 12: Train D loss: 1.0736, G loss: 1.3025
Epoch 13: Train D loss: 1.0847, G loss: 1.3232
Epoch 14: Train D loss: 1.0719, G loss: 1.2890
Epoch 15: Train D loss: 1.0308, G loss: 1.3940
Epoch 16: Train D loss: 1.0674, G loss: 1.3403
Epoch 17: Train D loss: 1.0661, G loss: 1.3169
Epoch 18: Train D loss: 1.0768, G loss: 1.3372
Epoch 19: Train D loss: 1.0884, G loss: 1.2901
Epoch 20: Train D loss: 1.0906, G loss: 1.3051
Epoch 21: Train D loss: 1.0893, G loss: 1.2822
Epoch 22: Train D loss: 1.0954, G loss: 1.2928
Epoch 23: Train D loss: 1.1046, G loss: 1.2994
Epoch 24: Train D loss: 1.1148, G loss: 1.2459
Epoch 25: Train D loss: 1.1094, G loss: 1.2694
Epoch 26: Train D loss: 1.0933, G loss: 1.3336
Epoch 27: Train D loss: 1.0758, G loss: 1.3245
Epoch 28: Train D loss: 1.0982, G loss: 1.3037
Epoch 29: Train D loss: 1.0962, G loss: 1.3157
Epoch 30: Train D loss: 1.0964, G loss: 1.3104
Epoch 31: Train D loss: 1.0724, G loss: 1.3115
Epoch 32: Train D loss: 1.0865, G loss: 1.3063
Epoch 33: Train D loss: 1.1004, G loss: 1.2856
Epoch 34: Train D loss: 1.1080, G loss: 1.2800
Epoch 35: Train D loss: 1.1101, G loss: 1.2834
Epoch 36: Train D loss: 1.1025, G loss: 1.2795
Epoch 37: Train D loss: 1.1234, G loss: 1.2600
Epoch 38: Train D loss: 1.1017, G loss: 1.2708
Epoch 39: Train D loss: 1.1237, G loss: 1.2449
Epoch 40: Train D loss: 1.1230, G loss: 1.2525
Epoch 41: Train D loss: 1.1228, G loss: 1.2605
Epoch 42: Train D loss: 1.1238, G loss: 1.2594
Epoch 43: Train D loss: 1.1149, G loss: 1.2411
Epoch 44: Train D loss: 1.1135, G loss: 1.2392
Epoch 45: Train D loss: 1.1308, G loss: 1.2189
Epoch 46: Train D loss: 1.1072, G loss: 1.2685
Epoch 47: Train D loss: 1.1002, G loss: 1.3011
Epoch 48: Train D loss: 1.1174, G loss: 1.2395
Epoch 49: Train D loss: 1.1197, G loss: 1.2757
Epoch 50: Train D loss: 1.1245, G loss: 1.2193
Epoch 51: Train D loss: 1.1292, G loss: 1.2130
Epoch 52: Train D loss: 1.1253, G loss: 1.2375
Epoch 53: Train D loss: 1.1124, G loss: 1.2234
Epoch 54: Train D loss: 1.1205, G loss: 1.2609
Epoch 55: Train D loss: 1.1471, G loss: 1.2197
Epoch 56: Train D loss: 1.1124, G loss: 1.2615
Epoch 57: Train D loss: 1.1222, G loss: 1.2320
Epoch 58: Train D loss: 1.1095, G loss: 1.2440
Epoch 59: Train D loss: 1.1336, G loss: 1.2440
Epoch 60: Train D loss: 1.1181, G loss: 1.2432
Epoch 61: Train D loss: 1.1277, G loss: 1.2391
Epoch 62: Train D loss: 1.1294, G loss: 1.2403
Epoch 63: Train D loss: 1.1377, G loss: 1.2410
Epoch 64: Train D loss: 1.1265, G loss: 1.2175
Epoch 65: Train D loss: 1.1265, G loss: 1.2886
Epoch 66: Train D loss: 1.1158, G loss: 1.2575
Epoch 67: Train D loss: 1.1066, G loss: 1.2554
Epoch 68: Train D loss: 1.1065, G loss: 1.2688
Epoch 69: Train D loss: 1.1181, G loss: 1.2756
Epoch 70: Train D loss: 1.1167, G loss: 1.2600
Epoch 71: Train D loss: 1.1186, G loss: 1.2660
Epoch 72: Train D loss: 1.1022, G loss: 1.2948
Epoch 73: Train D loss: 1.1089, G loss: 1.2779
Epoch 74: Train D loss: 1.1019, G loss: 1.3040
Epoch 75: Train D loss: 1.1211, G loss: 1.2732
Epoch 76: Train D loss: 1.0942, G loss: 1.3277
Epoch 77: Train D loss: 1.1080, G loss: 1.2794
Epoch 78: Train D loss: 1.0737, G loss: 1.3311
Epoch 79: Train D loss: 1.0908, G loss: 1.3429
Epoch 80: Train D loss: 1.0965, G loss: 1.3002
Epoch 81: Train D loss: 1.0829, G loss: 1.3260
Epoch 82: Train D loss: 1.0804, G loss: 1.3612
Epoch 83: Train D loss: 1.0843, G loss: 1.3444
Epoch 84: Train D loss: 1.0655, G loss: 1.3481
Epoch 85: Train D loss: 1.0808, G loss: 1.3640
Epoch 86: Train D loss: 1.0882, G loss: 1.3536
Epoch 87: Train D loss: 1.0728, G loss: 1.3587
Epoch 88: Train D loss: 1.0187, G loss: 1.4288
Epoch 89: Train D loss: 1.0442, G loss: 1.3970
Epoch 90: Train D loss: 1.0577, G loss: 1.3969
Epoch 91: Train D loss: 1.0337, G loss: 1.4507
Epoch 92: Train D loss: 1.0654, G loss: 1.4042
Epoch 93: Train D loss: 1.0480, G loss: 1.4118
Epoch 94: Train D loss: 1.0387, G loss: 1.3993
Epoch 95: Train D loss: 1.0224, G loss: 1.4461
Epoch 96: Train D loss: 1.0234, G loss: 1.4688
Epoch 97: Train D loss: 1.0574, G loss: 1.4508
Epoch 98: Train D loss: 1.0303, G loss: 1.4741
Epoch 99: Train D loss: 1.0033, G loss: 1.4639
训练完后,让我们来看一下G生成的图片效果,可以看到即使是一个简单的GAN在这种简单的数据集上的生成效果还是不错的,虽然仍然存在不少瑕疵,比如说我们可以看到生成的图片上的数字有很多奇怪的雪花等等.
让我们看一下G和D的loss变化曲线(运行下方语句.)
from utils import loss_plot
loss_plot(d_loss_hist, g_loss_hist)
作业:
观察G与D的loss曲线,与之前的训练的CNN的loss曲线相比,有什么不同?试简要回答你觉得可能产生这样的不同的原因.
答:
Generally speaking, in the training process, the loss curve tends to decline and eventually converges. However, in the GAN model, when D_loss
goes down, G_loss
goes up, and vice versa. This is because, in GAN, the generator and discriminator are against each other, the generator hopes that the generated image can cheat the recognizer, and the recognizer hopes that it can find the disguise of the generator, so the performance performance of the two is often opposite.
DCGAN
在DCGAN(Deep Convolution GAN)中,最大的改变是使用了CNN代替全连接层.在生成器G中,使用stride为2的转置卷积来生成图片同时扩大图片尺寸,而在判别器D中,使用stride为2的卷积来将图片进行卷积并下采样.除此之外,DCGAN加入了在层与层之间BatchNormalization(虽然我们在普通的GAN中就已经添加),在G中使用ReLU作为激活函数,而在D中使用LeakyReLU作为激活函数.
from utils import initialize_weights
class DCGenerator(nn.Module):
def __init__(self, image_size=32, latent_dim=64, output_channel=1):
super(DCGenerator, self).__init__()
self.image_size = image_size
self.latent_dim = latent_dim
self.output_channel = output_channel
self.init_size = image_size // 8
# fc: Linear -> BN -> ReLU
self.fc = nn.Sequential(
nn.Linear(latent_dim, 512 * self.init_size ** 2),
nn.BatchNorm1d(512 * self.init_size ** 2),
nn.ReLU(inplace=True)
)
# deconv: ConvTranspose2d(4, 2, 1) -> BN -> ReLU ->
# ConvTranspose2d(4, 2, 1) -> BN -> ReLU ->
# ConvTranspose2d(4, 2, 1) -> Tanh
self.deconv = nn.Sequential(
nn.ConvTranspose2d(512, 256, 4, stride=2, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.ConvTranspose2d(256, 128, 4, stride=2, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.ConvTranspose2d(128, output_channel, 4, stride=2, padding=1),
nn.Tanh(),
)
initialize_weights(self)
def forward(self, z):
out = self.fc(z)
out = out.view(out.shape[0], 512, self.init_size, self.init_size)
img = self.deconv(out)
return img
class DCDiscriminator(nn.Module):
def __init__(self, image_size=32, input_channel=1, sigmoid=True):
super(DCDiscriminator, self).__init__()
self.image_size = image_size
self.input_channel = input_channel
self.fc_size = image_size // 8
# conv: Conv2d(3,2,1) -> LeakyReLU
# Conv2d(3,2,1) -> BN -> LeakyReLU
# Conv2d(3,2,1) -> BN -> LeakyReLU
self.conv = nn.Sequential(
nn.Conv2d(input_channel, 128, 3, 2, 1),
nn.LeakyReLU(0.2),
nn.Conv2d(128, 256, 3, 2, 1),
nn.BatchNorm2d(256),
nn.LeakyReLU(0.2),
nn.Conv2d(256, 512, 3, 2, 1),
nn.BatchNorm2d(512),
nn.LeakyReLU(0.2),
)
# fc: Linear -> Sigmoid
self.fc = nn.Sequential(
nn.Linear(512 * self.fc_size * self.fc_size, 1),
)
if sigmoid:
self.fc.add_module('sigmoid', nn.Sigmoid())
initialize_weights(self)
def forward(self, img):
out = self.conv(img)
out = out.view(out.shape[0], -1)
out = self.fc(out)
return out
同样的,我们使用同样的mnist数据集对DCGAN进行训练.
# hyper params
# z dim
latent_dim = 100
# image size and channel
image_size=32
image_channel=1
# Adam lr and betas
learning_rate = 0.0002
betas = (0.5, 0.999)
# epochs and batch size
n_epochs = 100
batch_size = 32
# device : cpu or cuda:0/1/2/3
device = torch.device('cuda:1')
# mnist dataset and dataloader
train_dataset = load_mnist_data()
trainloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
# use BCELoss as loss function
bceloss = nn.BCELoss().to(device)
# G and D model, use DCGAN
G = DCGenerator(image_size=image_size, latent_dim=latent_dim, output_channel=image_channel).to(device)
D = DCDiscriminator(image_size=image_size, input_channel=image_channel).to(device)
# G and D optimizer, use Adam or SGD
G_optimizer = optim.Adam(G.parameters(), lr=learning_rate, betas=betas)
D_optimizer = optim.Adam(D.parameters(), lr=learning_rate, betas=betas)
d_loss_hist, g_loss_hist = run_gan(trainloader, G, D, G_optimizer, D_optimizer, bceloss,
n_epochs, device, latent_dim)
Epoch 0: Train D loss: 0.3584, G loss: 4.7953
Epoch 1: Train D loss: 0.2336, G loss: 5.6612
Epoch 2: Train D loss: 0.2451, G loss: 5.4808
Epoch 3: Train D loss: 0.1608, G loss: 4.2449
Epoch 4: Train D loss: 0.4068, G loss: 3.9953
Epoch 5: Train D loss: 0.5673, G loss: 3.1682
Epoch 6: Train D loss: 0.5268, G loss: 2.9006
Epoch 7: Train D loss: 0.5768, G loss: 2.6063
Epoch 8: Train D loss: 0.5841, G loss: 2.5660
Epoch 9: Train D loss: 0.5123, G loss: 2.9250
Epoch 10: Train D loss: 0.3945, G loss: 2.6949
Epoch 11: Train D loss: 0.5941, G loss: 2.4399
Epoch 12: Train D loss: 0.5572, G loss: 2.3926
Epoch 13: Train D loss: 0.6046, G loss: 2.5039
Epoch 14: Train D loss: 0.6513, G loss: 2.1637
Epoch 15: Train D loss: 0.5793, G loss: 2.4047
Epoch 16: Train D loss: 0.6361, G loss: 2.4416
Epoch 17: Train D loss: 0.6193, G loss: 2.3791
Epoch 18: Train D loss: 0.5141, G loss: 2.4461
Epoch 19: Train D loss: 0.5765, G loss: 2.4536
Epoch 20: Train D loss: 0.6813, G loss: 2.2990
Epoch 21: Train D loss: 0.5250, G loss: 2.4540
Epoch 22: Train D loss: 0.6458, G loss: 2.5284
Epoch 23: Train D loss: 0.5561, G loss: 2.3798
Epoch 24: Train D loss: 0.4879, G loss: 2.6305
Epoch 25: Train D loss: 0.3962, G loss: 2.8168
Epoch 26: Train D loss: 0.5705, G loss: 2.7171
Epoch 27: Train D loss: 0.3177, G loss: 3.0004
Epoch 28: Train D loss: 0.4139, G loss: 3.0095
Epoch 29: Train D loss: 0.4706, G loss: 3.0445
Epoch 30: Train D loss: 0.2796, G loss: 3.2369
Epoch 31: Train D loss: 0.3112, G loss: 3.3666
Epoch 32: Train D loss: 0.2850, G loss: 3.5337
Epoch 33: Train D loss: 0.5064, G loss: 3.1986
Epoch 34: Train D loss: 0.3508, G loss: 3.5686
Epoch 35: Train D loss: 0.3044, G loss: 3.4096
Epoch 36: Train D loss: 0.3091, G loss: 3.6790
Epoch 37: Train D loss: 0.2097, G loss: 3.5555
Epoch 38: Train D loss: 0.0981, G loss: 4.0560
Epoch 39: Train D loss: 0.7379, G loss: 3.0092
Epoch 40: Train D loss: 0.1962, G loss: 3.4945
Epoch 41: Train D loss: 0.0956, G loss: 4.0326
Epoch 42: Train D loss: 0.5153, G loss: 3.7515
Epoch 43: Train D loss: 0.5432, G loss: 2.8158
Epoch 44: Train D loss: 0.1706, G loss: 3.7669
Epoch 45: Train D loss: 0.6248, G loss: 2.8461
Epoch 46: Train D loss: 0.1040, G loss: 3.9352
Epoch 47: Train D loss: 0.0919, G loss: 4.2825
Epoch 48: Train D loss: 0.0546, G loss: 4.6079
Epoch 49: Train D loss: 0.0652, G loss: 4.6525
Epoch 50: Train D loss: 0.7597, G loss: 3.4988
Epoch 51: Train D loss: 0.3397, G loss: 3.6112
Epoch 52: Train D loss: 0.0811, G loss: 4.2338
Epoch 53: Train D loss: 0.0490, G loss: 4.4919
Epoch 54: Train D loss: 0.0371, G loss: 4.7790
Epoch 55: Train D loss: 0.0375, G loss: 4.9030
Epoch 56: Train D loss: 0.6475, G loss: 3.8161
Epoch 57: Train D loss: 0.0770, G loss: 4.2638
Epoch 58: Train D loss: 0.0456, G loss: 4.7263
Epoch 59: Train D loss: 0.0372, G loss: 4.8959
Epoch 60: Train D loss: 0.0351, G loss: 5.1594
Epoch 61: Train D loss: 0.0281, G loss: 5.1873
Epoch 62: Train D loss: 0.8205, G loss: 4.4411
Epoch 63: Train D loss: 0.2567, G loss: 3.6164
Epoch 64: Train D loss: 0.5532, G loss: 3.3090
Epoch 65: Train D loss: 0.0831, G loss: 4.2039
Epoch 66: Train D loss: 0.0528, G loss: 4.6532
Epoch 67: Train D loss: 0.0327, G loss: 4.9808
Epoch 68: Train D loss: 0.0259, G loss: 5.1778
Epoch 69: Train D loss: 0.0264, G loss: 5.2096
Epoch 70: Train D loss: 1.2088, G loss: 2.6591
Epoch 71: Train D loss: 0.5735, G loss: 2.8551
Epoch 72: Train D loss: 0.5057, G loss: 3.3956
Epoch 73: Train D loss: 0.1402, G loss: 3.9483
Epoch 74: Train D loss: 0.0552, G loss: 4.5401
Epoch 75: Train D loss: 0.0370, G loss: 4.9205
Epoch 76: Train D loss: 0.0301, G loss: 5.0844
Epoch 77: Train D loss: 0.0247, G loss: 5.2022
Epoch 78: Train D loss: 0.0227, G loss: 5.4283
Epoch 79: Train D loss: 0.0169, G loss: 5.5034
Epoch 80: Train D loss: 0.0184, G loss: 5.5792
Epoch 81: Train D loss: 0.0159, G loss: 5.6387
Epoch 82: Train D loss: 0.0175, G loss: 5.6909
Epoch 83: Train D loss: 0.0137, G loss: 5.8635
Epoch 84: Train D loss: 0.0156, G loss: 5.8242
Epoch 85: Train D loss: 0.0149, G loss: 5.8942
Epoch 86: Train D loss: 1.2041, G loss: 3.8859
Epoch 87: Train D loss: 0.7222, G loss: 2.0960
Epoch 88: Train D loss: 0.6053, G loss: 2.9342
Epoch 89: Train D loss: 0.4476, G loss: 3.1945
Epoch 90: Train D loss: 0.1500, G loss: 4.0948
Epoch 91: Train D loss: 0.0551, G loss: 4.6313
Epoch 92: Train D loss: 0.8641, G loss: 2.7378
Epoch 93: Train D loss: 0.5070, G loss: 3.1373
Epoch 94: Train D loss: 0.0750, G loss: 4.3132
Epoch 95: Train D loss: 0.0365, G loss: 4.7940
Epoch 96: Train D loss: 0.0257, G loss: 5.0818
Epoch 97: Train D loss: 0.0231, G loss: 5.2663
Epoch 98: Train D loss: 0.0208, G loss: 5.4650
Epoch 99: Train D loss: 0.0203, G loss: 5.8589
loss_plot(d_loss_hist, g_loss_hist)
可以看到,DCGAN的生成图片质量比起只有线性层的GAN要好不少.接下来,让我们尝试使用家具数据集来训练DCGAN.
# RGB image channel = 3
image_channel=3
# epochs
n_epochs = 300
# mnist dataset and dataloader
train_dataset = load_furniture_data()
trainloader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
# G and D model, use DCGAN
G = DCGenerator(image_size=image_size, latent_dim=latent_dim, output_channel=image_channel).to(device)
D = DCDiscriminator(image_size=image_size, input_channel=image_channel).to(device)
# G and D optimizer, use Adam or SGD
G_optimizer = optim.Adam(G.parameters(), lr=learning_rate, betas=betas)
D_optimizer = optim.Adam(D.parameters(), lr=learning_rate, betas=betas)
d_loss_hist, g_loss_hist = run_gan(trainloader, G, D, G_optimizer, D_optimizer, bceloss,
n_epochs, device, latent_dim)
Epoch 0: Train D loss: 0.8826, G loss: 3.9182
Epoch 1: Train D loss: 0.3575, G loss: 5.6344
Epoch 2: Train D loss: 0.2020, G loss: 6.2485
Epoch 3: Train D loss: 0.1214, G loss: 6.3474
Epoch 4: Train D loss: 0.1045, G loss: 6.3169
Epoch 5: Train D loss: 0.4780, G loss: 8.4332
Epoch 6: Train D loss: 0.0895, G loss: 6.2010
Epoch 7: Train D loss: 0.1221, G loss: 6.1602
Epoch 8: Train D loss: 0.0836, G loss: 5.3933
Epoch 9: Train D loss: 0.0696, G loss: 5.7825
Epoch 10: Train D loss: 0.0637, G loss: 5.8573
Epoch 11: Train D loss: 0.1293, G loss: 5.5485
Epoch 12: Train D loss: 0.5371, G loss: 6.3349
Epoch 13: Train D loss: 0.5318, G loss: 4.4861
Epoch 14: Train D loss: 0.4635, G loss: 3.9430
Epoch 15: Train D loss: 0.2749, G loss: 4.5340
Epoch 16: Train D loss: 0.3709, G loss: 4.8660
Epoch 17: Train D loss: 0.2258, G loss: 4.8558
Epoch 18: Train D loss: 0.2302, G loss: 5.6346
Epoch 19: Train D loss: 0.7460, G loss: 5.7239
Epoch 20: Train D loss: 0.2786, G loss: 4.3962
Epoch 21: Train D loss: 0.1235, G loss: 4.7795
Epoch 22: Train D loss: 0.3446, G loss: 5.7504
Epoch 23: Train D loss: 0.2496, G loss: 4.4360
Epoch 24: Train D loss: 0.2506, G loss: 4.8346
Epoch 25: Train D loss: 0.1725, G loss: 5.4387
Epoch 26: Train D loss: 0.5889, G loss: 5.5629
Epoch 27: Train D loss: 0.2373, G loss: 5.1965
Epoch 28: Train D loss: 0.5494, G loss: 6.3583
Epoch 29: Train D loss: 0.3330, G loss: 4.8053
......
Epoch 260: Train D loss: 0.1771, G loss: 3.6214
Epoch 261: Train D loss: 0.1395, G loss: 3.6892
Epoch 262: Train D loss: 0.1184, G loss: 3.7579
Epoch 263: Train D loss: 0.1154, G loss: 3.9557
Epoch 264: Train D loss: 0.1076, G loss: 3.9747
Epoch 265: Train D loss: 0.1028, G loss: 3.9015
Epoch 266: Train D loss: 0.0906, G loss: 3.9886
Epoch 267: Train D loss: 0.0865, G loss: 3.9569
Epoch 268: Train D loss: 0.0741, G loss: 4.0610
Epoch 269: Train D loss: 0.0750, G loss: 4.1080
Epoch 270: Train D loss: 0.0584, G loss: 4.1823
Epoch 271: Train D loss: 0.0580, G loss: 4.2771
Epoch 272: Train D loss: 0.0620, G loss: 4.2002
Epoch 273: Train D loss: 0.0568, G loss: 4.3134
Epoch 274: Train D loss: 0.0728, G loss: 4.4302
Epoch 275: Train D loss: 0.0595, G loss: 4.4666
Epoch 276: Train D loss: 0.0583, G loss: 4.3717
Epoch 277: Train D loss: 0.0567, G loss: 4.3564
Epoch 278: Train D loss: 0.0525, G loss: 4.3592
Epoch 279: Train D loss: 0.0518, G loss: 4.4249
Epoch 280: Train D loss: 0.0537, G loss: 4.4662
Epoch 281: Train D loss: 0.0453, G loss: 4.5406
Epoch 282: Train D loss: 0.0535, G loss: 4.4714
Epoch 283: Train D loss: 0.0508, G loss: 4.6274
Epoch 284: Train D loss: 0.0557, G loss: 4.5374
Epoch 285: Train D loss: 0.0536, G loss: 4.5408
Epoch 286: Train D loss: 0.0453, G loss: 4.5735
Epoch 287: Train D loss: 0.0442, G loss: 4.6368
Epoch 288: Train D loss: 0.0429, G loss: 4.6867
Epoch 289: Train D loss: 0.0469, G loss: 4.6189
Epoch 290: Train D loss: 0.0432, G loss: 4.7058
Epoch 291: Train D loss: 0.0428, G loss: 4.7552
Epoch 292: Train D loss: 0.0459, G loss: 4.6039
Epoch 293: Train D loss: 0.0482, G loss: 4.8490
Epoch 294: Train D loss: 0.0422, G loss: 4.7337
Epoch 295: Train D loss: 0.0427, G loss: 4.7856
Epoch 296: Train D loss: 0.0553, G loss: 4.8967
Epoch 297: Train D loss: 1.9257, G loss: 5.1035
Epoch 298: Train D loss: 1.1107, G loss: 4.4166
Epoch 299: Train D loss: 0.3915, G loss: 4.0837
loss_plot(d_loss_hist, g_loss_hist)