Deep Learning PyTorch Course, DCGAN

In this course, we will take a closer look at DCGAN (Deep Convolutional GAN), a type of Generative Adversarial Networks (GAN), which is a field of deep learning. DCGAN is a model specialized for image generation and transformation tasks, particularly excelling in high-resolution image generation.

1. Understanding GAN

GAN consists of two neural networks: a Generator and a Discriminator. The Generator generates fake data that resembles real data, while the Discriminator distinguishes between real and fake data. These two networks compete and learn from each other, with the Generator increasingly generating more realistic data.

1.1 Basic Concept of GAN

The learning process of GAN occurs as follows:

  • 1. The Generator G takes a random noise vector z as input and generates a fake image G(z).
  • 2. The Discriminator D takes both a real image x and the generated image G(z) as input and outputs the probabilities of each being real/fake.
  • 3. The Generator learns to mislead D into thinking the fake image is real, while the Discriminator learns to accurately distinguish real images.

2. Concept of DCGAN

DCGAN extends GAN to deep convolutional networks. DCGAN uses convolutional layers to learn a spatial hierarchy for better performance in image generation tasks. DCGAN has the following structural features:

  • Uses stride for downsampling instead of traditional pooling layers.
  • Applies Batch Normalization to stabilize learning.
  • Uses ReLU activation function, and Tanh activation function in the output layer of the Generator.

2.1 Structure of DCGAN

The structure of DCGAN is as follows:

  • Generator G:
    • Input: Random noise vector z
    • Layers: Several transposed convolution layers with batch normalization and ReLU activation function
    • Output: Generated image
  • Discriminator D:
    • Input: Image (real or generated)
    • Layers: Several convolution layers with batch normalization and Leaky ReLU activation function
    • Output: Probability of being real/fake

3. Python Implementation of DCGAN

Now, we will implement DCGAN in Python. Using PyTorch, we can train the model at high speed utilizing various supported GPUs. The following code establishes the basic structure of DCGAN.

3.1 Installing Required Libraries

!pip install torch torchvision

3.2 Loading the Dataset

In this example, we will use the MNIST dataset to generate handwritten digits. We will proceed to load and preprocess the data.


import torch
import torchvision
import torchvision.transforms as transforms

# Dataset transformation definition: Normalize images to 0-1 and convert to tensor
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])

# Load MNIST dataset
train_dataset = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
    

3.3 Defining the Generator and Discriminator

Now we will implement the Generator and Discriminator models. As explained earlier, the Generator uses transposed convolution layers to generate images, while the Discriminator uses convolution layers to discriminate images.


import torch.nn as nn

class Generator(nn.Module):
    def __init__(self):
        super(Generator, self).__init__()
        self.model = nn.Sequential(
            nn.ConvTranspose2d(100, 256, 4, 1, 0, bias=False),
            nn.BatchNorm2d(256),
            nn.ReLU(True),
            nn.ConvTranspose2d(256, 128, 4, 2, 1, bias=False),
            nn.BatchNorm2d(128),
            nn.ReLU(True),
            nn.ConvTranspose2d(128, 1, 4, 2, 1, bias=False),
            nn.Tanh()
        )

    def forward(self, input):
        return self.model(input)

class Discriminator(nn.Module):
    def __init__(self):
        super(Discriminator, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(1, 128, 4, 2, 1, bias=False),
            nn.LeakyReLU(0.2),
            nn.Conv2d(128, 256, 4, 2, 1, bias=False),
            nn.BatchNorm2d(256),
            nn.LeakyReLU(0.2),
            nn.Conv2d(256, 1, 4, 1, 0, bias=False),
            nn.Sigmoid()
        )

    def forward(self, input):
        return self.model(input)
    

3.4 Model Initialization

We will instantiate the Generator and Discriminator models and define the loss function and optimization algorithm. Here, we will use binary cross-entropy loss and the Adam optimizer.


device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# Instantiate models
generator = Generator().to(device)
discriminator = Discriminator().to(device)

# Define loss function and optimizer
criterion = nn.BCELoss()
optimizerG = torch.optim.Adam(generator.parameters(), lr=0.0002, betas=(0.5, 0.999))
optimizerD = torch.optim.Adam(discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999))
    

3.5 Training Loop

We will proceed with the training of DCGAN. In each iteration, we will log the loss of the Generator and Discriminator, and output some sample images to verify that the model is learning correctly.


num_epochs = 50
for epoch in range(num_epochs):
    for i, (images, _) in enumerate(train_loader):
        # Prepare training data
        images = images.to(device)

        # Define labels
        batch_size = images.size(0)
        labels = torch.full((batch_size,), 1, device=device)  # Labels for real images
        noise = torch.randn(batch_size, 100, 1, 1, device=device)  # Input noise for the Generator

        # ------------------- Discriminator Training -------------------
        optimizerD.zero_grad()

        # Loss for real images
        output = discriminator(images).view(-1)
        lossD_real = criterion(output, labels)
        lossD_real.backward()

        # Generate fake images and calculate loss
        fake_images = generator(noise)
        labels.fill_(0)  # Labels for fake images
        output = discriminator(fake_images.detach()).view(-1)
        lossD_fake = criterion(output, labels)
        lossD_fake.backward()

        # Optimize Discriminator
        optimizerD.step()

        # ------------------- Generator Training -------------------
        optimizerG.zero_grad()
        labels.fill_(1)  # The Generator wants to classify fake images as real
        output = discriminator(fake_images).view(-1)
        lossG = criterion(output, labels)
        lossG.backward()
        optimizerG.step()

    # Output results
    print(f'Epoch [{epoch+1}/{num_epochs}], Loss D: {lossD_real.item() + lossD_fake.item()}, Loss G: {lossG.item()}')
    

3.6 Visualizing Results

After the training, generated images can be visualized to check the results. For example, we can use matplotlib to output some sample images.


import matplotlib.pyplot as plt

def show_generated_images(num_images=25):
    noise = torch.randn(num_images, 100, 1, 1, device=device)
    with torch.no_grad():
        generated_images = generator(noise).cpu().detach().numpy()
    generated_images = (generated_images + 1) / 2  # Convert to [0, 1] range

    plt.figure(figsize=(10, 10))
    for i in range(num_images):
        plt.subplot(5, 5, i + 1)
        plt.imshow(generated_images[i][0], cmap='gray')
        plt.axis('off')
    plt.show()

show_generated_images()
    

4. Conclusion

In this course, we explored the theory and implementation process of DCGAN. GAN holds great potential in generative modeling, and DCGAN demonstrates particularly strong performance in the field of image generation. We encourage you to apply real cases to directly experience the model training process.

Challenge yourself with various image generation tasks using DCGAN!