DCGAN 教程

DCGAN 教程

介绍

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

生成对抗网络

什么是 GAN?

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

现在,让我们从判别器开始定义一些在整个教程中使用的符号。

什么是 DCGAN?

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

from __future__ import print_function
#%matplotlib inline
import argparse
import os
import random
import torch
import torch.nn as nn
import torch.nn.parallel
import torch.backends.cudnn as cudnn
import torch.optim as optim
import torch.utils.data
import torchvision.datasets as dset
import torchvision.transforms as transforms
import torchvision.utils as vutils
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from IPython.display import HTML

# Set random seed for reproducibility
manualSeed = 999
#manualSeed = random.randint(1, 10000) # use if you want new results
print("Random Seed: ", manualSeed)
random.seed(manualSeed)
torch.manual_seed(manualSeed)

出:

Random Seed:  999

输入项

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

  • dataroot -数据集文件夹根目录的路径。 我们将在下一节中进一步讨论数据集
  • worker -使用 DataLoader 加载数据的工作线程数
  • batch_size -训练中使用的批次大小。 DCGAN 纸使用的批处理大小为 128
  • image_size -用于训练的图像的空间大小。 此实现默认为 64x64。 如果需要其他尺寸,则必须更改 D 和 G 的结构。 有关更多详细信息,请参见此处的。
  • nc -输入图像中的颜色通道数。 对于彩色图像,这是 3
  • nz -潜矢量的长度
  • ngf -与通过生成器传送的特征图的深度有关
  • ndf -设置通过鉴别器传播的特征图的深度
  • num_epochs -要运行的训练时期数。 训练更长的时间可能会导致更好的结果,但也会花费更长的时间
  • lr -训练的学习率。 如 DCGAN 文件中所述,此数字应为 0.0002
  • beta1 -Adam 优化器的 beta1 超参数。 如论文所述,该数字应为 0.5
  • ngpu -可用的 GPU 数量。 如果为 0,代码将在 CPU 模式下运行。 如果此数字大于 0,它将在该数量的 GPU 上运行
# Root directory for dataset
dataroot = "data/celeba"

# Number of workers for dataloader
workers = 2

# Batch size during training
batch_size = 128

# Spatial size of training images. All images will be resized to this
#   size using a transformer.
image_size = 64

# Number of channels in the training images. For color images this is 3
nc = 3

# Size of z latent vector (i.e. size of generator input)
nz = 100

# Size of feature maps in generator
ngf = 64

# Size of feature maps in discriminator
ndf = 64

# Number of training epochs
num_epochs = 5

# Learning rate for optimizers
lr = 0.0002

# Beta1 hyperparam for Adam optimizers
beta1 = 0.5

# Number of GPUs available. Use 0 for CPU mode.
ngpu = 1

数据

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

/path/to/celeba
    -> img_align_celeba
        -> 188242.jpg
        -> 173822.jpg
        -> 284702.jpg
        -> 537394.jpg
           ...

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

# We can use an image folder dataset the way we have it setup.
# Create the dataset
dataset = dset.ImageFolder(root=dataroot,
                           transform=transforms.Compose([
                               transforms.Resize(image_size),
                               transforms.CenterCrop(image_size),
                               transforms.ToTensor(),
                               transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),
                           ]))
# Create the dataloader
dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size,
                                         shuffle=True, num_workers=workers)

# Decide which device we want to run on
device = torch.device("cuda:0" if (torch.cuda.is_available() and ngpu > 0) else "cpu")

# Plot some training images
real_batch = next(iter(dataloader))
plt.figure(figsize=(8,8))
plt.axis("off")
plt.title("Training Images")
plt.imshow(np.transpose(vutils.make_grid(real_batch[0].to(device)[:64], padding=2, normalize=True).cpu(),(1,2,0)))

实作

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

重量初始化

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

# custom weights initialization called on netG and netD
def weights_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)

生成器

生成器

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

# Generator Code

class Generator(nn.Module):
    def __init__(self, ngpu):
        super(Generator, self).__init__()
        self.ngpu = ngpu
        self.main = nn.Sequential(
            # input is Z, going into a convolution
            nn.ConvTranspose2d( nz, ngf * 8, 4, 1, 0, bias=False),
            nn.BatchNorm2d(ngf * 8),
            nn.ReLU(True),
            # state size. (ngf*8) x 4 x 4
            nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 4),
            nn.ReLU(True),
            # state size. (ngf*4) x 8 x 8
            nn.ConvTranspose2d( ngf * 4, ngf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf * 2),
            nn.ReLU(True),
            # state size. (ngf*2) x 16 x 16
            nn.ConvTranspose2d( ngf * 2, ngf, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ngf),
            nn.ReLU(True),
            # state size. (ngf) x 32 x 32
            nn.ConvTranspose2d( ngf, nc, 4, 2, 1, bias=False),
            nn.Tanh()
            # state size. (nc) x 64 x 64
        )

    def forward(self, input):
        return self.main(input)

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

# Create the generator
netG = Generator(ngpu).to(device)

# Handle multi-gpu if desired
if (device.type == 'cuda') and (ngpu > 1):
    netG = nn.DataParallel(netG, list(range(ngpu)))

# Apply the weights_init function to randomly initialize all weights
#  to mean=0, stdev=0.2.
netG.apply(weights_init)

# Print the model
print(netG)

Out:

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

鉴别器

如前所述的学习过程都是至关重要的。

鉴别码

class Discriminator(nn.Module):
    def __init__(self, ngpu):
        super(Discriminator, self).__init__()
        self.ngpu = ngpu
        self.main = nn.Sequential(
            # input is (nc) x 64 x 64
            nn.Conv2d(nc, ndf, 4, 2, 1, bias=False),
            nn.LeakyReLU(0.2, inplace=True),
            # state size. (ndf) x 32 x 32
            nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 2),
            nn.LeakyReLU(0.2, inplace=True),
            # state size. (ndf*2) x 16 x 16
            nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 4),
            nn.LeakyReLU(0.2, inplace=True),
            # state size. (ndf*4) x 8 x 8
            nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(ndf * 8),
            nn.LeakyReLU(0.2, inplace=True),
            # state size. (ndf*8) x 4 x 4
            nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),
            nn.Sigmoid()
        )

    def forward(self, input):
        return self.main(input)

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

# Create the Discriminator
netD = Discriminator(ngpu).to(device)

# Handle multi-gpu if desired
if (device.type == 'cuda') and (ngpu > 1):
    netD = nn.DataParallel(netD, list(range(ngpu)))

# Apply the weights_init function to randomly initialize all weights
#  to mean=0, stdev=0.2.
netD.apply(weights_init)

# Print the model
print(netD)

Out:

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

损失函数和优化器

通过,并且在迭代过程中,我们将看到图像形成于噪声之外。

# Initialize BCELoss function
criterion = nn.BCELoss()

# Create batch of latent vectors that we will use to visualize
#  the progression of the generator
fixed_noise = torch.randn(64, nz, 1, 1, device=device)

# Establish convention for real and fake labels during training
real_label = 1
fake_label = 0

# Setup Adam optimizers for both G and D
optimizerD = optim.Adam(netD.parameters(), lr=lr, betas=(beta1, 0.999))
optimizerG = optim.Adam(netG.parameters(), lr=lr, betas=(beta1, 0.999))

训练

最后,既然我们已经定义了 GAN 框架的所有部分,我们就可以对其进行训练。 请注意,训练 GAN 某种程度上是一种艺术形式,因为不正确的超参数设置会导致模式崩溃,而对失败的原因几乎没有解释。 在这里,我们将严格遵循 Goodfellow 论文中的算法 1,同时遵守 ganhacks 中显示的一些最佳做法。 即,我们将“为真实和伪造构建不同的小批量”图像,并调整 G 的目标函数以最大化[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ChIANKly-1690004751238)(img/195908caa7198673e0a28f3f81b251a3.jpg)]。 训练分为两个主要部分。 第 1 部分更新了鉴别器,第 2 部分更新了生成器。

第 1 部分-训练鉴别器

回想一下,训练鉴别器的目的是最大程度地提高将给定输入正确分类为真实或伪造的可能性。 关于古德费罗,我们希望“通过提高随机梯度来更新鉴别器”。 实际上,我们要最大化,然后_向后传递累积_梯度。 现在,利用从所有真实批次和所有伪批次累积的渐变,我们将其称为“鉴别器”优化器的一个步骤。

第 2 部分-训练生成器

如原始论文所述,我们希望通过最小化,这正是我们想要的。_

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

  • Loss_D -鉴别器损失,计算为所有真实批次和所有假批次的损失总和。
  • Loss_G -生成器损耗计算为[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
  • D(x)-所有真实批次的鉴别器的平均输出(整个批次)。 这应该从接近 1 开始,然后在 G 变得更好时理论上收敛到 0.5。 想想这是为什么。
  • D(G(z))-所有假批次的平均鉴别器输出。 第一个数字在 D 更新之前,第二个数字在 D 更新之后。 这些数字应从 0 开始,并随着 G 的提高收敛到 0.5。 想想这是为什么。

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

# Training Loop

# Lists to keep track of progress
img_list = []
G_losses = []
D_losses = []
iters = 0

print("Starting Training Loop...")
# For each epoch
for epoch in range(num_epochs):
    # For each batch in the dataloader
    for i, data in enumerate(dataloader, 0):

        ############################
        # (1) Update D network: maximize log(D(x)) + log(1 - D(G(z)))
        ###########################
        ## Train with all-real batch
        netD.zero_grad()
        # Format batch
        real_cpu = data[0].to(device)
        b_size = real_cpu.size(0)
        label = torch.full((b_size,), real_label, device=device)
        # Forward pass real batch through D
        output = netD(real_cpu).view(-1)
        # Calculate loss on all-real batch
        errD_real = criterion(output, label)
        # Calculate gradients for D in backward pass
        errD_real.backward()
        D_x = output.mean().item()

        ## Train with all-fake batch
        # Generate batch of latent vectors
        noise = torch.randn(b_size, nz, 1, 1, device=device)
        # Generate fake image batch with G
        fake = netG(noise)
        label.fill_(fake_label)
        # Classify all fake batch with D
        output = netD(fake.detach()).view(-1)
        # Calculate D's loss on the all-fake batch
        errD_fake = criterion(output, label)
        # Calculate the gradients for this batch
        errD_fake.backward()
        D_G_z1 = output.mean().item()
        # Add the gradients from the all-real and all-fake batches
        errD = errD_real + errD_fake
        # Update D
        optimizerD.step()

        ############################
        # (2) Update G network: maximize log(D(G(z)))
        ###########################
        netG.zero_grad()
        label.fill_(real_label)  # fake labels are real for generator cost
        # Since we just updated D, perform another forward pass of all-fake batch through D
        output = netD(fake).view(-1)
        # Calculate G's loss based on this output
        errG = criterion(output, label)
        # Calculate gradients for G
        errG.backward()
        D_G_z2 = output.mean().item()
        # Update G
        optimizerG.step()

        # Output training stats
        if i % 50 == 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))

        # Save Losses for plotting later
        G_losses.append(errG.item())
        D_losses.append(errD.item())

        # Check how the generator is doing by saving G's output on fixed_noise
        if (iters % 500 == 0) or ((epoch == num_epochs-1) and (i == len(dataloader)-1)):
            with torch.no_grad():
                fake = netG(fixed_noise).detach().cpu()
            img_list.append(vutils.make_grid(fake, padding=2, normalize=True))

        iters += 1

Out:

Starting Training Loop...
[0/5][0/1583]   Loss_D: 2.0937  Loss_G: 5.2060  D(x): 0.5704    D(G(z)): 0.6680 / 0.0090
[0/5][50/1583]  Loss_D: 0.2073  Loss_G: 12.9653 D(x): 0.9337    D(G(z)): 0.0000 / 0.0000
[0/5][100/1583] Loss_D: 0.0364  Loss_G: 34.5761 D(x): 0.9917    D(G(z)): 0.0000 / 0.0000
[0/5][150/1583] Loss_D: 0.0078  Loss_G: 39.3111 D(x): 0.9947    D(G(z)): 0.0000 / 0.0000
[0/5][200/1583] Loss_D: 0.0029  Loss_G: 38.7681 D(x): 0.9974    D(G(z)): 0.0000 / 0.0000
[0/5][250/1583] Loss_D: 1.2861  Loss_G: 13.3356 D(x): 0.8851    D(G(z)): 0.2970 / 0.0035
[0/5][300/1583] Loss_D: 1.2933  Loss_G: 6.7655  D(x): 0.8533    D(G(z)): 0.5591 / 0.0020
[0/5][350/1583] Loss_D: 0.7473  Loss_G: 3.2617  D(x): 0.5798    D(G(z)): 0.0514 / 0.0483
[0/5][400/1583] Loss_D: 0.5454  Loss_G: 4.0144  D(x): 0.8082    D(G(z)): 0.2346 / 0.0310
[0/5][450/1583] Loss_D: 1.1872  Loss_G: 3.2918  D(x): 0.4389    D(G(z)): 0.0360 / 0.0858
[0/5][500/1583] Loss_D: 0.7546  Loss_G: 4.7428  D(x): 0.9072    D(G(z)): 0.4049 / 0.0178
[0/5][550/1583] Loss_D: 0.3514  Loss_G: 3.7726  D(x): 0.8937    D(G(z)): 0.1709 / 0.0394
[0/5][600/1583] Loss_D: 0.4400  Loss_G: 4.1662  D(x): 0.7768    D(G(z)): 0.1069 / 0.0284
[0/5][650/1583] Loss_D: 0.3275  Loss_G: 4.3374  D(x): 0.8452    D(G(z)): 0.0852 / 0.0214
[0/5][700/1583] Loss_D: 0.7711  Loss_G: 5.0677  D(x): 0.9103    D(G(z)): 0.3848 / 0.0190
[0/5][750/1583] Loss_D: 0.5346  Loss_G: 5.7441  D(x): 0.8971    D(G(z)): 0.2969 / 0.0064
[0/5][800/1583] Loss_D: 0.5027  Loss_G: 2.5982  D(x): 0.6897    D(G(z)): 0.0431 / 0.1196
[0/5][850/1583] Loss_D: 0.4479  Loss_G: 4.8790  D(x): 0.7407    D(G(z)): 0.0456 / 0.0200
[0/5][900/1583] Loss_D: 0.9812  Loss_G: 5.8792  D(x): 0.8895    D(G(z)): 0.4801 / 0.0070
[0/5][950/1583] Loss_D: 0.5154  Loss_G: 3.4813  D(x): 0.7722    D(G(z)): 0.1549 / 0.0449
[0/5][1000/1583]        Loss_D: 0.8468  Loss_G: 6.6179  D(x): 0.8914    D(G(z)): 0.4262 / 0.0030
[0/5][1050/1583]        Loss_D: 0.4425  Loss_G: 3.9902  D(x): 0.8307    D(G(z)): 0.1872 / 0.0270
[0/5][1100/1583]        Loss_D: 0.6800  Loss_G: 4.3945  D(x): 0.8244    D(G(z)): 0.3022 / 0.0223
[0/5][1150/1583]        Loss_D: 0.7227  Loss_G: 2.2669  D(x): 0.6177    D(G(z)): 0.0625 / 0.1613
[0/5][1200/1583]        Loss_D: 0.4061  Loss_G: 5.7088  D(x): 0.9269    D(G(z)): 0.2367 / 0.0071
[0/5][1250/1583]        Loss_D: 0.8514  Loss_G: 3.8994  D(x): 0.7686    D(G(z)): 0.3573 / 0.0330
[0/5][1300/1583]        Loss_D: 0.5323  Loss_G: 3.0046  D(x): 0.7102    D(G(z)): 0.0742 / 0.1138
[0/5][1350/1583]        Loss_D: 0.5793  Loss_G: 4.6804  D(x): 0.8722    D(G(z)): 0.2877 / 0.0169
[0/5][1400/1583]        Loss_D: 0.6849  Loss_G: 5.4391  D(x): 0.8974    D(G(z)): 0.3630 / 0.0100
[0/5][1450/1583]        Loss_D: 1.1515  Loss_G: 6.0096  D(x): 0.8054    D(G(z)): 0.5186 / 0.0049
[0/5][1500/1583]        Loss_D: 0.4771  Loss_G: 3.3768  D(x): 0.8590    D(G(z)): 0.2357 / 0.0541
[0/5][1550/1583]        Loss_D: 0.6947  Loss_G: 5.9660  D(x): 0.8989    D(G(z)): 0.3671 / 0.0064
[1/5][0/1583]   Loss_D: 0.5001  Loss_G: 3.9243  D(x): 0.8238    D(G(z)): 0.2077 / 0.0377
[1/5][50/1583]  Loss_D: 0.4494  Loss_G: 4.4726  D(x): 0.8514    D(G(z)): 0.2159 / 0.0187
[1/5][100/1583] Loss_D: 0.4519  Loss_G: 2.6781  D(x): 0.7331    D(G(z)): 0.0688 / 0.0948
[1/5][150/1583] Loss_D: 0.3808  Loss_G: 3.6005  D(x): 0.8827    D(G(z)): 0.1908 / 0.0456
[1/5][200/1583] Loss_D: 0.4373  Loss_G: 4.0625  D(x): 0.8281    D(G(z)): 0.1719 / 0.0306
[1/5][250/1583] Loss_D: 0.5906  Loss_G: 3.1507  D(x): 0.7603    D(G(z)): 0.1952 / 0.0682
[1/5][300/1583] Loss_D: 1.4315  Loss_G: 6.2042  D(x): 0.9535    D(G(z)): 0.6480 / 0.0051
[1/5][350/1583] Loss_D: 0.8529  Loss_G: 1.2236  D(x): 0.5291    D(G(z)): 0.0552 / 0.3978
[1/5][400/1583] Loss_D: 0.8166  Loss_G: 5.3178  D(x): 0.8460    D(G(z)): 0.3872 / 0.0104
[1/5][450/1583] Loss_D: 0.6699  Loss_G: 2.4998  D(x): 0.6921    D(G(z)): 0.1719 / 0.1220
[1/5][500/1583] Loss_D: 0.4986  Loss_G: 4.3763  D(x): 0.8835    D(G(z)): 0.2643 / 0.0212
[1/5][550/1583] Loss_D: 0.9149  Loss_G: 5.6209  D(x): 0.9476    D(G(z)): 0.5069 / 0.0088
[1/5][600/1583] Loss_D: 0.5116  Loss_G: 3.4946  D(x): 0.8368    D(G(z)): 0.2444 / 0.0488
[1/5][650/1583] Loss_D: 0.4408  Loss_G: 2.8180  D(x): 0.7795    D(G(z)): 0.1262 / 0.0926
[1/5][700/1583] Loss_D: 0.3821  Loss_G: 3.5735  D(x): 0.8237    D(G(z)): 0.1387 / 0.0432
[1/5][750/1583] Loss_D: 0.5042  Loss_G: 2.4218  D(x): 0.6897    D(G(z)): 0.0541 / 0.1319
[1/5][800/1583] Loss_D: 1.3208  Loss_G: 4.7094  D(x): 0.9466    D(G(z)): 0.5988 / 0.0158
[1/5][850/1583] Loss_D: 0.3780  Loss_G: 2.9969  D(x): 0.8475    D(G(z)): 0.1662 / 0.0648
[1/5][900/1583] Loss_D: 0.4350  Loss_G: 3.2726  D(x): 0.8306    D(G(z)): 0.1925 / 0.0531
[1/5][950/1583] Loss_D: 0.4228  Loss_G: 2.5205  D(x): 0.7438    D(G(z)): 0.0493 / 0.1090
[1/5][1000/1583]        Loss_D: 0.4680  Loss_G: 4.4448  D(x): 0.8652    D(G(z)): 0.2433 / 0.0190
[1/5][1050/1583]        Loss_D: 0.4261  Loss_G: 2.7076  D(x): 0.7683    D(G(z)): 0.1049 / 0.0999
[1/5][1100/1583]        Loss_D: 0.5115  Loss_G: 1.9458  D(x): 0.6730    D(G(z)): 0.0449 / 0.2070
[1/5][1150/1583]        Loss_D: 0.6619  Loss_G: 2.0092  D(x): 0.6320    D(G(z)): 0.1115 / 0.1926
[1/5][1200/1583]        Loss_D: 0.4824  Loss_G: 2.0529  D(x): 0.7735    D(G(z)): 0.1647 / 0.1758
[1/5][1250/1583]        Loss_D: 0.4529  Loss_G: 4.3564  D(x): 0.9270    D(G(z)): 0.2881 / 0.0223
[1/5][1300/1583]        Loss_D: 0.5469  Loss_G: 2.5909  D(x): 0.7217    D(G(z)): 0.1403 / 0.1101
[1/5][1350/1583]        Loss_D: 0.4525  Loss_G: 1.4998  D(x): 0.7336    D(G(z)): 0.0904 / 0.2715
[1/5][1400/1583]        Loss_D: 0.5267  Loss_G: 2.3458  D(x): 0.7594    D(G(z)): 0.1700 / 0.1311
[1/5][1450/1583]        Loss_D: 0.4700  Loss_G: 3.7640  D(x): 0.9059    D(G(z)): 0.2852 / 0.0316
[1/5][1500/1583]        Loss_D: 0.7703  Loss_G: 1.4253  D(x): 0.5655    D(G(z)): 0.0683 / 0.3071
[1/5][1550/1583]        Loss_D: 0.5535  Loss_G: 2.4315  D(x): 0.6773    D(G(z)): 0.0834 / 0.1280
[2/5][0/1583]   Loss_D: 0.7237  Loss_G: 3.4642  D(x): 0.8383    D(G(z)): 0.3687 / 0.0442
[2/5][50/1583]  Loss_D: 0.4401  Loss_G: 2.4749  D(x): 0.7939    D(G(z)): 0.1526 / 0.1107
[2/5][100/1583] Loss_D: 0.7470  Loss_G: 1.8611  D(x): 0.5830    D(G(z)): 0.0871 / 0.2102
[2/5][150/1583] Loss_D: 0.7930  Loss_G: 1.3743  D(x): 0.5201    D(G(z)): 0.0343 / 0.3171
[2/5][200/1583] Loss_D: 0.5059  Loss_G: 2.9394  D(x): 0.8044    D(G(z)): 0.2128 / 0.0739
[2/5][250/1583] Loss_D: 0.5873  Loss_G: 1.6961  D(x): 0.6329    D(G(z)): 0.0561 / 0.2297
[2/5][300/1583] Loss_D: 0.5341  Loss_G: 1.9229  D(x): 0.7022    D(G(z)): 0.1145 / 0.1921
[2/5][350/1583] Loss_D: 0.7095  Loss_G: 1.3619  D(x): 0.5855    D(G(z)): 0.0707 / 0.3038
[2/5][400/1583] Loss_D: 0.5163  Loss_G: 3.0209  D(x): 0.8695    D(G(z)): 0.2828 / 0.0657
[2/5][450/1583] Loss_D: 0.5413  Loss_G: 3.5822  D(x): 0.8450    D(G(z)): 0.2748 / 0.0387
[2/5][500/1583] Loss_D: 0.4929  Loss_G: 2.1009  D(x): 0.7645    D(G(z)): 0.1692 / 0.1552
[2/5][550/1583] Loss_D: 0.5042  Loss_G: 2.5833  D(x): 0.7047    D(G(z)): 0.0888 / 0.1107
[2/5][600/1583] Loss_D: 0.4562  Loss_G: 2.5190  D(x): 0.8316    D(G(z)): 0.2151 / 0.0987
[2/5][650/1583] Loss_D: 0.9564  Loss_G: 2.5315  D(x): 0.7157    D(G(z)): 0.3861 / 0.1153
[2/5][700/1583] Loss_D: 0.6706  Loss_G: 3.0991  D(x): 0.7382    D(G(z)): 0.2497 / 0.0603
[2/5][750/1583] Loss_D: 0.5803  Loss_G: 2.9059  D(x): 0.7523    D(G(z)): 0.2092 / 0.0785
[2/5][800/1583] Loss_D: 0.8315  Loss_G: 3.7972  D(x): 0.9184    D(G(z)): 0.4829 / 0.0325
[2/5][850/1583] Loss_D: 0.6177  Loss_G: 2.2548  D(x): 0.7526    D(G(z)): 0.2470 / 0.1306
[2/5][900/1583] Loss_D: 0.7398  Loss_G: 3.2303  D(x): 0.8604    D(G(z)): 0.3999 / 0.0572
[2/5][950/1583] Loss_D: 0.7914  Loss_G: 1.5464  D(x): 0.6001    D(G(z)): 0.1507 / 0.2605
[2/5][1000/1583]        Loss_D: 0.9693  Loss_G: 4.0590  D(x): 0.9251    D(G(z)): 0.5270 / 0.0275
[2/5][1050/1583]        Loss_D: 0.5805  Loss_G: 2.1703  D(x): 0.6749    D(G(z)): 0.1185 / 0.1465
[2/5][1100/1583]        Loss_D: 0.8626  Loss_G: 0.9626  D(x): 0.5259    D(G(z)): 0.0865 / 0.4571
[2/5][1150/1583]        Loss_D: 0.7256  Loss_G: 4.0511  D(x): 0.9135    D(G(z)): 0.4172 / 0.0300
[2/5][1200/1583]        Loss_D: 0.5937  Loss_G: 3.8598  D(x): 0.8982    D(G(z)): 0.3440 / 0.0320
[2/5][1250/1583]        Loss_D: 0.6144  Loss_G: 1.8087  D(x): 0.6660    D(G(z)): 0.1424 / 0.2062
[2/5][1300/1583]        Loss_D: 0.8017  Loss_G: 1.2032  D(x): 0.5450    D(G(z)): 0.0746 / 0.3562
[2/5][1350/1583]        Loss_D: 0.7563  Loss_G: 1.6629  D(x): 0.6002    D(G(z)): 0.1437 / 0.2351
[2/5][1400/1583]        Loss_D: 0.7457  Loss_G: 1.5831  D(x): 0.6069    D(G(z)): 0.1493 / 0.2511
[2/5][1450/1583]        Loss_D: 0.6697  Loss_G: 2.8194  D(x): 0.7597    D(G(z)): 0.2677 / 0.0804
[2/5][1500/1583]        Loss_D: 0.5681  Loss_G: 2.2054  D(x): 0.7171    D(G(z)): 0.1626 / 0.1358
[2/5][1550/1583]        Loss_D: 0.6741  Loss_G: 2.9537  D(x): 0.8373    D(G(z)): 0.3492 / 0.0760
[3/5][0/1583]   Loss_D: 1.0265  Loss_G: 1.1510  D(x): 0.4474    D(G(z)): 0.0685 / 0.3681
[3/5][50/1583]  Loss_D: 0.6190  Loss_G: 1.9895  D(x): 0.7136    D(G(z)): 0.1900 / 0.1705
[3/5][100/1583] Loss_D: 0.7754  Loss_G: 3.2350  D(x): 0.8117    D(G(z)): 0.3782 / 0.0535
[3/5][150/1583] Loss_D: 1.8367  Loss_G: 5.1895  D(x): 0.9408    D(G(z)): 0.7750 / 0.0095
[3/5][200/1583] Loss_D: 0.6821  Loss_G: 2.4254  D(x): 0.7709    D(G(z)): 0.3020 / 0.1152
[3/5][250/1583] Loss_D: 1.1273  Loss_G: 4.2718  D(x): 0.9373    D(G(z)): 0.5970 / 0.0206
[3/5][300/1583] Loss_D: 0.5944  Loss_G: 2.2868  D(x): 0.7547    D(G(z)): 0.2306 / 0.1256
[3/5][350/1583] Loss_D: 0.7941  Loss_G: 3.4394  D(x): 0.7585    D(G(z)): 0.3472 / 0.0437
[3/5][400/1583] Loss_D: 0.7588  Loss_G: 3.7067  D(x): 0.8416    D(G(z)): 0.3981 / 0.0347
[3/5][450/1583] Loss_D: 0.7671  Loss_G: 2.7477  D(x): 0.7932    D(G(z)): 0.3686 / 0.0823
[3/5][500/1583] Loss_D: 1.0295  Loss_G: 1.6097  D(x): 0.6318    D(G(z)): 0.3568 / 0.2429
[3/5][550/1583] Loss_D: 0.5186  Loss_G: 2.1037  D(x): 0.7998    D(G(z)): 0.2266 / 0.1473
[3/5][600/1583] Loss_D: 0.5855  Loss_G: 1.9740  D(x): 0.6520    D(G(z)): 0.0972 / 0.1770
[3/5][650/1583] Loss_D: 0.5954  Loss_G: 2.2880  D(x): 0.7819    D(G(z)): 0.2611 / 0.1234
[3/5][700/1583] Loss_D: 1.0706  Loss_G: 1.1761  D(x): 0.4335    D(G(z)): 0.0681 / 0.3609
[3/5][750/1583] Loss_D: 0.7128  Loss_G: 1.5402  D(x): 0.5909    D(G(z)): 0.0993 / 0.2702
[3/5][800/1583] Loss_D: 0.8883  Loss_G: 2.4234  D(x): 0.8035    D(G(z)): 0.4176 / 0.1206
[3/5][850/1583] Loss_D: 0.7085  Loss_G: 2.7516  D(x): 0.7502    D(G(z)): 0.2918 / 0.0878
[3/5][900/1583] Loss_D: 0.8472  Loss_G: 3.5935  D(x): 0.8553    D(G(z)): 0.4403 / 0.0397
[3/5][950/1583] Loss_D: 0.4454  Loss_G: 2.3438  D(x): 0.7763    D(G(z)): 0.1519 / 0.1226
[3/5][1000/1583]        Loss_D: 1.2425  Loss_G: 1.0600  D(x): 0.3930    D(G(z)): 0.0889 / 0.4122
[3/5][1050/1583]        Loss_D: 1.0465  Loss_G: 1.4973  D(x): 0.4618    D(G(z)): 0.1165 / 0.2906
[3/5][1100/1583]        Loss_D: 0.5885  Loss_G: 2.7760  D(x): 0.8852    D(G(z)): 0.3356 / 0.0854
[3/5][1150/1583]        Loss_D: 0.5940  Loss_G: 2.5669  D(x): 0.7481    D(G(z)): 0.2109 / 0.1001
[3/5][1200/1583]        Loss_D: 0.9074  Loss_G: 3.0569  D(x): 0.7762    D(G(z)): 0.4214 / 0.0644
[3/5][1250/1583]        Loss_D: 0.7487  Loss_G: 3.0959  D(x): 0.8534    D(G(z)): 0.4052 / 0.0601
[3/5][1300/1583]        Loss_D: 0.5956  Loss_G: 2.5807  D(x): 0.7263    D(G(z)): 0.1887 / 0.1039
[3/5][1350/1583]        Loss_D: 1.7038  Loss_G: 0.6425  D(x): 0.2487    D(G(z)): 0.0507 / 0.5746
[3/5][1400/1583]        Loss_D: 0.5863  Loss_G: 1.7754  D(x): 0.6609    D(G(z)): 0.1044 / 0.2069
[3/5][1450/1583]        Loss_D: 0.4925  Loss_G: 2.7946  D(x): 0.7665    D(G(z)): 0.1660 / 0.0864
[3/5][1500/1583]        Loss_D: 0.6616  Loss_G: 2.9829  D(x): 0.9091    D(G(z)): 0.3944 / 0.0654
[3/5][1550/1583]        Loss_D: 1.2097  Loss_G: 1.0897  D(x): 0.4433    D(G(z)): 0.1887 / 0.3918
[4/5][0/1583]   Loss_D: 0.5653  Loss_G: 2.1567  D(x): 0.6781    D(G(z)): 0.1105 / 0.1464
[4/5][50/1583]  Loss_D: 0.7300  Loss_G: 1.7770  D(x): 0.7472    D(G(z)): 0.3011 / 0.2104
[4/5][100/1583] Loss_D: 0.5735  Loss_G: 1.7644  D(x): 0.6723    D(G(z)): 0.1219 / 0.2092
[4/5][150/1583] Loss_D: 1.0598  Loss_G: 0.6708  D(x): 0.4336    D(G(z)): 0.0800 / 0.5560
[4/5][200/1583] Loss_D: 0.6098  Loss_G: 2.0432  D(x): 0.6658    D(G(z)): 0.1378 / 0.1655
[4/5][250/1583] Loss_D: 0.7227  Loss_G: 1.6686  D(x): 0.5750    D(G(z)): 0.0759 / 0.2371
[4/5][300/1583] Loss_D: 0.8077  Loss_G: 2.7966  D(x): 0.7647    D(G(z)): 0.3703 / 0.0771
[4/5][350/1583] Loss_D: 0.7086  Loss_G: 1.3171  D(x): 0.5890    D(G(z)): 0.1103 / 0.3079
[4/5][400/1583] Loss_D: 0.6418  Loss_G: 2.3383  D(x): 0.6284    D(G(z)): 0.1060 / 0.1303
[4/5][450/1583] Loss_D: 0.7046  Loss_G: 3.6138  D(x): 0.8926    D(G(z)): 0.4057 / 0.0354
[4/5][500/1583] Loss_D: 1.7355  Loss_G: 2.1156  D(x): 0.5473    D(G(z)): 0.4802 / 0.2431
[4/5][550/1583] Loss_D: 0.6479  Loss_G: 2.5634  D(x): 0.7987    D(G(z)): 0.3139 / 0.0956
[4/5][600/1583] Loss_D: 0.5650  Loss_G: 1.9429  D(x): 0.6772    D(G(z)): 0.1203 / 0.1713
[4/5][650/1583] Loss_D: 0.9440  Loss_G: 3.2048  D(x): 0.7789    D(G(z)): 0.4225 / 0.0533
[4/5][700/1583] Loss_D: 0.5745  Loss_G: 2.5296  D(x): 0.7004    D(G(z)): 0.1496 / 0.1075
[4/5][750/1583] Loss_D: 0.7448  Loss_G: 1.5417  D(x): 0.5864    D(G(z)): 0.1132 / 0.2617
[4/5][800/1583] Loss_D: 0.5315  Loss_G: 2.4287  D(x): 0.7047    D(G(z)): 0.1254 / 0.1159
[4/5][850/1583] Loss_D: 1.1006  Loss_G: 0.9708  D(x): 0.4101    D(G(z)): 0.0549 / 0.4226
[4/5][900/1583] Loss_D: 0.8635  Loss_G: 1.1581  D(x): 0.5057    D(G(z)): 0.0711 / 0.3618
[4/5][950/1583] Loss_D: 0.5915  Loss_G: 2.8714  D(x): 0.8364    D(G(z)): 0.3005 / 0.0727
[4/5][1000/1583]        Loss_D: 1.5283  Loss_G: 0.4922  D(x): 0.2847    D(G(z)): 0.0228 / 0.6394
[4/5][1050/1583]        Loss_D: 0.7626  Loss_G: 1.7556  D(x): 0.5865    D(G(z)): 0.1282 / 0.2159
[4/5][1100/1583]        Loss_D: 0.6571  Loss_G: 1.7024  D(x): 0.6470    D(G(z)): 0.1505 / 0.2243
[4/5][1150/1583]        Loss_D: 0.7735  Loss_G: 1.2737  D(x): 0.5851    D(G(z)): 0.1427 / 0.3350
[4/5][1200/1583]        Loss_D: 0.4104  Loss_G: 3.2208  D(x): 0.8835    D(G(z)): 0.2290 / 0.0520
[4/5][1250/1583]        Loss_D: 0.4898  Loss_G: 2.1841  D(x): 0.7873    D(G(z)): 0.1912 / 0.1451
[4/5][1300/1583]        Loss_D: 0.6657  Loss_G: 2.5232  D(x): 0.6504    D(G(z)): 0.1283 / 0.1273
[4/5][1350/1583]        Loss_D: 1.0126  Loss_G: 4.9254  D(x): 0.9131    D(G(z)): 0.5439 / 0.0115
[4/5][1400/1583]        Loss_D: 1.2293  Loss_G: 5.6073  D(x): 0.9281    D(G(z)): 0.6209 / 0.0062
[4/5][1450/1583]        Loss_D: 0.3908  Loss_G: 2.4251  D(x): 0.7873    D(G(z)): 0.1181 / 0.1124
[4/5][1500/1583]        Loss_D: 1.1000  Loss_G: 0.9861  D(x): 0.4594    D(G(z)): 0.1542 / 0.4324
[4/5][1550/1583]        Loss_D: 0.9504  Loss_G: 3.8109  D(x): 0.9275    D(G(z)): 0.5386 / 0.0277

结果

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

损失与训练迭代

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

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

可视化 G 的进度

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

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

HTML(ani.to_jshtml())

实像与假像

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

# Grab a batch of real images from the dataloader
real_batch = next(iter(dataloader))

# Plot the real images
plt.figure(figsize=(15,15))
plt.subplot(1,2,1)
plt.axis("off")
plt.title("Real Images")
plt.imshow(np.transpose(vutils.make_grid(real_batch[0].to(device)[:64], padding=5, normalize=True).cpu(),(1,2,0)))

# Plot the fake images from the last epoch
plt.subplot(1,2,2)
plt.axis("off")
plt.title("Fake Images")
plt.imshow(np.transpose(img_list[-1],(1,2,0)))
plt.show()

你可能感兴趣的:(人工智能)