Generator model doesn't produce pictures during training

I'm training GAN with MNIST and I want to visualize Generator output with noise input during training.

Here is the code:

from numpy import expand_dims
import numpy as np
import time
import tensorflow as tf
from numpy import zeros
from numpy import ones
from numpy import vstack
from numpy.random import randn
from numpy.random import randint
from tensorflow.keras.datasets.mnist import load_data
from tensorflow.keras.optimizers import Adam
from tensorflow.keras import layers, Sequential
import matplotlib.pyplot as plt
from IPython import display
import imageio # for creating gifs
import PIL

(trainX, _), (_, _) = load_data()
# add channels dimension
X = expand_dims(trainX, axis=-1)
# convert from unsigned ints to floats
X = X.astype('float32')
# scale from [0,255] to [0,1]
dataset = X / 255.0

def define_generator(latent_dim):
    model = Sequential()
    # foundation for 7x7 image
    n_nodes = 128 * 7 * 7
    model.add(layers.Dense(n_nodes, input_dim=latent_dim))
    model.add(layers.LeakyReLU())
    model.add(layers.Reshape((7, 7, 128)))
    # upsample to 14x14
    model.add(layers.Conv2DTranspose(128, (4,4), strides=(2,2), padding='same'))
    model.add(layers.LeakyReLU())
    # upsample to 28x28
    model.add(layers.Conv2DTranspose(128, (4,4), strides=(2,2), padding='same'))
    model.add(layers.LeakyReLU())
    model.add(layers.Conv2D(1, (7,7), activation='sigmoid', padding='same'))
    return model

def define_discriminator(in_shape=(28,28,1)):
    model = Sequential()
    model.add(layers.Conv2D(128, (5,5), strides=(2, 2), padding='same', input_shape=in_shape))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3))
    model.add(layers.Conv2D(128, (5,5), strides=(2, 2), padding='same'))
    model.add(layers.LeakyReLU())
    model.add(layers.Dropout(0.3))
    model.add(layers.Flatten())
    model.add(layers.Dense(1, activation='sigmoid'))
    # compile model
    opt = Adam(lr=0.0002)
    model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])
    return model

# size of the noise vector
latent_dim = 100
num_examples_to_generate = 16

g_model = define_generator(latent_dim)

d_model = define_discriminator()

# define the combined generator and discriminator model, for updating the generator
def define_gan(g_model, d_model):
    # make weights in the discriminator not trainable
    d_model.trainable = False
    # connect them
    model = Sequential()
    # add generator
    model.add(g_model)
    # add the discriminator
    model.add(d_model)
    # compile model
    opt = Adam(lr=0.0002)
    model.compile(loss='binary_crossentropy', optimizer=opt)
    return model

gan_model = define_gan(g_model, d_model)

# select real samples
def generate_real_samples(dataset, n_samples):
    # choose random instances
    ix = randint(0, dataset.shape[0], n_samples)
    # retrieve selected images
    X = dataset[ix]
    # generate 'real' class labels (1)
    y = ones((n_samples, 1))
    return X, y

# generate points in latent space as input for the generator
def generate_latent_points(latent_dim, n_samples):
    # generate noise vector for training
    x_input = randn(latent_dim * n_samples)
    # reshape into a batch of inputs for the network
    x_input = x_input.reshape(n_samples, latent_dim)
    return x_input

# use the generator to generate n fake examples, with class labels
def generate_fake_samples(g_model, latent_dim, n_samples):
    # generate points in latent space
    x_input = generate_latent_points(latent_dim, n_samples)
    # predict outputs
    X = g_model.predict(x_input)
    # create 'fake' class labels (0)
    y = zeros((n_samples, 1))
    return X, y

def generate_and_save_images(epoch):
  # for generating the fake images after each epoch

  # generate points in the latent space
  noise = randn(latent_dim * num_examples_to_generate)
  # reshape into a batch of inputs for the network
  noise = noise.reshape(num_examples_to_generate, latent_dim)
 
  predictions = g_model(noise, training=False)

  fig = plt.figure(figsize=(4, 4))

  for i in range(predictions.shape[0]):
      plt.subplot(4, 4, i+1)
      plt.imshow(predictions[i, :, :, 0], cmap='gray')
      plt.axis('off')

  plt.savefig('image_at_epoch_{:04d}.png'.format(epoch))
  plt.show()

def train(g_model, d_model, gan_model, dataset, latent_dim, n_epochs=60, n_batch=256):
  bat_per_epo = int(dataset.shape[0] / n_batch)
  half_batch = int(n_batch / 2)

  for epoch in range(n_epochs):

    start = time.time()

    for batch in range(bat_per_epo):
      
      X_real, y_real = generate_real_samples(dataset, half_batch)

      X_fake, y_fake = generate_fake_samples(g_model, latent_dim, half_batch)

      X = vstack((X_real, X_fake))

      y = vstack((y_real, y_fake))

      d_loss, _ = d_model.train_on_batch(X,y)

      X_gan = generate_latent_points(latent_dim, n_batch)

      y_gan = ones((n_batch, 1))

      g_loss = gan_model.train_on_batch(X_gan, y_gan)

    display.clear_output(wait=True)
    generate_and_save_images(epoch + 1)

    print('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start))

  display.clear_output(wait=True)
  generate_and_save_images(n_epochs)

train(g_model, d_model, gan_model, dataset, latent_dim)

The output that I'm getting is:

Output for train(...) command

There is no error or something just I can't see the output from the Generator with the noise input.

The function that is supposed to show the output is generate_and_save_images.


when you use cmap="gray" in plt.imshow() you must either unscale your output or set vmin and vmax. From what I see you scaled by dividing 255, so you must multiply your data by 255 or, alternativle set vmin=0, vmax=1 Option1:

plt.imshow(predictions[i, :, :, 0]*255, cmap='gray')

Option2:

plt.imshow(predictions[i, :, :, 0], cmap='gray', vmin=0, vmax=1)