Developing a DCGAN Model in Tensorflow 2.0 | by Mouhamed Ndoye | Towards Data Science

In early March 2019, TensorFlow 2.0 was released and we decided to create an image generator based on Taehoon Kim’s implementation of DCGAN. Here’s a tutorial on how to develop a DCGAN model in TensorFlow 2.0.
“To avoid the fast convergence of D (discriminator) network, G (generator) network is updated twice for each D network update, which differs from original paper.”
— Taehoon Kim
Jupyter Notebook
TensorFlow 2.0
Access to high-performing GPU
The image below illustrates the generator referenced in the DCGAN paper. Essentially, this network takes in a 100x1 noise vector, labeled 100z, and maps it into the G(Z) output which is 64x64x3.
100x1 → 1024x4x4 → 512x8x8 → 256x16x16 → 128x32x32 → 64x64x3
The first layer expands the random noise by projecting and reshaping at each step
The stride specifies the ‘steps’ of the convolution along the height and width. Here’s an animated example:
generator = make_generator_model()noise = tf.random.normal([1,100]) # shape is 1, 100generated_image = generator(noise, training = False)plt.imshow(generated_image[0, :, :, 0], cmap =”gist_rainbow”)
In Keras, you can create layers to develop models. A model is usually a network of layers, in which, the most common type is a stack of layers
Adding a densely-connected layer to the model will take as input arrays of shape (*, 100). The shape of the data will be (*, 4*4*1024) after the first layer. In this case, you won’t need to specify the size of the input moving forward because of automatic shape inferenceBatch normalization functions similarly to preprocessing at every layer of the network.
ReLU is linear for all positive values and set to zero for all negative values. Leaky ReLU has a smaller slope for negative values, instead of altogether zero.
For example, leaky ReLU may have y = 0.01x when x < 0
def make_generator_model(): model = tf.keras.Sequential()  model.add(layers.Dense(4*4*1024, use_bias = False, input_shape = (100,)))  model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU())
The generator uses a transposed convolutional layer (upsampling) to produce an image from seed (random noise).
512 is the dimensionality of the output space
(5,5) specifies the height and width of the 2D convolution window
Strides = (2,2)
model.add(layers.Conv2DTranspose(512, (5, 5), strides = (2,2), padding = “same”, use_bias = False)) assert model.output_shape == (None, 8, 8, 512)model.add(layers.BatchNormalization())model.add(layers.LeakyReLU())
The generator uses a transposed convolutional layer (upsampling) to produce an image from the previous layer.
256 is the dimensionality of the output space
(5,5) specifies the height and width of the 2D convolution window
Strides = (2,2)
model.add(layers.Conv2DTranspose(256, (5,5), strides = (2,2), padding = “same”, use_bias = False))assert model.output_shape == (None, 16, 16, 256)model.add(layers.BatchNormalization())model.add(layers.LeakyReLU())
The generator uses a transposed convolutional layer (upsampling) to produce an image from the previous layer.
128 is the dimensionality of the output space
(5,5) specifies the height and width of the 2D convolution window
Strides = (2,2)
model.add(layers.Conv2DTranspose(128, (5,5), strides = (2,2), padding = “same”, use_bias = False))assert model.output_shape == (None, 32, 32, 128)model.add(layers.BatchNormalization())model.add(layers.LeakyReLU())
The generator uses a transposed convolutional layer (upsampling) to produce an image from the previous layer.
64 is the dimensionality of the output space
(5,5) specifies the height and width of the 2D convolution window
Strides = (2,2) specifies the strides of the convolution along the height and width
model.add(layers.Conv2DTranspose(3, (5,5), strides = (2,2), padding = “same”, use_bias = False, activation = “tanh”))assert model.output_shape == (None, 64, 64, 3) return model
The generator’s loss quantifies how well it was able to trick the discriminator. Intuitively, if the generator is performing well, the discriminator will classify the fake images as real (or 1).
Here, we will compare the discriminators decisions on the generated images to an array of 1s.
def generator_loss(fake_output): return cross_entropy(tf.ones_like(fake_output), fake_output)
The discriminator and the generator optimizers are different since we will train two networks, separately. The Adam optimization algorithm is an extension of stochastic gradient descent.
Stochastic gradient descent maintains a single learning rate (termed alpha) for all weight updates while the learning rate does not change during training.A learning rate is maintained for each network weight (parameter) and adapts as learning unfolds.
generator_optimizer = tf.keras.optimizers.Adam(1e-4)discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)
To start off, we trained our DCGAN model with 3 Deconvolutional layers on the MNIST dataset (28 x 28 grayscale images) which resulted in clearer renderings which can be seen below:
Using a DCGAN model with 4 DC layers trained on a subset of the CelebA dataset (25,600 / 202,599 images), we were able to generate images resembling faces with a run of 100 epochs.
TensorFlow 1.5 — GPU — Py3 — P5000
TensorFlow 2.0 — GPU — Py3 — P5000
TensorFlow 2.0 — GPU — Py3 — Tesla V100
60,000 images
128 x 128
202,599 images
Transformed 218 x 178 to 64 x 64
Understanding GAN model created using Tensorflow
Developing DCGAN model using Tensorflow 2.0
Resizing/cropping the dataset images from 218 x 178 to 64 x 64
Memory leakage in Jupyter Notebook while training the new model
Incompatibilities with TensorFlow 1.3 and 2.0
Paperspace auto-shutdown after 12 hrs
Migrate the model to an environment which can compute 100 epochs using the CelebA dataset in its entirety
Tune the model architecture to generate better images
Develop a solution to resize images for more efficiently
github.com
We couldn’t have completed this project without the great people of the Internet. Please check out the following resources for your next data science project:
Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks — https://arxiv.org/abs/1511.06434
Compressed Sensing using Generative Models — https://arxiv.org/pdf/1703.03208.pdf
Image Completion with Deep Learning in TensorFlow — http://bamos.github.io/2016/08/09/deep-completion/