Introducción

En esta sección, aprenderemos a crear una Red Generativa Adversarial (GAN) para la generación de imágenes. Las GANs son un tipo de red neuronal que consta de dos sub-redes: el generador y el discriminador. Estas redes compiten entre sí en un juego de suma cero, donde el generador intenta crear imágenes que parezcan reales y el discriminador intenta distinguir entre imágenes reales y generadas.

Objetivos

  • Comprender la arquitectura de una GAN.
  • Implementar una GAN básica para la generación de imágenes.
  • Entrenar la GAN y evaluar su rendimiento.

Arquitectura de una GAN

Una GAN consta de dos componentes principales:

  1. Generador (G): Toma un vector de ruido como entrada y genera una imagen.
  2. Discriminador (D): Toma una imagen como entrada y predice si es real o generada.

Diagrama de una GAN

Vector de Ruido (z) --> Generador (G) --> Imagen Generada (G(z))
Imagen Real (x) --> Discriminador (D) --> Probabilidad de ser Real (D(x))
Imagen Generada (G(z)) --> Discriminador (D) --> Probabilidad de ser Real (D(G(z)))

Implementación de una GAN

Paso 1: Importar las Librerías Necesarias

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.datasets as dsets
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt

Paso 2: Definir el Generador

class Generator(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(Generator, self).__init__()
        self.main = nn.Sequential(
            nn.Linear(input_size, hidden_size),
            nn.ReLU(True),
            nn.Linear(hidden_size, hidden_size),
            nn.ReLU(True),
            nn.Linear(hidden_size, output_size),
            nn.Tanh()
        )

    def forward(self, x):
        return self.main(x)

Paso 3: Definir el Discriminador

class Discriminator(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(Discriminator, self).__init__()
        self.main = nn.Sequential(
            nn.Linear(input_size, hidden_size),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Linear(hidden_size, hidden_size),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Linear(hidden_size, output_size),
            nn.Sigmoid()
        )

    def forward(self, x):
        return self.main(x)

Paso 4: Configurar el Entrenamiento

# Hiperparámetros
batch_size = 100
learning_rate = 0.0002
num_epochs = 100
input_size = 784  # Para imágenes de 28x28
hidden_size = 256
latent_size = 64

# Cargar el dataset MNIST
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=(0.5,), std=(0.5,))
])

mnist = dsets.MNIST(root='./data', train=True, transform=transform, download=True)
data_loader = DataLoader(dataset=mnist, batch_size=batch_size, shuffle=True)

# Crear las redes
G = Generator(latent_size, hidden_size, input_size)
D = Discriminator(input_size, hidden_size, 1)

# Configurar los optimizadores
criterion = nn.BCELoss()
optimizerD = optim.Adam(D.parameters(), lr=learning_rate)
optimizerG = optim.Adam(G.parameters(), lr=learning_rate)

Paso 5: Entrenar la GAN

for epoch in range(num_epochs):
    for i, (images, _) in enumerate(data_loader):
        # Preparar datos reales y etiquetas
        images = images.view(batch_size, -1)
        real_labels = torch.ones(batch_size, 1)
        fake_labels = torch.zeros(batch_size, 1)

        # Entrenar el discriminador
        outputs = D(images)
        d_loss_real = criterion(outputs, real_labels)
        real_score = outputs

        z = torch.randn(batch_size, latent_size)
        fake_images = G(z)
        outputs = D(fake_images)
        d_loss_fake = criterion(outputs, fake_labels)
        fake_score = outputs

        d_loss = d_loss_real + d_loss_fake
        optimizerD.zero_grad()
        d_loss.backward()
        optimizerD.step()

        # Entrenar el generador
        z = torch.randn(batch_size, latent_size)
        fake_images = G(z)
        outputs = D(fake_images)
        g_loss = criterion(outputs, real_labels)

        optimizerG.zero_grad()
        g_loss.backward()
        optimizerG.step()

    print(f'Epoch [{epoch+1}/{num_epochs}], d_loss: {d_loss.item():.4f}, g_loss: {g_loss.item():.4f}, D(x): {real_score.mean().item():.2f}, D(G(z)): {fake_score.mean().item():.2f}')

Paso 6: Generar y Visualizar Imágenes

# Generar imágenes después del entrenamiento
z = torch.randn(batch_size, latent_size)
fake_images = G(z)
fake_images = fake_images.view(fake_images.size(0), 1, 28, 28)
fake_images = fake_images.data

# Visualizar algunas imágenes generadas
for i in range(6):
    plt.subplot(2, 3, i+1)
    plt.imshow(fake_images[i][0], cmap='gray')
plt.show()

Ejercicio Práctico

Ejercicio 1: Modificar la Arquitectura del Generador

Modifica la arquitectura del generador para que tenga más capas y neuronas. Observa cómo esto afecta la calidad de las imágenes generadas.

Ejercicio 2: Entrenar la GAN con un Dataset Diferente

Entrena la GAN utilizando un dataset diferente, como CIFAR-10. Asegúrate de ajustar los tamaños de entrada y salida en consecuencia.

Soluciones

Solución al Ejercicio 1

class Generator(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(Generator, self).__init__()
        self.main = nn.Sequential(
            nn.Linear(input_size, hidden_size),
            nn.ReLU(True),
            nn.Linear(hidden_size, hidden_size),
            nn.ReLU(True),
            nn.Linear(hidden_size, hidden_size),
            nn.ReLU(True),
            nn.Linear(hidden_size, output_size),
            nn.Tanh()
        )

    def forward(self, x):
        return self.main(x)

Solución al Ejercicio 2

# Cargar el dataset CIFAR-10
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
])

cifar10 = dsets.CIFAR10(root='./data', train=True, transform=transform, download=True)
data_loader = DataLoader(dataset=cifar10, batch_size=batch_size, shuffle=True)

# Ajustar los tamaños de entrada y salida
input_size = 3072  # Para imágenes de 32x32x3
output_size = 3072

Conclusión

En esta sección, hemos aprendido a crear y entrenar una GAN para la generación de imágenes. Hemos explorado la arquitectura básica de una GAN y cómo implementar tanto el generador como el discriminador. Además, hemos realizado ejercicios prácticos para modificar y mejorar la GAN. Con estos conocimientos, estás preparado para explorar aplicaciones más avanzadas y personalizadas de las GANs en tus propios proyectos.

© Copyright 2024. Todos los derechos reservados