GAN Specialization Notes
  • GANs
  • Apply Generative Adversial Networks (GANs)
    • GAN Applications
  • Building Basic Generative Adversial Networks (GANs)
    • Generative Adversial Networks
  • Building Better Generative Adversial Networks (GANs)
    • Building Better GANs
  • Notebooks
    • Components of BigGAN
    • Your First GAN
    • Wasserstein GAN with Gradient Penalty (WGAN-GP)
    • Build a Conditional GAN
    • Controllable Generation
    • Deep Convolutional GAN (DCGAN)
    • Evaluating GANs
    • Neural Radiance Fields (NeRF)
    • Bias
    • Components of StyleGAN
    • Data Augmentation
    • U-Net
    • U-Net
    • Pix2Pix
    • CycleGAN
    • Perceptual Path Length (PPL)
    • Spectrally Normalized Generative Adversarial Networks (SN-GAN)
    • StyleGAN2
  • Previous
  • Next
  • Your First GAN
    • Getting Started
    • Generator
    • Noise
    • Discriminator
    • Training

Your First GAN¶

Goal¶

In this notebook, you're going to create your first generative adversarial network (GAN) for this course! Specifically, you will build and train a GAN that can generate hand-written images of digits (0-9). You will be using PyTorch in this specialization, so if you're not familiar with this framework, you may find the PyTorch documentation useful. The hints will also often include links to relevant documentation.

Learning Objectives¶

  1. Build the generator and discriminator components of a GAN from scratch.
  2. Create generator and discriminator loss functions.
  3. Train your GAN and visualize the generated images.

Getting Started¶

You will begin by importing some useful packages and the dataset you will use to build and train your GAN. You are also provided with a visualizer function to help you investigate the images your GAN will create.

In [1]:
Copied!
import torch
from torch import nn
from tqdm.auto import tqdm
from torchvision import transforms
from torchvision.datasets import MNIST # Training dataset
from torchvision.utils import make_grid
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
torch.manual_seed(0) # Set for testing purposes, please do not change!

def show_tensor_images(image_tensor, num_images=25, size=(1, 28, 28)):
    '''
    Function for visualizing images: Given a tensor of images, number of images, and
    size per image, plots and prints the images in a uniform grid.
    '''
    image_unflat = image_tensor.detach().cpu().view(-1, *size)
    image_grid = make_grid(image_unflat[:num_images], nrow=5)
    plt.imshow(image_grid.permute(1, 2, 0).squeeze())
    plt.show()
import torch from torch import nn from tqdm.auto import tqdm from torchvision import transforms from torchvision.datasets import MNIST # Training dataset from torchvision.utils import make_grid from torch.utils.data import DataLoader import matplotlib.pyplot as plt torch.manual_seed(0) # Set for testing purposes, please do not change! def show_tensor_images(image_tensor, num_images=25, size=(1, 28, 28)): ''' Function for visualizing images: Given a tensor of images, number of images, and size per image, plots and prints the images in a uniform grid. ''' image_unflat = image_tensor.detach().cpu().view(-1, *size) image_grid = make_grid(image_unflat[:num_images], nrow=5) plt.imshow(image_grid.permute(1, 2, 0).squeeze()) plt.show()

MNIST Dataset¶

The training images your discriminator will be using is from a dataset called MNIST. It contains 60,000 images of handwritten digits, from 0 to 9, like these:

MNIST Digits

You may notice that the images are quite pixelated -- this is because they are all only 28 x 28! The small size of its images makes MNIST ideal for simple training. Additionally, these images are also in black-and-white so only one dimension, or "color channel", is needed to represent them (more on this later in the course).

Tensor¶

You will represent the data using tensors. Tensors are a generalization of matrices: for example, a stack of three matrices with the amounts of red, green, and blue at different locations in a 64 x 64 pixel image is a tensor with the shape 3 x 64 x 64.

Tensors are easy to manipulate and supported by PyTorch, the machine learning library you will be using. Feel free to explore them more, but you can imagine these as multi-dimensional matrices or vectors!

Batches¶

While you could train your model after generating one image, it is extremely inefficient and leads to less stable training. In GANs, and in machine learning in general, you will process multiple images per training step. These are called batches.

This means that your generator will generate an entire batch of images and receive the discriminator's feedback on each before updating the model. The same goes for the discriminator, it will calculate its loss on the entire batch of generated images as well as on the reals before the model is updated.

Generator¶

The first step is to build the generator component.

You will start by creating a function to make a single layer/block for the generator's neural network. Each block should include a linear transformation to map to another shape, a batch normalization for stabilization, and finally a non-linear activation function (you use a ReLU here) so the output can be transformed in complex ways. You will learn more about activations and batch normalization later in the course.

In [4]:
Copied!
# UNQ_C1 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)
# GRADED FUNCTION: get_generator_block
def get_generator_block(input_dim, output_dim):
    '''
    Function for returning a block of the generator's neural network
    given input and output dimensions.
    Parameters:
        input_dim: the dimension of the input vector, a scalar
        output_dim: the dimension of the output vector, a scalar
    Returns:
        a generator neural network layer, with a linear transformation 
          followed by a batch normalization and then a relu activation
    '''
    return nn.Sequential(
        # Hint: Replace all of the "None" with the appropriate dimensions.
        # The documentation may be useful if you're less familiar with PyTorch:
        # https://pytorch.org/docs/stable/nn.html.
        #### START CODE HERE ####
        nn.Linear(input_dim, output_dim),
        nn.BatchNorm1d(output_dim),
        #### END CODE HERE ####
        nn.ReLU(inplace=True)
    )
# UNQ_C1 (UNIQUE CELL IDENTIFIER, DO NOT EDIT) # GRADED FUNCTION: get_generator_block def get_generator_block(input_dim, output_dim): ''' Function for returning a block of the generator's neural network given input and output dimensions. Parameters: input_dim: the dimension of the input vector, a scalar output_dim: the dimension of the output vector, a scalar Returns: a generator neural network layer, with a linear transformation followed by a batch normalization and then a relu activation ''' return nn.Sequential( # Hint: Replace all of the "None" with the appropriate dimensions. # The documentation may be useful if you're less familiar with PyTorch: # https://pytorch.org/docs/stable/nn.html. #### START CODE HERE #### nn.Linear(input_dim, output_dim), nn.BatchNorm1d(output_dim), #### END CODE HERE #### nn.ReLU(inplace=True) )
In [5]:
Copied!
# Verify the generator block function
def test_gen_block(in_features, out_features, num_test=1000):
    block = get_generator_block(in_features, out_features)

    # Check the three parts
    assert len(block) == 3
    assert type(block[0]) == nn.Linear
    assert type(block[1]) == nn.BatchNorm1d
    assert type(block[2]) == nn.ReLU
    
    # Check the output shape
    test_input = torch.randn(num_test, in_features)
    test_output = block(test_input)
    assert tuple(test_output.shape) == (num_test, out_features)
    assert test_output.std() > 0.55
    assert test_output.std() < 0.65

test_gen_block(25, 12)
test_gen_block(15, 28)
print("Success!")
# Verify the generator block function def test_gen_block(in_features, out_features, num_test=1000): block = get_generator_block(in_features, out_features) # Check the three parts assert len(block) == 3 assert type(block[0]) == nn.Linear assert type(block[1]) == nn.BatchNorm1d assert type(block[2]) == nn.ReLU # Check the output shape test_input = torch.randn(num_test, in_features) test_output = block(test_input) assert tuple(test_output.shape) == (num_test, out_features) assert test_output.std() > 0.55 assert test_output.std() < 0.65 test_gen_block(25, 12) test_gen_block(15, 28) print("Success!")
Success!

Now you can build the generator class. It will take 3 values:

  • The noise vector dimension
  • The image dimension
  • The initial hidden dimension

Using these values, the generator will build a neural network with 5 layers/blocks. Beginning with the noise vector, the generator will apply non-linear transformations via the block function until the tensor is mapped to the size of the image to be outputted (the same size as the real images from MNIST). You will need to fill in the code for final layer since it is different than the others. The final layer does not need a normalization or activation function, but does need to be scaled with a sigmoid function.

Finally, you are given a forward pass function that takes in a noise vector and generates an image of the output dimension using your neural network.

Optional hints for Generator
  1. The output size of the final linear transformation should be im_dim, but remember you need to scale the outputs between 0 and 1 using the sigmoid function.
  2. nn.Linear and nn.Sigmoid will be useful here.
In [6]:
Copied!
# UNQ_C2 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)
# GRADED FUNCTION: Generator
class Generator(nn.Module):
    '''
    Generator Class
    Values:
        z_dim: the dimension of the noise vector, a scalar
        im_dim: the dimension of the images, fitted for the dataset used, a scalar
          (MNIST images are 28 x 28 = 784 so that is your default)
        hidden_dim: the inner dimension, a scalar
    '''
    def __init__(self, z_dim=10, im_dim=784, hidden_dim=128):
        super(Generator, self).__init__()
        # Build the neural network
        self.gen = nn.Sequential(
            get_generator_block(z_dim, hidden_dim),
            get_generator_block(hidden_dim, hidden_dim * 2),
            get_generator_block(hidden_dim * 2, hidden_dim * 4),
            get_generator_block(hidden_dim * 4, hidden_dim * 8),
            # There is a dropdown with hints if you need them! 
            #### START CODE HERE ####
            nn.Linear(hidden_dim * 8, im_dim),
            nn.Sigmoid()
            #### END CODE HERE ####
        )
    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, z_dim)
        '''
        return self.gen(noise)
    
    # Needed for grading
    def get_gen(self):
        '''
        Returns:
            the sequential model
        '''
        return self.gen
# UNQ_C2 (UNIQUE CELL IDENTIFIER, DO NOT EDIT) # GRADED FUNCTION: Generator class Generator(nn.Module): ''' Generator Class Values: z_dim: the dimension of the noise vector, a scalar im_dim: the dimension of the images, fitted for the dataset used, a scalar (MNIST images are 28 x 28 = 784 so that is your default) hidden_dim: the inner dimension, a scalar ''' def __init__(self, z_dim=10, im_dim=784, hidden_dim=128): super(Generator, self).__init__() # Build the neural network self.gen = nn.Sequential( get_generator_block(z_dim, hidden_dim), get_generator_block(hidden_dim, hidden_dim * 2), get_generator_block(hidden_dim * 2, hidden_dim * 4), get_generator_block(hidden_dim * 4, hidden_dim * 8), # There is a dropdown with hints if you need them! #### START CODE HERE #### nn.Linear(hidden_dim * 8, im_dim), nn.Sigmoid() #### END CODE HERE #### ) 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, z_dim) ''' return self.gen(noise) # Needed for grading def get_gen(self): ''' Returns: the sequential model ''' return self.gen
In [7]:
Copied!
# Verify the generator class
def test_generator(z_dim, im_dim, hidden_dim, num_test=10000):
    gen = Generator(z_dim, im_dim, hidden_dim).get_gen()
    
    # Check there are six modules in the sequential part
    assert len(gen) == 6
    test_input = torch.randn(num_test, z_dim)
    test_output = gen(test_input)

    # Check that the output shape is correct
    assert tuple(test_output.shape) == (num_test, im_dim)
    assert test_output.max() < 1, "Make sure to use a sigmoid"
    assert test_output.min() > 0, "Make sure to use a sigmoid"
    assert test_output.min() < 0.5, "Don't use a block in your solution"
    assert test_output.std() > 0.05, "Don't use batchnorm here"
    assert test_output.std() < 0.15, "Don't use batchnorm here"

test_generator(5, 10, 20)
test_generator(20, 8, 24)
print("Success!")
# Verify the generator class def test_generator(z_dim, im_dim, hidden_dim, num_test=10000): gen = Generator(z_dim, im_dim, hidden_dim).get_gen() # Check there are six modules in the sequential part assert len(gen) == 6 test_input = torch.randn(num_test, z_dim) test_output = gen(test_input) # Check that the output shape is correct assert tuple(test_output.shape) == (num_test, im_dim) assert test_output.max() < 1, "Make sure to use a sigmoid" assert test_output.min() > 0, "Make sure to use a sigmoid" assert test_output.min() < 0.5, "Don't use a block in your solution" assert test_output.std() > 0.05, "Don't use batchnorm here" assert test_output.std() < 0.15, "Don't use batchnorm here" test_generator(5, 10, 20) test_generator(20, 8, 24) print("Success!")
Success!

Noise¶

To be able to use your generator, you will need to be able to create noise vectors. The noise vector z has the important role of making sure the images generated from the same class don't all look the same -- think of it as a random seed. You will generate it randomly using PyTorch by sampling random numbers from the normal distribution. Since multiple images will be processed per pass, you will generate all the noise vectors at once.

Note that whenever you create a new tensor using torch.ones, torch.zeros, or torch.randn, you either need to create it on the target device, e.g. torch.ones(3, 3, device=device), or move it onto the target device using torch.ones(3, 3).to(device). You do not need to do this if you're creating a tensor by manipulating another tensor or by using a variation that defaults the device to the input, such as torch.ones_like. In general, use torch.ones_like and torch.zeros_like instead of torch.ones or torch.zeros where possible.

Optional hint for get_noise
  1. You will probably find torch.randn useful here.
In [8]:
Copied!
# UNQ_C3 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)
# GRADED FUNCTION: get_noise
def get_noise(n_samples, z_dim, device='cpu'):
    '''
    Function for creating noise vectors: Given the dimensions (n_samples, z_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
        z_dim: the dimension of the noise vector, a scalar
        device: the device type
    '''
    # NOTE: To use this on GPU with device='cuda', make sure to pass the device 
    # argument to the function you use to generate the noise.
    #### START CODE HERE ####
    return torch.randn(n_samples, z_dim, device=device)
    #### END CODE HERE ####
# UNQ_C3 (UNIQUE CELL IDENTIFIER, DO NOT EDIT) # GRADED FUNCTION: get_noise def get_noise(n_samples, z_dim, device='cpu'): ''' Function for creating noise vectors: Given the dimensions (n_samples, z_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 z_dim: the dimension of the noise vector, a scalar device: the device type ''' # NOTE: To use this on GPU with device='cuda', make sure to pass the device # argument to the function you use to generate the noise. #### START CODE HERE #### return torch.randn(n_samples, z_dim, device=device) #### END CODE HERE ####
In [9]:
Copied!
# Verify the noise vector function
def test_get_noise(n_samples, z_dim, device='cpu'):
    noise = get_noise(n_samples, z_dim, device)
    
    # Make sure a normal distribution was used
    assert tuple(noise.shape) == (n_samples, z_dim)
    assert torch.abs(noise.std() - torch.tensor(1.0)) < 0.01
    assert str(noise.device).startswith(device)

test_get_noise(1000, 100, 'cpu')
if torch.cuda.is_available():
    test_get_noise(1000, 32, 'cuda')
print("Success!")
# Verify the noise vector function def test_get_noise(n_samples, z_dim, device='cpu'): noise = get_noise(n_samples, z_dim, device) # Make sure a normal distribution was used assert tuple(noise.shape) == (n_samples, z_dim) assert torch.abs(noise.std() - torch.tensor(1.0)) < 0.01 assert str(noise.device).startswith(device) test_get_noise(1000, 100, 'cpu') if torch.cuda.is_available(): test_get_noise(1000, 32, 'cuda') print("Success!")
Success!

Discriminator¶

The second component that you need to construct is the discriminator. As with the generator component, you will start by creating a function that builds a neural network block for the discriminator.

Note: You use leaky ReLUs to prevent the "dying ReLU" problem, which refers to the phenomenon where the parameters stop changing due to consistently negative values passed to a ReLU, which result in a zero gradient. You will learn more about this in the following lectures!

REctified Linear Unit (ReLU) Leaky ReLU
In [10]:
Copied!
# UNQ_C4 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)
# GRADED FUNCTION: get_discriminator_block
def get_discriminator_block(input_dim, output_dim):
    '''
    Discriminator Block
    Function for returning a neural network of the discriminator given input and output dimensions.
    Parameters:
        input_dim: the dimension of the input vector, a scalar
        output_dim: the dimension of the output vector, a scalar
    Returns:
        a discriminator neural network layer, with a linear transformation 
          followed by an nn.LeakyReLU activation with negative slope of 0.2 
          (https://pytorch.org/docs/master/generated/torch.nn.LeakyReLU.html)
    '''
    return nn.Sequential(
        #### START CODE HERE ####
        nn.Linear(input_dim, output_dim),
        nn.LeakyReLU(0.2, inplace=True)
        #### END CODE HERE ####
    )
# UNQ_C4 (UNIQUE CELL IDENTIFIER, DO NOT EDIT) # GRADED FUNCTION: get_discriminator_block def get_discriminator_block(input_dim, output_dim): ''' Discriminator Block Function for returning a neural network of the discriminator given input and output dimensions. Parameters: input_dim: the dimension of the input vector, a scalar output_dim: the dimension of the output vector, a scalar Returns: a discriminator neural network layer, with a linear transformation followed by an nn.LeakyReLU activation with negative slope of 0.2 (https://pytorch.org/docs/master/generated/torch.nn.LeakyReLU.html) ''' return nn.Sequential( #### START CODE HERE #### nn.Linear(input_dim, output_dim), nn.LeakyReLU(0.2, inplace=True) #### END CODE HERE #### )
In [11]:
Copied!
# Verify the discriminator block function
def test_disc_block(in_features, out_features, num_test=10000):
    block = get_discriminator_block(in_features, out_features)

    # Check there are two parts
    assert len(block) == 2
    test_input = torch.randn(num_test, in_features)
    test_output = block(test_input)

    # Check that the shape is right
    assert tuple(test_output.shape) == (num_test, out_features)
    
    # Check that the LeakyReLU slope is about 0.2
    assert -test_output.min() / test_output.max() > 0.1
    assert -test_output.min() / test_output.max() < 0.3
    assert test_output.std() > 0.3
    assert test_output.std() < 0.5

test_disc_block(25, 12)
test_disc_block(15, 28)
print("Success!")
# Verify the discriminator block function def test_disc_block(in_features, out_features, num_test=10000): block = get_discriminator_block(in_features, out_features) # Check there are two parts assert len(block) == 2 test_input = torch.randn(num_test, in_features) test_output = block(test_input) # Check that the shape is right assert tuple(test_output.shape) == (num_test, out_features) # Check that the LeakyReLU slope is about 0.2 assert -test_output.min() / test_output.max() > 0.1 assert -test_output.min() / test_output.max() < 0.3 assert test_output.std() > 0.3 assert test_output.std() < 0.5 test_disc_block(25, 12) test_disc_block(15, 28) print("Success!")
Success!

Now you can use these blocks to make a discriminator! The discriminator class holds 2 values:

  • The image dimension
  • The hidden dimension

The discriminator will build a neural network with 4 layers. It will start with the image tensor and transform it until it returns a single number (1-dimension tensor) output. This output classifies whether an image is fake or real. Note that you do not need a sigmoid after the output layer since it is included in the loss function. Finally, to use your discrimator's neural network you are given a forward pass function that takes in an image tensor to be classified.

In [12]:
Copied!
# UNQ_C5 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)
# GRADED FUNCTION: Discriminator
class Discriminator(nn.Module):
    '''
    Discriminator Class
    Values:
        im_dim: the dimension of the images, fitted for the dataset used, a scalar
            (MNIST images are 28x28 = 784 so that is your default)
        hidden_dim: the inner dimension, a scalar
    '''
    def __init__(self, im_dim=784, hidden_dim=128):
        super(Discriminator, self).__init__()
        self.disc = nn.Sequential(
            get_discriminator_block(im_dim, hidden_dim * 4),
            get_discriminator_block(hidden_dim * 4, hidden_dim * 2),
            get_discriminator_block(hidden_dim * 2, hidden_dim),
            # Hint: You want to transform the final output into a single value,
            #       so add one more linear map.
            #### START CODE HERE ####
            nn.Linear(hidden_dim, 1)
            #### END CODE HERE ####
        )

    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_dim)
        '''
        return self.disc(image)
    
    # Needed for grading
    def get_disc(self):
        '''
        Returns:
            the sequential model
        '''
        return self.disc
# UNQ_C5 (UNIQUE CELL IDENTIFIER, DO NOT EDIT) # GRADED FUNCTION: Discriminator class Discriminator(nn.Module): ''' Discriminator Class Values: im_dim: the dimension of the images, fitted for the dataset used, a scalar (MNIST images are 28x28 = 784 so that is your default) hidden_dim: the inner dimension, a scalar ''' def __init__(self, im_dim=784, hidden_dim=128): super(Discriminator, self).__init__() self.disc = nn.Sequential( get_discriminator_block(im_dim, hidden_dim * 4), get_discriminator_block(hidden_dim * 4, hidden_dim * 2), get_discriminator_block(hidden_dim * 2, hidden_dim), # Hint: You want to transform the final output into a single value, # so add one more linear map. #### START CODE HERE #### nn.Linear(hidden_dim, 1) #### END CODE HERE #### ) 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_dim) ''' return self.disc(image) # Needed for grading def get_disc(self): ''' Returns: the sequential model ''' return self.disc
In [13]:
Copied!
# Verify the discriminator class
def test_discriminator(z_dim, hidden_dim, num_test=100):
    
    disc = Discriminator(z_dim, hidden_dim).get_disc()

    # Check there are three parts
    assert len(disc) == 4

    # Check the linear layer is correct
    test_input = torch.randn(num_test, z_dim)
    test_output = disc(test_input)
    assert tuple(test_output.shape) == (num_test, 1)
    
    # Don't use a block
    assert not isinstance(disc[-1], nn.Sequential)

test_discriminator(5, 10)
test_discriminator(20, 8)
print("Success!")
# Verify the discriminator class def test_discriminator(z_dim, hidden_dim, num_test=100): disc = Discriminator(z_dim, hidden_dim).get_disc() # Check there are three parts assert len(disc) == 4 # Check the linear layer is correct test_input = torch.randn(num_test, z_dim) test_output = disc(test_input) assert tuple(test_output.shape) == (num_test, 1) # Don't use a block assert not isinstance(disc[-1], nn.Sequential) test_discriminator(5, 10) test_discriminator(20, 8) print("Success!")
Success!

Training¶

Now you can put it all together! First, you will set your parameters:

  • 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, here using a GPU (which runs CUDA), not CPU

Next, you will load the MNIST dataset as tensors using a dataloader.

In [14]:
Copied!
# Set your parameters
criterion = nn.BCEWithLogitsLoss()
n_epochs = 200
z_dim = 64
display_step = 500
batch_size = 128
lr = 0.00001

# Load MNIST dataset as tensors
dataloader = DataLoader(
    MNIST('.', download=False, transform=transforms.ToTensor()),
    batch_size=batch_size,
    shuffle=True)

### DO NOT EDIT ###
device = 'cuda'
# Set your parameters criterion = nn.BCEWithLogitsLoss() n_epochs = 200 z_dim = 64 display_step = 500 batch_size = 128 lr = 0.00001 # Load MNIST dataset as tensors dataloader = DataLoader( MNIST('.', download=False, transform=transforms.ToTensor()), batch_size=batch_size, shuffle=True) ### DO NOT EDIT ### device = 'cuda'

Now, you can initialize your generator, discriminator, and optimizers. Note that each optimizer only takes the parameters of one particular model, since we want each optimizer to optimize only one of the models.

In [15]:
Copied!
gen = Generator(z_dim).to(device)
gen_opt = torch.optim.Adam(gen.parameters(), lr=lr)
disc = Discriminator().to(device) 
disc_opt = torch.optim.Adam(disc.parameters(), lr=lr)
gen = Generator(z_dim).to(device) gen_opt = torch.optim.Adam(gen.parameters(), lr=lr) disc = Discriminator().to(device) disc_opt = torch.optim.Adam(disc.parameters(), lr=lr)

Before you train your GAN, you will need to create functions to calculate the discriminator's loss and the generator's loss. This is how the discriminator and generator will know how they are doing and improve themselves. Since the generator is needed when calculating the discriminator's loss, you will need to call .detach() on the generator result to ensure that only the discriminator is updated!

Remember that you have already defined a loss function earlier (criterion) and you are encouraged to use torch.ones_like and torch.zeros_like instead of torch.ones or torch.zeros. If you use torch.ones or torch.zeros, you'll need to pass device=device to them.

In [18]:
Copied!
# UNQ_C6 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)
# GRADED FUNCTION: get_disc_loss
def get_disc_loss(gen, disc, criterion, real, num_images, z_dim, device):
    '''
    Return the loss of the discriminator given inputs.
    Parameters:
        gen: the generator model, which returns an image given z-dimensional noise
        disc: the discriminator model, which returns a single-dimensional prediction of real/fake
        criterion: the loss function, which should be used to compare 
               the discriminator's predictions to the ground truth reality of the images 
               (e.g. fake = 0, real = 1)
        real: a batch of real images
        num_images: the number of images the generator should produce, 
                which is also the length of the real images
        z_dim: the dimension of the noise vector, a scalar
        device: the device type
    Returns:
        disc_loss: a torch scalar loss value for the current batch
    '''
    #     These are the steps you will need to complete:
    #       1) Create noise vectors and generate a batch (num_images) of fake images. 
    #            Make sure to pass the device argument to the noise.
    #       2) Get the discriminator's prediction of the fake image 
    #            and calculate the loss. Don't forget to detach the generator!
    #            (Remember the loss function you set earlier -- criterion. You need a 
    #            'ground truth' tensor in order to calculate the loss. 
    #            For example, a ground truth tensor for a fake image is all zeros.)
    #       3) Get the discriminator's prediction of the real image and calculate the loss.
    #       4) Calculate the discriminator's loss by averaging the real and fake loss
    #            and set it to disc_loss.
    #     *Important*: You should NOT write your own loss function here - use criterion(pred, true)!
    #### START CODE HERE ####
    input_noise = get_noise(num_images, z_dim, device=device)
    
    # Generate fake batch of images
    fake_batch = gen(input_noise)
    discriminator_prediction_on_fake_images = disc(fake_batch.detach())
    discriminator_fake_loss = criterion(discriminator_prediction_on_fake_images, torch.zeros_like(discriminator_prediction_on_fake_images))
    discriminator_prediction_on_real_images = disc(real)
    discriminator_real_loss = criterion(discriminator_prediction_on_real_images, torch.ones_like(discriminator_prediction_on_real_images))
    disc_loss = (discriminator_fake_loss + discriminator_real_loss) / 2
    #### END CODE HERE ####
    return disc_loss
# UNQ_C6 (UNIQUE CELL IDENTIFIER, DO NOT EDIT) # GRADED FUNCTION: get_disc_loss def get_disc_loss(gen, disc, criterion, real, num_images, z_dim, device): ''' Return the loss of the discriminator given inputs. Parameters: gen: the generator model, which returns an image given z-dimensional noise disc: the discriminator model, which returns a single-dimensional prediction of real/fake criterion: the loss function, which should be used to compare the discriminator's predictions to the ground truth reality of the images (e.g. fake = 0, real = 1) real: a batch of real images num_images: the number of images the generator should produce, which is also the length of the real images z_dim: the dimension of the noise vector, a scalar device: the device type Returns: disc_loss: a torch scalar loss value for the current batch ''' # These are the steps you will need to complete: # 1) Create noise vectors and generate a batch (num_images) of fake images. # Make sure to pass the device argument to the noise. # 2) Get the discriminator's prediction of the fake image # and calculate the loss. Don't forget to detach the generator! # (Remember the loss function you set earlier -- criterion. You need a # 'ground truth' tensor in order to calculate the loss. # For example, a ground truth tensor for a fake image is all zeros.) # 3) Get the discriminator's prediction of the real image and calculate the loss. # 4) Calculate the discriminator's loss by averaging the real and fake loss # and set it to disc_loss. # *Important*: You should NOT write your own loss function here - use criterion(pred, true)! #### START CODE HERE #### input_noise = get_noise(num_images, z_dim, device=device) # Generate fake batch of images fake_batch = gen(input_noise) discriminator_prediction_on_fake_images = disc(fake_batch.detach()) discriminator_fake_loss = criterion(discriminator_prediction_on_fake_images, torch.zeros_like(discriminator_prediction_on_fake_images)) discriminator_prediction_on_real_images = disc(real) discriminator_real_loss = criterion(discriminator_prediction_on_real_images, torch.ones_like(discriminator_prediction_on_real_images)) disc_loss = (discriminator_fake_loss + discriminator_real_loss) / 2 #### END CODE HERE #### return disc_loss
In [19]:
Copied!
def test_disc_reasonable(num_images=10):
    # Don't use explicit casts to cuda - use the device argument
    import inspect, re
    lines = inspect.getsource(get_disc_loss)
    assert (re.search(r"to\(.cuda.\)", lines)) is None
    assert (re.search(r"\.cuda\(\)", lines)) is None
    
    z_dim = 64
    gen = torch.zeros_like
    disc = lambda x: x.mean(1)[:, None]
    criterion = torch.mul # Multiply
    real = torch.ones(num_images, z_dim)
    disc_loss = get_disc_loss(gen, disc, criterion, real, num_images, z_dim, 'cpu')
    assert torch.all(torch.abs(disc_loss.mean() - 0.5) < 1e-5)
    
    gen = torch.ones_like
    criterion = torch.mul # Multiply
    real = torch.zeros(num_images, z_dim)
    assert torch.all(torch.abs(get_disc_loss(gen, disc, criterion, real, num_images, z_dim, 'cpu')) < 1e-5)
    
    gen = lambda x: torch.ones(num_images, 10)
    disc = lambda x: x.mean(1)[:, None] + 10
    criterion = torch.mul # Multiply
    real = torch.zeros(num_images, 10)
    assert torch.all(torch.abs(get_disc_loss(gen, disc, criterion, real, num_images, z_dim, 'cpu').mean() - 5) < 1e-5)

    gen = torch.ones_like
    disc = nn.Linear(64, 1, bias=False)
    real = torch.ones(num_images, 64) * 0.5
    disc.weight.data = torch.ones_like(disc.weight.data) * 0.5
    disc_opt = torch.optim.Adam(disc.parameters(), lr=lr)
    criterion = lambda x, y: torch.sum(x) + torch.sum(y)
    disc_loss = get_disc_loss(gen, disc, criterion, real, num_images, z_dim, 'cpu').mean()
    disc_loss.backward()
    assert torch.isclose(torch.abs(disc.weight.grad.mean() - 11.25), torch.tensor(3.75))
    
def test_disc_loss(max_tests = 10):
    z_dim = 64
    gen = Generator(z_dim).to(device)
    gen_opt = torch.optim.Adam(gen.parameters(), lr=lr)
    disc = Discriminator().to(device) 
    disc_opt = torch.optim.Adam(disc.parameters(), lr=lr)
    num_steps = 0
    for real, _ in dataloader:
        cur_batch_size = len(real)
        real = real.view(cur_batch_size, -1).to(device)

        ### Update discriminator ###
        # Zero out the gradient before backpropagation
        disc_opt.zero_grad()

        # Calculate discriminator loss
        disc_loss = get_disc_loss(gen, disc, criterion, real, cur_batch_size, z_dim, device)
        assert (disc_loss - 0.68).abs() < 0.05

        # Update gradients
        disc_loss.backward(retain_graph=True)

        # Check that they detached correctly
        assert gen.gen[0][0].weight.grad is None

        # Update optimizer
        old_weight = disc.disc[0][0].weight.data.clone()
        disc_opt.step()
        new_weight = disc.disc[0][0].weight.data
        
        # Check that some discriminator weights changed
        assert not torch.all(torch.eq(old_weight, new_weight))
        num_steps += 1
        if num_steps >= max_tests:
            break

test_disc_reasonable()
test_disc_loss()
print("Success!")
def test_disc_reasonable(num_images=10): # Don't use explicit casts to cuda - use the device argument import inspect, re lines = inspect.getsource(get_disc_loss) assert (re.search(r"to\(.cuda.\)", lines)) is None assert (re.search(r"\.cuda\(\)", lines)) is None z_dim = 64 gen = torch.zeros_like disc = lambda x: x.mean(1)[:, None] criterion = torch.mul # Multiply real = torch.ones(num_images, z_dim) disc_loss = get_disc_loss(gen, disc, criterion, real, num_images, z_dim, 'cpu') assert torch.all(torch.abs(disc_loss.mean() - 0.5) < 1e-5) gen = torch.ones_like criterion = torch.mul # Multiply real = torch.zeros(num_images, z_dim) assert torch.all(torch.abs(get_disc_loss(gen, disc, criterion, real, num_images, z_dim, 'cpu')) < 1e-5) gen = lambda x: torch.ones(num_images, 10) disc = lambda x: x.mean(1)[:, None] + 10 criterion = torch.mul # Multiply real = torch.zeros(num_images, 10) assert torch.all(torch.abs(get_disc_loss(gen, disc, criterion, real, num_images, z_dim, 'cpu').mean() - 5) < 1e-5) gen = torch.ones_like disc = nn.Linear(64, 1, bias=False) real = torch.ones(num_images, 64) * 0.5 disc.weight.data = torch.ones_like(disc.weight.data) * 0.5 disc_opt = torch.optim.Adam(disc.parameters(), lr=lr) criterion = lambda x, y: torch.sum(x) + torch.sum(y) disc_loss = get_disc_loss(gen, disc, criterion, real, num_images, z_dim, 'cpu').mean() disc_loss.backward() assert torch.isclose(torch.abs(disc.weight.grad.mean() - 11.25), torch.tensor(3.75)) def test_disc_loss(max_tests = 10): z_dim = 64 gen = Generator(z_dim).to(device) gen_opt = torch.optim.Adam(gen.parameters(), lr=lr) disc = Discriminator().to(device) disc_opt = torch.optim.Adam(disc.parameters(), lr=lr) num_steps = 0 for real, _ in dataloader: cur_batch_size = len(real) real = real.view(cur_batch_size, -1).to(device) ### Update discriminator ### # Zero out the gradient before backpropagation disc_opt.zero_grad() # Calculate discriminator loss disc_loss = get_disc_loss(gen, disc, criterion, real, cur_batch_size, z_dim, device) assert (disc_loss - 0.68).abs() < 0.05 # Update gradients disc_loss.backward(retain_graph=True) # Check that they detached correctly assert gen.gen[0][0].weight.grad is None # Update optimizer old_weight = disc.disc[0][0].weight.data.clone() disc_opt.step() new_weight = disc.disc[0][0].weight.data # Check that some discriminator weights changed assert not torch.all(torch.eq(old_weight, new_weight)) num_steps += 1 if num_steps >= max_tests: break test_disc_reasonable() test_disc_loss() print("Success!")
Success!
In [20]:
Copied!
# UNQ_C7 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)
# GRADED FUNCTION: get_gen_loss
def get_gen_loss(gen, disc, criterion, num_images, z_dim, device):
    '''
    Return the loss of the generator given inputs.
    Parameters:
        gen: the generator model, which returns an image given z-dimensional noise
        disc: the discriminator model, which returns a single-dimensional prediction of real/fake
        criterion: the loss function, which should be used to compare 
               the discriminator's predictions to the ground truth reality of the images 
               (e.g. fake = 0, real = 1)
        num_images: the number of images the generator should produce, 
                which is also the length of the real images
        z_dim: the dimension of the noise vector, a scalar
        device: the device type
    Returns:
        gen_loss: a torch scalar loss value for the current batch
    '''
    #     These are the steps you will need to complete:
    #       1) Create noise vectors and generate a batch of fake images. 
    #           Remember to pass the device argument to the get_noise function.
    #       2) Get the discriminator's prediction of the fake image.
    #       3) Calculate the generator's loss. Remember the generator wants
    #          the discriminator to think that its fake images are real
    #     *Important*: You should NOT write your own loss function here - use criterion(pred, true)!

    #### START CODE HERE ####
    input_noise = get_noise(num_images, z_dim, device=device)
    fake_images = gen(input_noise)
    discriminator_prediction_on_fake_images = disc(fake_images)
    gen_loss = criterion(discriminator_prediction_on_fake_images, torch.ones_like(discriminator_prediction_on_fake_images))
    
    #### END CODE HERE ####
    return gen_loss
# UNQ_C7 (UNIQUE CELL IDENTIFIER, DO NOT EDIT) # GRADED FUNCTION: get_gen_loss def get_gen_loss(gen, disc, criterion, num_images, z_dim, device): ''' Return the loss of the generator given inputs. Parameters: gen: the generator model, which returns an image given z-dimensional noise disc: the discriminator model, which returns a single-dimensional prediction of real/fake criterion: the loss function, which should be used to compare the discriminator's predictions to the ground truth reality of the images (e.g. fake = 0, real = 1) num_images: the number of images the generator should produce, which is also the length of the real images z_dim: the dimension of the noise vector, a scalar device: the device type Returns: gen_loss: a torch scalar loss value for the current batch ''' # These are the steps you will need to complete: # 1) Create noise vectors and generate a batch of fake images. # Remember to pass the device argument to the get_noise function. # 2) Get the discriminator's prediction of the fake image. # 3) Calculate the generator's loss. Remember the generator wants # the discriminator to think that its fake images are real # *Important*: You should NOT write your own loss function here - use criterion(pred, true)! #### START CODE HERE #### input_noise = get_noise(num_images, z_dim, device=device) fake_images = gen(input_noise) discriminator_prediction_on_fake_images = disc(fake_images) gen_loss = criterion(discriminator_prediction_on_fake_images, torch.ones_like(discriminator_prediction_on_fake_images)) #### END CODE HERE #### return gen_loss
In [21]:
Copied!
def test_gen_reasonable(num_images=10):
    # Don't use explicit casts to cuda - use the device argument
    import inspect, re
    lines = inspect.getsource(get_gen_loss)
    assert (re.search(r"to\(.cuda.\)", lines)) is None
    assert (re.search(r"\.cuda\(\)", lines)) is None
    
    z_dim = 64
    gen = torch.zeros_like
    disc = nn.Identity()
    criterion = torch.mul # Multiply
    gen_loss_tensor = get_gen_loss(gen, disc, criterion, num_images, z_dim, 'cpu')
    assert torch.all(torch.abs(gen_loss_tensor) < 1e-5)
    #Verify shape. Related to gen_noise parametrization
    assert tuple(gen_loss_tensor.shape) == (num_images, z_dim)

    gen = torch.ones_like
    disc = nn.Identity()
    criterion = torch.mul # Multiply
    gen_loss_tensor = get_gen_loss(gen, disc, criterion, num_images, z_dim, 'cpu')
    assert torch.all(torch.abs(gen_loss_tensor - 1) < 1e-5)
    #Verify shape. Related to gen_noise parametrization
    assert tuple(gen_loss_tensor.shape) == (num_images, z_dim)
    

def test_gen_loss(num_images):
    z_dim = 64
    gen = Generator(z_dim).to(device)
    gen_opt = torch.optim.Adam(gen.parameters(), lr=lr)
    disc = Discriminator().to(device) 
    disc_opt = torch.optim.Adam(disc.parameters(), lr=lr)
    
    gen_loss = get_gen_loss(gen, disc, criterion, num_images, z_dim, device)
    
    # Check that the loss is reasonable
    assert (gen_loss - 0.7).abs() < 0.1
    gen_loss.backward()
    old_weight = gen.gen[0][0].weight.clone()
    gen_opt.step()
    new_weight = gen.gen[0][0].weight
    assert not torch.all(torch.eq(old_weight, new_weight))


test_gen_reasonable(10)
test_gen_loss(18)
print("Success!")
def test_gen_reasonable(num_images=10): # Don't use explicit casts to cuda - use the device argument import inspect, re lines = inspect.getsource(get_gen_loss) assert (re.search(r"to\(.cuda.\)", lines)) is None assert (re.search(r"\.cuda\(\)", lines)) is None z_dim = 64 gen = torch.zeros_like disc = nn.Identity() criterion = torch.mul # Multiply gen_loss_tensor = get_gen_loss(gen, disc, criterion, num_images, z_dim, 'cpu') assert torch.all(torch.abs(gen_loss_tensor) < 1e-5) #Verify shape. Related to gen_noise parametrization assert tuple(gen_loss_tensor.shape) == (num_images, z_dim) gen = torch.ones_like disc = nn.Identity() criterion = torch.mul # Multiply gen_loss_tensor = get_gen_loss(gen, disc, criterion, num_images, z_dim, 'cpu') assert torch.all(torch.abs(gen_loss_tensor - 1) < 1e-5) #Verify shape. Related to gen_noise parametrization assert tuple(gen_loss_tensor.shape) == (num_images, z_dim) def test_gen_loss(num_images): z_dim = 64 gen = Generator(z_dim).to(device) gen_opt = torch.optim.Adam(gen.parameters(), lr=lr) disc = Discriminator().to(device) disc_opt = torch.optim.Adam(disc.parameters(), lr=lr) gen_loss = get_gen_loss(gen, disc, criterion, num_images, z_dim, device) # Check that the loss is reasonable assert (gen_loss - 0.7).abs() < 0.1 gen_loss.backward() old_weight = gen.gen[0][0].weight.clone() gen_opt.step() new_weight = gen.gen[0][0].weight assert not torch.all(torch.eq(old_weight, new_weight)) test_gen_reasonable(10) test_gen_loss(18) print("Success!")
Success!

Finally, you can put everything together! For each epoch, you will process the entire dataset in batches. For every batch, you will need to update the discriminator and generator using their loss. Batches are sets of images that will be predicted on before the loss functions are calculated (instead of calculating the loss function after each image). Note that you may see a loss to be greater than 1, this is okay since binary cross entropy loss can be any positive number for a sufficiently confident wrong guess.

It’s also often the case that the discriminator will outperform the generator, especially at the start, because its job is easier. It's important that neither one gets too good (that is, near-perfect accuracy), which would cause the entire model to stop learning. Balancing the two models is actually remarkably hard to do in a standard GAN and something you will see more of in later lectures and assignments.

After you've submitted a working version with the original architecture, feel free to play around with the architecture if you want to see how different architectural choices can lead to better or worse GANs. For example, consider changing the size of the hidden dimension, or making the networks shallower or deeper by changing the number of layers.

But remember, don’t expect anything spectacular: this is only the first lesson. The results will get better with later lessons as you learn methods to help keep your generator and discriminator at similar levels.

You should roughly expect to see this progression. On a GPU, this should take about 15 seconds per 500 steps, on average, while on CPU it will take roughly 1.5 minutes: MNIST Digits

In [22]:
Copied!
# OPTIONAL PART

cur_step = 0
mean_generator_loss = 0
mean_discriminator_loss = 0
test_generator = True # Whether the generator should be tested
gen_loss = False
error = False
for epoch in range(n_epochs):
  
    # Dataloader returns the batches
    for real, _ in tqdm(dataloader):
        cur_batch_size = len(real)

        # Flatten the batch of real images from the dataset
        real = real.view(cur_batch_size, -1).to(device)

        ### Update discriminator ###
        # Zero out the gradients before backpropagation
        disc_opt.zero_grad()

        # Calculate discriminator loss
        disc_loss = get_disc_loss(gen, disc, criterion, real, cur_batch_size, z_dim, device)

        # Update gradients
        disc_loss.backward(retain_graph=True)

        # Update optimizer
        disc_opt.step()

        # For testing purposes, to keep track of the generator weights
        if test_generator:
            old_generator_weights = gen.gen[0][0].weight.detach().clone()

        ### Update generator ###
        #     Hint: This code will look a lot like the discriminator updates!
        #     These are the steps you will need to complete:
        #       1) Zero out the gradients.
        #       2) Calculate the generator loss, assigning it to gen_loss.
        #       3) Backprop through the generator: update the gradients and optimizer.
        #### START CODE HERE ####
        gen_opt.zero_grad()
        gen_loss = get_gen_loss(gen, disc, criterion, cur_batch_size, z_dim, device)
        gen_loss.backward()
        gen_opt.step()
        #### END CODE HERE ####

        # For testing purposes, to check that your code changes the generator weights
        if test_generator:
            try:
                assert lr > 0.0000002 or (gen.gen[0][0].weight.grad.abs().max() < 0.0005 and epoch == 0)
                assert torch.any(gen.gen[0][0].weight.detach().clone() != old_generator_weights)
            except:
                error = True
                print("Runtime tests have failed")

        # Keep track of the average discriminator loss
        mean_discriminator_loss += disc_loss.item() / display_step

        # Keep track of the average generator loss
        mean_generator_loss += gen_loss.item() / display_step

        ### Visualization code ###
        if cur_step % display_step == 0 and cur_step > 0:
            print(f"Step {cur_step}: Generator loss: {mean_generator_loss}, discriminator loss: {mean_discriminator_loss}")
            fake_noise = get_noise(cur_batch_size, z_dim, device=device)
            fake = gen(fake_noise)
            show_tensor_images(fake)
            show_tensor_images(real)
            mean_generator_loss = 0
            mean_discriminator_loss = 0
        cur_step += 1
# OPTIONAL PART cur_step = 0 mean_generator_loss = 0 mean_discriminator_loss = 0 test_generator = True # Whether the generator should be tested gen_loss = False error = False for epoch in range(n_epochs): # Dataloader returns the batches for real, _ in tqdm(dataloader): cur_batch_size = len(real) # Flatten the batch of real images from the dataset real = real.view(cur_batch_size, -1).to(device) ### Update discriminator ### # Zero out the gradients before backpropagation disc_opt.zero_grad() # Calculate discriminator loss disc_loss = get_disc_loss(gen, disc, criterion, real, cur_batch_size, z_dim, device) # Update gradients disc_loss.backward(retain_graph=True) # Update optimizer disc_opt.step() # For testing purposes, to keep track of the generator weights if test_generator: old_generator_weights = gen.gen[0][0].weight.detach().clone() ### Update generator ### # Hint: This code will look a lot like the discriminator updates! # These are the steps you will need to complete: # 1) Zero out the gradients. # 2) Calculate the generator loss, assigning it to gen_loss. # 3) Backprop through the generator: update the gradients and optimizer. #### START CODE HERE #### gen_opt.zero_grad() gen_loss = get_gen_loss(gen, disc, criterion, cur_batch_size, z_dim, device) gen_loss.backward() gen_opt.step() #### END CODE HERE #### # For testing purposes, to check that your code changes the generator weights if test_generator: try: assert lr > 0.0000002 or (gen.gen[0][0].weight.grad.abs().max() < 0.0005 and epoch == 0) assert torch.any(gen.gen[0][0].weight.detach().clone() != old_generator_weights) except: error = True print("Runtime tests have failed") # Keep track of the average discriminator loss mean_discriminator_loss += disc_loss.item() / display_step # Keep track of the average generator loss mean_generator_loss += gen_loss.item() / display_step ### Visualization code ### if cur_step % display_step == 0 and cur_step > 0: print(f"Step {cur_step}: Generator loss: {mean_generator_loss}, discriminator loss: {mean_discriminator_loss}") fake_noise = get_noise(cur_batch_size, z_dim, device=device) fake = gen(fake_noise) show_tensor_images(fake) show_tensor_images(real) mean_generator_loss = 0 mean_discriminator_loss = 0 cur_step += 1
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 500: Generator loss: 1.4302745277881619, discriminator loss: 0.4202722601890564
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 1000: Generator loss: 1.8087053074836734, discriminator loss: 0.2701563952863217
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 1500: Generator loss: 2.134711436510085, discriminator loss: 0.14956932044029236
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 2000: Generator loss: 1.8106944882869724, discriminator loss: 0.1968922269940376
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 2500: Generator loss: 1.679555094003677, discriminator loss: 0.21664462408423435
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 3000: Generator loss: 1.9274883055686935, discriminator loss: 0.17116721224784853
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 3500: Generator loss: 2.385545147418976, discriminator loss: 0.124955167800188
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 4000: Generator loss: 2.7636030840873724, discriminator loss: 0.11762473592162141
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 4500: Generator loss: 2.997701193809508, discriminator loss: 0.10401653781533246
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 5000: Generator loss: 3.372794588565826, discriminator loss: 0.0803466418832541
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 5500: Generator loss: 3.663240928173067, discriminator loss: 0.06644653165340421
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 6000: Generator loss: 3.922063869953156, discriminator loss: 0.06022396452724938
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 6500: Generator loss: 4.070119934558871, discriminator loss: 0.05890820964425803
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 7000: Generator loss: 4.179288742542267, discriminator loss: 0.05817713452130552
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 7500: Generator loss: 4.361417913436888, discriminator loss: 0.047341182246804316
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 8000: Generator loss: 4.461196029663087, discriminator loss: 0.05155227056518196
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 8500: Generator loss: 4.227819447040558, discriminator loss: 0.062414671838283545
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 9000: Generator loss: 4.345865888595579, discriminator loss: 0.0602483522742986
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 9500: Generator loss: 4.272239718437194, discriminator loss: 0.06230839007347829
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 10000: Generator loss: 4.141332411289215, discriminator loss: 0.06240396473556762
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 10500: Generator loss: 4.213147602558136, discriminator loss: 0.05172080077975983
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 11000: Generator loss: 4.275936953067778, discriminator loss: 0.04936915568262343
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 11500: Generator loss: 4.191896306037902, discriminator loss: 0.06078267326951023
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 12000: Generator loss: 4.118025050640105, discriminator loss: 0.07156328955292712
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 12500: Generator loss: 4.12081666326523, discriminator loss: 0.08302331647276875
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 13000: Generator loss: 4.046120879650113, discriminator loss: 0.07999776003509758
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 13500: Generator loss: 3.8873408837318397, discriminator loss: 0.0886415009573103
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 14000: Generator loss: 3.950662484169008, discriminator loss: 0.08795279936492442
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 14500: Generator loss: 3.878493126869205, discriminator loss: 0.09753796890377994
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 15000: Generator loss: 3.9586869826316846, discriminator loss: 0.07909342116862536
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 15500: Generator loss: 3.88502211618423, discriminator loss: 0.10100123754143728
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 16000: Generator loss: 3.747188694953917, discriminator loss: 0.10484690211713309
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 16500: Generator loss: 3.612464189529417, discriminator loss: 0.11437303143739691
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 17000: Generator loss: 3.684795359611511, discriminator loss: 0.11077060181647541
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 17500: Generator loss: 3.6703928480148322, discriminator loss: 0.11089472842961554
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 18000: Generator loss: 3.5283632893562347, discriminator loss: 0.12300472079217434
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 18500: Generator loss: 3.4669026737213104, discriminator loss: 0.13567298169434056
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 19000: Generator loss: 3.4485266990661607, discriminator loss: 0.1317555493414401
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 19500: Generator loss: 3.5604365673065166, discriminator loss: 0.1291644089892507
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 20000: Generator loss: 3.4758054528236375, discriminator loss: 0.13593167647719379
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 20500: Generator loss: 3.3498177185058595, discriminator loss: 0.15318311087042102
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 21000: Generator loss: 3.158295547008511, discriminator loss: 0.16725886219739908
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 21500: Generator loss: 3.096468394279484, discriminator loss: 0.1674504834413529
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 22000: Generator loss: 3.0724838466644315, discriminator loss: 0.17235950177907952
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 22500: Generator loss: 3.0314186353683468, discriminator loss: 0.19032618144154545
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 23000: Generator loss: 2.8184734888076792, discriminator loss: 0.2226431193053722
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 23500: Generator loss: 2.7356433677673326, discriminator loss: 0.22586893096566182
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 24000: Generator loss: 2.8836750822067256, discriminator loss: 0.18451388277113415
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 24500: Generator loss: 2.8367629246711736, discriminator loss: 0.1983457911908628
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 25000: Generator loss: 2.8241010217666616, discriminator loss: 0.1972871148586272
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 25500: Generator loss: 2.7754881668090823, discriminator loss: 0.21305245491862293
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 26000: Generator loss: 2.7012986750602703, discriminator loss: 0.22318228584527974
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 26500: Generator loss: 2.688074496746065, discriminator loss: 0.21980723470449443
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 27000: Generator loss: 2.608096789121627, discriminator loss: 0.22143887272477164
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 27500: Generator loss: 2.6006266000270832, discriminator loss: 0.21129789748787867
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 28000: Generator loss: 2.614777601242066, discriminator loss: 0.2057693020552396
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 28500: Generator loss: 2.6638825807571416, discriminator loss: 0.20602123770117756
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 29000: Generator loss: 2.615960039138793, discriminator loss: 0.22333501413464563
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 29500: Generator loss: 2.57677267098427, discriminator loss: 0.2129647933840751
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 30000: Generator loss: 2.54936637687683, discriminator loss: 0.22932162505388265
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 30500: Generator loss: 2.553826134204864, discriminator loss: 0.2303309726566075
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 31000: Generator loss: 2.4638727509975435, discriminator loss: 0.25435588747262927
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 31500: Generator loss: 2.351501177787783, discriminator loss: 0.2599580121636392
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 32000: Generator loss: 2.4342266077995287, discriminator loss: 0.23293823170661926
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 32500: Generator loss: 2.5427093997001617, discriminator loss: 0.2141051734685897
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 33000: Generator loss: 2.4590027618408206, discriminator loss: 0.25094213607907284
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 33500: Generator loss: 2.3867101833820326, discriminator loss: 0.2567918685972691
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 34000: Generator loss: 2.3722957577705395, discriminator loss: 0.2434389894902707
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 34500: Generator loss: 2.3729509806633007, discriminator loss: 0.2584994663000104
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 35000: Generator loss: 2.329233546733857, discriminator loss: 0.264056102156639
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 35500: Generator loss: 2.2603826599121106, discriminator loss: 0.27860142660141
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 36000: Generator loss: 2.267944099426269, discriminator loss: 0.28124926370382325
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 36500: Generator loss: 2.3093815207481363, discriminator loss: 0.2522632811963559
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 37000: Generator loss: 2.28641965866089, discriminator loss: 0.2542850351333618
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 37500: Generator loss: 2.3280041697025284, discriminator loss: 0.2594938386380673
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 38000: Generator loss: 2.2997655513286586, discriminator loss: 0.25696822631359095
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 38500: Generator loss: 2.3048592708110824, discriminator loss: 0.26181580260396004
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 39000: Generator loss: 2.18949762749672, discriminator loss: 0.2806376186311243
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 39500: Generator loss: 2.2210186161994936, discriminator loss: 0.2754444340169428
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 40000: Generator loss: 2.1560306074619313, discriminator loss: 0.2920223442912098
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 40500: Generator loss: 2.1377104263305644, discriminator loss: 0.283247116357088
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 41000: Generator loss: 2.1111869952678677, discriminator loss: 0.30185759121179573
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 41500: Generator loss: 2.0815027644634245, discriminator loss: 0.30492498967051507
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 42000: Generator loss: 1.9973397126197814, discriminator loss: 0.3232439219355582
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 42500: Generator loss: 1.9939378006458282, discriminator loss: 0.3077021397948266
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 43000: Generator loss: 2.0156668570041654, discriminator loss: 0.30261180698871615
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 43500: Generator loss: 2.1152633941173575, discriminator loss: 0.28914846718311316
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 44000: Generator loss: 2.0225940670967084, discriminator loss: 0.31100994533300397
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 44500: Generator loss: 2.0490037217140187, discriminator loss: 0.297395463734865
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 45000: Generator loss: 2.100620343685152, discriminator loss: 0.28794829195737803
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 45500: Generator loss: 2.022119452476501, discriminator loss: 0.3093636177480221
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 46000: Generator loss: 1.9722090086936943, discriminator loss: 0.31805285710096354
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 46500: Generator loss: 1.9715818300247205, discriminator loss: 0.30777838689088843
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 47000: Generator loss: 1.8456179027557373, discriminator loss: 0.3430971109271052
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 47500: Generator loss: 1.821552887439726, discriminator loss: 0.3454304473102093
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 48000: Generator loss: 1.8649550261497487, discriminator loss: 0.331017247438431
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 48500: Generator loss: 1.8152527809143049, discriminator loss: 0.35479869449138635
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 49000: Generator loss: 1.767901315450668, discriminator loss: 0.3534528301656249
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 49500: Generator loss: 1.8033210709094998, discriminator loss: 0.34837399071454955
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 50000: Generator loss: 1.8551986405849454, discriminator loss: 0.3347047256529332
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 50500: Generator loss: 1.8380940039157865, discriminator loss: 0.3342424839138986
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 51000: Generator loss: 1.8203671491146083, discriminator loss: 0.33081715810298884
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 51500: Generator loss: 1.7927206020355224, discriminator loss: 0.35794814354181265
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 52000: Generator loss: 1.7780032827854164, discriminator loss: 0.367132912099361
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 52500: Generator loss: 1.7731318862438208, discriminator loss: 0.35608103471994396
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 53000: Generator loss: 1.8088634984493268, discriminator loss: 0.3421199712753291
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 53500: Generator loss: 1.7835096008777616, discriminator loss: 0.34630403244495395
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 54000: Generator loss: 1.7567483963966364, discriminator loss: 0.357701490879059
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 54500: Generator loss: 1.6862002315521216, discriminator loss: 0.37697139084339176
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 55000: Generator loss: 1.7079094614982604, discriminator loss: 0.35724302795529367
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 55500: Generator loss: 1.7945421688556666, discriminator loss: 0.3543385914564129
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 56000: Generator loss: 1.7814435372352608, discriminator loss: 0.35909371083974834
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 56500: Generator loss: 1.7212584311962127, discriminator loss: 0.3700042355060579
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 57000: Generator loss: 1.8311930358409874, discriminator loss: 0.34469830745458596
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 57500: Generator loss: 1.7150849719047538, discriminator loss: 0.35963974469900134
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 58000: Generator loss: 1.7429371516704564, discriminator loss: 0.3677425230145453
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 58500: Generator loss: 1.6711410677433023, discriminator loss: 0.3873109254240985
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 59000: Generator loss: 1.638924180030823, discriminator loss: 0.3985368683338164
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 59500: Generator loss: 1.7057628557682027, discriminator loss: 0.37253839415311824
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 60000: Generator loss: 1.6696665966510775, discriminator loss: 0.37538645565509804
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 60500: Generator loss: 1.7109522552490244, discriminator loss: 0.36233557677268996
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 61000: Generator loss: 1.6605322237014764, discriminator loss: 0.37659465241432194
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 61500: Generator loss: 1.6414867470264436, discriminator loss: 0.3859708636999131
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 62000: Generator loss: 1.565134314537047, discriminator loss: 0.39072778075933456
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 62500: Generator loss: 1.6335458929538738, discriminator loss: 0.38077901113033297
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 63000: Generator loss: 1.5497114362716664, discriminator loss: 0.4071533764600751
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 63500: Generator loss: 1.6368594315052032, discriminator loss: 0.37850343829393407
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 64000: Generator loss: 1.6319764254093194, discriminator loss: 0.38864695781469344
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 64500: Generator loss: 1.624964429378509, discriminator loss: 0.38144866013526857
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 65000: Generator loss: 1.4950726592540744, discriminator loss: 0.4151010075211528
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 65500: Generator loss: 1.5449602577686306, discriminator loss: 0.39342658466100694
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 66000: Generator loss: 1.4607211720943458, discriminator loss: 0.434460762917995
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 66500: Generator loss: 1.4764779832363129, discriminator loss: 0.4276858519315723
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 67000: Generator loss: 1.4891025030612943, discriminator loss: 0.43017480593919744
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 67500: Generator loss: 1.5584838435649866, discriminator loss: 0.4037664337158201
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 68000: Generator loss: 1.5534689111709585, discriminator loss: 0.41967494451999654
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 68500: Generator loss: 1.593097581386567, discriminator loss: 0.3978276094198225
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 69000: Generator loss: 1.562704643249513, discriminator loss: 0.4025637742280957
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 69500: Generator loss: 1.5934089481830602, discriminator loss: 0.3957956177592277
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 70000: Generator loss: 1.5830006859302532, discriminator loss: 0.40021651959419235
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 70500: Generator loss: 1.4922392973899836, discriminator loss: 0.432962763428688
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 71000: Generator loss: 1.5164444830417636, discriminator loss: 0.4231314943432807
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 71500: Generator loss: 1.3821642379760737, discriminator loss: 0.4510206421017649
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 72000: Generator loss: 1.445999433755875, discriminator loss: 0.4288115984201432
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 72500: Generator loss: 1.4443625912666307, discriminator loss: 0.4366539249420162
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 73000: Generator loss: 1.3899963676929483, discriminator loss: 0.44863152146339397
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 73500: Generator loss: 1.3819792485237126, discriminator loss: 0.45896874654293046
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 74000: Generator loss: 1.3569951319694524, discriminator loss: 0.4545011696815489
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 74500: Generator loss: 1.3495491163730622, discriminator loss: 0.4598758752346042
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 75000: Generator loss: 1.3593809752464305, discriminator loss: 0.46223303139209754
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 75500: Generator loss: 1.3649655098915088, discriminator loss: 0.45781097286939615
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 76000: Generator loss: 1.3308189561367032, discriminator loss: 0.4664177824854849
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 76500: Generator loss: 1.3747665410041823, discriminator loss: 0.4518169267773627
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 77000: Generator loss: 1.357443357467651, discriminator loss: 0.45987209802865997
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 77500: Generator loss: 1.3935016489028926, discriminator loss: 0.4403234825730319
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 78000: Generator loss: 1.3939295959472666, discriminator loss: 0.44445717024803144
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 78500: Generator loss: 1.3752578983306891, discriminator loss: 0.45804064691066726
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 79000: Generator loss: 1.3648700439929955, discriminator loss: 0.4538082633018493
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 79500: Generator loss: 1.321422227621079, discriminator loss: 0.4687521419525145
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 80000: Generator loss: 1.318615782976151, discriminator loss: 0.4682886509895327
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 80500: Generator loss: 1.284792397022248, discriminator loss: 0.4812784096002577
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 81000: Generator loss: 1.1544841206073768, discriminator loss: 0.5440180184245117
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 81500: Generator loss: 1.4227072601318371, discriminator loss: 0.43481448340415924
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 82000: Generator loss: 1.3744773752689357, discriminator loss: 0.4435349630713462
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 82500: Generator loss: 1.2703965952396405, discriminator loss: 0.47786427545547483
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 83000: Generator loss: 1.2795236725807202, discriminator loss: 0.4744043198227882
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 83500: Generator loss: 1.239476920127869, discriminator loss: 0.4830328267812729
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 84000: Generator loss: 1.3015914068222043, discriminator loss: 0.47356029933691035
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 84500: Generator loss: 1.2591782264709477, discriminator loss: 0.4828403453826904
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 85000: Generator loss: 1.2290350024700167, discriminator loss: 0.5044798950552943
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 85500: Generator loss: 1.241285803556442, discriminator loss: 0.5001752986311914
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 86000: Generator loss: 1.2344867165088649, discriminator loss: 0.5017858257293706
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 86500: Generator loss: 1.222887257337569, discriminator loss: 0.5044576249122624
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 87000: Generator loss: 1.210473301172257, discriminator loss: 0.5021420741081234
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 87500: Generator loss: 1.2234658865928654, discriminator loss: 0.4995439181923866
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 88000: Generator loss: 1.210398120641708, discriminator loss: 0.4931778007149697
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 88500: Generator loss: 1.204054476499558, discriminator loss: 0.49534984511136976
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 89000: Generator loss: 1.2093874897956844, discriminator loss: 0.49507686352729807
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 89500: Generator loss: 1.103548044085504, discriminator loss: 0.5405788466930388
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 90000: Generator loss: 1.178600237369538, discriminator loss: 0.5139029342532162
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 90500: Generator loss: 1.2068829796314233, discriminator loss: 0.4969159538149827
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
  0%|          | 0/469 [00:00<?, ?it/s]
Step 91000: Generator loss: 1.254151371717453, discriminator loss: 0.4840004702210424
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 91500: Generator loss: 1.2246218752861022, discriminator loss: 0.49427056825160953
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 92000: Generator loss: 1.232499586820602, discriminator loss: 0.5023536002039906
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 92500: Generator loss: 1.2075946340560915, discriminator loss: 0.5072172141075137
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 93000: Generator loss: 1.2450470690727249, discriminator loss: 0.49037133157253265
No description has been provided for this image
No description has been provided for this image
  0%|          | 0/469 [00:00<?, ?it/s]
Step 93500: Generator loss: 1.2237422788143164, discriminator loss: 0.49255747973918923
No description has been provided for this image
No description has been provided for this image
In [ ]:
Copied!

In [ ]:
Copied!

If you don't get any runtime error, it means that your code works. We check that the weights are changing in each iteration within the function.

Congratulations, you have trained your first GAN

In [ ]:
Copied!


Documentation built with MkDocs.

Keyboard Shortcuts

Keys Action
? Open this help
n Next page
p Previous page
s Search