DCGAN 教程

原文:https://pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html

作者Nathan Inkawhich

简介

本教程将通过一个示例对 DCGAN 进行介绍。 在向其展示许多真实名人的照片后,我们将训练一个生成对抗网络(GAN)来产生新名人。 此处的大多数代码来自pytorch/examples中的 dcgan 实现,并且本文档将对该实现进行详尽的解释,并阐明此模型的工作方式和原因。 但请放心,不需要 GAN 的先验知识,但这可能需要新手花一些时间来推理幕后实际发生的事情。 同样,为了节省时间,拥有一两个 GPU 也将有所帮助。 让我们从头开始。

生成对抗网络

什么是 GAN?

GAN 是用于教授 DL 模型以捕获训练数据分布的框架,因此我们可以从同一分布中生成新数据。 GAN 由 Ian Goodfellow 于 2014 年发明,并在论文《生成对抗网络》中首次进行了描述。 它们由两个不同的模型组成:生成器判别器。 生成器的工作是生成看起来像训练图像的“假”图像。 判别器的工作是查看图像并从生成器输出它是真实的训练图像还是伪图像。 在训练过程中,生成器不断尝试通过生成越来越好的伪造品而使判别器的表现超过智者,而判别器正在努力成为更好的侦探并正确地对真实和伪造图像进行分类。 博弈的平衡点是当生成器生成的伪造品看起来像直接来自训练数据时,而判别器则总是猜测生成器输出是真实还是伪造品的 50% 置信度。

现在,让我们从判别器开始定义一些在整个教程中使用的符号。 令x为代表图像的数据。 D(x)是判别器网络,其输出x来自训练数据而不是生成器的(标量)概率。 在这里,由于我们要处理图像,因此D(x)的输入是 CHW 大小为3x64x64的图像。 直观地,当x来自训练数据时,D(x)应该为高,而当x来自生成器时,它应该为低。 D(x)也可以被认为是传统的二分类器。

对于生成器的表示法,令z是从标准正态分布中采样的潜在空间向量。 G(z)表示将隐向量z映射到数据空间的生成器函数。 G的目标是估计训练数据来自p_data的分布,以便它可以从该估计分布(p_g)生成假样本。

因此,D(G(z))是生成器G的输出是真实图像的概率(标量)。 如 Goodfellow 的论文中所述,DG玩一个 minimax 游戏,其中D试图最大化其正确分类实物和假物log D(x),并且G尝试最小化D预测其输出为假的概率log(1 - D(G(g(x))))。 从本文来看,GAN 损失函数为

DCGAN 教程 - 图1

从理论上讲,此极小极大游戏的解决方案是p_g = p_data,判别器会随机猜测输入是真实的还是假的。 但是,GAN 的收敛理论仍在积极研究中,实际上,模型并不总是能达到这一目的。

什么是 DCGAN?

DCGAN 是上述 GAN 的直接扩展,不同之处在于,DCGAN 分别在判别器和生成器中分别使用卷积和卷积转置层。 它最早由 Radford 等人,在论文《使用深度卷积生成对抗网络的无监督表示学习》中描述。 判别器由分层的卷积层批量规范层LeakyReLU 激活组成。 输入是3x64x64的输入图像,输出是输入来自真实数据分布的标量概率。 生成器由转置卷积层,批量规范层和 ReLU 激活组成。 输入是从标准正态分布中提取的潜向量z,输出是3x64x64 RGB 图像。 跨步的转置层使潜向量可以转换为具有与图像相同形状的体积。 在本文中,作者还提供了一些有关如何设置优化器,如何计算损失函数以及如何初始化模型权重的提示,所有这些都将在接下来的部分中进行解释。

  1. from __future__ import print_function
  2. #%matplotlib inline
  3. import argparse
  4. import os
  5. import random
  6. import torch
  7. import torch.nn as nn
  8. import torch.nn.parallel
  9. import torch.backends.cudnn as cudnn
  10. import torch.optim as optim
  11. import torch.utils.data
  12. import torchvision.datasets as dset
  13. import torchvision.transforms as transforms
  14. import torchvision.utils as vutils
  15. import numpy as np
  16. import matplotlib.pyplot as plt
  17. import matplotlib.animation as animation
  18. from IPython.display import HTML
  19. # Set random seed for reproducibility
  20. manualSeed = 999
  21. #manualSeed = random.randint(1, 10000) # use if you want new results
  22. print("Random Seed: ", manualSeed)
  23. random.seed(manualSeed)
  24. torch.manual_seed(manualSeed)

出:

  1. Random Seed: 999

输入

让我们为跑步定义一些输入:

  • dataroot-数据集文件夹根目录的路径。 我们将在下一节中进一步讨论数据集
  • worker-使用DataLoader加载数据的工作线程数
  • batch_size-训练中使用的批量大小。 DCGAN 纸使用的批量大小为 128
  • image_size-用于训练的图像的空间大小。 此实现默认为64x64。 如果需要其他尺寸,则必须更改DG的结构。 有关更多详细信息,请参见此处
  • nc-输入图像中的彩色通道数。 对于彩色图像,这是 3
  • nz-潜向量的长度
  • ngf-与通过生成器传送的特征映射的深度有关
  • ndf-设置通过判别器传播的特征映射的深度
  • num_epochs-要运行的训练周期数。 训练更长的时间可能会导致更好的结果,但也会花费更长的时间
  • lr-训练的学习率。 如 DCGAN 文件中所述,此数字应为 0.0002
  • beta1-Adam 优化器的beta1超参数。 如论文所述,该数字应为 0.5
  • ngpu-可用的 GPU 数量。 如果为 0,则代码将在 CPU 模式下运行。 如果此数字大于 0,它将在该数量的 GPU 上运行
  1. # Root directory for dataset
  2. dataroot = "data/celeba"
  3. # Number of workers for dataloader
  4. workers = 2
  5. # Batch size during training
  6. batch_size = 128
  7. # Spatial size of training images. All images will be resized to this
  8. # size using a transformer.
  9. image_size = 64
  10. # Number of channels in the training images. For color images this is 3
  11. nc = 3
  12. # Size of z latent vector (i.e. size of generator input)
  13. nz = 100
  14. # Size of feature maps in generator
  15. ngf = 64
  16. # Size of feature maps in discriminator
  17. ndf = 64
  18. # Number of training epochs
  19. num_epochs = 5
  20. # Learning rate for optimizers
  21. lr = 0.0002
  22. # Beta1 hyperparam for Adam optimizers
  23. beta1 = 0.5
  24. # Number of GPUs available. Use 0 for CPU mode.
  25. ngpu = 1

数据

在本教程中,我们将使用 Celeb-A Faces 数据集,该数据集可在链接的站点或 Google 云端硬盘中下载。 数据集将下载为名为img_align_celeba.zip的文件。 下载完成后,创建一个名为celeba的目录,并将 zip 文件解压缩到该目录中。 然后,将此笔记本的dataroot输入设置为刚创建的celeba目录。 结果目录结构应为:

  1. /path/to/celeba
  2. -> img_align_celeba
  3. -> 188242.jpg
  4. -> 173822.jpg
  5. -> 284702.jpg
  6. -> 537394.jpg
  7. ...

这是重要的一步,因为我们将使用ImageFolder数据集类,该类要求数据集的根文件夹中有子目录。 现在,我们可以创建数据集,创建数据加载器,将设备设置为可以运行,并最终可视化一些训练数据。

  1. # We can use an image folder dataset the way we have it setup.
  2. # Create the dataset
  3. dataset = dset.ImageFolder(root=dataroot,
  4. transform=transforms.Compose([
  5. transforms.Resize(image_size),
  6. transforms.CenterCrop(image_size),
  7. transforms.ToTensor(),
  8. transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
  9. ]))
  10. # Create the dataloader
  11. dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size,
  12. shuffle=True, num_workers=workers)
  13. # Decide which device we want to run on
  14. device = torch.device("cuda:0" if (torch.cuda.is_available() and ngpu > 0) else "cpu")
  15. # Plot some training images
  16. real_batch = next(iter(dataloader))
  17. plt.figure(figsize=(8,8))
  18. plt.axis("off")
  19. plt.title("Training Images")
  20. plt.imshow(np.transpose(vutils.make_grid(real_batch[0].to(device)[:64], padding=2, normalize=True).cpu(),(1,2,0)))

../_img/sphx_glr_dcgan_faces_tutorial_001.png

实现

设置好输入参数并准备好数据集后,我们现在可以进入实现了。 我们将从权重初始化策略开始,然后详细讨论生成器,判别器,损失函数和训练循环。

权重初始化

在 DCGAN 论文中,作者指定所有模型权重均应从均值为 0,stdev = 0.02的正态分布中随机初始化。 weights_init函数采用已初始化的模型作为输入,并重新初始化所有卷积,卷积转置和批量归一化层以满足此标准。 初始化后立即将此函数应用于模型。

  1. # custom weights initialization called on netG and netD
  2. def weights_init(m):
  3. classname = m.__class__.__name__
  4. if classname.find('Conv') != -1:
  5. nn.init.normal_(m.weight.data, 0.0, 0.02)
  6. elif classname.find('BatchNorm') != -1:
  7. nn.init.normal_(m.weight.data, 1.0, 0.02)
  8. nn.init.constant_(m.bias.data, 0)

生成器

生成器G用于将潜在空间向量(z)映射到数据空间。 由于我们的数据是图像,因此将z转换为数据空间意味着最终创建与训练图像大小相同的 RGB 图像(即3x64x64)。 在实践中,这是通过一系列跨步的二维卷积转置层来完成的,每个层都与 2d 批量规范层和 relu 激活配对。 生成器的输出通过 tanh 函数馈送,以使其返回到输入数据范围[-1,1]。 值得注意的是,在卷积转置层之后存在批量规范函数,因为这是 DCGAN 论文的关键贡献。 这些层有助于训练过程中的梯度流动。 DCGAN 纸生成的图像如下所示。

dcgan_generator

请注意,我们在输入部分中设置的输入(nzngfnc)如何影响代码中的生成器架构。 nzz输入向量的长度,ngf与通过生成器传播的特征映射的大小有关, nc是输出图像中的通道(对于 RGB 图像设置为 3)。 下面是生成器的代码。

  1. # Generator Code
  2. class Generator(nn.Module):
  3. def __init__(self, ngpu):
  4. super(Generator, self).__init__()
  5. self.ngpu = ngpu
  6. self.main = nn.Sequential(
  7. # input is Z, going into a convolution
  8. nn.ConvTranspose2d( nz, ngf * 8, 4, 1, 0, bias=False),
  9. nn.BatchNorm2d(ngf * 8),
  10. nn.ReLU(True),
  11. # state size. (ngf*8) x 4 x 4
  12. nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
  13. nn.BatchNorm2d(ngf * 4),
  14. nn.ReLU(True),
  15. # state size. (ngf*4) x 8 x 8
  16. nn.ConvTranspose2d( ngf * 4, ngf * 2, 4, 2, 1, bias=False),
  17. nn.BatchNorm2d(ngf * 2),
  18. nn.ReLU(True),
  19. # state size. (ngf*2) x 16 x 16
  20. nn.ConvTranspose2d( ngf * 2, ngf, 4, 2, 1, bias=False),
  21. nn.BatchNorm2d(ngf),
  22. nn.ReLU(True),
  23. # state size. (ngf) x 32 x 32
  24. nn.ConvTranspose2d( ngf, nc, 4, 2, 1, bias=False),
  25. nn.Tanh()
  26. # state size. (nc) x 64 x 64
  27. )
  28. def forward(self, input):
  29. return self.main(input)

现在,我们可以实例化生成器并应用weights_init函数。 签出打印的模型以查看生成器对象的结构。

  1. # Create the generator
  2. netG = Generator(ngpu).to(device)
  3. # Handle multi-gpu if desired
  4. if (device.type == 'cuda') and (ngpu > 1):
  5. netG = nn.DataParallel(netG, list(range(ngpu)))
  6. # Apply the weights_init function to randomly initialize all weights
  7. # to mean=0, stdev=0.2.
  8. netG.apply(weights_init)
  9. # Print the model
  10. print(netG)

出:

  1. Generator(
  2. (main): Sequential(
  3. (0): ConvTranspose2d(100, 512, kernel_size=(4, 4), stride=(1, 1), bias=False)
  4. (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  5. (2): ReLU(inplace=True)
  6. (3): ConvTranspose2d(512, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
  7. (4): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  8. (5): ReLU(inplace=True)
  9. (6): ConvTranspose2d(256, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
  10. (7): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  11. (8): ReLU(inplace=True)
  12. (9): ConvTranspose2d(128, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
  13. (10): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  14. (11): ReLU(inplace=True)
  15. (12): ConvTranspose2d(64, 3, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
  16. (13): Tanh()
  17. )
  18. )

判别器

如前所述,判别器D是一个二分类网络,将图像作为输入并输出标量概率,即输入图像是真实的(与假的相对)。 在这里,D拍摄3x64x64的输入图像,通过一系列的Conv2dBatchNorm2dLeakyReLU层对其进行处理,然后通过 Sigmoid 激活函数输出最终概率。 如果需要解决此问题,可以用更多层扩展此架构,但是使用跨步卷积,BatchNormLeakyReLU仍然很重要。 DCGAN 论文提到,使用跨步卷积而不是通过池化来进行下采样是一个好习惯,因为它可以让网络学习自己的池化特征。 批量规范和泄漏 ReLU 函数还可以促进健康的梯度流,这对于GD的学习过程都是至关重要的。

鉴别码

  1. class Discriminator(nn.Module):
  2. def __init__(self, ngpu):
  3. super(Discriminator, self).__init__()
  4. self.ngpu = ngpu
  5. self.main = nn.Sequential(
  6. # input is (nc) x 64 x 64
  7. nn.Conv2d(nc, ndf, 4, 2, 1, bias=False),
  8. nn.LeakyReLU(0.2, inplace=True),
  9. # state size. (ndf) x 32 x 32
  10. nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
  11. nn.BatchNorm2d(ndf * 2),
  12. nn.LeakyReLU(0.2, inplace=True),
  13. # state size. (ndf*2) x 16 x 16
  14. nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
  15. nn.BatchNorm2d(ndf * 4),
  16. nn.LeakyReLU(0.2, inplace=True),
  17. # state size. (ndf*4) x 8 x 8
  18. nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),
  19. nn.BatchNorm2d(ndf * 8),
  20. nn.LeakyReLU(0.2, inplace=True),
  21. # state size. (ndf*8) x 4 x 4
  22. nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
  23. nn.Sigmoid()
  24. )
  25. def forward(self, input):
  26. return self.main(input)

现在,与生成器一样,我们可以创建判别器,应用weights_init函数,并打印模型的结构。

  1. # Create the Discriminator
  2. netD = Discriminator(ngpu).to(device)
  3. # Handle multi-gpu if desired
  4. if (device.type == 'cuda') and (ngpu > 1):
  5. netD = nn.DataParallel(netD, list(range(ngpu)))
  6. # Apply the weights_init function to randomly initialize all weights
  7. # to mean=0, stdev=0.2.
  8. netD.apply(weights_init)
  9. # Print the model
  10. print(netD)

出:

  1. Discriminator(
  2. (main): Sequential(
  3. (0): Conv2d(3, 64, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
  4. (1): LeakyReLU(negative_slope=0.2, inplace=True)
  5. (2): Conv2d(64, 128, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
  6. (3): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  7. (4): LeakyReLU(negative_slope=0.2, inplace=True)
  8. (5): Conv2d(128, 256, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
  9. (6): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  10. (7): LeakyReLU(negative_slope=0.2, inplace=True)
  11. (8): Conv2d(256, 512, kernel_size=(4, 4), stride=(2, 2), padding=(1, 1), bias=False)
  12. (9): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  13. (10): LeakyReLU(negative_slope=0.2, inplace=True)
  14. (11): Conv2d(512, 1, kernel_size=(4, 4), stride=(1, 1), bias=False)
  15. (12): Sigmoid()
  16. )
  17. )

损失函数和优化器

使用DG设置,我们可以指定它们如何通过损失函数和优化器学习。 我们将使用在 PyTorch 中定义的二进制交叉熵损失(BCELoss)函数:

DCGAN 教程 - 图4

请注意,此函数如何提供目标函数中两个对数分量的计算(即log D(x)log(1 - D(G(z))))。 我们可以指定y输入使用 BCE 方程的哪一部分。 这是在即将到来的训练循环中完成的,但重要的是要了解我们如何仅通过更改y(即GT标签)即可选择希望计算的分量。

接下来,我们将实际标签定义为 1,将假标签定义为 0。这些标签将在计算DG的损失时使用,这也是 GAN 原始论文中使用的惯例 。 最后,我们设置了两个单独的优化器,一个用于D,另一个用于G。 如 DCGAN 论文中所指定,这两个都是学习速度为 0.0002 和Beta1 = 0.5的 Adam 优化器。 为了跟踪生成器的学习进度,我们将生成一批固定的潜在向量,这些向量是从高斯分布(即fixed_noise)中提取的。 在训练循环中,我们将定期将此fixed_noise输入到G中,并且在迭代过程中,我们将看到图像形成于噪声之外。

  1. # Initialize BCELoss function
  2. criterion = nn.BCELoss()
  3. # Create batch of latent vectors that we will use to visualize
  4. # the progression of the generator
  5. fixed_noise = torch.randn(64, nz, 1, 1, device=device)
  6. # Establish convention for real and fake labels during training
  7. real_label = 1.
  8. fake_label = 0.
  9. # Setup Adam optimizers for both G and D
  10. optimizerD = optim.Adam(netD.parameters(), lr=lr, betas=(beta1, 0.999))
  11. optimizerG = optim.Adam(netG.parameters(), lr=lr, betas=(beta1, 0.999))

训练

最后,既然我们已经定义了 GAN 框架的所有部分,我们就可以对其进行训练。 请注意,训练 GAN 某种程度上是一种艺术形式,因为不正确的超参数设置会导致模式崩溃,而对失败的原因几乎没有解释。 在这里,我们将严格遵循 Goodfellow 论文中的算法 1,同时遵守ganhacks中显示的一些最佳做法。 即,我们将“为真实和伪造构建不同的小批量”图像,并调整G的目标函数以最大化log D(G(z))。 训练分为两个主要部分。 第 1 部分更新了判别器,第 2 部分更新了生成器。

第 1 部分-训练判别器

回想一下,训练判别器的目的是最大程度地提高将给定输入正确分类为真实或伪造的可能性。 就古德费罗而言,我们希望“通过提高其随机梯度来更新判别器”。 实际上,我们要最大化log D(x) + log(1 - D(G(z))。 由于 ganhacks 提出了单独的小批量建议,因此我们将分两步进行计算。 首先,我们将从训练集中构造一批真实样本,向前通过D,计算损失(log D(x)),然后在向后通过中计算梯度。 其次,我们将使用当前生成器构造一批假样本,将这批伪造通过D,计算损失(log(1 - D(G(z)))),然后反向累积梯度。 现在,利用全批量和全批量的累积梯度,我们称之为判别器优化程序的一个步骤。

第 2 部分-训练生成器

如原始论文所述,我们希望通过最小化log(1 - D(G(z)))来训练生成器,以产生更好的假货。 如前所述,Goodfellow 证明这不能提供足够的梯度,尤其是在学习过程的早期。 作为解决方法,我们希望最大化log D(G(z))。 在代码中,我们通过以下步骤来实现此目的:将第 1 部分的生成器输出与判别器进行分类,使用实数标签GT计算G的损失,反向计算G的梯度,最后使用优化器步骤更新G的参数。 将真实标签用作损失函数的GT标签似乎是违反直觉的,但这使我们可以使用 BCELoss 的log(x)部分(而不是log(1 - x)部分),这正是我们想要的。

最后,我们将进行一些统计报告,并在每个周期结束时,将我们的fixed_noise批量推送到生成器中,以直观地跟踪G的训练进度。 报告的训练统计数据是:

  • Loss_D-判别器损失,计算为所有真实批量和所有假批量的损失总和(log D(x) + log D(G(z)))。
  • Loss_G-生成器损失计算为log D(G(z))
  • D(x)-所有真实批量的判别器的平均输出(整个批量)。 这应该从接近 1 开始,然后在G变得更好时理论上收敛到 0.5。 想想这是为什么。
  • D(G(z))-所有假批量的平均判别器输出。 第一个数字在D更新之前,第二个数字在D更新之后。 这些数字应从 0 开始,并随着G的提高收敛到 0.5。 想想这是为什么。

注意:此步骤可能需要一段时间,具体取决于您运行了多少个周期以及是否从数据集中删除了一些数据。

  1. # Training Loop
  2. # Lists to keep track of progress
  3. img_list = []
  4. G_losses = []
  5. D_losses = []
  6. iters = 0
  7. print("Starting Training Loop...")
  8. # For each epoch
  9. for epoch in range(num_epochs):
  10. # For each batch in the dataloader
  11. for i, data in enumerate(dataloader, 0):
  12. ############################
  13. # (1) Update D network: maximize log(D(x)) + log(1 - D(G(z)))
  14. ###########################
  15. ## Train with all-real batch
  16. netD.zero_grad()
  17. # Format batch
  18. real_cpu = data[0].to(device)
  19. b_size = real_cpu.size(0)
  20. label = torch.full((b_size,), real_label, dtype=torch.float, device=device)
  21. # Forward pass real batch through D
  22. output = netD(real_cpu).view(-1)
  23. # Calculate loss on all-real batch
  24. errD_real = criterion(output, label)
  25. # Calculate gradients for D in backward pass
  26. errD_real.backward()
  27. D_x = output.mean().item()
  28. ## Train with all-fake batch
  29. # Generate batch of latent vectors
  30. noise = torch.randn(b_size, nz, 1, 1, device=device)
  31. # Generate fake image batch with G
  32. fake = netG(noise)
  33. label.fill_(fake_label)
  34. # Classify all fake batch with D
  35. output = netD(fake.detach()).view(-1)
  36. # Calculate D's loss on the all-fake batch
  37. errD_fake = criterion(output, label)
  38. # Calculate the gradients for this batch
  39. errD_fake.backward()
  40. D_G_z1 = output.mean().item()
  41. # Add the gradients from the all-real and all-fake batches
  42. errD = errD_real + errD_fake
  43. # Update D
  44. optimizerD.step()
  45. ############################
  46. # (2) Update G network: maximize log(D(G(z)))
  47. ###########################
  48. netG.zero_grad()
  49. label.fill_(real_label) # fake labels are real for generator cost
  50. # Since we just updated D, perform another forward pass of all-fake batch through D
  51. output = netD(fake).view(-1)
  52. # Calculate G's loss based on this output
  53. errG = criterion(output, label)
  54. # Calculate gradients for G
  55. errG.backward()
  56. D_G_z2 = output.mean().item()
  57. # Update G
  58. optimizerG.step()
  59. # Output training stats
  60. if i % 50 == 0:
  61. print('[%d/%d][%d/%d]\tLoss_D: %.4f\tLoss_G: %.4f\tD(x): %.4f\tD(G(z)): %.4f / %.4f'
  62. % (epoch, num_epochs, i, len(dataloader),
  63. errD.item(), errG.item(), D_x, D_G_z1, D_G_z2))
  64. # Save Losses for plotting later
  65. G_losses.append(errG.item())
  66. D_losses.append(errD.item())
  67. # Check how the generator is doing by saving G's output on fixed_noise
  68. if (iters % 500 == 0) or ((epoch == num_epochs-1) and (i == len(dataloader)-1)):
  69. with torch.no_grad():
  70. fake = netG(fixed_noise).detach().cpu()
  71. img_list.append(vutils.make_grid(fake, padding=2, normalize=True))
  72. iters += 1

出:

  1. Starting Training Loop...
  2. [0/5][0/1583] Loss_D: 1.9847 Loss_G: 5.5914 D(x): 0.6004 D(G(z)): 0.6680 / 0.0062
  3. [0/5][50/1583] Loss_D: 0.7168 Loss_G: 35.7954 D(x): 0.7127 D(G(z)): 0.0000 / 0.0000
  4. [0/5][100/1583] Loss_D: 0.0007 Loss_G: 28.2580 D(x): 0.9994 D(G(z)): 0.0000 / 0.0000
  5. [0/5][150/1583] Loss_D: 0.0001 Loss_G: 42.5731 D(x): 0.9999 D(G(z)): 0.0000 / 0.0000
  6. [0/5][200/1583] Loss_D: 0.0138 Loss_G: 42.3603 D(x): 0.9933 D(G(z)): 0.0000 / 0.0000
  7. [0/5][250/1583] Loss_D: 0.0010 Loss_G: 42.2029 D(x): 0.9991 D(G(z)): 0.0000 / 0.0000
  8. [0/5][300/1583] Loss_D: 0.0000 Loss_G: 41.9521 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  9. [0/5][350/1583] Loss_D: 0.0000 Loss_G: 41.7962 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  10. [0/5][400/1583] Loss_D: 0.0000 Loss_G: 41.6345 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  11. [0/5][450/1583] Loss_D: 0.0000 Loss_G: 41.6058 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  12. [0/5][500/1583] Loss_D: 0.0001 Loss_G: 41.6208 D(x): 0.9999 D(G(z)): 0.0000 / 0.0000
  13. [0/5][550/1583] Loss_D: 0.0000 Loss_G: 41.3979 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  14. [0/5][600/1583] Loss_D: 0.0000 Loss_G: 41.2545 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  15. [0/5][650/1583] Loss_D: 0.0000 Loss_G: 41.0200 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  16. [0/5][700/1583] Loss_D: 0.0000 Loss_G: 39.6461 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  17. [0/5][750/1583] Loss_D: 0.0000 Loss_G: 38.8834 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  18. [0/5][800/1583] Loss_D: 0.0000 Loss_G: 38.5914 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  19. [0/5][850/1583] Loss_D: 0.0000 Loss_G: 38.8209 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  20. [0/5][900/1583] Loss_D: 0.0000 Loss_G: 38.9713 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  21. [0/5][950/1583] Loss_D: 0.0000 Loss_G: 38.4995 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  22. [0/5][1000/1583] Loss_D: 0.0001 Loss_G: 38.5549 D(x): 0.9999 D(G(z)): 0.0000 / 0.0000
  23. [0/5][1050/1583] Loss_D: 0.0000 Loss_G: 39.1773 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  24. [0/5][1100/1583] Loss_D: 0.0000 Loss_G: 39.0142 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  25. [0/5][1150/1583] Loss_D: 0.0000 Loss_G: 38.6368 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  26. [0/5][1200/1583] Loss_D: 0.0000 Loss_G: 38.7159 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  27. [0/5][1250/1583] Loss_D: 0.0000 Loss_G: 38.7660 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  28. [0/5][1300/1583] Loss_D: 0.0000 Loss_G: 38.5522 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  29. [0/5][1350/1583] Loss_D: 0.0001 Loss_G: 38.6703 D(x): 0.9999 D(G(z)): 0.0000 / 0.0000
  30. [0/5][1400/1583] Loss_D: 0.0000 Loss_G: 38.5487 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  31. [0/5][1450/1583] Loss_D: 0.0000 Loss_G: 38.0378 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  32. [0/5][1500/1583] Loss_D: 0.0000 Loss_G: 38.1258 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  33. [0/5][1550/1583] Loss_D: 0.0000 Loss_G: 38.3473 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  34. [1/5][0/1583] Loss_D: 0.0000 Loss_G: 37.8825 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  35. [1/5][50/1583] Loss_D: 0.0000 Loss_G: 38.2248 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  36. [1/5][100/1583] Loss_D: 0.0000 Loss_G: 38.2204 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  37. [1/5][150/1583] Loss_D: 0.0000 Loss_G: 38.0967 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  38. [1/5][200/1583] Loss_D: 0.0000 Loss_G: 38.0669 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  39. [1/5][250/1583] Loss_D: 0.0000 Loss_G: 37.4736 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  40. [1/5][300/1583] Loss_D: 0.0000 Loss_G: 37.0766 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  41. [1/5][350/1583] Loss_D: 0.0000 Loss_G: 36.6055 D(x): 1.0000 D(G(z)): 0.0000 / 0.0000
  42. [1/5][400/1583] Loss_D: 2.5403 Loss_G: 12.8251 D(x): 0.8672 D(G(z)): 0.8088 / 0.0000
  43. [1/5][450/1583] Loss_D: 1.3779 Loss_G: 2.0631 D(x): 0.5850 D(G(z)): 0.4734 / 0.1820
  44. [1/5][500/1583] Loss_D: 1.0299 Loss_G: 2.4048 D(x): 0.5165 D(G(z)): 0.1698 / 0.1333
  45. [1/5][550/1583] Loss_D: 1.4922 Loss_G: 3.2383 D(x): 0.5854 D(G(z)): 0.4773 / 0.0888
  46. [1/5][600/1583] Loss_D: 0.9283 Loss_G: 1.8533 D(x): 0.6231 D(G(z)): 0.2962 / 0.2153
  47. [1/5][650/1583] Loss_D: 0.8065 Loss_G: 2.9684 D(x): 0.6684 D(G(z)): 0.2624 / 0.0715
  48. [1/5][700/1583] Loss_D: 0.6909 Loss_G: 2.8746 D(x): 0.7910 D(G(z)): 0.3013 / 0.0819
  49. [1/5][750/1583] Loss_D: 1.3242 Loss_G: 2.5236 D(x): 0.7183 D(G(z)): 0.5300 / 0.1090
  50. [1/5][800/1583] Loss_D: 1.0871 Loss_G: 2.0203 D(x): 0.4993 D(G(z)): 0.1716 / 0.1727
  51. [1/5][850/1583] Loss_D: 1.7561 Loss_G: 4.9674 D(x): 0.8542 D(G(z)): 0.7052 / 0.0133
  52. [1/5][900/1583] Loss_D: 0.8294 Loss_G: 2.5024 D(x): 0.6913 D(G(z)): 0.2910 / 0.1178
  53. [1/5][950/1583] Loss_D: 0.9390 Loss_G: 2.2087 D(x): 0.5508 D(G(z)): 0.1638 / 0.1617
  54. [1/5][1000/1583] Loss_D: 1.8202 Loss_G: 1.2178 D(x): 0.2535 D(G(z)): 0.0684 / 0.3527
  55. [1/5][1050/1583] Loss_D: 0.9816 Loss_G: 3.7976 D(x): 0.7310 D(G(z)): 0.3944 / 0.0343
  56. [1/5][1100/1583] Loss_D: 0.9798 Loss_G: 2.0990 D(x): 0.5963 D(G(z)): 0.2328 / 0.1660
  57. [1/5][1150/1583] Loss_D: 0.7173 Loss_G: 2.7879 D(x): 0.6385 D(G(z)): 0.1424 / 0.1057
  58. [1/5][1200/1583] Loss_D: 0.8903 Loss_G: 2.3547 D(x): 0.7371 D(G(z)): 0.3589 / 0.1251
  59. [1/5][1250/1583] Loss_D: 0.6137 Loss_G: 2.1031 D(x): 0.7491 D(G(z)): 0.2062 / 0.1588
  60. [1/5][1300/1583] Loss_D: 1.0179 Loss_G: 5.0280 D(x): 0.7465 D(G(z)): 0.4325 / 0.0129
  61. [1/5][1350/1583] Loss_D: 0.7131 Loss_G: 3.6670 D(x): 0.7931 D(G(z)): 0.3270 / 0.0398
  62. [1/5][1400/1583] Loss_D: 1.0736 Loss_G: 4.2392 D(x): 0.8172 D(G(z)): 0.4861 / 0.0351
  63. [1/5][1450/1583] Loss_D: 0.6050 Loss_G: 2.6052 D(x): 0.7590 D(G(z)): 0.2240 / 0.1019
  64. [1/5][1500/1583] Loss_D: 1.3370 Loss_G: 1.9105 D(x): 0.3786 D(G(z)): 0.0405 / 0.2013
  65. [1/5][1550/1583] Loss_D: 0.6698 Loss_G: 2.3040 D(x): 0.6444 D(G(z)): 0.1071 / 0.1372
  66. [2/5][0/1583] Loss_D: 1.3043 Loss_G: 2.1213 D(x): 0.4073 D(G(z)): 0.0423 / 0.1682
  67. [2/5][50/1583] Loss_D: 1.3636 Loss_G: 3.4322 D(x): 0.7959 D(G(z)): 0.6129 / 0.0510
  68. [2/5][100/1583] Loss_D: 0.8047 Loss_G: 3.4262 D(x): 0.9067 D(G(z)): 0.4371 / 0.0536
  69. [2/5][150/1583] Loss_D: 0.7103 Loss_G: 2.4974 D(x): 0.6212 D(G(z)): 0.0862 / 0.1273
  70. [2/5][200/1583] Loss_D: 0.8335 Loss_G: 2.9292 D(x): 0.7340 D(G(z)): 0.3396 / 0.0772
  71. [2/5][250/1583] Loss_D: 1.4766 Loss_G: 1.4532 D(x): 0.3469 D(G(z)): 0.0140 / 0.3162
  72. [2/5][300/1583] Loss_D: 0.8063 Loss_G: 2.5363 D(x): 0.6939 D(G(z)): 0.2714 / 0.1160
  73. [2/5][350/1583] Loss_D: 2.4655 Loss_G: 1.7710 D(x): 0.1625 D(G(z)): 0.0049 / 0.2345
  74. [2/5][400/1583] Loss_D: 0.9256 Loss_G: 1.4698 D(x): 0.5101 D(G(z)): 0.1192 / 0.2926
  75. [2/5][450/1583] Loss_D: 0.7932 Loss_G: 3.1267 D(x): 0.8831 D(G(z)): 0.4330 / 0.0657
  76. [2/5][500/1583] Loss_D: 1.0515 Loss_G: 1.8415 D(x): 0.4922 D(G(z)): 0.0817 / 0.2372
  77. [2/5][550/1583] Loss_D: 1.1575 Loss_G: 2.3904 D(x): 0.8286 D(G(z)): 0.5113 / 0.1394
  78. [2/5][600/1583] Loss_D: 0.8667 Loss_G: 4.0253 D(x): 0.8805 D(G(z)): 0.4499 / 0.0329
  79. [2/5][650/1583] Loss_D: 0.9943 Loss_G: 3.0625 D(x): 0.8224 D(G(z)): 0.4700 / 0.0678
  80. [2/5][700/1583] Loss_D: 0.7634 Loss_G: 3.7297 D(x): 0.7855 D(G(z)): 0.3507 / 0.0369
  81. [2/5][750/1583] Loss_D: 0.6280 Loss_G: 2.7439 D(x): 0.7664 D(G(z)): 0.2518 / 0.0897
  82. [2/5][800/1583] Loss_D: 0.9011 Loss_G: 1.3725 D(x): 0.5495 D(G(z)): 0.1341 / 0.3033
  83. [2/5][850/1583] Loss_D: 0.4595 Loss_G: 3.0410 D(x): 0.8186 D(G(z)): 0.1808 / 0.0721
  84. [2/5][900/1583] Loss_D: 0.8331 Loss_G: 1.3725 D(x): 0.5696 D(G(z)): 0.1528 / 0.3128
  85. [2/5][950/1583] Loss_D: 1.2701 Loss_G: 4.4360 D(x): 0.9365 D(G(z)): 0.6218 / 0.0226
  86. [2/5][1000/1583] Loss_D: 0.5165 Loss_G: 3.2817 D(x): 0.7543 D(G(z)): 0.1460 / 0.0651
  87. [2/5][1050/1583] Loss_D: 0.5562 Loss_G: 2.5533 D(x): 0.8034 D(G(z)): 0.2385 / 0.1047
  88. [2/5][1100/1583] Loss_D: 0.9842 Loss_G: 3.5247 D(x): 0.7936 D(G(z)): 0.4511 / 0.0446
  89. [2/5][1150/1583] Loss_D: 0.6793 Loss_G: 3.2208 D(x): 0.8038 D(G(z)): 0.3133 / 0.0571
  90. [2/5][1200/1583] Loss_D: 1.8110 Loss_G: 5.4461 D(x): 0.8337 D(G(z)): 0.7185 / 0.0090
  91. [2/5][1250/1583] Loss_D: 0.6310 Loss_G: 2.8066 D(x): 0.7859 D(G(z)): 0.2644 / 0.0822
  92. [2/5][1300/1583] Loss_D: 0.6009 Loss_G: 1.6727 D(x): 0.6759 D(G(z)): 0.1297 / 0.2422
  93. [2/5][1350/1583] Loss_D: 0.5156 Loss_G: 3.5893 D(x): 0.8552 D(G(z)): 0.2686 / 0.0385
  94. [2/5][1400/1583] Loss_D: 0.7672 Loss_G: 1.0321 D(x): 0.5755 D(G(z)): 0.0938 / 0.4195
  95. [2/5][1450/1583] Loss_D: 0.6583 Loss_G: 2.0611 D(x): 0.6727 D(G(z)): 0.1675 / 0.1591
  96. [2/5][1500/1583] Loss_D: 1.2956 Loss_G: 3.7047 D(x): 0.9324 D(G(z)): 0.6345 / 0.0479
  97. [2/5][1550/1583] Loss_D: 0.8555 Loss_G: 3.0119 D(x): 0.8243 D(G(z)): 0.4237 / 0.0696
  98. [3/5][0/1583] Loss_D: 0.7295 Loss_G: 2.0605 D(x): 0.7051 D(G(z)): 0.2466 / 0.1671
  99. [3/5][50/1583] Loss_D: 0.6551 Loss_G: 3.0267 D(x): 0.8502 D(G(z)): 0.3419 / 0.0676
  100. [3/5][100/1583] Loss_D: 0.9209 Loss_G: 1.3069 D(x): 0.5238 D(G(z)): 0.1032 / 0.3367
  101. [3/5][150/1583] Loss_D: 0.6289 Loss_G: 1.8684 D(x): 0.6835 D(G(z)): 0.1555 / 0.1994
  102. [3/5][200/1583] Loss_D: 1.0600 Loss_G: 1.3343 D(x): 0.4512 D(G(z)): 0.0575 / 0.3259
  103. [3/5][250/1583] Loss_D: 0.7251 Loss_G: 1.7242 D(x): 0.6128 D(G(z)): 0.1340 / 0.2269
  104. [3/5][300/1583] Loss_D: 0.7097 Loss_G: 1.7072 D(x): 0.7143 D(G(z)): 0.2623 / 0.2238
  105. [3/5][350/1583] Loss_D: 0.8045 Loss_G: 2.7455 D(x): 0.7958 D(G(z)): 0.3825 / 0.0901
  106. [3/5][400/1583] Loss_D: 0.8351 Loss_G: 1.6116 D(x): 0.5394 D(G(z)): 0.1106 / 0.2425
  107. [3/5][450/1583] Loss_D: 1.4829 Loss_G: 0.5346 D(x): 0.3523 D(G(z)): 0.0987 / 0.6289
  108. [3/5][500/1583] Loss_D: 0.6972 Loss_G: 2.1915 D(x): 0.7656 D(G(z)): 0.2987 / 0.1450
  109. [3/5][550/1583] Loss_D: 0.7369 Loss_G: 1.7250 D(x): 0.6402 D(G(z)): 0.1899 / 0.2224
  110. [3/5][600/1583] Loss_D: 0.8170 Loss_G: 2.6806 D(x): 0.7843 D(G(z)): 0.3880 / 0.0929
  111. [3/5][650/1583] Loss_D: 1.1531 Loss_G: 0.9077 D(x): 0.4340 D(G(z)): 0.1224 / 0.4550
  112. [3/5][700/1583] Loss_D: 0.8751 Loss_G: 1.0230 D(x): 0.5587 D(G(z)): 0.1808 / 0.4021
  113. [3/5][750/1583] Loss_D: 0.7169 Loss_G: 2.1268 D(x): 0.6690 D(G(z)): 0.2219 / 0.1588
  114. [3/5][800/1583] Loss_D: 0.9772 Loss_G: 3.1279 D(x): 0.8451 D(G(z)): 0.5081 / 0.0632
  115. [3/5][850/1583] Loss_D: 0.6574 Loss_G: 1.9605 D(x): 0.7010 D(G(z)): 0.2120 / 0.1775
  116. [3/5][900/1583] Loss_D: 0.6153 Loss_G: 2.8981 D(x): 0.8399 D(G(z)): 0.3197 / 0.0697
  117. [3/5][950/1583] Loss_D: 0.9155 Loss_G: 1.1091 D(x): 0.5482 D(G(z)): 0.1730 / 0.3799
  118. [3/5][1000/1583] Loss_D: 0.9873 Loss_G: 3.9150 D(x): 0.8838 D(G(z)): 0.5423 / 0.0284
  119. [3/5][1050/1583] Loss_D: 0.8369 Loss_G: 2.1366 D(x): 0.8039 D(G(z)): 0.4067 / 0.1533
  120. [3/5][1100/1583] Loss_D: 0.9522 Loss_G: 3.4744 D(x): 0.8732 D(G(z)): 0.5049 / 0.0412
  121. [3/5][1150/1583] Loss_D: 0.6371 Loss_G: 2.1278 D(x): 0.7648 D(G(z)): 0.2672 / 0.1424
  122. [3/5][1200/1583] Loss_D: 1.0349 Loss_G: 2.7710 D(x): 0.7604 D(G(z)): 0.4512 / 0.0920
  123. [3/5][1250/1583] Loss_D: 0.9350 Loss_G: 2.7946 D(x): 0.8007 D(G(z)): 0.4649 / 0.0805
  124. [3/5][1300/1583] Loss_D: 0.7655 Loss_G: 2.7838 D(x): 0.7965 D(G(z)): 0.3724 / 0.0803
  125. [3/5][1350/1583] Loss_D: 0.7623 Loss_G: 2.2647 D(x): 0.7979 D(G(z)): 0.3641 / 0.1414
  126. [3/5][1400/1583] Loss_D: 0.9361 Loss_G: 3.1341 D(x): 0.8601 D(G(z)): 0.4938 / 0.0628
  127. [3/5][1450/1583] Loss_D: 0.7966 Loss_G: 3.1544 D(x): 0.8568 D(G(z)): 0.4211 / 0.0623
  128. [3/5][1500/1583] Loss_D: 1.0768 Loss_G: 3.8304 D(x): 0.8364 D(G(z)): 0.5348 / 0.0353
  129. [3/5][1550/1583] Loss_D: 0.8528 Loss_G: 3.3978 D(x): 0.8824 D(G(z)): 0.4788 / 0.0491
  130. [4/5][0/1583] Loss_D: 0.8361 Loss_G: 1.9086 D(x): 0.6756 D(G(z)): 0.2975 / 0.1872
  131. [4/5][50/1583] Loss_D: 0.7666 Loss_G: 2.3647 D(x): 0.7698 D(G(z)): 0.3487 / 0.1232
  132. [4/5][100/1583] Loss_D: 0.7536 Loss_G: 1.6556 D(x): 0.6398 D(G(z)): 0.2084 / 0.2423
  133. [4/5][150/1583] Loss_D: 0.8390 Loss_G: 1.7737 D(x): 0.6400 D(G(z)): 0.2714 / 0.2181
  134. [4/5][200/1583] Loss_D: 0.8608 Loss_G: 2.5683 D(x): 0.7898 D(G(z)): 0.4126 / 0.1009
  135. [4/5][250/1583] Loss_D: 0.8651 Loss_G: 1.8416 D(x): 0.6033 D(G(z)): 0.2312 / 0.1954
  136. [4/5][300/1583] Loss_D: 0.8790 Loss_G: 1.2224 D(x): 0.5099 D(G(z)): 0.0960 / 0.3501
  137. [4/5][350/1583] Loss_D: 2.0809 Loss_G: 0.5006 D(x): 0.1907 D(G(z)): 0.0415 / 0.6501
  138. [4/5][400/1583] Loss_D: 1.0178 Loss_G: 2.6912 D(x): 0.7134 D(G(z)): 0.4299 / 0.0977
  139. [4/5][450/1583] Loss_D: 0.7773 Loss_G: 1.5577 D(x): 0.6859 D(G(z)): 0.2705 / 0.2527
  140. [4/5][500/1583] Loss_D: 1.0217 Loss_G: 2.8968 D(x): 0.8227 D(G(z)): 0.5103 / 0.0755
  141. [4/5][550/1583] Loss_D: 0.6428 Loss_G: 2.8346 D(x): 0.8293 D(G(z)): 0.3290 / 0.0793
  142. [4/5][600/1583] Loss_D: 1.7683 Loss_G: 4.1924 D(x): 0.9236 D(G(z)): 0.7656 / 0.0211
  143. [4/5][650/1583] Loss_D: 0.8692 Loss_G: 2.2491 D(x): 0.7046 D(G(z)): 0.3386 / 0.1336
  144. [4/5][700/1583] Loss_D: 0.8933 Loss_G: 1.5814 D(x): 0.6256 D(G(z)): 0.2963 / 0.2476
  145. [4/5][750/1583] Loss_D: 1.2154 Loss_G: 2.6798 D(x): 0.8082 D(G(z)): 0.5792 / 0.0862
  146. [4/5][800/1583] Loss_D: 0.7252 Loss_G: 1.6059 D(x): 0.6257 D(G(z)): 0.1717 / 0.2486
  147. [4/5][850/1583] Loss_D: 0.6888 Loss_G: 2.4141 D(x): 0.7470 D(G(z)): 0.2786 / 0.1207
  148. [4/5][900/1583] Loss_D: 1.0490 Loss_G: 1.1737 D(x): 0.4731 D(G(z)): 0.1746 / 0.3528
  149. [4/5][950/1583] Loss_D: 1.1517 Loss_G: 0.5954 D(x): 0.4083 D(G(z)): 0.0727 / 0.5876
  150. [4/5][1000/1583] Loss_D: 0.7451 Loss_G: 2.1440 D(x): 0.7385 D(G(z)): 0.3118 / 0.1455
  151. [4/5][1050/1583] Loss_D: 1.2439 Loss_G: 0.8178 D(x): 0.3806 D(G(z)): 0.0852 / 0.4825
  152. [4/5][1100/1583] Loss_D: 0.8468 Loss_G: 3.3432 D(x): 0.8220 D(G(z)): 0.4289 / 0.0484
  153. [4/5][1150/1583] Loss_D: 0.9824 Loss_G: 0.8542 D(x): 0.4712 D(G(z)): 0.1120 / 0.4808
  154. [4/5][1200/1583] Loss_D: 1.1658 Loss_G: 3.3930 D(x): 0.8771 D(G(z)): 0.5939 / 0.0450
  155. [4/5][1250/1583] Loss_D: 0.8152 Loss_G: 1.3158 D(x): 0.5988 D(G(z)): 0.1721 / 0.3111
  156. [4/5][1300/1583] Loss_D: 0.7013 Loss_G: 2.0752 D(x): 0.6751 D(G(z)): 0.2173 / 0.1596
  157. [4/5][1350/1583] Loss_D: 0.8809 Loss_G: 3.0340 D(x): 0.8292 D(G(z)): 0.4574 / 0.0636
  158. [4/5][1400/1583] Loss_D: 0.7911 Loss_G: 2.7713 D(x): 0.7982 D(G(z)): 0.3830 / 0.0829
  159. [4/5][1450/1583] Loss_D: 1.0299 Loss_G: 2.8774 D(x): 0.7987 D(G(z)): 0.4941 / 0.0761
  160. [4/5][1500/1583] Loss_D: 0.8572 Loss_G: 2.5340 D(x): 0.7273 D(G(z)): 0.3717 / 0.1009
  161. [4/5][1550/1583] Loss_D: 0.8135 Loss_G: 1.6428 D(x): 0.5799 D(G(z)): 0.1693 / 0.2267

结果

最后,让我们看看我们是如何做到的。 在这里,我们将看三个不同的结果。 首先,我们将了解DG的损失在训练过程中如何变化。 其次,我们将在每个周期将G的输出显示为fixed_noise批量。 第三,我们将查看一批真实数据以及来自G的一批伪数据。

损失与训练迭代

下面是D&G的损失与训练迭代的关系图。

  1. plt.figure(figsize=(10,5))
  2. plt.title("Generator and Discriminator Loss During Training")
  3. plt.plot(G_losses,label="G")
  4. plt.plot(D_losses,label="D")
  5. plt.xlabel("iterations")
  6. plt.ylabel("Loss")
  7. plt.legend()
  8. plt.show()

../_img/sphx_glr_dcgan_faces_tutorial_002.png

可视化G的进度

请记住,在每次训练之后,我们如何将生成器的输出保存为fixed_noise批量。 现在,我们可以用动画形象化G的训练进度。 按下播放按钮开始动画。

  1. #%%capture
  2. fig = plt.figure(figsize=(8,8))
  3. plt.axis("off")
  4. ims = [[plt.imshow(np.transpose(i,(1,2,0)), animated=True)] for i in img_list]
  5. ani = animation.ArtistAnimation(fig, ims, interval=1000, repeat_delay=1000, blit=True)
  6. HTML(ani.to_jshtml())

../_img/sphx_glr_dcgan_faces_tutorial_003.png

真实图像和伪图像

最后,让我们并排查看一些真实图像和伪图像。

  1. # Grab a batch of real images from the dataloader
  2. real_batch = next(iter(dataloader))
  3. # Plot the real images
  4. plt.figure(figsize=(15,15))
  5. plt.subplot(1,2,1)
  6. plt.axis("off")
  7. plt.title("Real Images")
  8. plt.imshow(np.transpose(vutils.make_grid(real_batch[0].to(device)[:64], padding=5, normalize=True).cpu(),(1,2,0)))
  9. # Plot the fake images from the last epoch
  10. plt.subplot(1,2,2)
  11. plt.axis("off")
  12. plt.title("Fake Images")
  13. plt.imshow(np.transpose(img_list[-1],(1,2,0)))
  14. plt.show()

../_img/sphx_glr_dcgan_faces_tutorial_004.png

下一步去哪里

我们已经走到了旅程的尽头,但是您可以从这里到达几个地方。 你可以:

  • 训练更长的时间,看看效果如何
  • 修改此模型以采用其他数据集,并可能更改图像的大小和模型架构
  • 查看其他一些不错的 GAN 项目
  • 创建可生成音乐的 GAN

脚本的总运行时间:(29 分钟 17.480 秒)

下载 Python 源码:dcgan_faces_tutorial.py

下载 Jupyter 笔记本:dcgan_faces_tutorial.ipynb

由 Sphinx 画廊生成的画廊