# 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:

- 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).
- It then generates a series of points between these two points using linear interpolation. The number of points is defined by
`n_interpolations`

. - 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. - 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:

- 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`

. - 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.
- 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:

- 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).
- It then generates a series of points between these two points using linear interpolation. The number of points is defined by
`n_interpolations`

. - 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. - 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:

- 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`

. - 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.
- 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:

- 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).
- It then generates a series of points between these two points using linear interpolation. The number of points is defined by
`n_interpolations`

. - 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. - 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:

- 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`

. - 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.
- 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

### 6.3.1 Sampling from the Latent Space

**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)

### 6.3.2 Visualizing the Latent Space

**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)

`interpolate_latent_space`

, which performs latent space interpolation.

The function works as follows:

- It then generates a series of points between these two points using linear interpolation. The number of points is defined by
`n_interpolations`

. - 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.

`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

**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)

### 6.3.4 Generating Diverse Digits

**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)

The function works in the following way:

- 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`

. - 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.

**Summary**