Build a Conditional GAN¶
Goals¶
In this notebook, you're going to make a conditional GAN in order to generate hand-written images of digits, conditioned on the digit to be generated (the class vector). This will let you choose what digit you want to generate.
You'll then do some exploration of the generated images to visualize what the noise and class vectors mean.
Learning Objectives¶
- Learn the technical difference between a conditional and unconditional GAN.
- Understand the distinction between the class and noise vector in a conditional GAN.
Getting Started¶
For this assignment, you will be using the MNIST dataset again, but there's nothing stopping you from applying this generator code to produce images of animals conditioned on the species or pictures of faces conditioned on facial characteristics.
Note that this assignment requires no changes to the architectures of the generator or discriminator, only changes to the data passed to both. The generator will no longer take z_dim as an argument, but input_dim instead, since you need to pass in both the noise and class vectors. In addition to good variable naming, this also means that you can use the generator and discriminator code you have previously written with different parameters.
You will begin by importing the necessary libraries and building the generator and discriminator.
Packages and Visualization¶
import torch
from torch import nn
from tqdm.auto import tqdm
from torchvision import transforms
from torchvision.datasets import MNIST
from torchvision.utils import make_grid
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
torch.manual_seed(0) # Set for our testing purposes, please do not change!
def show_tensor_images(image_tensor, num_images=25, size=(1, 28, 28), nrow=5, show=True):
'''
Function for visualizing images: Given a tensor of images, number of images, and
size per image, plots and prints the images in an uniform grid.
'''
image_tensor = (image_tensor + 1) / 2
image_unflat = image_tensor.detach().cpu()
image_grid = make_grid(image_unflat[:num_images], nrow=nrow)
plt.imshow(image_grid.permute(1, 2, 0).squeeze())
if show:
plt.show()
Generator and Noise¶
class Generator(nn.Module):
'''
Generator Class
Values:
input_dim: the dimension of the input vector, a scalar
im_chan: the number of channels in the images, fitted for the dataset used, a scalar
(MNIST is black-and-white, so 1 channel is your default)
hidden_dim: the inner dimension, a scalar
'''
def __init__(self, input_dim=10, im_chan=1, hidden_dim=64):
super(Generator, self).__init__()
self.input_dim = input_dim
# Build the neural network
self.gen = nn.Sequential(
self.make_gen_block(input_dim, hidden_dim * 4),
self.make_gen_block(hidden_dim * 4, hidden_dim * 2, kernel_size=4, stride=1),
self.make_gen_block(hidden_dim * 2, hidden_dim),
self.make_gen_block(hidden_dim, im_chan, kernel_size=4, final_layer=True),
)
def make_gen_block(self, input_channels, output_channels, kernel_size=3, stride=2, final_layer=False):
'''
Function to return a sequence of operations corresponding to a generator block of DCGAN;
a transposed convolution, a batchnorm (except in the final layer), and an activation.
Parameters:
input_channels: how many channels the input feature representation has
output_channels: how many channels the output feature representation should have
kernel_size: the size of each convolutional filter, equivalent to (kernel_size, kernel_size)
stride: the stride of the convolution
final_layer: a boolean, true if it is the final layer and false otherwise
(affects activation and batchnorm)
'''
if not final_layer:
return nn.Sequential(
nn.ConvTranspose2d(input_channels, output_channels, kernel_size, stride),
nn.BatchNorm2d(output_channels),
nn.ReLU(inplace=True),
)
else:
return nn.Sequential(
nn.ConvTranspose2d(input_channels, output_channels, kernel_size, stride),
nn.Tanh(),
)
def forward(self, noise):
'''
Function for completing a forward pass of the generator: Given a noise tensor,
returns generated images.
Parameters:
noise: a noise tensor with dimensions (n_samples, input_dim)
'''
x = noise.view(len(noise), self.input_dim, 1, 1)
return self.gen(x)
def get_noise(n_samples, input_dim, device='cpu'):
'''
Function for creating noise vectors: Given the dimensions (n_samples, input_dim)
creates a tensor of that shape filled with random numbers from the normal distribution.
Parameters:
n_samples: the number of samples to generate, a scalar
input_dim: the dimension of the input vector, a scalar
device: the device type
'''
return torch.randn(n_samples, input_dim, device=device)
Discriminator¶
class Discriminator(nn.Module):
'''
Discriminator Class
Values:
im_chan: the number of channels in the images, fitted for the dataset used, a scalar
(MNIST is black-and-white, so 1 channel is your default)
hidden_dim: the inner dimension, a scalar
'''
def __init__(self, im_chan=1, hidden_dim=64):
super(Discriminator, self).__init__()
self.disc = nn.Sequential(
self.make_disc_block(im_chan, hidden_dim),
self.make_disc_block(hidden_dim, hidden_dim * 2),
self.make_disc_block(hidden_dim * 2, 1, final_layer=True),
)
def make_disc_block(self, input_channels, output_channels, kernel_size=4, stride=2, final_layer=False):
'''
Function to return a sequence of operations corresponding to a discriminator block of the DCGAN;
a convolution, a batchnorm (except in the final layer), and an activation (except in the final layer).
Parameters:
input_channels: how many channels the input feature representation has
output_channels: how many channels the output feature representation should have
kernel_size: the size of each convolutional filter, equivalent to (kernel_size, kernel_size)
stride: the stride of the convolution
final_layer: a boolean, true if it is the final layer and false otherwise
(affects activation and batchnorm)
'''
if not final_layer:
return nn.Sequential(
nn.Conv2d(input_channels, output_channels, kernel_size, stride),
nn.BatchNorm2d(output_channels),
nn.LeakyReLU(0.2, inplace=True),
)
else:
return nn.Sequential(
nn.Conv2d(input_channels, output_channels, kernel_size, stride),
)
def forward(self, image):
'''
Function for completing a forward pass of the discriminator: Given an image tensor,
returns a 1-dimension tensor representing fake/real.
Parameters:
image: a flattened image tensor with dimension (im_chan)
'''
disc_pred = self.disc(image)
return disc_pred.view(len(disc_pred), -1)
Class Input¶
In conditional GANs, the input vector for the generator will also need to include the class information. The class is represented using a one-hot encoded vector where its length is the number of classes and each index represents a class. The vector is all 0's and a 1 on the chosen class. Given the labels of multiple images (e.g. from a batch) and number of classes, please create one-hot vectors for each label. There is a class within the PyTorch functional library that can help you.
Optional hints for get_one_hot_labels
- This code can be done in one line.
- The documentation for F.one_hot may be helpful.
# UNQ_C1 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)
# GRADED FUNCTION: get_one_hot_labels
import torch.nn.functional as F
def get_one_hot_labels(labels, n_classes):
'''
Function for creating one-hot vectors for the labels, returns a tensor of shape (?, num_classes).
Parameters:
labels: tensor of labels from the dataloader, size (?)
n_classes: the total number of classes in the dataset, an integer scalar
'''
#### START CODE HERE ####
return F.one_hot(labels, n_classes)
#### END CODE HERE ####
assert (
get_one_hot_labels(
labels=torch.Tensor([[0, 2, 1]]).long(),
n_classes=3
).tolist() ==
[[
[1, 0, 0],
[0, 0, 1],
[0, 1, 0]
]]
)
# Check that the device of get_one_hot_labels matches the input device
if torch.cuda.is_available():
assert str(get_one_hot_labels(torch.Tensor([[0]]).long().cuda(), 1).device).startswith("cuda")
print("Success!")
Success!
Next, you need to be able to concatenate the one-hot class vector to the noise vector before giving it to the generator. You will also need to do this when adding the class channels to the discriminator.
To do this, you will need to write a function that combines two vectors. Remember that you need to ensure that the vectors are the same type: floats. Again, you can look to the PyTorch library for help.
Optional hints for combine_vectors
- This code can also be written in one line.
- The documentation for torch.cat may be helpful.
- Specifically, you might want to look at what the
dimargument oftorch.catdoes.
# UNQ_C2 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)
# GRADED FUNCTION: combine_vectors
def combine_vectors(x, y):
'''
Function for combining two vectors with shapes (n_samples, ?) and (n_samples, ?).
Parameters:
x: (n_samples, ?) the first vector.
In this assignment, this will be the noise vector of shape (n_samples, z_dim),
but you shouldn't need to know the second dimension's size.
y: (n_samples, ?) the second vector.
Once again, in this assignment this will be the one-hot class vector
with the shape (n_samples, n_classes), but you shouldn't assume this in your code.
'''
# Note: Make sure this function outputs a float no matter what inputs it receives
#### START CODE HERE ####
combined = torch.cat((x.float(), y.float()), 1)
#### END CODE HERE ####
return combined
combined = combine_vectors(torch.tensor([[1, 2], [3, 4]]), torch.tensor([[5, 6], [7, 8]]))
if torch.cuda.is_available():
# Check that it doesn't break with cuda
cuda_check = combine_vectors(torch.tensor([[1, 2], [3, 4]]).cuda(), torch.tensor([[5, 6], [7, 8]]).cuda())
assert str(cuda_check.device).startswith("cuda")
# Check exact order of elements
assert torch.all(combined == torch.tensor([[1, 2, 5, 6], [3, 4, 7, 8]]))
# Tests that items are of float type
assert (type(combined[0][0].item()) == float)
# Check shapes
combined = combine_vectors(torch.randn(1, 4, 5), torch.randn(1, 8, 5));
assert tuple(combined.shape) == (1, 12, 5)
assert tuple(combine_vectors(torch.randn(1, 10, 12).long(), torch.randn(1, 20, 12).long()).shape) == (1, 30, 12)
# Check that the float transformation doesn't happen after the inputs are concatenated
assert tuple(combine_vectors(torch.randn(1, 10, 12).long(), torch.randn(1, 20, 12)).shape) == (1, 30, 12)
print("Success!")
Success!
Training¶
Now you can start to put it all together! First, you will define some new parameters:
- mnist_shape: the number of pixels in each MNIST image, which has dimensions 28 x 28 and one channel (because it's black-and-white) so 1 x 28 x 28
- n_classes: the number of classes in MNIST (10, since there are the digits from 0 to 9)
mnist_shape = (1, 28, 28)
n_classes = 10
And you also include the same parameters from previous assignments:
- criterion: the loss function
- n_epochs: the number of times you iterate through the entire dataset when training
- z_dim: the dimension of the noise vector
- display_step: how often to display/visualize the images
- batch_size: the number of images per forward/backward pass
- lr: the learning rate
- device: the device type
criterion = nn.BCEWithLogitsLoss()
n_epochs = 200
z_dim = 64
display_step = 500
batch_size = 128
lr = 0.0002
device = 'cuda'
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,)),
])
dataloader = DataLoader(
MNIST('.', download=False, transform=transform),
batch_size=batch_size,
shuffle=True)
Then, you can initialize your generator, discriminator, and optimizers. To do this, you will need to update the input dimensions for both models. For the generator, you will need to calculate the size of the input vector; recall that for conditional GANs, the generator's input is the noise vector concatenated with the class vector. For the discriminator, you need to add a channel for every class.
# UNQ_C3 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)
# GRADED FUNCTION: get_input_dimensions
def get_input_dimensions(z_dim, mnist_shape, n_classes):
'''
Function for getting the size of the conditional input dimensions
from z_dim, the image shape, and number of classes.
Parameters:
z_dim: the dimension of the noise vector, a scalar
mnist_shape: the shape of each MNIST image as (C, W, H), which is (1, 28, 28)
n_classes: the total number of classes in the dataset, an integer scalar
(10 for MNIST)
Returns:
generator_input_dim: the input dimensionality of the conditional generator,
which takes the noise and class vectors
discriminator_im_chan: the number of input channels to the discriminator
(e.g. C x 28 x 28 for MNIST)
'''
#### START CODE HERE ####
generator_input_dim = z_dim + n_classes
discriminator_im_chan = mnist_shape[0] + n_classes
#### END CODE HERE ####
return generator_input_dim, discriminator_im_chan
def test_input_dims():
gen_dim, disc_dim = get_input_dimensions(23, (12, 23, 52), 9)
assert gen_dim == 32
assert disc_dim == 21
test_input_dims()
print("Success!")
Success!
generator_input_dim, discriminator_im_chan = get_input_dimensions(z_dim, mnist_shape, n_classes)
gen = Generator(input_dim=generator_input_dim).to(device)
gen_opt = torch.optim.Adam(gen.parameters(), lr=lr)
disc = Discriminator(im_chan=discriminator_im_chan).to(device)
disc_opt = torch.optim.Adam(disc.parameters(), lr=lr)
def weights_init(m):
if isinstance(m, nn.Conv2d) or isinstance(m, nn.ConvTranspose2d):
torch.nn.init.normal_(m.weight, 0.0, 0.02)
if isinstance(m, nn.BatchNorm2d):
torch.nn.init.normal_(m.weight, 0.0, 0.02)
torch.nn.init.constant_(m.bias, 0)
gen = gen.apply(weights_init)
disc = disc.apply(weights_init)
Now to train, you would like both your generator and your discriminator to know what class of image should be generated. There are a few locations where you will need to implement code.
For example, if you're generating a picture of the number "1", you would need to:
- Tell that to the generator, so that it knows it should be generating a "1"
- Tell that to the discriminator, so that it knows it should be looking at a "1". If the discriminator is told it should be looking at a 1 but sees something that's clearly an 8, it can guess that it's probably fake
There are no explicit unit tests here -- if this block of code runs and you don't change any of the other variables, then you've done it correctly!
# UNQ_C4 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)
# GRADED CELL
cur_step = 0
generator_losses = []
discriminator_losses = []
#UNIT TEST NOTE: Initializations needed for grading
noise_and_labels = False
fake = False
fake_image_and_labels = False
real_image_and_labels = False
disc_fake_pred = False
disc_real_pred = False
for epoch in range(n_epochs):
# Dataloader returns the batches and the labels
for real, labels in tqdm(dataloader):
cur_batch_size = len(real)
# Flatten the batch of real images from the dataset
real = real.to(device)
one_hot_labels = get_one_hot_labels(labels.to(device), n_classes)
image_one_hot_labels = one_hot_labels[:, :, None, None]
image_one_hot_labels = image_one_hot_labels.repeat(1, 1, mnist_shape[1], mnist_shape[2])
### Update discriminator ###
# Zero out the discriminator gradients
disc_opt.zero_grad()
# Get noise corresponding to the current batch_size
fake_noise = get_noise(cur_batch_size, z_dim, device=device)
# Now you can get the images from the generator
# Steps: 1) Combine the noise vectors and the one-hot labels for the generator
# 2) Generate the conditioned fake images
#### START CODE HERE ####
noise_and_labels = combine_vectors(fake_noise, one_hot_labels)
fake = gen(noise_and_labels)
#### END CODE HERE ####
# Make sure that enough images were generated
assert len(fake) == len(real)
# Check that correct tensors were combined
assert tuple(noise_and_labels.shape) == (cur_batch_size, fake_noise.shape[1] + one_hot_labels.shape[1])
# It comes from the correct generator
assert tuple(fake.shape) == (len(real), 1, 28, 28)
# Now you can get the predictions from the discriminator
# Steps: 1) Create the input for the discriminator
# a) Combine the fake images with image_one_hot_labels,
# remember to detach the generator (.detach()) so you do not backpropagate through it
# b) Combine the real images with image_one_hot_labels
# 2) Get the discriminator's prediction on the fakes as disc_fake_pred
# 3) Get the discriminator's prediction on the reals as disc_real_pred
#### START CODE HERE ####
fake_image_and_labels = combine_vectors(fake, image_one_hot_labels)
real_image_and_labels = combine_vectors(real, image_one_hot_labels)
disc_fake_pred = disc(fake_image_and_labels.detach())
disc_real_pred = disc(real_image_and_labels)
#### END CODE HERE ####
# Make sure shapes are correct
assert tuple(fake_image_and_labels.shape) == (len(real), fake.detach().shape[1] + image_one_hot_labels.shape[1], 28 ,28)
assert tuple(real_image_and_labels.shape) == (len(real), real.shape[1] + image_one_hot_labels.shape[1], 28 ,28)
# Make sure that enough predictions were made
assert len(disc_real_pred) == len(real)
# Make sure that the inputs are different
assert torch.any(fake_image_and_labels != real_image_and_labels)
# Shapes must match
assert tuple(fake_image_and_labels.shape) == tuple(real_image_and_labels.shape)
assert tuple(disc_fake_pred.shape) == tuple(disc_real_pred.shape)
disc_fake_loss = criterion(disc_fake_pred, torch.zeros_like(disc_fake_pred))
disc_real_loss = criterion(disc_real_pred, torch.ones_like(disc_real_pred))
disc_loss = (disc_fake_loss + disc_real_loss) / 2
disc_loss.backward(retain_graph=True)
disc_opt.step()
# Keep track of the average discriminator loss
discriminator_losses += [disc_loss.item()]
### Update generator ###
# Zero out the generator gradients
gen_opt.zero_grad()
fake_image_and_labels = combine_vectors(fake, image_one_hot_labels)
# This will error if you didn't concatenate your labels to your image correctly
disc_fake_pred = disc(fake_image_and_labels)
gen_loss = criterion(disc_fake_pred, torch.ones_like(disc_fake_pred))
gen_loss.backward()
gen_opt.step()
# Keep track of the generator losses
generator_losses += [gen_loss.item()]
#
if cur_step % display_step == 0 and cur_step > 0:
gen_mean = sum(generator_losses[-display_step:]) / display_step
disc_mean = sum(discriminator_losses[-display_step:]) / display_step
print(f"Epoch {epoch}, step {cur_step}: Generator loss: {gen_mean}, discriminator loss: {disc_mean}")
show_tensor_images(fake)
show_tensor_images(real)
step_bins = 20
x_axis = sorted([i * step_bins for i in range(len(generator_losses) // step_bins)] * step_bins)
num_examples = (len(generator_losses) // step_bins) * step_bins
plt.plot(
range(num_examples // step_bins),
torch.Tensor(generator_losses[:num_examples]).view(-1, step_bins).mean(1),
label="Generator Loss"
)
plt.plot(
range(num_examples // step_bins),
torch.Tensor(discriminator_losses[:num_examples]).view(-1, step_bins).mean(1),
label="Discriminator Loss"
)
plt.legend()
plt.show()
elif cur_step == 0:
print("Congratulations! If you've gotten here, it's working. Please let this train until you're happy with how the generated numbers look, and then go on to the exploration!")
cur_step += 1
0%| | 0/469 [00:00<?, ?it/s]
Congratulations! If you've gotten here, it's working. Please let this train until you're happy with how the generated numbers look, and then go on to the exploration!
0%| | 0/469 [00:00<?, ?it/s]
Epoch 1, step 500: Generator loss: 2.2115664736032485, discriminator loss: 0.2685868946425617
0%| | 0/469 [00:00<?, ?it/s]
Epoch 2, step 1000: Generator loss: 4.221269572257996, discriminator loss: 0.051587830167263746
0%| | 0/469 [00:00<?, ?it/s]
Epoch 3, step 1500: Generator loss: 4.211510757923127, discriminator loss: 0.05655083135422319
0%| | 0/469 [00:00<?, ?it/s]
Epoch 4, step 2000: Generator loss: 3.2707153000831606, discriminator loss: 0.10579101647436619
0%| | 0/469 [00:00<?, ?it/s]
Epoch 5, step 2500: Generator loss: 2.4357875924110415, discriminator loss: 0.2713673864603043
0%| | 0/469 [00:00<?, ?it/s]
Epoch 6, step 3000: Generator loss: 2.240764480113983, discriminator loss: 0.3099766071140766
0%| | 0/469 [00:00<?, ?it/s]
Epoch 7, step 3500: Generator loss: 1.9961848113536835, discriminator loss: 0.3215213434398174
0%| | 0/469 [00:00<?, ?it/s]
Epoch 8, step 4000: Generator loss: 2.110323561668396, discriminator loss: 0.3168881052732468
0%| | 0/469 [00:00<?, ?it/s]
Epoch 9, step 4500: Generator loss: 2.1868630158901214, discriminator loss: 0.31629042902588844
0%| | 0/469 [00:00<?, ?it/s]
Epoch 10, step 5000: Generator loss: 1.9912456004619599, discriminator loss: 0.3248158627450466
0%| | 0/469 [00:00<?, ?it/s]
Epoch 11, step 5500: Generator loss: 1.8978509147167206, discriminator loss: 0.37217000997066496
0%| | 0/469 [00:00<?, ?it/s]
Epoch 12, step 6000: Generator loss: 1.6967354121208191, discriminator loss: 0.3952812244296074
0%| | 0/469 [00:00<?, ?it/s]
Epoch 13, step 6500: Generator loss: 1.6692118233442306, discriminator loss: 0.42982025346159936
0%| | 0/469 [00:00<?, ?it/s]
Epoch 14, step 7000: Generator loss: 1.6109941833019257, discriminator loss: 0.4480661828517914
0%| | 0/469 [00:00<?, ?it/s]
Epoch 15, step 7500: Generator loss: 1.4511568641662598, discriminator loss: 0.4665398987531662
0%| | 0/469 [00:00<?, ?it/s]
0%| | 0/469 [00:00<?, ?it/s]
Epoch 17, step 8000: Generator loss: 1.463431914329529, discriminator loss: 0.48082829689979556
0%| | 0/469 [00:00<?, ?it/s]
Epoch 18, step 8500: Generator loss: 1.4653161545991897, discriminator loss: 0.4920199128985405
0%| | 0/469 [00:00<?, ?it/s]
Epoch 19, step 9000: Generator loss: 1.3783783526420594, discriminator loss: 0.4872072164714336
0%| | 0/469 [00:00<?, ?it/s]
Epoch 20, step 9500: Generator loss: 1.3555809535980226, discriminator loss: 0.508311718583107
0%| | 0/469 [00:00<?, ?it/s]
Epoch 21, step 10000: Generator loss: 1.2925225931406021, discriminator loss: 0.5252812886238098
0%| | 0/469 [00:00<?, ?it/s]
Epoch 22, step 10500: Generator loss: 1.267152936577797, discriminator loss: 0.5367066763043403
0%| | 0/469 [00:00<?, ?it/s]
Epoch 23, step 11000: Generator loss: 1.2421369094848633, discriminator loss: 0.5377380474209785
0%| | 0/469 [00:00<?, ?it/s]
Epoch 24, step 11500: Generator loss: 1.195749608397484, discriminator loss: 0.5449688808321953
0%| | 0/469 [00:00<?, ?it/s]
Epoch 25, step 12000: Generator loss: 1.2062078047990799, discriminator loss: 0.5494959956407547
0%| | 0/469 [00:00<?, ?it/s]
Epoch 26, step 12500: Generator loss: 1.1992291980981826, discriminator loss: 0.5466335816979409
0%| | 0/469 [00:00<?, ?it/s]
Epoch 27, step 13000: Generator loss: 1.1271400240659715, discriminator loss: 0.5497399532794952
0%| | 0/469 [00:00<?, ?it/s]
Epoch 28, step 13500: Generator loss: 1.1880803110599518, discriminator loss: 0.5669176105856896
0%| | 0/469 [00:00<?, ?it/s]
Epoch 29, step 14000: Generator loss: 1.1068376694917679, discriminator loss: 0.5652729490995407
0%| | 0/469 [00:00<?, ?it/s]
Epoch 30, step 14500: Generator loss: 1.1210307332277298, discriminator loss: 0.5693431765437126
0%| | 0/469 [00:00<?, ?it/s]
Epoch 31, step 15000: Generator loss: 1.1203343322277068, discriminator loss: 0.5783644264936447
0%| | 0/469 [00:00<?, ?it/s]
0%| | 0/469 [00:00<?, ?it/s]
Epoch 33, step 15500: Generator loss: 1.097046187400818, discriminator loss: 0.5738002940416336
0%| | 0/469 [00:00<?, ?it/s]
Epoch 34, step 16000: Generator loss: 1.0974226466417312, discriminator loss: 0.5746870115995407
0%| | 0/469 [00:00<?, ?it/s]
Epoch 35, step 16500: Generator loss: 1.053877674818039, discriminator loss: 0.5848516648411751
0%| | 0/469 [00:00<?, ?it/s]
Epoch 36, step 17000: Generator loss: 1.0862391217947007, discriminator loss: 0.5933754278421401
0%| | 0/469 [00:00<?, ?it/s]
Epoch 37, step 17500: Generator loss: 1.0735066876411439, discriminator loss: 0.5906632270216942
0%| | 0/469 [00:00<?, ?it/s]
Epoch 38, step 18000: Generator loss: 1.0594507942199707, discriminator loss: 0.5892614134550095
0%| | 0/469 [00:00<?, ?it/s]
Epoch 39, step 18500: Generator loss: 1.0485818824768067, discriminator loss: 0.5867860596776009
0%| | 0/469 [00:00<?, ?it/s]
Epoch 40, step 19000: Generator loss: 1.0400051473379135, discriminator loss: 0.5895858646631241
0%| | 0/469 [00:00<?, ?it/s]
Epoch 41, step 19500: Generator loss: 1.0303877574205398, discriminator loss: 0.5942053529024124
0%| | 0/469 [00:00<?, ?it/s]
Epoch 42, step 20000: Generator loss: 1.021188020825386, discriminator loss: 0.5943220034241676
0%| | 0/469 [00:00<?, ?it/s]
Epoch 43, step 20500: Generator loss: 1.0374075932502747, discriminator loss: 0.6046830003857613
0%| | 0/469 [00:00<?, ?it/s]
Epoch 44, step 21000: Generator loss: 1.0003213359117509, discriminator loss: 0.5927331103086472
0%| | 0/469 [00:00<?, ?it/s]
Epoch 45, step 21500: Generator loss: 1.003862419605255, discriminator loss: 0.6006475481390953
0%| | 0/469 [00:00<?, ?it/s]
Epoch 46, step 22000: Generator loss: 1.0291843024492264, discriminator loss: 0.5935961366891861
0%| | 0/469 [00:00<?, ?it/s]
Epoch 47, step 22500: Generator loss: 1.01244744181633, discriminator loss: 0.6002081248164177
0%| | 0/469 [00:00<?, ?it/s]
0%| | 0/469 [00:00<?, ?it/s]
Epoch 49, step 23000: Generator loss: 0.9994891800880432, discriminator loss: 0.5912844946980477
0%| | 0/469 [00:00<?, ?it/s]
Epoch 50, step 23500: Generator loss: 0.9970093793869018, discriminator loss: 0.5980668722987175
0%| | 0/469 [00:00<?, ?it/s]
Epoch 51, step 24000: Generator loss: 0.998129741191864, discriminator loss: 0.5971390585303307
0%| | 0/469 [00:00<?, ?it/s]
Epoch 52, step 24500: Generator loss: 1.0279298236370087, discriminator loss: 0.5956838793754577
0%| | 0/469 [00:00<?, ?it/s]
Epoch 53, step 25000: Generator loss: 1.009993726491928, discriminator loss: 0.5950178966522217
0%| | 0/469 [00:00<?, ?it/s]
Epoch 54, step 25500: Generator loss: 0.9973953018188476, discriminator loss: 0.5946959819793701
0%| | 0/469 [00:00<?, ?it/s]
Epoch 55, step 26000: Generator loss: 0.9892833046913146, discriminator loss: 0.5994198529124259
0%| | 0/469 [00:00<?, ?it/s]
Epoch 56, step 26500: Generator loss: 0.9789396873712539, discriminator loss: 0.5982562866806984
0%| | 0/469 [00:00<?, ?it/s]
Epoch 57, step 27000: Generator loss: 0.9849927604198456, discriminator loss: 0.6008585188388824
0%| | 0/469 [00:00<?, ?it/s]
Epoch 58, step 27500: Generator loss: 0.9754113411903381, discriminator loss: 0.6034010851383209
0%| | 0/469 [00:00<?, ?it/s]
Epoch 59, step 28000: Generator loss: 1.009461210489273, discriminator loss: 0.6033989825248718
0%| | 0/469 [00:00<?, ?it/s]
Epoch 60, step 28500: Generator loss: 0.9828067841529846, discriminator loss: 0.603311533510685
0%| | 0/469 [00:00<?, ?it/s]
Epoch 61, step 29000: Generator loss: 0.9908032495975494, discriminator loss: 0.6042174013257027
0%| | 0/469 [00:00<?, ?it/s]
Epoch 62, step 29500: Generator loss: 0.957794203042984, discriminator loss: 0.607917101919651
0%| | 0/469 [00:00<?, ?it/s]
Epoch 63, step 30000: Generator loss: 0.9627190870046616, discriminator loss: 0.601711801469326
0%| | 0/469 [00:00<?, ?it/s]
0%| | 0/469 [00:00<?, ?it/s]
Epoch 65, step 30500: Generator loss: 0.9748913640975952, discriminator loss: 0.5978434380292893
0%| | 0/469 [00:00<?, ?it/s]
Epoch 66, step 31000: Generator loss: 0.9770773639678955, discriminator loss: 0.6008287969827651
0%| | 0/469 [00:00<?, ?it/s]
Epoch 67, step 31500: Generator loss: 0.9694072247743607, discriminator loss: 0.6035050277709961
0%| | 0/469 [00:00<?, ?it/s]
Epoch 68, step 32000: Generator loss: 0.976947183251381, discriminator loss: 0.6025677533149719
0%| | 0/469 [00:00<?, ?it/s]
Epoch 69, step 32500: Generator loss: 0.972094788312912, discriminator loss: 0.597560405254364
0%| | 0/469 [00:00<?, ?it/s]
Epoch 70, step 33000: Generator loss: 0.9888450082540512, discriminator loss: 0.6054033529162407
0%| | 0/469 [00:00<?, ?it/s]
Epoch 71, step 33500: Generator loss: 0.970538076877594, discriminator loss: 0.5995624731183052
0%| | 0/469 [00:00<?, ?it/s]
Epoch 72, step 34000: Generator loss: 0.9666918925046921, discriminator loss: 0.6075156236886978
0%| | 0/469 [00:00<?, ?it/s]
Epoch 73, step 34500: Generator loss: 0.985197079539299, discriminator loss: 0.6011134975552559
0%| | 0/469 [00:00<?, ?it/s]
Epoch 74, step 35000: Generator loss: 0.9729308484792709, discriminator loss: 0.5966345617771148
0%| | 0/469 [00:00<?, ?it/s]
Epoch 75, step 35500: Generator loss: 0.9634453411102295, discriminator loss: 0.597517226934433
0%| | 0/469 [00:00<?, ?it/s]
Epoch 76, step 36000: Generator loss: 0.9687848848104477, discriminator loss: 0.6013473935723305
0%| | 0/469 [00:00<?, ?it/s]
Epoch 77, step 36500: Generator loss: 0.9802024928331375, discriminator loss: 0.6005387331843376
0%| | 0/469 [00:00<?, ?it/s]
Epoch 78, step 37000: Generator loss: 0.9731533393859864, discriminator loss: 0.5963126164674759
0%| | 0/469 [00:00<?, ?it/s]
Epoch 79, step 37500: Generator loss: 0.9780632754564286, discriminator loss: 0.5968187508583069
0%| | 0/469 [00:00<?, ?it/s]
0%| | 0/469 [00:00<?, ?it/s]
Epoch 81, step 38000: Generator loss: 0.9595166032314301, discriminator loss: 0.5972266513109207
0%| | 0/469 [00:00<?, ?it/s]
Epoch 82, step 38500: Generator loss: 0.9946556317806244, discriminator loss: 0.59203677880764
0%| | 0/469 [00:00<?, ?it/s]
Epoch 83, step 39000: Generator loss: 1.0046718139648438, discriminator loss: 0.6016295446157456
0%| | 0/469 [00:00<?, ?it/s]
Epoch 84, step 39500: Generator loss: 0.9973438510894775, discriminator loss: 0.5925647712945938
0%| | 0/469 [00:00<?, ?it/s]
Epoch 85, step 40000: Generator loss: 0.9907611086368561, discriminator loss: 0.5950615196824074
0%| | 0/469 [00:00<?, ?it/s]
Epoch 86, step 40500: Generator loss: 0.9770873655080795, discriminator loss: 0.5914944817423821
0%| | 0/469 [00:00<?, ?it/s]
Epoch 87, step 41000: Generator loss: 0.9874985775947571, discriminator loss: 0.6006929357051849
0%| | 0/469 [00:00<?, ?it/s]
Epoch 88, step 41500: Generator loss: 0.968919203877449, discriminator loss: 0.5986975821256637
0%| | 0/469 [00:00<?, ?it/s]
Epoch 89, step 42000: Generator loss: 0.9951355646848679, discriminator loss: 0.592059340596199
0%| | 0/469 [00:00<?, ?it/s]
Epoch 90, step 42500: Generator loss: 1.004955737233162, discriminator loss: 0.5939880201816559
0%| | 0/469 [00:00<?, ?it/s]
Epoch 91, step 43000: Generator loss: 0.9943067176342011, discriminator loss: 0.592178800880909
0%| | 0/469 [00:00<?, ?it/s]
Epoch 92, step 43500: Generator loss: 0.9897982699871063, discriminator loss: 0.5893359208703041
0%| | 0/469 [00:00<?, ?it/s]
Epoch 93, step 44000: Generator loss: 1.0014823336601257, discriminator loss: 0.5867925834059715
0%| | 0/469 [00:00<?, ?it/s]
Epoch 94, step 44500: Generator loss: 1.0084335910081863, discriminator loss: 0.588168249309063
0%| | 0/469 [00:00<?, ?it/s]
Epoch 95, step 45000: Generator loss: 0.9918670070171356, discriminator loss: 0.5872072502970695
0%| | 0/469 [00:00<?, ?it/s]
0%| | 0/469 [00:00<?, ?it/s]
Epoch 97, step 45500: Generator loss: 0.9993983345031738, discriminator loss: 0.5832995727658272
0%| | 0/469 [00:00<?, ?it/s]
Epoch 98, step 46000: Generator loss: 1.0084207981824875, discriminator loss: 0.5893421694636345
0%| | 0/469 [00:00<?, ?it/s]
Epoch 99, step 46500: Generator loss: 1.005779152035713, discriminator loss: 0.5812958228588104
0%| | 0/469 [00:00<?, ?it/s]
Epoch 100, step 47000: Generator loss: 1.0012432055473328, discriminator loss: 0.5822467103600502
0%| | 0/469 [00:00<?, ?it/s]
Epoch 101, step 47500: Generator loss: 1.0169043349027633, discriminator loss: 0.5826327429413796
0%| | 0/469 [00:00<?, ?it/s]
Epoch 102, step 48000: Generator loss: 1.0110969021320344, discriminator loss: 0.5813872421383858
0%| | 0/469 [00:00<?, ?it/s]
Epoch 103, step 48500: Generator loss: 1.023488322019577, discriminator loss: 0.5831918702125549
0%| | 0/469 [00:00<?, ?it/s]
Epoch 104, step 49000: Generator loss: 1.0335553978681564, discriminator loss: 0.5784744457006454
0%| | 0/469 [00:00<?, ?it/s]
Epoch 105, step 49500: Generator loss: 1.0189447674751282, discriminator loss: 0.5820126984715461
0%| | 0/469 [00:00<?, ?it/s]
Epoch 106, step 50000: Generator loss: 1.0221210837364196, discriminator loss: 0.5716938080191613
0%| | 0/469 [00:00<?, ?it/s]
Epoch 107, step 50500: Generator loss: 1.0251933991909028, discriminator loss: 0.5766321730017662
0%| | 0/469 [00:00<?, ?it/s]
Epoch 108, step 51000: Generator loss: 1.0197134354114532, discriminator loss: 0.5801153265833855
0%| | 0/469 [00:00<?, ?it/s]
Epoch 109, step 51500: Generator loss: 1.0264078443050384, discriminator loss: 0.573182380259037
0%| | 0/469 [00:00<?, ?it/s]
Epoch 110, step 52000: Generator loss: 1.025400733590126, discriminator loss: 0.578817637860775
0%| | 0/469 [00:00<?, ?it/s]
Epoch 111, step 52500: Generator loss: 1.0250889576673508, discriminator loss: 0.5751831395626068
0%| | 0/469 [00:00<?, ?it/s]
0%| | 0/469 [00:00<?, ?it/s]
Epoch 113, step 53000: Generator loss: 1.0345792025327682, discriminator loss: 0.5761105507016182
0%| | 0/469 [00:00<?, ?it/s]
Epoch 114, step 53500: Generator loss: 1.046409807920456, discriminator loss: 0.5670096014738083
0%| | 0/469 [00:00<?, ?it/s]
Epoch 115, step 54000: Generator loss: 1.043058182477951, discriminator loss: 0.5697268338799477
0%| | 0/469 [00:00<?, ?it/s]
Epoch 116, step 54500: Generator loss: 1.0440865910053254, discriminator loss: 0.5709615953564644
0%| | 0/469 [00:00<?, ?it/s]
Epoch 117, step 55000: Generator loss: 1.0426995037794113, discriminator loss: 0.5676410868763924
0%| | 0/469 [00:00<?, ?it/s]
Epoch 118, step 55500: Generator loss: 1.0447862722873689, discriminator loss: 0.570641079068184
0%| | 0/469 [00:00<?, ?it/s]
Epoch 119, step 56000: Generator loss: 1.0509468381404876, discriminator loss: 0.5667704539299011
0%| | 0/469 [00:00<?, ?it/s]
Epoch 120, step 56500: Generator loss: 1.0431218415498733, discriminator loss: 0.5697332881093026
0%| | 0/469 [00:00<?, ?it/s]
Epoch 121, step 57000: Generator loss: 1.0509914045333861, discriminator loss: 0.5675132256150246
0%| | 0/469 [00:00<?, ?it/s]
Epoch 122, step 57500: Generator loss: 1.0600460569858552, discriminator loss: 0.5695472390055657
0%| | 0/469 [00:00<?, ?it/s]
Epoch 123, step 58000: Generator loss: 1.049864450097084, discriminator loss: 0.5721188992857933
0%| | 0/469 [00:00<?, ?it/s]
Epoch 124, step 58500: Generator loss: 1.057814681649208, discriminator loss: 0.5665506597161293
0%| | 0/469 [00:00<?, ?it/s]
Epoch 125, step 59000: Generator loss: 1.0607161283493043, discriminator loss: 0.5659274329543114
0%| | 0/469 [00:00<?, ?it/s]
Epoch 126, step 59500: Generator loss: 1.0576261911392213, discriminator loss: 0.5697718257308007
0%| | 0/469 [00:00<?, ?it/s]
Epoch 127, step 60000: Generator loss: 1.0615184675455094, discriminator loss: 0.5659393563866615
0%| | 0/469 [00:00<?, ?it/s]
Epoch 128, step 60500: Generator loss: 1.0663750462532045, discriminator loss: 0.5642126491069793
0%| | 0/469 [00:00<?, ?it/s]
0%| | 0/469 [00:00<?, ?it/s]
Epoch 130, step 61000: Generator loss: 1.0743729020357131, discriminator loss: 0.5611261808276177
0%| | 0/469 [00:00<?, ?it/s]
Epoch 131, step 61500: Generator loss: 1.0573465493917464, discriminator loss: 0.5666580362915993
0%| | 0/469 [00:00<?, ?it/s]
Epoch 132, step 62000: Generator loss: 1.0756184371709823, discriminator loss: 0.5646456980109215
0%| | 0/469 [00:00<?, ?it/s]
Epoch 133, step 62500: Generator loss: 1.0694524844884872, discriminator loss: 0.569121537566185
0%| | 0/469 [00:00<?, ?it/s]
Epoch 134, step 63000: Generator loss: 1.0663066757917403, discriminator loss: 0.5699702188372612
0%| | 0/469 [00:00<?, ?it/s]
Epoch 135, step 63500: Generator loss: 1.0663514223098756, discriminator loss: 0.5695594551563263
0%| | 0/469 [00:00<?, ?it/s]
Epoch 136, step 64000: Generator loss: 1.0644668765068055, discriminator loss: 0.5682681980729103
0%| | 0/469 [00:00<?, ?it/s]
Epoch 137, step 64500: Generator loss: 1.0550921256542205, discriminator loss: 0.5696422832608223
0%| | 0/469 [00:00<?, ?it/s]
Epoch 138, step 65000: Generator loss: 1.055631823182106, discriminator loss: 0.5705020905137063
0%| | 0/469 [00:00<?, ?it/s]
Epoch 139, step 65500: Generator loss: 1.058024223446846, discriminator loss: 0.5688595096468926
0%| | 0/469 [00:00<?, ?it/s]
Epoch 140, step 66000: Generator loss: 1.0759759875535966, discriminator loss: 0.573324174284935
0%| | 0/469 [00:00<?, ?it/s]
Epoch 141, step 66500: Generator loss: 1.0771814155578614, discriminator loss: 0.5739586219787598
0%| | 0/469 [00:00<?, ?it/s]
Epoch 142, step 67000: Generator loss: 1.0670026228427887, discriminator loss: 0.565967336654663
0%| | 0/469 [00:00<?, ?it/s]
Epoch 143, step 67500: Generator loss: 1.0589428154230118, discriminator loss: 0.5749310872554779
0%| | 0/469 [00:00<?, ?it/s]
Epoch 144, step 68000: Generator loss: 1.0735257205963136, discriminator loss: 0.5708859901428223
0%| | 0/469 [00:00<?, ?it/s]
Epoch 146, step 68500: Generator loss: 1.085207364320755, discriminator loss: 0.5710993441343307
0%| | 0/469 [00:00<?, ?it/s]
Epoch 147, step 69000: Generator loss: 1.0593492151498796, discriminator loss: 0.5720132147073745
0%| | 0/469 [00:00<?, ?it/s]
Epoch 148, step 69500: Generator loss: 1.064256736278534, discriminator loss: 0.5665577530860901
0%| | 0/469 [00:00<?, ?it/s]
Epoch 149, step 70000: Generator loss: 1.0695160275697708, discriminator loss: 0.573642312347889
0%| | 0/469 [00:00<?, ?it/s]
Epoch 150, step 70500: Generator loss: 1.0682124434709548, discriminator loss: 0.5700670898556709
0%| | 0/469 [00:00<?, ?it/s]
Epoch 151, step 71000: Generator loss: 1.0720481954813004, discriminator loss: 0.5675706258416175
0%| | 0/469 [00:00<?, ?it/s]
Epoch 152, step 71500: Generator loss: 1.0719645861387253, discriminator loss: 0.5696461454629899
0%| | 0/469 [00:00<?, ?it/s]
Epoch 153, step 72000: Generator loss: 1.0640132036209107, discriminator loss: 0.5676938418149948
0%| | 0/469 [00:00<?, ?it/s]
Epoch 154, step 72500: Generator loss: 1.0774863104820251, discriminator loss: 0.5696572477817535
0%| | 0/469 [00:00<?, ?it/s]
Epoch 155, step 73000: Generator loss: 1.0846751042604446, discriminator loss: 0.5695129683613778
0%| | 0/469 [00:00<?, ?it/s]
Epoch 156, step 73500: Generator loss: 1.0688781418800355, discriminator loss: 0.5694116997122765
0%| | 0/469 [00:00<?, ?it/s]
Epoch 157, step 74000: Generator loss: 1.071542314171791, discriminator loss: 0.5739160211086273
0%| | 0/469 [00:00<?, ?it/s]
Epoch 158, step 74500: Generator loss: 1.0847300235033035, discriminator loss: 0.5704194900393486
0%| | 0/469 [00:00<?, ?it/s]
Epoch 159, step 75000: Generator loss: 1.0868128070831298, discriminator loss: 0.5691923908591271
0%| | 0/469 [00:00<?, ?it/s]
Epoch 160, step 75500: Generator loss: 1.055856355190277, discriminator loss: 0.5733889238834381
0%| | 0/469 [00:00<?, ?it/s]
0%| | 0/469 [00:00<?, ?it/s]
Epoch 162, step 76000: Generator loss: 1.0819706790447234, discriminator loss: 0.5653914992213249
0%| | 0/469 [00:00<?, ?it/s]
Epoch 163, step 76500: Generator loss: 1.0538540441989899, discriminator loss: 0.5795382104516029
0%| | 0/469 [00:00<?, ?it/s]
Epoch 164, step 77000: Generator loss: 1.0863464752435683, discriminator loss: 0.568696259200573
0%| | 0/469 [00:00<?, ?it/s]
Epoch 165, step 77500: Generator loss: 1.0780459738969803, discriminator loss: 0.5726611486077309
0%| | 0/469 [00:00<?, ?it/s]
Epoch 166, step 78000: Generator loss: 1.0684958882331848, discriminator loss: 0.5709155834913254
0%| | 0/469 [00:00<?, ?it/s]
Epoch 167, step 78500: Generator loss: 1.0799500557184218, discriminator loss: 0.5744387047886849
0%| | 0/469 [00:00<?, ?it/s]
Epoch 168, step 79000: Generator loss: 1.0891749030351638, discriminator loss: 0.5703308569192886
0%| | 0/469 [00:00<?, ?it/s]
Epoch 169, step 79500: Generator loss: 1.0801849263906478, discriminator loss: 0.5717149977684021
0%| | 0/469 [00:00<?, ?it/s]
Epoch 170, step 80000: Generator loss: 1.0773317233324051, discriminator loss: 0.572909461915493
0%| | 0/469 [00:00<?, ?it/s]
Epoch 171, step 80500: Generator loss: 1.0868586196899415, discriminator loss: 0.5702256690263748
0%| | 0/469 [00:00<?, ?it/s]
Epoch 172, step 81000: Generator loss: 1.0818107388019562, discriminator loss: 0.5666396592259407
0%| | 0/469 [00:00<?, ?it/s]
Epoch 173, step 81500: Generator loss: 1.0765926374197006, discriminator loss: 0.5795883925557137
0%| | 0/469 [00:00<?, ?it/s]
Epoch 174, step 82000: Generator loss: 1.064666698694229, discriminator loss: 0.5703501603603363
0%| | 0/469 [00:00<?, ?it/s]
Epoch 175, step 82500: Generator loss: 1.0683815361261368, discriminator loss: 0.5778474681973458
0%| | 0/469 [00:00<?, ?it/s]
Epoch 176, step 83000: Generator loss: 1.0776479239463805, discriminator loss: 0.5652679976820946
0%| | 0/469 [00:00<?, ?it/s]
0%| | 0/469 [00:00<?, ?it/s]
Epoch 178, step 83500: Generator loss: 1.0784572540521622, discriminator loss: 0.5711396316289902
0%| | 0/469 [00:00<?, ?it/s]
Epoch 179, step 84000: Generator loss: 1.0799720207452774, discriminator loss: 0.5715777632594109
0%| | 0/469 [00:00<?, ?it/s]
Epoch 180, step 84500: Generator loss: 1.0897232381105424, discriminator loss: 0.5722200784087181
0%| | 0/469 [00:00<?, ?it/s]
Epoch 181, step 85000: Generator loss: 1.0807708615064622, discriminator loss: 0.573267793238163
0%| | 0/469 [00:00<?, ?it/s]
Epoch 182, step 85500: Generator loss: 1.0747569193840028, discriminator loss: 0.568444437801838
0%| | 0/469 [00:00<?, ?it/s]
Epoch 183, step 86000: Generator loss: 1.0965240434408188, discriminator loss: 0.5684093906879425
0%| | 0/469 [00:00<?, ?it/s]
Epoch 184, step 86500: Generator loss: 1.0669475437402725, discriminator loss: 0.570864848613739
0%| | 0/469 [00:00<?, ?it/s]
Epoch 185, step 87000: Generator loss: 1.0866483138799667, discriminator loss: 0.5801505998969078
0%| | 0/469 [00:00<?, ?it/s]
Epoch 186, step 87500: Generator loss: 1.0898144243955612, discriminator loss: 0.577188600718975
0%| | 0/469 [00:00<?, ?it/s]
Epoch 187, step 88000: Generator loss: 1.0560118396282197, discriminator loss: 0.57802058416605
0%| | 0/469 [00:00<?, ?it/s]
Epoch 188, step 88500: Generator loss: 1.081513246178627, discriminator loss: 0.5700414397716522
0%| | 0/469 [00:00<?, ?it/s]
Epoch 189, step 89000: Generator loss: 1.08189000415802, discriminator loss: 0.5706097315549851
0%| | 0/469 [00:00<?, ?it/s]
Epoch 190, step 89500: Generator loss: 1.0741279730796813, discriminator loss: 0.5842734354138375
0%| | 0/469 [00:00<?, ?it/s]
Epoch 191, step 90000: Generator loss: 1.0650814998149871, discriminator loss: 0.5789232801198959
0%| | 0/469 [00:00<?, ?it/s]
Epoch 192, step 90500: Generator loss: 1.0703366216421126, discriminator loss: 0.5697177290916443
0%| | 0/469 [00:00<?, ?it/s]
0%| | 0/469 [00:00<?, ?it/s]
Epoch 194, step 91000: Generator loss: 1.0717908999919892, discriminator loss: 0.5789009360074997
0%| | 0/469 [00:00<?, ?it/s]
Epoch 195, step 91500: Generator loss: 1.0874603331089019, discriminator loss: 0.5739682900309563
0%| | 0/469 [00:00<?, ?it/s]
Epoch 196, step 92000: Generator loss: 1.069947368979454, discriminator loss: 0.5766175038814545
0%| | 0/469 [00:00<?, ?it/s]
Epoch 197, step 92500: Generator loss: 1.107958074271679, discriminator loss: 0.5807928264141082
0%| | 0/469 [00:00<?, ?it/s]
Epoch 198, step 93000: Generator loss: 1.0663117953538894, discriminator loss: 0.5773091700673103
0%| | 0/469 [00:00<?, ?it/s]
Epoch 199, step 93500: Generator loss: 1.0706544547080994, discriminator loss: 0.5798768946528434
Exploration¶
You can do a bit of exploration now!
# Before you explore, you should put the generator
# in eval mode, both in general and so that batch norm
# doesn't cause you issues and is using its eval statistics
gen = gen.eval()
Changing the Class Vector¶
You can generate some numbers with your new model! You can add interpolation as well to make it more interesting.
So starting from a image, you will produce intermediate images that look more and more like the ending image until you get to the final image. Your're basically morphing one image into another. You can choose what these two images will be using your conditional GAN.
import math
### Change me! ###
n_interpolation = 9 # Choose the interpolation: how many intermediate images you want + 2 (for the start and end image)
interpolation_noise = get_noise(1, z_dim, device=device).repeat(n_interpolation, 1)
def interpolate_class(first_number, second_number):
first_label = get_one_hot_labels(torch.Tensor([first_number]).long(), n_classes)
second_label = get_one_hot_labels(torch.Tensor([second_number]).long(), n_classes)
# Calculate the interpolation vector between the two labels
percent_second_label = torch.linspace(0, 1, n_interpolation)[:, None]
interpolation_labels = first_label * (1 - percent_second_label) + second_label * percent_second_label
# Combine the noise and the labels
noise_and_labels = combine_vectors(interpolation_noise, interpolation_labels.to(device))
fake = gen(noise_and_labels)
show_tensor_images(fake, num_images=n_interpolation, nrow=int(math.sqrt(n_interpolation)), show=False)
### Change me! ###
start_plot_number = 1 # Choose the start digit
### Change me! ###
end_plot_number = 5 # Choose the end digit
plt.figure(figsize=(8, 8))
interpolate_class(start_plot_number, end_plot_number)
_ = plt.axis('off')
### Uncomment the following lines of code if you would like to visualize a set of pairwise class
### interpolations for a collection of different numbers, all in a single grid of interpolations.
### You'll also see another visualization like this in the next code block!
plot_numbers = [2, 3, 4, 5, 7]
n_numbers = len(plot_numbers)
plt.figure(figsize=(8, 8))
for i, first_plot_number in enumerate(plot_numbers):
for j, second_plot_number in enumerate(plot_numbers):
plt.subplot(n_numbers, n_numbers, i * n_numbers + j + 1)
interpolate_class(first_plot_number, second_plot_number)
plt.axis('off')
plt.subplots_adjust(top=1, bottom=0, left=0, right=1, hspace=0.1, wspace=0)
plt.show()
plt.close()
Changing the Noise Vector¶
Now, what happens if you hold the class constant, but instead you change the noise vector? You can also interpolate the noise vector and generate an image at each step.
n_interpolation = 9 # How many intermediate images you want + 2 (for the start and end image)
# This time you're interpolating between the noise instead of the labels
interpolation_label = get_one_hot_labels(torch.Tensor([5]).long(), n_classes).repeat(n_interpolation, 1).float()
def interpolate_noise(first_noise, second_noise):
# This time you're interpolating between the noise instead of the labels
percent_first_noise = torch.linspace(0, 1, n_interpolation)[:, None].to(device)
interpolation_noise = first_noise * percent_first_noise + second_noise * (1 - percent_first_noise)
# Combine the noise and the labels again
noise_and_labels = combine_vectors(interpolation_noise, interpolation_label.to(device))
fake = gen(noise_and_labels)
show_tensor_images(fake, num_images=n_interpolation, nrow=int(math.sqrt(n_interpolation)), show=False)
# Generate noise vectors to interpolate between
### Change me! ###
n_noise = 5 # Choose the number of noise examples in the grid
plot_noises = [get_noise(1, z_dim, device=device) for i in range(n_noise)]
plt.figure(figsize=(8, 8))
for i, first_plot_noise in enumerate(plot_noises):
for j, second_plot_noise in enumerate(plot_noises):
plt.subplot(n_noise, n_noise, i * n_noise + j + 1)
interpolate_noise(first_plot_noise, second_plot_noise)
plt.axis('off')
plt.subplots_adjust(top=1, bottom=0, left=0, right=1, hspace=0.1, wspace=0)
plt.show()
plt.close()