什么是GAN?
2014年,Goodfellow等人提出了一种生成模型训练方法,简称生成对抗网络(generative Adversarial Networks,简称GANs)。在GAN中,我们构建两种不同的神经网络。我们的第一个网络是传统的分类网络,称为鉴别器。我们将训练鉴别器来拍摄图像,并将其分类为真实(属于训练集)或虚假(不存在于训练集)。我们的另一个网络称为生成器,它将随机噪声作为输入,并使用神经网络对其进行变换以生成图像。生成器的目的是让鉴别器误以为它产生的图像是真实的。
我们可以将生成器()试图愚弄鉴别器()和鉴别器试图正确区分真实与虚假的这种来回过程视为minimax游戏:
minimize G maximize D E x ∼ p data [ log D ( x ) ] + E z ∼ p ( z ) [ log ( 1 − D ( G ( z ) ) ) ] \underset{G}{\text{minimize}}\; \underset{D}{\text{maximize}}\; \mathbb{E}_{x \sim p_\text{data}}\left[\log D(x)\right] + \mathbb{E}_{z \sim p(z)}\left[\log \left(1-D(G(z))\right)\right] GminimizeDmaximizeEx∼pdata[logD(x)]+Ez∼p(z)[log(1−D(G(z)))]
其中~()为随机噪声样本,()为利用神经网络生成器生成的图像,为鉴别器的输出,表示输入为真实的概率。在Goodfellow等人的研究中,他们分析了这个极小极大博弈,并展示了它在训练数据分布和生成的样本之间如何影响minimax Jensen-Shannon divergence(JS散度)
为了优化这个极大极小博弈,我们将交替使用目标上的梯度下降步骤和目标上的梯度上升步骤:
1.更新生成器()以最小化鉴别器做出正确选择的概率。
2.更新鉴别器()以使鉴别器做出正确选择的概率最大化。
虽然这些更新对分析很有用,但它们在实践中表现不佳。相反,当我们更新生成器时,我们将使用一个不同的目标:最大化鉴别器做出错误选择的概率。这个小变化有助于缓解当鉴别器确定时生成器梯度消失的问题。这是大多数GAN论文使用的标准更新,Goodfellow等人的原始论文也使用了该标准。
在这次作业中,我们将交替更新以下内容:
1.更新生成器()以最大限度地提高鉴别器对生成的数据做出错误选择的概率
maximize G E z ∼ p ( z ) [ log D ( G ( z ) ) ] \underset{G}{\text{maximize}}\; \mathbb{E}_{z \sim p(z)}\left[\log D(G(z))\right] GmaximizeEz∼p(z)[logD(G(z))]
2.更新鉴别器(),最大限度地提高鉴别器对真实数据和生成数据做出正确选择的概率:
maximize D E x ∼ p data [ log D ( x ) ] + E z ∼ p ( z ) [ log ( 1 − D ( G ( z ) ) ) ] \underset{D}{\text{maximize}}\; \mathbb{E}_{x \sim p_\text{data}}\left[\log D(x)\right] + \mathbb{E}_{z \sim p(z)}\left[\log \left(1-D(G(z))\right)\right] DmaximizeEx∼pdata[logD(x)]+Ez∼p(z)[log(1−D(G(z)))]
这是一个例子,训练的三个不同模型的输出。请注意,GAN有时很挑剔,所以您的输出可能不完全像这样。这只是关于你所期待的质量的一个粗略的指导方针:
ln[1]:
# Run this cell to see sample outputs.
from IPython.display import Image
Image('images/gan_outputs_pytorch.png')
# Setup cell.
import numpy as np
import torch
import torch.nn as nn
from torch.nn import init
import torchvision
import torchvision.transforms as T
import torch.optim as optim
from torch.utils.data import DataLoader
from torch.utils.data import sampler
import torchvision.datasets as dset
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from cs231n.gan_pytorch import preprocess_img, deprocess_img, rel_error, count_params, ChunkSampler
%matplotlib inline
plt.rcParams['figure.figsize'] = (10.0, 8.0) # Set default size of plots.
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
%load_ext autoreload
%autoreload 2
def show_images(images):
images = np.reshape(images, [images.shape[0], -1]) # Images reshape to (batch_size, D).
sqrtn = int(np.ceil(np.sqrt(images.shape[0])))
sqrtimg = int(np.ceil(np.sqrt(images.shape[1])))
fig = plt.figure(figsize=(sqrtn, sqrtn))
gs = gridspec.GridSpec(sqrtn, sqrtn)
gs.update(wspace=0.05, hspace=0.05)
for i, img in enumerate(images):
ax = plt.subplot(gs[i])
plt.axis('off')
ax.set_xticklabels([])
ax.set_yticklabels([])
ax.set_aspect('equal')
plt.imshow(img.reshape([sqrtimg,sqrtimg]))
return
answers = dict(np.load('gan-checks.npz'))
dtype = torch.cuda.FloatTensor if torch.cuda.is_available() else torch.FloatTensor
数据集
GAN对超参数的挑剔是出了名的,而且还需要许多训练阶段。为了在没有GPU的情况下实现分配,我们将使用MNIST数据集,该数据集包含60,000张训练图像和10,000张测试图像。每幅图片都包含一个黑色背景上的白色数字的中心图像(0到9)。这是最早用于训练卷积神经网络的数据集之一,一个标准的CNN模型可以轻易超过99%的准确率。
为了简化这里的代码,我们将使用PyTorch MNIST包装器,它下载并加载MNIST数据集。有关接口的更多信息,请参阅文档。默认参数将取5000个训练示例,并将它们放入验证数据集。数据将被保存到一个名为MNIST_data的文件夹中。
ln[3]:
NUM_TRAIN = 50000
NUM_VAL = 5000
NOISE_DIM = 96
batch_size = 128
mnist_train = dset.MNIST(
'./cs231n/datasets/MNIST_data',
train=True,
download=True,
transform=T.ToTensor()
)
loader_train = DataLoader(
mnist_train,
batch_size=batch_size,
sampler=ChunkSampler(NUM_TRAIN, 0)
)
mnist_val = dset.MNIST(
'./cs231n/datasets/MNIST_data',
train=True,
download=True,
transform=T.ToTensor()
)
loader_val = DataLoader(
mnist_val,
batch_size=batch_size,
sampler=ChunkSampler(NUM_VAL, NUM_TRAIN)
)
imgs = loader_train.__iter__().next()[0].view(batch_size, 784).numpy().squeeze()
show_images(imgs)
随机噪声
用形状[batch_size, dim]生成从-1到1的均匀噪声。
在cs231n/ gan_pytorch.py中实现sample_noise。
def sample_noise(batch_size, dim, seed=None):
"""
Generate a PyTorch Tensor of uniform random noise.
Input:
- batch_size: Integer giving the batch size of noise to generate.
- dim: Integer giving the dimension of noise to generate.
Output:
- A PyTorch Tensor of shape (batch_size, dim) containing uniform
random noise in the range (-1, 1).
"""
if seed is not None:
torch.manual_seed(seed)
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
#torch.rand是0到1的正态分布,我们要得到-1,1所以我们应该先乘2再-1
return 2 * torch.rand(batch_size, dim) - 1
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
ln[4]:
from cs231n.gan_pytorch import sample_noise
def test_sample_noise():
batch_size = 3
dim = 4
torch.manual_seed(231)
z = sample_noise(batch_size, dim)
np_z = z.cpu().numpy()
assert np_z.shape == (batch_size, dim)
assert torch.is_tensor(z)
assert np.all(np_z >= -1.0) and np.all(np_z <= 1.0)
assert np.any(np_z < 0.0) and np.any(np_z > 0.0)
print('All tests passed!')
test_sample_noise()
Flatten
回想一下我们的Flatten操作…这一次,我们还提供了Unflatten,您可能希望在实现卷积生成器时使用它。我们还提供了一个权重初始化器(并为您调用它),它使用Xavier初始化而不是PyTorch的统一默认值。
ln[5]:
from cs231n.gan_pytorch import Flatten, Unflatten, initialize_weights
鉴别器
我们的第一步是建立一个鉴别器。所有完全连接的层都应该包含偏置项。架构是:
1.全连接层,输入尺寸784和输出尺寸256
2.LeakyReLU与α=0.01
3.全连接层,输入大小256,输出大小256
4.LeakyReLU与α=0.01
5.全连接层,输入尺寸256,输出尺寸1
回想一下Leaky ReLU的非线性计算()=max(,)为某个固定常数;对于上面架构中的LeakyReLU非线性,我们设置=0.01。
该判别器的输出应该是shape [batch_size, 1],并且包含实数,对应每一个batch_size输入的分数都是实数图像。
完成cs231n/gan_pytorch.py中的discriminator
def discriminator(seed=None):
"""
Build and return a PyTorch model implementing the architecture above.
"""
if seed is not None:
torch.manual_seed(seed)
model = None
##############################################################################
# TODO: Implement architecture #
# #
# HINT: nn.Sequential might be helpful. #
##############################################################################
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
model = nn.Sequential(
Flatten(),
nn.Linear(784, 256),
nn.LeakyReLU(),
nn.Linear(256, 256),
nn.LeakyReLU(),
nn.Linear(256, 1)
)
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
##############################################################################
# END OF YOUR CODE #
##############################################################################
return model
ln[6]:
from cs231n.gan_pytorch import discriminator
def test_discriminator(true_count=267009):
model = discriminator()
cur_count = count_params(model)
if cur_count != true_count:
print('Incorrect number of parameters in discriminator. Check your achitecture.')
else:
print('Correct number of parameters in discriminator.')
test_discriminator()
Generator(生成器)
架构:
1.全连接层 from noise_dim to 1024
2.ReLU
3.全连接层尺寸为1024
4.ReLU
5.全连接层尺寸为784
6.TanH 将图像裁剪到[-1,1]范围内
完成 generator in cs231n/gan_pytorch.py
def generator(noise_dim=NOISE_DIM, seed=None):
"""
Build and return a PyTorch model implementing the architecture above.
"""
if seed is not None:
torch.manual_seed(seed)
model = None
##############################################################################
# TODO: Implement architecture #
# #
# HINT: nn.Sequential might be helpful. #
##############################################################################
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
model = nn.Sequential(
nn.Linear(noise_dim, 1024),
nn.ReLU(),
nn.Linear(1024, 1024),
nn.ReLU(),
nn.Linear(1024, 784),
nn.Tanh()
)
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
##############################################################################
# END OF YOUR CODE #
##############################################################################
return model
ln[7]:
from cs231n.gan_pytorch import generator
def test_generator(true_count=1858320):
model = generator(4)
cur_count = count_params(model)
if cur_count != true_count:
print('Incorrect number of parameters in generator. Check your achitecture.')
else:
print('Correct number of parameters in generator.')
test_generator()
GAN Loss
The generator loss is:
ℓ G = − E z ∼ p ( z ) [ log D ( G ( z ) ) ] \ell_G = -\mathbb{E}_{z \sim p(z)}\left[\log D(G(z))\right] ℓG=−Ez∼p(z)[logD(G(z))]
the discriminator loss is:
ℓ D = − E x ∼ p data [ log D ( x ) ] − E z ∼ p ( z ) [ log ( 1 − D ( G ( z ) ) ) ] \ell_D = -\mathbb{E}_{x \sim p_\text{data}}\left[\log D(x)\right] - \mathbb{E}_{z \sim p(z)}\left[\log \left(1-D(G(z))\right)\right] ℓD=−Ex∼pdata[logD(x)]−Ez∼p(z)[log(1−D(G(z)))]
请注意,这些是从前面提出的方程中被否定的,因为我们将最小化这些损失
应该使用下面定义的bce_loss函数来根据鉴别器的logits输出,给出计算真实标签的对数概率所需的二叉熵损失。给定一个分数∈ℝ和一个标签∈{0,1},则二元交叉熵损失为
b c e ( s , y ) = − y ∗ log ( s ) − ( 1 − y ) ∗ log ( 1 − s ) bce(s, y) = -y * \log(s) - (1 - y) * \log(1 - s) bce(s,y)=−y∗log(s)−(1−y)∗log(1−s)
关于这个公式详细解释参考https://blog.csdn.net/qq_23981335/article/details/105701240
这个公式的简单实现可能在数值上不稳定,所以我们在下面为您提供了一个数值稳定的实现。
您还需要计算对应于real或fake的标签,并使用logit参数来确定它们的大小。确保使用全局dtype变量将这些标签强制转换为正确的数据类型,例如:
true_labels = torch.ones(size).type(dtype)
我们不是计算(())、()和(1−(())的期望,而是对minibatch的元素进行平均,因此请确保通过平均而不是求和来合并损失。
完成 bce_loss, discriminator_loss, generator_loss in cs231n/gan_pytorch.py
def bce_loss(input, target):
"""
Numerically stable version of the binary cross-entropy loss function.
As per https://github.com/pytorch/pytorch/issues/751
See the TensorFlow docs for a derivation of this formula:
https://www.tensorflow.org/api_docs/python/tf/nn/sigmoid_cross_entropy_with_logits
Inputs:
- input: PyTorch Tensor of shape (N, ) giving scores.
- target: PyTorch Tensor of shape (N,) containing 0 and 1 giving targets.
Returns:
- A PyTorch Tensor containing the mean BCE loss over the minibatch of input data.
"""
neg_abs = - input.abs()
#input.clamp(min=0) 的意思是 max(0,x)
loss = input.clamp(min=0) - input * target + (1 + neg_abs.exp()).log()
return loss.mean()
def discriminator_loss(logits_real, logits_fake):
"""
Computes the discriminator loss described above.
Inputs:
- logits_real: PyTorch Tensor of shape (N,) giving scores for the real data.
- logits_fake: PyTorch Tensor of shape (N,) giving scores for the fake data.
Returns:
- loss: PyTorch Tensor containing (scalar) the loss for the discriminator.
"""
loss = None
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
labels_real = torch.ones(logits_real.shape).type(dtype)
labels_fake = torch.zeros(logits_fake.shape).type(dtype)
loss = bce_loss(logits_real, labels_real) + bce_loss(logits_fake, labels_fake)
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
return loss
def generator_loss(logits_fake):
"""
Computes the generator loss described above.
Inputs:
- logits_fake: PyTorch Tensor of shape (N,) giving scores for the fake data.
Returns:
- loss: PyTorch Tensor containing the (scalar) loss for the generator.
"""
loss = None
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
labels_fake = torch.ones(logits_fake.shape).type(dtype)
loss = bce_loss(logits_fake, labels_fake)
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
return loss
ln[8]:
from cs231n.gan_pytorch import bce_loss, discriminator_loss, generator_loss
def test_discriminator_loss(logits_real, logits_fake, d_loss_true):
d_loss = discriminator_loss(torch.Tensor(logits_real).type(dtype),
torch.Tensor(logits_fake).type(dtype)).cpu().numpy()
print("Maximum error in d_loss: %g"%rel_error(d_loss_true, d_loss))
test_discriminator_loss(
answers['logits_real'],
answers['logits_fake'],
answers['d_loss_true']
)
ln[9]:
def test_generator_loss(logits_fake, g_loss_true):
g_loss = generator_loss(torch.Tensor(logits_fake).type(dtype)).cpu().numpy()
print("Maximum error in g_loss: %g"%rel_error(g_loss_true, g_loss))
test_generator_loss(
answers['logits_fake'],
answers['g_loss_true']
)
Optimizing our Loss
创建一个返回optim.Adam优化给定模型的学习率为1e-3, beta1=0.5, beta2=0.999。在本笔记本的其余部分中,您将使用它为生成器和鉴别器构建优化器。
完成 get_optimizer in cs231n/gan_pytorch.py
def get_optimizer(model):
"""
Construct and return an Adam optimizer for the model with learning rate 1e-3,
beta1=0.5, and beta2=0.999.
Input:
- model: A PyTorch model that we want to optimize.
Returns:
- An Adam optimizer for the model with the desired hyperparameters.
"""
optimizer = None
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
optimizer = optim.Adam(model.parameters(), lr=1e-3, betas=(0.5, 0.999))
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
return optimizer
Training a GAN!
ln[10]:
from cs231n.gan_pytorch import get_optimizer, run_a_gan
# Make the discriminator
D = discriminator().type(dtype)
# Make the generator
G = generator().type(dtype)
# Use the function you wrote earlier to get optimizers for the Discriminator and the Generator
D_solver = get_optimizer(D)
G_solver = get_optimizer(G)
# Run it!
images = run_a_gan(
D,
G,
D_solver,
G_solver,
discriminator_loss,
generator_loss,
loader_train
)
numIter = 0
for img in images:
print("Iter: {}".format(numIter))
show_images(img)
plt.show()
numIter += 250
print()
# This output is your answer.
print("Vanilla GAN final image:")
show_images(images[-1])
plt.show()
其实也没那么难,对吧?在将近100次的迭代中,你会看到黑色的背景,接近1000次的模糊形状,以及接近3000次的清晰形状。
Least Squares GAN
最小二乘GAN是一种更新、更稳定的GAN损失函数。对于这一部分,我们所要做的就是改变损失函数并对模型进行重新培训。
ℓ G = 1 2 E z ∼ p ( z ) [ ( D ( G ( z ) ) − 1 ) 2 ] \ell_G = \frac{1}{2}\mathbb{E}_{z \sim p(z)}\left[\left(D(G(z))-1\right)^2\right] ℓG=21Ez∼p(z)[(D(G(z))−1)2]
ℓ D = 1 2 E x ∼ p data [ ( D ( x ) − 1 ) 2 ] + 1 2 E z ∼ p ( z ) [ ( D ( G ( z ) ) ) 2 ] \ell_D = \frac{1}{2}\mathbb{E}_{x \sim p_\text{data}}\left[\left(D(x)-1\right)^2\right] + \frac{1}{2}\mathbb{E}_{z \sim p(z)}\left[ \left(D(G(z))\right)^2\right] ℓD=21Ex∼pdata[(D(x)−1)2]+21Ez∼p(z)[(D(G(z)))2]
我们将对minibatch中的元素进行平均,而不是计算期望,因此请确保通过平均而不是求和来合并损失。当插入()和(())时,使用标识符的直接输出(scores_real和scores_fake)。
完成ls_discriminator_loss, ls_generator_loss in cs231n/gan_pytorch.py
def ls_discriminator_loss(scores_real, scores_fake):
"""
Compute the Least-Squares GAN loss for the discriminator.
Inputs:
- scores_real: PyTorch Tensor of shape (N,) giving scores for the real data.
- scores_fake: PyTorch Tensor of shape (N,) giving scores for the fake data.
Outputs:
- loss: A PyTorch Tensor containing the loss.
"""
loss = None
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
loss = 0.5 * torch.mean((scores_real - 1)**2) + 0.5 * torch.mean(scores_fake**2)
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
return loss
def ls_generator_loss(scores_fake):
"""
Computes the Least-Squares GAN loss for the generator.
Inputs:
- scores_fake: PyTorch Tensor of shape (N,) giving scores for the fake data.
Outputs:
- loss: A PyTorch Tensor containing the loss.
"""
loss = None
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
loss = 0.5 * torch.mean((scores_fake - 1)**2)
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
return loss
check
ln[13]:
from cs231n.gan_pytorch import ls_discriminator_loss, ls_generator_loss
def test_lsgan_loss(score_real, score_fake, d_loss_true, g_loss_true):
score_real = torch.Tensor(score_real).type(dtype)
score_fake = torch.Tensor(score_fake).type(dtype)
d_loss = ls_discriminator_loss(score_real, score_fake).cpu().numpy()
g_loss = ls_generator_loss(score_fake).cpu().numpy()
print("Maximum error in d_loss: %g"%rel_error(d_loss_true, d_loss))
print("Maximum error in g_loss: %g"%rel_error(g_loss_true, g_loss))
test_lsgan_loss(
answers['logits_real'],
answers['logits_fake'],
answers['d_loss_lsgan_true'],
answers['g_loss_lsgan_true']
)
D_LS = discriminator().type(dtype)
G_LS = generator().type(dtype)
D_LS_solver = get_optimizer(D_LS)
G_LS_solver = get_optimizer(G_LS)
images = run_a_gan(
D_LS,
G_LS,
D_LS_solver,
G_LS_solver,
ls_discriminator_loss,
ls_generator_loss,
loader_train
)
numIter = 0
for img in images:
print("Iter: {}".format(numIter))
show_images(img)
plt.show()
numIter += 250
print()
ln[16]:
# This output is your answer.
print("LSGAN final image:")
show_images(images[-1])
plt.show()
Deeply Convolutional GANs
我们实现了几乎直接复制Ian Goodfellow的原始GAN网络。然而,这种网络结构不允许真正的空间推理。一般来说,它无法推理出“锐边”之类的东西,因为它缺乏任何卷积层。因此,在本节中,我们将实现DCGAN的一些想法,其中我们使用卷积网络
鉴别器:
我们将使用受TensorFlow MNIST分类教程启发的鉴别器,它能够在MNIST数据集上相当快地获得99%以上的准确率。
1.重塑为图像张量(使用Unflatten!)
2.Conv2D: 32 filter, 5x5, Stride1
3.Leaky ReLU(α= 0.01)
4.Max Pool 2x2, Stride 2
5.Conv2D: 64 filter, 5x5, Stride 1
6.Leaky ReLU(α= 0.01)
7.Max Pool 2x2, Stride 2
8.Flatten
9.全连接输出尺寸4 x 4 x 64
10.Leaky ReLU(α= 0.01)
11.全连接输出尺寸 1
完成 build_dc_classifier in cs231n/gan_pytorch.py
def build_dc_classifier(batch_size):
"""
Build and return a PyTorch model for the DCGAN discriminator implementing
the architecture above.
"""
##############################################################################
# TODO: Implement architecture #
# #
# HINT: nn.Sequential might be helpful. #
##############################################################################
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
model = nn.Sequential(
Unflatten(batch_size, 1, 28, 28), # out: 1 * 28 * 28
nn.Conv2d(1, 32, 5, 1), # out: 32 * 24 * 24
nn.LeakyReLU(),
nn.MaxPool2d(2, 2), # out: 32 * 12 * 12
nn.Conv2d(32, 64, 5, 1), # out: 64 * 8 * 8
nn.LeakyReLU(),
nn.MaxPool2d(2, 2), # out: 64 * 4 * 4
Flatten(),
nn.Linear(64 * 4 * 4, 4 * 4 * 64),
nn.LeakyReLU(),
nn.Linear(4 * 4 * 64, 1)
)
return model
# *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
##############################################################################
# END OF YOUR CODE #
##############################################################################
ln[17]:
from cs231n.gan_pytorch import build_dc_classifier
data = next(enumerate(loader_train))[-1][0].type(dtype)
b = build_dc_classifier(batch_size).type(dtype)
out = b(data)
print(out.size())
def test_dc_classifer(true_count=1102721):
model = build_dc_classifier(batch_size)
cur_count = count_params(model)
if cur_count != true_count:
print('Incorrect number of parameters in generator. Check your achitecture.')
else:
print('Correct number of parameters in generator.')
test_dc_classifer()
2.ReLU
3.BatchNorm
4.全连接输出尺寸7 x 7 x 128
5.ReLU
6.BatchNorm
7.重塑成形状为7,7,128的图像张量
8.Conv2DT(转置):64个4x4滤波器,步幅2,'相同’填充(使用填充=1)
9.ReLU
10.BatchNorm
11.con2d T (Transpose): 1 filter of 4x4, stride 2, ‘same’ padding(使用padding=1)
12.TanH应该有一个28x28x1的图像,重塑回784向量
def build_dc_generator(noise_dim=NOISE_DIM):
"""
Build and return a PyTorch model implementing the DCGAN generator using
the architecture described above.
"""
##############################################################################
# TODO: Implement architecture #
# #
# HINT: nn.Sequential might be helpful. #
##############################################################################
# *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
model = nn.Sequential(
nn.Linear(noise_dim, 1024),
nn.ReLU(),
nn.BatchNorm1d(1024),
nn.Linear(1024, 7 * 7 * 128),
nn.ReLU(),
nn.BatchNorm1d(7 * 7 * 128),
nn.Unflatten(1, (128, 7, 7)),
nn.ConvTranspose2d(128, 64, 4, 2, 1),
nn.ReLU(),
nn.BatchNorm2d(64),
nn.ConvTranspose2d(64, 1, 4, 2, 1),
nn.Tanh(),
nn.Flatten()
)
return model
ln[19]:
from cs231n.gan_pytorch import build_dc_generator
test_g_gan = build_dc_generator().type(dtype)
test_g_gan.apply(initialize_weights)
fake_seed = torch.randn(batch_size, NOISE_DIM).type(dtype)
fake_images = test_g_gan.forward(fake_seed)
fake_images.size()
check
ln[20]:
def test_dc_generator(true_count=6580801):
model = build_dc_generator(4)
cur_count = count_params(model)
if cur_count != true_count:
print('Incorrect number of parameters in generator. Check your achitecture.')
else:
print('Correct number of parameters in generator.')
test_dc_generator()
D_DC = build_dc_classifier(batch_size).type(dtype)
D_DC.apply(initialize_weights)
G_DC = build_dc_generator().type(dtype)
G_DC.apply(initialize_weights)
D_DC_solver = get_optimizer(D_DC)
G_DC_solver = get_optimizer(G_DC)
images = run_a_gan(
D_DC,
G_DC,
D_DC_solver,
G_DC_solver,
discriminator_loss,
generator_loss,
loader_train,
num_epochs=5
)
ln[22]:
numIter = 0
for img in images:
print("Iter: {}".format(numIter))
show_images(img)
plt.show()
numIter += 250
print()
ln[23]:
# This output is your answer.
print("DCGAN final image:")
show_images(images[-1])
plt.show()
内联问题
我们将通过一个例子来了解为什么相同目标的交替最小化(就像GAN)是一件棘手的事情。
考虑()=。minmax(,)的评价是什么?(提示:minmax试图最小化可达到的最大值。)
现在尝试对这个函数进行6步数值计算,从点(1,1)开始,使用交替梯度(首先更新y,然后使用更新的y更新x),步长为1。这里步长是learning_rate,步骤是learning_rate x 梯度。你会发现用,,+1,+1写出更新步骤会很有用。
简要解释minmax(,)的计算结果,并在下表中记录(,)的六对显式值。
内联问题
用这种方法,我们能达到最优值吗?为什么或为什么不?
你的答案:
不,因为我们陷入了一个循环。
内联问题
如果在训练过程中,生成器损失降低,而鉴别器损失从一开始就保持在一个恒定的高值,这是一个好迹象吗?为什么或为什么不?
你的答案:
低的生成器器损失仅仅意味着它产生的数据可以被鉴别器预测为真实数据。然而,鉴别器本身并不是很准确,它的预测也是如此。