Chapter 4: Project: Face Generation with GANs
4.2 Model Creation
The model creation stage involves defining the architecture of our Generative Adversarial Network (GAN). As we know from Chapter 3, a GAN is composed of two main parts: the generator and the discriminator.
4.2.1 The Generator
The generator's purpose is to generate new data from random noise. The output of the generator should ideally be indistinguishable from the true data.
In our case, we're generating images, so our generator will output an image of the same size as the training images.
We'll use a Deep Convolutional GAN (DCGAN) structure for our generator. Here is an example of what the generator's architecture might look like in code:
from keras.models import Sequential
from keras.layers import Dense, Reshape, Conv2DTranspose, LeakyReLU, BatchNormalization
# Generator model
def create_generator(latent_dim):
model = Sequential()
# Start with dense layer from which to reshape
model.add(Dense(256*16*16, input_dim=latent_dim))
model.add(LeakyReLU(alpha=0.2))
model.add(Reshape((16, 16, 256)))
# Up-sample to 32x32
model.add(Conv2DTranspose(128, (4,4), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
# Up-sample to 64x64
model.add(Conv2DTranspose(64, (4,4), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
# Output layer
model.add(Conv2DTranspose(3, (3,3), activation='tanh', padding='same'))
return model
This model starts with a dense layer and reshapes it into a multi-dimensional tensor. It then uses convolutional transpose layers (also known as deconvolutional layers) to upsample the data and generate an image.
4.2.2 The Discriminator
The discriminator's job is to distinguish between the real and fake (generated) images. It's essentially a binary classification model that classifies images as real (1) or fake (0).
Like our generator, we'll use a convolutional structure for our discriminator. Here's an example of what the discriminator's architecture might look like:
from keras.layers import Conv2D, Flatten, Dropout
from keras.models import Sequential
# Discriminator model
def create_discriminator(image_shape):
model = Sequential()
# Down-sample to 32x32
model.add(Conv2D(64, (3,3), strides=(2,2), padding='same', input_shape=image_shape))
model.add(LeakyReLU(alpha=0.2))
# Down-sample to 16x16
model.add(Conv2D(128, (3,3), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.4))
# Down-sample to 8x8
model.add(Conv2D(256, (3,3), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.4))
# Classifier
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
return model
This model uses standard convolutional layers to downsample the input image and classify it as real or fake. The dropout layers are used to prevent overfitting, and the LeakyReLU activation function is used to introduce nonlinearity into the model.
These code snippets provided here are a good starting point for the architecture of the GAN. However, when it comes to designing your own GAN for a specific task, a lot of experimentation is often needed to find an architecture and set of hyperparameters that work well.
With the generator and discriminator defined, we can now compile them into a GAN. The GAN will chain the generator and discriminator together: the generator will receive a point from the latent space as input and will output a candidate image, which will be fed into the discriminator alongside real images.
Here's an example of how we can compile our models into a GAN:
from keras.models import Model
from keras.optimizers import Adam
from keras.layers import Input
# Build and compile the discriminator
discriminator = create_discriminator(image_shape)
discriminator.compile(loss='binary_crossentropy',
optimizer=Adam(0.0002, 0.5),
metrics=['accuracy'])
# Build the generator
generator = create_generator(latent_dim)
# The generator takes noise as input and generates imgs
z = Input(shape=(latent_dim,))
img = generator(z)
# For the combined model we will only train the generator
discriminator.trainable = False
# The discriminator takes generated images as input and determines validity
validity = discriminator(img)
# The combined model (stacked generator and discriminator)
# Trains the generator to fool the discriminator
combined = Model(z, validity)
combined.compile(loss='binary_crossentropy',
optimizer=Adam(0.0002, 0.5))
This sets up the basic model structure for our GAN. The generator and discriminator are trained in tandem: the discriminator learning to better distinguish real from fake, and the generator learning to create more convincing fakes based on the discriminator's feedback.
In the next sections, we will look at how to train this model and generate new faces.
4.2 Model Creation
The model creation stage involves defining the architecture of our Generative Adversarial Network (GAN). As we know from Chapter 3, a GAN is composed of two main parts: the generator and the discriminator.
4.2.1 The Generator
The generator's purpose is to generate new data from random noise. The output of the generator should ideally be indistinguishable from the true data.
In our case, we're generating images, so our generator will output an image of the same size as the training images.
We'll use a Deep Convolutional GAN (DCGAN) structure for our generator. Here is an example of what the generator's architecture might look like in code:
from keras.models import Sequential
from keras.layers import Dense, Reshape, Conv2DTranspose, LeakyReLU, BatchNormalization
# Generator model
def create_generator(latent_dim):
model = Sequential()
# Start with dense layer from which to reshape
model.add(Dense(256*16*16, input_dim=latent_dim))
model.add(LeakyReLU(alpha=0.2))
model.add(Reshape((16, 16, 256)))
# Up-sample to 32x32
model.add(Conv2DTranspose(128, (4,4), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
# Up-sample to 64x64
model.add(Conv2DTranspose(64, (4,4), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
# Output layer
model.add(Conv2DTranspose(3, (3,3), activation='tanh', padding='same'))
return model
This model starts with a dense layer and reshapes it into a multi-dimensional tensor. It then uses convolutional transpose layers (also known as deconvolutional layers) to upsample the data and generate an image.
4.2.2 The Discriminator
The discriminator's job is to distinguish between the real and fake (generated) images. It's essentially a binary classification model that classifies images as real (1) or fake (0).
Like our generator, we'll use a convolutional structure for our discriminator. Here's an example of what the discriminator's architecture might look like:
from keras.layers import Conv2D, Flatten, Dropout
from keras.models import Sequential
# Discriminator model
def create_discriminator(image_shape):
model = Sequential()
# Down-sample to 32x32
model.add(Conv2D(64, (3,3), strides=(2,2), padding='same', input_shape=image_shape))
model.add(LeakyReLU(alpha=0.2))
# Down-sample to 16x16
model.add(Conv2D(128, (3,3), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.4))
# Down-sample to 8x8
model.add(Conv2D(256, (3,3), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.4))
# Classifier
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
return model
This model uses standard convolutional layers to downsample the input image and classify it as real or fake. The dropout layers are used to prevent overfitting, and the LeakyReLU activation function is used to introduce nonlinearity into the model.
These code snippets provided here are a good starting point for the architecture of the GAN. However, when it comes to designing your own GAN for a specific task, a lot of experimentation is often needed to find an architecture and set of hyperparameters that work well.
With the generator and discriminator defined, we can now compile them into a GAN. The GAN will chain the generator and discriminator together: the generator will receive a point from the latent space as input and will output a candidate image, which will be fed into the discriminator alongside real images.
Here's an example of how we can compile our models into a GAN:
from keras.models import Model
from keras.optimizers import Adam
from keras.layers import Input
# Build and compile the discriminator
discriminator = create_discriminator(image_shape)
discriminator.compile(loss='binary_crossentropy',
optimizer=Adam(0.0002, 0.5),
metrics=['accuracy'])
# Build the generator
generator = create_generator(latent_dim)
# The generator takes noise as input and generates imgs
z = Input(shape=(latent_dim,))
img = generator(z)
# For the combined model we will only train the generator
discriminator.trainable = False
# The discriminator takes generated images as input and determines validity
validity = discriminator(img)
# The combined model (stacked generator and discriminator)
# Trains the generator to fool the discriminator
combined = Model(z, validity)
combined.compile(loss='binary_crossentropy',
optimizer=Adam(0.0002, 0.5))
This sets up the basic model structure for our GAN. The generator and discriminator are trained in tandem: the discriminator learning to better distinguish real from fake, and the generator learning to create more convincing fakes based on the discriminator's feedback.
In the next sections, we will look at how to train this model and generate new faces.
4.2 Model Creation
The model creation stage involves defining the architecture of our Generative Adversarial Network (GAN). As we know from Chapter 3, a GAN is composed of two main parts: the generator and the discriminator.
4.2.1 The Generator
The generator's purpose is to generate new data from random noise. The output of the generator should ideally be indistinguishable from the true data.
In our case, we're generating images, so our generator will output an image of the same size as the training images.
We'll use a Deep Convolutional GAN (DCGAN) structure for our generator. Here is an example of what the generator's architecture might look like in code:
from keras.models import Sequential
from keras.layers import Dense, Reshape, Conv2DTranspose, LeakyReLU, BatchNormalization
# Generator model
def create_generator(latent_dim):
model = Sequential()
# Start with dense layer from which to reshape
model.add(Dense(256*16*16, input_dim=latent_dim))
model.add(LeakyReLU(alpha=0.2))
model.add(Reshape((16, 16, 256)))
# Up-sample to 32x32
model.add(Conv2DTranspose(128, (4,4), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
# Up-sample to 64x64
model.add(Conv2DTranspose(64, (4,4), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
# Output layer
model.add(Conv2DTranspose(3, (3,3), activation='tanh', padding='same'))
return model
This model starts with a dense layer and reshapes it into a multi-dimensional tensor. It then uses convolutional transpose layers (also known as deconvolutional layers) to upsample the data and generate an image.
4.2.2 The Discriminator
The discriminator's job is to distinguish between the real and fake (generated) images. It's essentially a binary classification model that classifies images as real (1) or fake (0).
Like our generator, we'll use a convolutional structure for our discriminator. Here's an example of what the discriminator's architecture might look like:
from keras.layers import Conv2D, Flatten, Dropout
from keras.models import Sequential
# Discriminator model
def create_discriminator(image_shape):
model = Sequential()
# Down-sample to 32x32
model.add(Conv2D(64, (3,3), strides=(2,2), padding='same', input_shape=image_shape))
model.add(LeakyReLU(alpha=0.2))
# Down-sample to 16x16
model.add(Conv2D(128, (3,3), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.4))
# Down-sample to 8x8
model.add(Conv2D(256, (3,3), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.4))
# Classifier
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
return model
This model uses standard convolutional layers to downsample the input image and classify it as real or fake. The dropout layers are used to prevent overfitting, and the LeakyReLU activation function is used to introduce nonlinearity into the model.
These code snippets provided here are a good starting point for the architecture of the GAN. However, when it comes to designing your own GAN for a specific task, a lot of experimentation is often needed to find an architecture and set of hyperparameters that work well.
With the generator and discriminator defined, we can now compile them into a GAN. The GAN will chain the generator and discriminator together: the generator will receive a point from the latent space as input and will output a candidate image, which will be fed into the discriminator alongside real images.
Here's an example of how we can compile our models into a GAN:
from keras.models import Model
from keras.optimizers import Adam
from keras.layers import Input
# Build and compile the discriminator
discriminator = create_discriminator(image_shape)
discriminator.compile(loss='binary_crossentropy',
optimizer=Adam(0.0002, 0.5),
metrics=['accuracy'])
# Build the generator
generator = create_generator(latent_dim)
# The generator takes noise as input and generates imgs
z = Input(shape=(latent_dim,))
img = generator(z)
# For the combined model we will only train the generator
discriminator.trainable = False
# The discriminator takes generated images as input and determines validity
validity = discriminator(img)
# The combined model (stacked generator and discriminator)
# Trains the generator to fool the discriminator
combined = Model(z, validity)
combined.compile(loss='binary_crossentropy',
optimizer=Adam(0.0002, 0.5))
This sets up the basic model structure for our GAN. The generator and discriminator are trained in tandem: the discriminator learning to better distinguish real from fake, and the generator learning to create more convincing fakes based on the discriminator's feedback.
In the next sections, we will look at how to train this model and generate new faces.
4.2 Model Creation
The model creation stage involves defining the architecture of our Generative Adversarial Network (GAN). As we know from Chapter 3, a GAN is composed of two main parts: the generator and the discriminator.
4.2.1 The Generator
The generator's purpose is to generate new data from random noise. The output of the generator should ideally be indistinguishable from the true data.
In our case, we're generating images, so our generator will output an image of the same size as the training images.
We'll use a Deep Convolutional GAN (DCGAN) structure for our generator. Here is an example of what the generator's architecture might look like in code:
from keras.models import Sequential
from keras.layers import Dense, Reshape, Conv2DTranspose, LeakyReLU, BatchNormalization
# Generator model
def create_generator(latent_dim):
model = Sequential()
# Start with dense layer from which to reshape
model.add(Dense(256*16*16, input_dim=latent_dim))
model.add(LeakyReLU(alpha=0.2))
model.add(Reshape((16, 16, 256)))
# Up-sample to 32x32
model.add(Conv2DTranspose(128, (4,4), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
# Up-sample to 64x64
model.add(Conv2DTranspose(64, (4,4), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(BatchNormalization(momentum=0.8))
# Output layer
model.add(Conv2DTranspose(3, (3,3), activation='tanh', padding='same'))
return model
This model starts with a dense layer and reshapes it into a multi-dimensional tensor. It then uses convolutional transpose layers (also known as deconvolutional layers) to upsample the data and generate an image.
4.2.2 The Discriminator
The discriminator's job is to distinguish between the real and fake (generated) images. It's essentially a binary classification model that classifies images as real (1) or fake (0).
Like our generator, we'll use a convolutional structure for our discriminator. Here's an example of what the discriminator's architecture might look like:
from keras.layers import Conv2D, Flatten, Dropout
from keras.models import Sequential
# Discriminator model
def create_discriminator(image_shape):
model = Sequential()
# Down-sample to 32x32
model.add(Conv2D(64, (3,3), strides=(2,2), padding='same', input_shape=image_shape))
model.add(LeakyReLU(alpha=0.2))
# Down-sample to 16x16
model.add(Conv2D(128, (3,3), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.4))
# Down-sample to 8x8
model.add(Conv2D(256, (3,3), strides=(2,2), padding='same'))
model.add(LeakyReLU(alpha=0.2))
model.add(Dropout(0.4))
# Classifier
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
return model
This model uses standard convolutional layers to downsample the input image and classify it as real or fake. The dropout layers are used to prevent overfitting, and the LeakyReLU activation function is used to introduce nonlinearity into the model.
These code snippets provided here are a good starting point for the architecture of the GAN. However, when it comes to designing your own GAN for a specific task, a lot of experimentation is often needed to find an architecture and set of hyperparameters that work well.
With the generator and discriminator defined, we can now compile them into a GAN. The GAN will chain the generator and discriminator together: the generator will receive a point from the latent space as input and will output a candidate image, which will be fed into the discriminator alongside real images.
Here's an example of how we can compile our models into a GAN:
from keras.models import Model
from keras.optimizers import Adam
from keras.layers import Input
# Build and compile the discriminator
discriminator = create_discriminator(image_shape)
discriminator.compile(loss='binary_crossentropy',
optimizer=Adam(0.0002, 0.5),
metrics=['accuracy'])
# Build the generator
generator = create_generator(latent_dim)
# The generator takes noise as input and generates imgs
z = Input(shape=(latent_dim,))
img = generator(z)
# For the combined model we will only train the generator
discriminator.trainable = False
# The discriminator takes generated images as input and determines validity
validity = discriminator(img)
# The combined model (stacked generator and discriminator)
# Trains the generator to fool the discriminator
combined = Model(z, validity)
combined.compile(loss='binary_crossentropy',
optimizer=Adam(0.0002, 0.5))
This sets up the basic model structure for our GAN. The generator and discriminator are trained in tandem: the discriminator learning to better distinguish real from fake, and the generator learning to create more convincing fakes based on the discriminator's feedback.
In the next sections, we will look at how to train this model and generate new faces.