Menu iconMenu iconGenerative Deep Learning Updated Edition
Generative Deep Learning Updated Edition

Chapter 6: Project: Handwritten Digit Generation with VAEs

6.3 Generating New Handwritten Digits

With our Variational Autoencoder (VAE) model trained, we can now use it to generate new handwritten digits. This section will guide you through the process of sampling from the latent space and using the decoder to generate new images. We will also discuss how to visualize these generated digits and interpret the results.

6.3.1 Sampling from the Latent Space

The latent space is a lower-dimensional space where the VAE encodes the input data. To generate new images, we need to sample points from this latent space and pass them through the decoder to produce images.

Since the latent variables are modeled as Gaussian distributions, we can sample from a standard normal distribution to generate new latent variables.

Example: Sampling and Generating Images

import numpy as np
import matplotlib.pyplot as plt

# Function to generate new images from the latent space
def generate_images(decoder, latent_dim, n_samples=10):
    # Sample random latent vectors from a standard normal distribution
    random_latent_vectors = np.random.normal(size=(n_samples, latent_dim))
    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(random_latent_vectors)
    # Reshape the generated images for visualization
    generated_images = generated_images.reshape((n_samples, 28, 28))

    # Plot the generated images
    plt.figure(figsize=(10, 2))
    for i in range(n_samples):
        plt.subplot(1, n_samples, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Generate and visualize new images
generate_images(decoder, latent_dim)

The function 'generate_images' takes as input a decoder, the dimension of the latent space, and the number of samples to be generated. It first samples random latent vectors from a standard normal distribution. These vectors are then passed to the decoder to generate new images. The generated images are reshaped for visualization and then plotted using matplotlib.

6.3.2 Visualizing the Latent Space

Visualizing the latent space can provide insights into how the VAE has learned to represent the data. By interpolating between points in the latent space, we can observe how the generated images change smoothly, which indicates that the VAE has learned a meaningful representation of the data.

Example: Latent Space Interpolation

# Function to perform latent space interpolation
def interpolate_latent_space(decoder, latent_dim, n_interpolations=10):
    # Sample two random latent vectors from a standard normal distribution
    start_point = np.random.normal(size=(1, latent_dim))
    end_point = np.random.normal(size=(1, latent_dim))
    # Linearly interpolate between the two points
    interpolation = np.linspace(start_point, end_point, n_interpolations)

    # Generate images by decoding the interpolated latent vectors
    generated_images = decoder.predict(interpolation)
    generated_images = generated_images.reshape((n_interpolations, 28, 28))

    # Plot the interpolated images
    plt.figure(figsize=(15, 2))
    for i in range(n_interpolations):
        plt.subplot(1, n_interpolations, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Interpolate and visualize the latent space
interpolate_latent_space(decoder, latent_dim)

The example code defines a function called interpolate_latent_space, which performs latent space interpolation.

The function works as follows:

  1. It samples two random vectors from a standard normal distribution. These vectors represent points in the latent space (the start point and the end point).
  2. It then generates a series of points between these two points using linear interpolation. The number of points is defined by n_interpolations.
  3. The function then uses a decoder (a part of the model that transforms points in the latent space into data points) to generate new images from these interpolated points.
  4. These images are then reshaped and plotted for visualization. The images represent the gradual transformation from the data representation of the start point to that of the end point in the latent space.

Finally, the function interpolate_latent_space is called with decoder and latent_dim as arguments to perform and visualize the latent space interpolation.

6.3.3 Generating Digits with Specific Features

By exploring different regions of the latent space, we can generate digits with specific features. For instance, we might find that certain areas of the latent space correspond to digits with specific shapes or strokes. This can be useful for applications where specific types of digits are needed.

Example: Exploring Specific Latent Features

# Function to explore specific latent features
def explore_latent_features(decoder, latent_dim, feature_vector, variation_range=(-3, 3), n_variations=10):
    # Create a set of latent vectors varying one feature
    feature_variations = np.linspace(variation_range[0], variation_range[1], n_variations)
    latent_vectors = np.zeros((n_variations, latent_dim))
    for i, variation in enumerate(feature_variations):
        latent_vectors[i] = feature_vector
        latent_vectors[i, 0] = variation  # Vary the first feature for demonstration

    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(latent_vectors)
    generated_images = generated_images.reshape((n_variations, 28, 28))

    # Plot the generated images
    plt.figure(figsize=(15, 2))
    for i in range(n_variations):
        plt.subplot(1, n_variations, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Example feature vector
example_feature_vector = np.random.normal(size=(latent_dim,))

# Explore specific latent features
explore_latent_features(decoder, latent_dim, example_feature_vector)

This code defines a function named 'explore_latent_features'. This function is designed to examine specific latent features in a neural network's decoder.

The function takes a decoder, the dimension of the latent space, a feature vector, and two optional parameters defining the range of variation and the number of variations.

It works by creating a set of latent vectors that vary one feature across a range specified by the user. These latent vectors are then passed through the decoder to generate images.

The generated images are reshaped and plotted to visualize how varying the specific latent feature affects the output. The function is then called with an example feature vector to demonstrate its use.

6.3.4 Generating Diverse Digits

To generate a diverse set of digits, we can sample multiple points from the latent space. By ensuring that the latent space is well-structured and diverse, we can generate a wide variety of digits that resemble the training data.

Example: Generating a Diverse Set of Digits

# Function to generate a diverse set of digits
def generate_diverse_digits(decoder, latent_dim, n_samples=100):
    # Sample random latent vectors from a standard normal distribution
    random_latent_vectors = np.random.normal(size=(n_samples, latent_dim))
    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(random_latent_vectors)
    generated_images = generated_images.reshape((n_samples, 28, 28))

    # Plot a subset of the generated images
    n_display = 10
    plt.figure(figsize=(10, 2))
    for i in range(n_display):
        plt.subplot(1, n_display, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Generate and visualize a diverse set of digits
generate_diverse_digits(decoder, latent_dim)

This script defines and calls a function named "generate_diverse_digits". The purpose of this function is to generate a diverse set of digit images using a decoder model and latent dimension.

The function works in the following way:

  1. It samples random latent vectors from a standard normal distribution. The number of samples is determined by the n_samples parameter, and the dimensionality of each vector is determined by latent_dim.
  2. It uses the decoder model to generate images from the random latent vectors. The generated images are reshaped into a 2D grid of 28x28 pixel images.
  3. It plots a subset of the generated images. The number of images to plot is determined by n_display. For each generated image, it creates a subplot, displays the image in grayscale, and removes the axis.

Finally, the function is called with the decoder model and latent dimension to generate and visualize a diverse set of digits.

Summary

In this section, we explored the process of generating new handwritten digits using a trained Variational Autoencoder (VAE). We discussed how to sample from the latent space and use the decoder to generate images. We also demonstrated how to visualize the latent space through interpolation and explore specific latent features. By generating diverse sets of digits, we highlighted the VAE's ability to produce a wide variety of realistic images.

These techniques provide valuable insights into the capabilities of VAEs and their potential applications in generative modeling. 

6.3 Generating New Handwritten Digits

With our Variational Autoencoder (VAE) model trained, we can now use it to generate new handwritten digits. This section will guide you through the process of sampling from the latent space and using the decoder to generate new images. We will also discuss how to visualize these generated digits and interpret the results.

6.3.1 Sampling from the Latent Space

The latent space is a lower-dimensional space where the VAE encodes the input data. To generate new images, we need to sample points from this latent space and pass them through the decoder to produce images.

Since the latent variables are modeled as Gaussian distributions, we can sample from a standard normal distribution to generate new latent variables.

Example: Sampling and Generating Images

import numpy as np
import matplotlib.pyplot as plt

# Function to generate new images from the latent space
def generate_images(decoder, latent_dim, n_samples=10):
    # Sample random latent vectors from a standard normal distribution
    random_latent_vectors = np.random.normal(size=(n_samples, latent_dim))
    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(random_latent_vectors)
    # Reshape the generated images for visualization
    generated_images = generated_images.reshape((n_samples, 28, 28))

    # Plot the generated images
    plt.figure(figsize=(10, 2))
    for i in range(n_samples):
        plt.subplot(1, n_samples, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Generate and visualize new images
generate_images(decoder, latent_dim)

The function 'generate_images' takes as input a decoder, the dimension of the latent space, and the number of samples to be generated. It first samples random latent vectors from a standard normal distribution. These vectors are then passed to the decoder to generate new images. The generated images are reshaped for visualization and then plotted using matplotlib.

6.3.2 Visualizing the Latent Space

Visualizing the latent space can provide insights into how the VAE has learned to represent the data. By interpolating between points in the latent space, we can observe how the generated images change smoothly, which indicates that the VAE has learned a meaningful representation of the data.

Example: Latent Space Interpolation

# Function to perform latent space interpolation
def interpolate_latent_space(decoder, latent_dim, n_interpolations=10):
    # Sample two random latent vectors from a standard normal distribution
    start_point = np.random.normal(size=(1, latent_dim))
    end_point = np.random.normal(size=(1, latent_dim))
    # Linearly interpolate between the two points
    interpolation = np.linspace(start_point, end_point, n_interpolations)

    # Generate images by decoding the interpolated latent vectors
    generated_images = decoder.predict(interpolation)
    generated_images = generated_images.reshape((n_interpolations, 28, 28))

    # Plot the interpolated images
    plt.figure(figsize=(15, 2))
    for i in range(n_interpolations):
        plt.subplot(1, n_interpolations, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Interpolate and visualize the latent space
interpolate_latent_space(decoder, latent_dim)

The example code defines a function called interpolate_latent_space, which performs latent space interpolation.

The function works as follows:

  1. It samples two random vectors from a standard normal distribution. These vectors represent points in the latent space (the start point and the end point).
  2. It then generates a series of points between these two points using linear interpolation. The number of points is defined by n_interpolations.
  3. The function then uses a decoder (a part of the model that transforms points in the latent space into data points) to generate new images from these interpolated points.
  4. These images are then reshaped and plotted for visualization. The images represent the gradual transformation from the data representation of the start point to that of the end point in the latent space.

Finally, the function interpolate_latent_space is called with decoder and latent_dim as arguments to perform and visualize the latent space interpolation.

6.3.3 Generating Digits with Specific Features

By exploring different regions of the latent space, we can generate digits with specific features. For instance, we might find that certain areas of the latent space correspond to digits with specific shapes or strokes. This can be useful for applications where specific types of digits are needed.

Example: Exploring Specific Latent Features

# Function to explore specific latent features
def explore_latent_features(decoder, latent_dim, feature_vector, variation_range=(-3, 3), n_variations=10):
    # Create a set of latent vectors varying one feature
    feature_variations = np.linspace(variation_range[0], variation_range[1], n_variations)
    latent_vectors = np.zeros((n_variations, latent_dim))
    for i, variation in enumerate(feature_variations):
        latent_vectors[i] = feature_vector
        latent_vectors[i, 0] = variation  # Vary the first feature for demonstration

    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(latent_vectors)
    generated_images = generated_images.reshape((n_variations, 28, 28))

    # Plot the generated images
    plt.figure(figsize=(15, 2))
    for i in range(n_variations):
        plt.subplot(1, n_variations, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Example feature vector
example_feature_vector = np.random.normal(size=(latent_dim,))

# Explore specific latent features
explore_latent_features(decoder, latent_dim, example_feature_vector)

This code defines a function named 'explore_latent_features'. This function is designed to examine specific latent features in a neural network's decoder.

The function takes a decoder, the dimension of the latent space, a feature vector, and two optional parameters defining the range of variation and the number of variations.

It works by creating a set of latent vectors that vary one feature across a range specified by the user. These latent vectors are then passed through the decoder to generate images.

The generated images are reshaped and plotted to visualize how varying the specific latent feature affects the output. The function is then called with an example feature vector to demonstrate its use.

6.3.4 Generating Diverse Digits

To generate a diverse set of digits, we can sample multiple points from the latent space. By ensuring that the latent space is well-structured and diverse, we can generate a wide variety of digits that resemble the training data.

Example: Generating a Diverse Set of Digits

# Function to generate a diverse set of digits
def generate_diverse_digits(decoder, latent_dim, n_samples=100):
    # Sample random latent vectors from a standard normal distribution
    random_latent_vectors = np.random.normal(size=(n_samples, latent_dim))
    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(random_latent_vectors)
    generated_images = generated_images.reshape((n_samples, 28, 28))

    # Plot a subset of the generated images
    n_display = 10
    plt.figure(figsize=(10, 2))
    for i in range(n_display):
        plt.subplot(1, n_display, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Generate and visualize a diverse set of digits
generate_diverse_digits(decoder, latent_dim)

This script defines and calls a function named "generate_diverse_digits". The purpose of this function is to generate a diverse set of digit images using a decoder model and latent dimension.

The function works in the following way:

  1. It samples random latent vectors from a standard normal distribution. The number of samples is determined by the n_samples parameter, and the dimensionality of each vector is determined by latent_dim.
  2. It uses the decoder model to generate images from the random latent vectors. The generated images are reshaped into a 2D grid of 28x28 pixel images.
  3. It plots a subset of the generated images. The number of images to plot is determined by n_display. For each generated image, it creates a subplot, displays the image in grayscale, and removes the axis.

Finally, the function is called with the decoder model and latent dimension to generate and visualize a diverse set of digits.

Summary

In this section, we explored the process of generating new handwritten digits using a trained Variational Autoencoder (VAE). We discussed how to sample from the latent space and use the decoder to generate images. We also demonstrated how to visualize the latent space through interpolation and explore specific latent features. By generating diverse sets of digits, we highlighted the VAE's ability to produce a wide variety of realistic images.

These techniques provide valuable insights into the capabilities of VAEs and their potential applications in generative modeling. 

6.3 Generating New Handwritten Digits

With our Variational Autoencoder (VAE) model trained, we can now use it to generate new handwritten digits. This section will guide you through the process of sampling from the latent space and using the decoder to generate new images. We will also discuss how to visualize these generated digits and interpret the results.

6.3.1 Sampling from the Latent Space

The latent space is a lower-dimensional space where the VAE encodes the input data. To generate new images, we need to sample points from this latent space and pass them through the decoder to produce images.

Since the latent variables are modeled as Gaussian distributions, we can sample from a standard normal distribution to generate new latent variables.

Example: Sampling and Generating Images

import numpy as np
import matplotlib.pyplot as plt

# Function to generate new images from the latent space
def generate_images(decoder, latent_dim, n_samples=10):
    # Sample random latent vectors from a standard normal distribution
    random_latent_vectors = np.random.normal(size=(n_samples, latent_dim))
    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(random_latent_vectors)
    # Reshape the generated images for visualization
    generated_images = generated_images.reshape((n_samples, 28, 28))

    # Plot the generated images
    plt.figure(figsize=(10, 2))
    for i in range(n_samples):
        plt.subplot(1, n_samples, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Generate and visualize new images
generate_images(decoder, latent_dim)

The function 'generate_images' takes as input a decoder, the dimension of the latent space, and the number of samples to be generated. It first samples random latent vectors from a standard normal distribution. These vectors are then passed to the decoder to generate new images. The generated images are reshaped for visualization and then plotted using matplotlib.

6.3.2 Visualizing the Latent Space

Visualizing the latent space can provide insights into how the VAE has learned to represent the data. By interpolating between points in the latent space, we can observe how the generated images change smoothly, which indicates that the VAE has learned a meaningful representation of the data.

Example: Latent Space Interpolation

# Function to perform latent space interpolation
def interpolate_latent_space(decoder, latent_dim, n_interpolations=10):
    # Sample two random latent vectors from a standard normal distribution
    start_point = np.random.normal(size=(1, latent_dim))
    end_point = np.random.normal(size=(1, latent_dim))
    # Linearly interpolate between the two points
    interpolation = np.linspace(start_point, end_point, n_interpolations)

    # Generate images by decoding the interpolated latent vectors
    generated_images = decoder.predict(interpolation)
    generated_images = generated_images.reshape((n_interpolations, 28, 28))

    # Plot the interpolated images
    plt.figure(figsize=(15, 2))
    for i in range(n_interpolations):
        plt.subplot(1, n_interpolations, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Interpolate and visualize the latent space
interpolate_latent_space(decoder, latent_dim)

The example code defines a function called interpolate_latent_space, which performs latent space interpolation.

The function works as follows:

  1. It samples two random vectors from a standard normal distribution. These vectors represent points in the latent space (the start point and the end point).
  2. It then generates a series of points between these two points using linear interpolation. The number of points is defined by n_interpolations.
  3. The function then uses a decoder (a part of the model that transforms points in the latent space into data points) to generate new images from these interpolated points.
  4. These images are then reshaped and plotted for visualization. The images represent the gradual transformation from the data representation of the start point to that of the end point in the latent space.

Finally, the function interpolate_latent_space is called with decoder and latent_dim as arguments to perform and visualize the latent space interpolation.

6.3.3 Generating Digits with Specific Features

By exploring different regions of the latent space, we can generate digits with specific features. For instance, we might find that certain areas of the latent space correspond to digits with specific shapes or strokes. This can be useful for applications where specific types of digits are needed.

Example: Exploring Specific Latent Features

# Function to explore specific latent features
def explore_latent_features(decoder, latent_dim, feature_vector, variation_range=(-3, 3), n_variations=10):
    # Create a set of latent vectors varying one feature
    feature_variations = np.linspace(variation_range[0], variation_range[1], n_variations)
    latent_vectors = np.zeros((n_variations, latent_dim))
    for i, variation in enumerate(feature_variations):
        latent_vectors[i] = feature_vector
        latent_vectors[i, 0] = variation  # Vary the first feature for demonstration

    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(latent_vectors)
    generated_images = generated_images.reshape((n_variations, 28, 28))

    # Plot the generated images
    plt.figure(figsize=(15, 2))
    for i in range(n_variations):
        plt.subplot(1, n_variations, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Example feature vector
example_feature_vector = np.random.normal(size=(latent_dim,))

# Explore specific latent features
explore_latent_features(decoder, latent_dim, example_feature_vector)

This code defines a function named 'explore_latent_features'. This function is designed to examine specific latent features in a neural network's decoder.

The function takes a decoder, the dimension of the latent space, a feature vector, and two optional parameters defining the range of variation and the number of variations.

It works by creating a set of latent vectors that vary one feature across a range specified by the user. These latent vectors are then passed through the decoder to generate images.

The generated images are reshaped and plotted to visualize how varying the specific latent feature affects the output. The function is then called with an example feature vector to demonstrate its use.

6.3.4 Generating Diverse Digits

To generate a diverse set of digits, we can sample multiple points from the latent space. By ensuring that the latent space is well-structured and diverse, we can generate a wide variety of digits that resemble the training data.

Example: Generating a Diverse Set of Digits

# Function to generate a diverse set of digits
def generate_diverse_digits(decoder, latent_dim, n_samples=100):
    # Sample random latent vectors from a standard normal distribution
    random_latent_vectors = np.random.normal(size=(n_samples, latent_dim))
    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(random_latent_vectors)
    generated_images = generated_images.reshape((n_samples, 28, 28))

    # Plot a subset of the generated images
    n_display = 10
    plt.figure(figsize=(10, 2))
    for i in range(n_display):
        plt.subplot(1, n_display, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Generate and visualize a diverse set of digits
generate_diverse_digits(decoder, latent_dim)

This script defines and calls a function named "generate_diverse_digits". The purpose of this function is to generate a diverse set of digit images using a decoder model and latent dimension.

The function works in the following way:

  1. It samples random latent vectors from a standard normal distribution. The number of samples is determined by the n_samples parameter, and the dimensionality of each vector is determined by latent_dim.
  2. It uses the decoder model to generate images from the random latent vectors. The generated images are reshaped into a 2D grid of 28x28 pixel images.
  3. It plots a subset of the generated images. The number of images to plot is determined by n_display. For each generated image, it creates a subplot, displays the image in grayscale, and removes the axis.

Finally, the function is called with the decoder model and latent dimension to generate and visualize a diverse set of digits.

Summary

In this section, we explored the process of generating new handwritten digits using a trained Variational Autoencoder (VAE). We discussed how to sample from the latent space and use the decoder to generate images. We also demonstrated how to visualize the latent space through interpolation and explore specific latent features. By generating diverse sets of digits, we highlighted the VAE's ability to produce a wide variety of realistic images.

These techniques provide valuable insights into the capabilities of VAEs and their potential applications in generative modeling. 

6.3 Generating New Handwritten Digits

With our Variational Autoencoder (VAE) model trained, we can now use it to generate new handwritten digits. This section will guide you through the process of sampling from the latent space and using the decoder to generate new images. We will also discuss how to visualize these generated digits and interpret the results.

6.3.1 Sampling from the Latent Space

The latent space is a lower-dimensional space where the VAE encodes the input data. To generate new images, we need to sample points from this latent space and pass them through the decoder to produce images.

Since the latent variables are modeled as Gaussian distributions, we can sample from a standard normal distribution to generate new latent variables.

Example: Sampling and Generating Images

import numpy as np
import matplotlib.pyplot as plt

# Function to generate new images from the latent space
def generate_images(decoder, latent_dim, n_samples=10):
    # Sample random latent vectors from a standard normal distribution
    random_latent_vectors = np.random.normal(size=(n_samples, latent_dim))
    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(random_latent_vectors)
    # Reshape the generated images for visualization
    generated_images = generated_images.reshape((n_samples, 28, 28))

    # Plot the generated images
    plt.figure(figsize=(10, 2))
    for i in range(n_samples):
        plt.subplot(1, n_samples, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Generate and visualize new images
generate_images(decoder, latent_dim)

The function 'generate_images' takes as input a decoder, the dimension of the latent space, and the number of samples to be generated. It first samples random latent vectors from a standard normal distribution. These vectors are then passed to the decoder to generate new images. The generated images are reshaped for visualization and then plotted using matplotlib.

6.3.2 Visualizing the Latent Space

Visualizing the latent space can provide insights into how the VAE has learned to represent the data. By interpolating between points in the latent space, we can observe how the generated images change smoothly, which indicates that the VAE has learned a meaningful representation of the data.

Example: Latent Space Interpolation

# Function to perform latent space interpolation
def interpolate_latent_space(decoder, latent_dim, n_interpolations=10):
    # Sample two random latent vectors from a standard normal distribution
    start_point = np.random.normal(size=(1, latent_dim))
    end_point = np.random.normal(size=(1, latent_dim))
    # Linearly interpolate between the two points
    interpolation = np.linspace(start_point, end_point, n_interpolations)

    # Generate images by decoding the interpolated latent vectors
    generated_images = decoder.predict(interpolation)
    generated_images = generated_images.reshape((n_interpolations, 28, 28))

    # Plot the interpolated images
    plt.figure(figsize=(15, 2))
    for i in range(n_interpolations):
        plt.subplot(1, n_interpolations, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Interpolate and visualize the latent space
interpolate_latent_space(decoder, latent_dim)

The example code defines a function called interpolate_latent_space, which performs latent space interpolation.

The function works as follows:

  1. It samples two random vectors from a standard normal distribution. These vectors represent points in the latent space (the start point and the end point).
  2. It then generates a series of points between these two points using linear interpolation. The number of points is defined by n_interpolations.
  3. The function then uses a decoder (a part of the model that transforms points in the latent space into data points) to generate new images from these interpolated points.
  4. These images are then reshaped and plotted for visualization. The images represent the gradual transformation from the data representation of the start point to that of the end point in the latent space.

Finally, the function interpolate_latent_space is called with decoder and latent_dim as arguments to perform and visualize the latent space interpolation.

6.3.3 Generating Digits with Specific Features

By exploring different regions of the latent space, we can generate digits with specific features. For instance, we might find that certain areas of the latent space correspond to digits with specific shapes or strokes. This can be useful for applications where specific types of digits are needed.

Example: Exploring Specific Latent Features

# Function to explore specific latent features
def explore_latent_features(decoder, latent_dim, feature_vector, variation_range=(-3, 3), n_variations=10):
    # Create a set of latent vectors varying one feature
    feature_variations = np.linspace(variation_range[0], variation_range[1], n_variations)
    latent_vectors = np.zeros((n_variations, latent_dim))
    for i, variation in enumerate(feature_variations):
        latent_vectors[i] = feature_vector
        latent_vectors[i, 0] = variation  # Vary the first feature for demonstration

    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(latent_vectors)
    generated_images = generated_images.reshape((n_variations, 28, 28))

    # Plot the generated images
    plt.figure(figsize=(15, 2))
    for i in range(n_variations):
        plt.subplot(1, n_variations, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Example feature vector
example_feature_vector = np.random.normal(size=(latent_dim,))

# Explore specific latent features
explore_latent_features(decoder, latent_dim, example_feature_vector)

This code defines a function named 'explore_latent_features'. This function is designed to examine specific latent features in a neural network's decoder.

The function takes a decoder, the dimension of the latent space, a feature vector, and two optional parameters defining the range of variation and the number of variations.

It works by creating a set of latent vectors that vary one feature across a range specified by the user. These latent vectors are then passed through the decoder to generate images.

The generated images are reshaped and plotted to visualize how varying the specific latent feature affects the output. The function is then called with an example feature vector to demonstrate its use.

6.3.4 Generating Diverse Digits

To generate a diverse set of digits, we can sample multiple points from the latent space. By ensuring that the latent space is well-structured and diverse, we can generate a wide variety of digits that resemble the training data.

Example: Generating a Diverse Set of Digits

# Function to generate a diverse set of digits
def generate_diverse_digits(decoder, latent_dim, n_samples=100):
    # Sample random latent vectors from a standard normal distribution
    random_latent_vectors = np.random.normal(size=(n_samples, latent_dim))
    # Generate images by decoding the latent vectors
    generated_images = decoder.predict(random_latent_vectors)
    generated_images = generated_images.reshape((n_samples, 28, 28))

    # Plot a subset of the generated images
    n_display = 10
    plt.figure(figsize=(10, 2))
    for i in range(n_display):
        plt.subplot(1, n_display, i + 1)
        plt.imshow(generated_images[i], cmap='gray')
        plt.axis('off')
    plt.show()

# Generate and visualize a diverse set of digits
generate_diverse_digits(decoder, latent_dim)

This script defines and calls a function named "generate_diverse_digits". The purpose of this function is to generate a diverse set of digit images using a decoder model and latent dimension.

The function works in the following way:

  1. It samples random latent vectors from a standard normal distribution. The number of samples is determined by the n_samples parameter, and the dimensionality of each vector is determined by latent_dim.
  2. It uses the decoder model to generate images from the random latent vectors. The generated images are reshaped into a 2D grid of 28x28 pixel images.
  3. It plots a subset of the generated images. The number of images to plot is determined by n_display. For each generated image, it creates a subplot, displays the image in grayscale, and removes the axis.

Finally, the function is called with the decoder model and latent dimension to generate and visualize a diverse set of digits.

Summary

In this section, we explored the process of generating new handwritten digits using a trained Variational Autoencoder (VAE). We discussed how to sample from the latent space and use the decoder to generate images. We also demonstrated how to visualize the latent space through interpolation and explore specific latent features. By generating diverse sets of digits, we highlighted the VAE's ability to produce a wide variety of realistic images.

These techniques provide valuable insights into the capabilities of VAEs and their potential applications in generative modeling.