Menu iconMenu icon
Aprendizaje Profundo Generativo Edición Actualizada

Capítulo 3: Profundizando en las Redes Generativas Antagónicas (GANs)

3.5 Variaciones de las GANs

Desde la introducción de las innovadoras Redes Generativas Adversariales (GANs), se han desarrollado meticulosamente una gran cantidad de modificaciones y mejoras con el objetivo de abordar desafíos específicos que se encontraron y de expandir significativamente las capacidades del marco original de las GANs.

Estas variaciones son numerosas y diversas, incluyendo, pero no limitándose a, las GANs de Convolución Profunda (DCGANs), las innovadoras CycleGANs y las altamente versátiles StyleGANs, entre muchas otras.

Cada una de estas variaciones únicas introduce su propio conjunto de cambios arquitectónicos y técnicas de entrenamiento novedosas. Estas están cuidadosamente adaptadas para atender aplicaciones específicas o para mejorar el rendimiento. En esta sección en particular, profundizaremos en algunas de las variaciones de GANs más prominentes y reconocidas que han revolucionado el campo. Al hacerlo, proporcionaremos explicaciones detalladas que sean fáciles de entender, junto con código de ejemplo para ilustrar vívidamente su implementación práctica y uso en escenarios del mundo real.

3.5.1 GANs de Convolución Profunda (DCGANs)

Las GANs de Convolución Profunda (DCGANs) fueron introducidas por Radford et al. en 2015, y representan una mejora significativa sobre la arquitectura original de las GANs. Estas DCGANs aprovechan las capas convolucionales tanto en las redes del generador como del discriminador, lo cual es un cambio respecto al uso de capas totalmente conectadas. Esta adaptación es particularmente beneficiosa para manejar datos de imagen y conduce a un entrenamiento más estable y a imágenes generadas de mejor calidad.

Características clave de las DCGANs incluyen:

  • El uso de capas convolucionales en lugar de capas totalmente conectadas.
  • Sustitución de capas de pooling con convoluciones estratificadas en el discriminador y convoluciones transpuestas en el generador.
  • El uso de normalización por lotes (batch normalization) para estabilizar el entrenamiento.
  • El empleo de diferentes funciones de activación en el generador y el discriminador: activación ReLU en el generador y LeakyReLU en el discriminador.

Estas características contribuyen al rendimiento y la estabilidad mejorados de las DCGANs en comparación con las GANs originales. Al utilizar capas convolucionales, las DCGANs pueden aprender jerarquías espaciales de características de manera no supervisada, lo cual es altamente beneficioso para tareas que involucran imágenes.

En general, las DCGANs representan un hito significativo en el desarrollo de las GANs y han allanado el camino para numerosas variaciones y mejoras subsiguientes en la arquitectura de las GANs.

Ejemplo: Implementación de DCGAN con TensorFlow/Keras

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, LeakyReLU, BatchNormalization, Reshape, Dense, Flatten
from tensorflow.keras.models import Sequential
import numpy as np
import matplotlib.pyplot as plt

# DCGAN Generator
def build_dcgan_generator(latent_dim):
    model = Sequential([
        Dense(256 * 7 * 7, activation="relu", input_dim=latent_dim),
        Reshape((7, 7, 256)),
        BatchNormalization(),
        Conv2DTranspose(128, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2DTranspose(64, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2DTranspose(1, kernel_size=4, strides=1, padding='same', activation='tanh')
    ])
    return model

# DCGAN Discriminator
def build_dcgan_discriminator(img_shape):
    model = Sequential([
        Conv2D(64, kernel_size=4, strides=2, padding='same', input_shape=img_shape),
        LeakyReLU(alpha=0.2),
        Conv2D(128, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2D(256, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Flatten(),
        Dense(1, activation='sigmoid')
    ])
    return model

# Training the DCGAN
latent_dim = 100
img_shape = (28, 28, 1)

generator = build_dcgan_generator(latent_dim)
discriminator = build_dcgan_discriminator(img_shape)
discriminator.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
gan_input = tf.keras.Input(shape=(latent_dim,))
generated_img = generator(gan_input)
validity = discriminator(generated_img)
dcgan = tf.keras.Model(gan_input, validity)
dcgan.compile(optimizer='adam', loss='binary_crossentropy')

# Load and preprocess the MNIST dataset
(x_train, _), (_, _) = tf.keras.datasets.mnist.load_data()
x_train = (x_train.astype(np.float32) - 127.5) / 127.5  # Normalize to [-1, 1]
x_train = np.expand_dims(x_train, axis=-1)

# Training parameters
epochs = 10000
batch_size = 64
sample_interval = 1000

for epoch in range(epochs):
    # Train the discriminator
    idx = np.random.randint(0, x_train.shape[0], batch_size)
    real_images = x_train[idx]
    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    fake_images = generator.predict(noise)
    d_loss_real = discriminator.train_on_batch(real_images, np.ones((batch_size, 1)))
    d_loss_fake = discriminator.train_on_batch(fake_images, np.zeros((batch_size, 1)))
    d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)

    # Train the generator
    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    g_loss = dcgan.train_on_batch(noise, np.ones((batch_size, 1)))

    # Print progress
    if epoch % sample_interval == 0:
        print(f"{epoch} [D loss: {d_loss[0]}, acc.: {d_loss[1] * 100}%] [G loss: {g_loss}]")

        # Generate and save images
        noise = np.random.normal(0, 1, (10, latent_dim))
        generated_images = generator.predict(noise)
        fig, axs = plt.subplots(1, 10, figsize=(20, 2))
        for i, img in enumerate(generated_images):
            axs[i].imshow(img.squeeze(), cmap='gray')
            axs[i].axis('off')
        plt.show()

En este ejemplo:

El script comienza importando las bibliotecas necesarias, que incluyen TensorFlow, Keras, NumPy y Matplotlib. TensorFlow es una biblioteca de código abierto popular para el aprendizaje automático e inteligencia artificial, mientras que Keras es una API de redes neuronales de alto nivel escrita en Python y capaz de ejecutarse sobre TensorFlow. NumPy se usa para cálculos numéricos y Matplotlib se usa para generar gráficos.

El script luego define dos funciones, build_dcgan_generator y build_dcgan_discriminator, que crean los modelos del generador y del discriminador respectivamente. El modelo del generador toma una dimensión latente como entrada y produce una imagen, mientras que el discriminador toma una imagen como entrada y produce una probabilidad que indica si la imagen es real o falsa. El modelo del generador se construye usando una secuencia de capas densas, de reconfiguración, de normalización por lotes y de convolución transpuesta, mientras que el modelo del discriminador usa una secuencia de capas de convolución, de normalización por lotes, LeakyReLU, de aplanamiento y densas.

Después de definir los modelos, el script crea instancias del generador y del discriminador y compila el modelo del discriminador. El modelo del discriminador se compila con el optimizador Adam y la pérdida de entropía cruzada binaria. Durante el entrenamiento de la GAN, los parámetros del modelo del discriminador se configuran como no entrenables.

El script luego define el modelo de GAN, que toma un vector latente como entrada y da salida a la validez de la imagen generada según lo determine el discriminador. El modelo de GAN se compila con el optimizador Adam y la pérdida de entropía cruzada binaria.

A continuación, el script carga el conjunto de datos MNIST, que es una gran base de datos de dígitos escritos a mano que se utiliza comúnmente para entrenar varios sistemas de procesamiento de imágenes. Después de cargar el conjunto de datos, el script normaliza los datos de la imagen para que estén entre -1 y 1 y expande la dimensión del conjunto de datos.

El script luego establece los parámetros de entrenamiento, que incluyen el número de épocas, el tamaño del lote y el intervalo de muestreo. También inicializa matrices para almacenar las pérdidas y precisiones del discriminador y la pérdida del generador.

El script luego entra en el bucle de entrenamiento. Para cada época, el script selecciona un lote aleatorio de imágenes del conjunto de datos y genera un lote correspondiente de vectores de ruido. Utiliza el modelo del generador para generar un lote de imágenes falsas a partir de los vectores de ruido. El modelo del discriminador se entrena luego en las imágenes reales y falsas. El modelo del generador se entrena luego para generar imágenes que el modelo del discriminador considera reales.

Cada 1000 épocas, el script imprime el número de época, la pérdida y precisión del discriminador en las imágenes reales y falsas, y la pérdida del generador. También genera un lote de imágenes del modelo del generador usando un lote fijo de vectores de ruido y traza estas imágenes en una cuadrícula de 1 por 10.

3.5.2 CycleGAN

CycleGAN, introducida por Zhu et al. en 2017, es un tipo específico de Red Generativa Adversarial (GAN) que se centra en la traducción de imágenes a imágenes. Su característica distintiva principal es su capacidad para transformar imágenes de un dominio a otro sin necesidad de ejemplos de entrenamiento pareados. Este es un avance significativo sobre los modelos anteriores, ya que elimina la necesidad de un conjunto de datos que contenga pares de imágenes perfectamente emparejadas de los dominios fuente y destino.

Por ejemplo, si deseas convertir imágenes de caballos en imágenes de cebras, un modelo tradicional de traducción de imágenes a imágenes requeriría un conjunto de datos de imágenes de caballos y cebras emparejadas. CycleGAN, sin embargo, puede aprender esta transformación sin tal conjunto de datos. Esto es particularmente útil para tareas donde es difícil o imposible recopilar datos de entrenamiento pareados.

La arquitectura de CycleGAN incluye dos redes generadoras y dos redes discriminadoras. Las redes generadoras son responsables de la transformación de las imágenes entre los dos dominios. Un generador transforma del dominio fuente al dominio destino, mientras que el otro transforma en la dirección inversa. Las redes discriminadoras, por otro lado, se utilizan para imponer el realismo de las imágenes transformadas.

Además de las funciones de pérdida tradicionales de GAN, CycleGAN también introduce una función de pérdida de consistencia cíclica. Esta función asegura que una imagen que se transforma de un dominio a otro y luego de regreso al dominio original será la misma que la imagen original. Este proceso cíclico ayuda al modelo a aprender mapeos precisos y coherentes entre los dos dominios.

En general, CycleGAN ha sido fundamental en el campo de la traducción de imágenes y la transferencia de estilo, permitiendo transformaciones que anteriormente eran desafiantes o imposibles con GANs tradicionales. Se ha utilizado en una amplia variedad de aplicaciones, desde convertir pinturas en fotografías, cambiar estaciones en imágenes de paisajes, e incluso traducir imágenes de Google Maps a imágenes satelitales.

Resumen de Características Clave y Funcionalidades de CycleGAN:

  • CycleGAN hace uso de dos modelos generadores separados, cada uno designado para un dominio específico, así como dos modelos discriminadores individuales. Este enfoque, que implica vías duales, permite que el modelo aprenda y mapee las características de un dominio a otro.
  • Una característica única y crítica de CycleGAN es la introducción de lo que se conoce como pérdida de consistencia cíclica. Este mecanismo innovador impone el principio de que cuando una imagen se traduce de su dominio original al dominio objetivo, y luego se traduce de nuevo al dominio original, el modelo debe producir una imagen que refleje la imagen de entrada original. Este es un aspecto fundamental del diseño del modelo, ya que ayuda a asegurar la precisión de las traducciones entre dominios.

Ejemplo: Implementación de CycleGAN con TensorFlow/Keras

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, LeakyReLU, BatchNormalization, Input
from tensorflow.keras.models import Model
import numpy as np
import matplotlib.pyplot as plt

# CycleGAN Generator
def build_cyclegan_generator(img_shape):
    input_img = Input(shape=img_shape)
    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(input_img)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    x = Conv2DTranspose(64, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    output_img = Conv2DTranspose(3, kernel_size=4, strides=2, padding='same', activation='tanh')(x)
    return Model(input_img, output_img)

# CycleGAN Discriminator
def build_cyclegan_discriminator(img_shape):
    input_img = Input(shape=img_shape)
    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(input_img)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Flatten()(x)
    validity = Dense(1, activation='sigmoid')(x)
    return Model(input_img, validity)

# Build CycleGAN models
img_shape = (128, 128, 3)
G_AB = build_cyclegan_generator(img_shape)
G_BA = build_cyclegan_generator(img_shape)
D_A = build_cyclegan_discriminator(img_shape)
D_B = build_cyclegan_discriminator(img_shape)

D_A.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
D_B.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

# CycleGAN loss
def cycle_loss(y_true, y_pred):
    return tf.reduce_mean(tf.abs(y_true - y_pred))

# Full CycleGAN model
img_A = Input(shape=img_shape)
img_B = Input(shape=img_shape)

fake_B = G_AB(img_A)
reconstr_A = G_BA(fake_B)
fake_A = G_BA(img_B)
reconstr_B = G_AB(fake_A)

D_A.trainable = False
D_B.trainable = False

valid_A = D_A(fake_A)
valid_B = D_B(fake_B)

cycle_gan = Model(inputs=[img_A, img_B], outputs=[valid_A, valid_B, reconstr_A, reconstr_B])
cycle_gan.compile(optimizer='adam', loss=['binary_crossentropy', 'binary_crossentropy', cycle_loss, cycle_loss])

# Summary of the models
G_AB.summary()
G_BA.summary()
D_A.summary()
D_B.summary()
cycle_gan.summary()

En este ejemplo:

La primera parte del script importa las bibliotecas necesarias, que incluyen TensorFlow para el aprendizaje automático, Keras para la API de redes neuronales, numpy para cálculos numéricos y matplotlib para generar gráficos.

El script luego define dos funciones, build_cyclegan_generator y build_cyclegan_discriminator. Estas dos funciones se utilizan para construir los modelos generador y discriminador de la CycleGAN.

El modelo del generador está diseñado para transformar una imagen de un dominio a otro. El modelo comienza con una imagen de entrada y aplica una serie de capas convolucionales, de activación LeakyReLU y de normalización por lotes para procesar la imagen. La imagen procesada se pasa luego a través de un conjunto de capas de convolución transpuesta para generar la imagen de salida.

El modelo del discriminador es responsable de determinar si una imagen dada es real (del conjunto de datos) o falsa (generada por el generador). El modelo toma una imagen como entrada y aplica una serie de capas convolucionales y de activación LeakyReLU. La imagen procesada se aplana y se pasa a través de una capa densa para dar salida a un único valor que representa la probabilidad de que la imagen sea real.

Después de definir los modelos generador y discriminador, el script crea instancias de estos modelos para dos dominios de imagen, referidos como A y B. El script también compila los modelos discriminadores, especificando 'adam' como el optimizador, 'binary_crossentropy' como la función de pérdida y 'accuracy' como la métrica.

El script luego define una función de pérdida especial para la CycleGAN, llamada pérdida cíclica. Esta función mide la diferencia absoluta entre la imagen original y la imagen reconstruida (es decir, una imagen que ha sido transformada de un dominio a otro y luego de vuelta al dominio original). La pérdida cíclica anima a la CycleGAN a aprender mapeos capaces de reconstruir la imagen original con precisión.

A continuación, el script construye el modelo completo de CycleGAN. Este modelo toma dos imágenes como entrada (una del dominio A y una del dominio B), transforma cada imagen al otro dominio utilizando los generadores, y luego de vuelta al dominio original. El modelo también pasa las imágenes transformadas a través de los discriminadores para determinar su realismo. Las salidas del modelo incluyen la validez de las imágenes transformadas y las imágenes reconstruidas.

El modelo de CycleGAN se compila con el optimizador 'adam' y una lista de funciones de pérdida que incluyen la entropía cruzada binaria para las salidas de validez y la pérdida cíclica para las salidas de reconstrucción. Además, para asegurar que el entrenamiento de la CycleGAN se centre en mejorar los generadores, el script establece el atributo trainable de los discriminadores en False antes de compilar el modelo de CycleGAN.

Finalmente, el script imprime un resumen de cada modelo para proporcionar una visión general de sus arquitecturas. Esto incluye las capas en cada modelo, la forma de las salidas de cada capa y el número de parámetros en cada capa.

3.5.3 StyleGAN

StyleGAN, o Style Generative Adversarial Network, es un tipo avanzado de modelo GAN introducido por Karras et al. de NVIDIA en 2019. Este modelo representa un avance significativo en el campo de los modelos generativos debido a su capacidad para generar imágenes extremadamente realistas y de alta calidad.

La principal innovación en StyleGAN reside en su arquitectura única del generador basada en estilos. Esta nueva arquitectura permite un control detallado y específico del proceso de síntesis de imágenes, separando las influencias de atributos de alto nivel y la variación estocástica en las imágenes generadas. Con esto, es posible manipular aspectos específicos de las imágenes generadas de manera independiente, lo cual no era posible con modelos GAN anteriores.

La arquitectura de StyleGAN incluye una red de mapeo y una red de síntesis. La red de mapeo toma un código latente y lo mapea a un espacio latente intermedio, que controla los estilos de varios aspectos de la imagen generada. La red de síntesis toma esta representación intermedia y genera la imagen final.

Las características clave de StyleGAN incluyen el uso de normalización adaptativa de instancias (AdaIN) para la modulación de estilos, el crecimiento progresivo tanto del generador como del discriminador para un entrenamiento estable y una calidad mejorada, y una red de mapeo con inyección de estilo para controlar los atributos de la imagen.

Una de las aplicaciones más conocidas de StyleGAN es el sitio web 'This Person Does Not Exist', donde el modelo genera rostros humanos altamente realistas de personas que no existen. Otras aplicaciones incluyen la manipulación de características específicas de una imagen, como cambiar el color del cabello o la edad de una persona, y transferir el estilo de una imagen a otra, como cambiar una foto diurna a nocturna.

En conclusión, StyleGAN representa un avance significativo en el campo de los modelos generativos, abriendo nuevas posibilidades para la síntesis, manipulación y comprensión de imágenes.

Resumen de Características Clave de StyleGAN:

  • Utiliza una arquitectura de generador basada en estilos, que proporciona un enfoque único en cómo el generador maneja y procesa los vectores de ruido. Esta arquitectura se combina con la normalización adaptativa de instancias (AdaIN), una técnica que permite la transferencia de estilo desde las imágenes de estilo a las imágenes generadas.
  • Emplea una metodología de crecimiento progresivo tanto para el generador como para el discriminador. Esto significa que la red comienza entrenando con imágenes de baja resolución y luego aumenta progresivamente la resolución añadiendo más capas. Esta estrategia mejora significativamente la estabilidad del entrenamiento y permite que la red genere imágenes de alta calidad.
  • Proporciona la capacidad de controlar atributos específicos de la imagen, como el estilo y la estructura de las imágenes generadas. Esto se logra mediante el uso de una red de mapeo y la inyección de estilo. La red de mapeo permite que el modelo aprenda representaciones más separadas, y la inyección de estilo proporciona una forma de controlar el estilo en diferentes niveles de detalle.

Ejemplo: Uso de un Modelo StyleGAN Pre-entrenado

Para usar un modelo StyleGAN pre-entrenado, podemos aprovechar bibliotecas como stylegan2-pytorch para mayor simplicidad. Aquí hay un ejemplo:

import torch
from stylegan2_pytorch import ModelLoader
import matplotlib.pyplot as plt

# Load pre-trained StyleGAN2 model
model = ModelLoader(name='ffhq', load_model=True)

# Generate random latent vectors
num_images = 5
latent_vectors = torch.randn(num_images, 512)

# Generate images using the model
generated_images = model.generate(latent_vectors)

# Plot the generated images
fig, axs = plt.subplots(1, num_images, figsize=(15, 15))
for i, img in enumerate(generated_images):
    axs[i].imshow(img.permute(1, 2, 0).cpu().numpy())
    axs[i].axis('off')

plt.show()

Este ejemplo utiliza la biblioteca stylegan2-pytorch para generar imágenes a partir de un modelo preentrenado de StyleGAN2.

Aquí tienes un desglose de los pasos:

Importar Bibliotecas:

  • torch: La biblioteca PyTorch para el aprendizaje profundo.
  • from stylegan2_pytorch import ModelLoader: Importa la clase ModelLoader de la biblioteca stylegan2-pytorch. Esta clase ayuda a cargar y gestionar los modelos StyleGAN2.
  • matplotlib.pyplot as plt: Utilizado para trazar las imágenes generadas.

Cargar el Modelo Preentrenado:

  • model = ModelLoader(name='ffhq', load_model=True): Crea una instancia de ModelLoader llamada model.
    • name='ffhq': Especifica el nombre del modelo preentrenado, probablemente "ffhq", que se refiere al conjunto de datos Flickr-Faces-HQ, comúnmente utilizado para el entrenamiento de StyleGAN2.
    • load_model=True: Instruye a ModelLoader que cargue los parámetros del modelo preentrenado.

Generar Vectores Latentes Aleatorios:

  • num_images = 5: Define el número de imágenes a generar (establecido en 5 en este ejemplo).
  • latent_vectors = torch.randn(num_images, 512): Crea un tensor aleatorio llamado latent_vectors con dimensiones (num_images, 512). Este tensor representa el ruido latente utilizado para generar imágenes. La dimensionalidad específica (512 en este caso) depende de la arquitectura del modelo preentrenado.

Generar Imágenes:

  • generated_images = model.generate(latent_vectors): Esta línea utiliza la función model.generate para generar imágenes a partir de los vectores latentes proporcionados. Las imágenes generadas se almacenan en el tensor generated_images.

Trazar las Imágenes Generadas:

  • plt.subplots(1, num_images, figsize=(15, 15)): Crea una figura de Matplotlib con una sola fila y num_images columnas para mostrar las imágenes generadas. También establece el tamaño de la figura en 15x15 para una mejor visualización.
  • El bucle itera a través de cada imagen en generated_images:
    • axs[i].imshow(...): Esta línea muestra la imagen actual en una subtrama utilizando la función imshow de Matplotlib.
      • .permute(1, 2, 0).cpu().numpy(): Esta línea reorganiza las dimensiones del tensor de imagen del formato de PyTorch (canales primero) al formato de Matplotlib (canales al final) y lo convierte en un array de NumPy para la compatibilidad con imshow.
    • axs[i].axis('off'): Apaga las etiquetas de los ejes para una presentación más limpia.
  • plt.show(): Muestra las imágenes generadas en la pantalla.

En resumen, este ejemplo demuestra cómo generar imágenes con un modelo StyleGAN2 proporcionando ruido latente aleatorio como entrada y visualizando los resultados generados.

3.5.4 Otras Variaciones de GAN

1. Wasserstein GAN (WGAN):

Wasserstein GAN, a menudo abreviado como WGAN, es una variante de las Redes Generativas Antagónicas (GANs). Introducidas por Martin Arjovsky, Soumith Chintala y Léon Bottou en 2017, las WGANs representan un avance significativo en el campo de las GANs, abordando principalmente dos problemas críticos que a menudo afectan a las GANs tradicionales: la inestabilidad en el entrenamiento y el colapso de modos.

El nombre "Wasserstein" proviene del tipo de función de pérdida utilizada en estas GANs, conocida como la distancia Wasserstein o la distancia del "trasportador de tierra". Esta es una medida de la distancia entre dos distribuciones de probabilidad y se usa en lugar de las funciones de pérdida tradicionales de GAN, como la divergencia de Jensen-Shannon. Este cambio en la función de pérdida conduce a una superficie de pérdida más suave y significativa, lo que hace que el proceso de entrenamiento sea más estable.

Las WGANs también introducen una característica única conocida como recorte de pesos, que ayuda a garantizar que la función del discriminador (también conocida como el crítico en la terminología de WGAN) se encuentre dentro de un espacio compacto, facilitando el cálculo de la distancia Wasserstein.

La innovación de las WGANs ha tenido un impacto significativo en la mejora de la calidad y diversidad de las muestras generadas, así como en la estabilidad del proceso de entrenamiento de las GAN. Ha permitido procesos de entrenamiento más confiables, abriendo así nuevas posibilidades para la aplicación de las GAN en varios dominios.

Sin embargo, vale la pena señalar que, aunque las WGANs abordan algunos problemas en las GANs estándar, también tienen su propio conjunto de desafíos y limitaciones, como problemas con el recorte de pesos que conducen a comportamientos de función no deseados. Esto ha llevado a desarrollos y mejoras adicionales en el campo de las GAN, como la introducción de WGAN-GP (Wasserstein GAN con Penalización de Gradiente) que reemplaza el recorte de pesos con una penalización de gradiente para un entrenamiento más estable y eficiente.

2. BigGAN:

BigGAN, abreviatura de Big Generative Adversarial Network, es un tipo de modelo de aprendizaje automático que pertenece a la clase de Redes Generativas Antagónicas (GANs). Las GANs, introducidas por Ian Goodfellow y sus colegas en 2014, están diseñadas para generar nuevas instancias sintéticas de datos que puedan pasar por datos reales. Consisten en dos partes: un 'generador' que produce los datos sintéticos y un 'discriminador' que intenta diferenciar entre los datos generados y los datos reales.

En el contexto de BigGAN, el modelo está diseñado para producir imágenes de alta resolución y altamente realistas que a menudo pueden pasar como reales para el ojo inexperto. El término "big" se refiere a la naturaleza a gran escala del modelo, que emplea tamaños de lote grandes y conjuntos de datos de entrenamiento extensivos para crear estas imágenes de alta calidad.

El modelo BigGAN es una evolución en el campo de las GANs, con sus predecesores que incluyen el modelo GAN original, DCGAN, WGAN y otros. Cada evolución generalmente apunta a resolver algunos de los problemas enfrentados por los modelos anteriores o a mejorar la calidad de los datos generados. En el caso de BigGAN, el enfoque está en mejorar la resolución y el realismo de las imágenes generadas.

El uso de BigGAN y modelos similares se extiende más allá de solo generar imágenes de aspecto realista. Se utilizan en una amplia variedad de aplicaciones, incluyendo la mejora de imágenes, la transferencia de estilo, la traducción de imagen a imagen y más. Al mejorar continuamente la calidad y versatilidad de estos modelos, los investigadores están ampliando los límites de lo que es posible en el campo de la modelación generativa.

3. SRGAN (Super-Resolution GAN):

SRGAN, abreviatura de Super-Resolution Generative Adversarial Network, es una variante particular de las Redes Generativas Antagónicas (GANs) diseñadas específicamente para tareas de super-resolución de imágenes. Este tipo de GAN se utiliza principalmente para mejorar la resolución de imágenes de baja resolución, asegurando que las imágenes resultantes de alta resolución mantengan una alta calidad visual.

El término "super-resolución" se refiere al proceso de aumentar la resolución de una imagen, video u otro tipo de imagen. En el contexto de SRGAN, esto significa transformar una imagen de baja resolución en una versión de alta resolución que tenga más detalles y sea visualmente más atractiva.

La estructura básica de SRGAN, como otras GANs, consta de dos componentes principales: una red generadora y una red discriminadora. La red generadora tiene la tarea de tomar una imagen de baja resolución y generar una versión de alta resolución de la misma. La red discriminadora, por otro lado, tiene la tarea de determinar si una imagen de alta resolución dada proviene del conjunto de datos de imágenes de alta resolución reales o fue creada por el generador.

Una de las características clave de SRGAN que la distingue de otros métodos de super-resolución es su capacidad para recuperar detalles más finos en la imagen aumentada. Los métodos tradicionales a menudo producen imágenes de alta resolución que son más borrosas y carecen de algunos de los detalles texturales presentes en la imagen original. SRGAN supera esta limitación utilizando una función de pérdida perceptual que anima al generador a crear imágenes que no solo tengan los valores de píxeles correctos, sino que también tengan características de alto nivel que coincidan con las de la imagen original de alta resolución.

Como resultado de estas capacidades, SRGAN ha encontrado una amplia aplicación en campos donde la resolución de imagen de alta calidad es esencial. Estos incluyen imágenes médicas (por ejemplo, mejorando escaneos de MRI), imágenes satelitales y aéreas, gráficos de videojuegos y transmisión de video, entre otros.

SRGAN representa un avance importante en el campo de la super-resolución de imágenes, proporcionando una herramienta poderosa para mejorar la calidad de imágenes de baja resolución.

4. Conditional GAN (cGAN):

Las Redes Generativas Antagónicas Condicionales (cGANs) son un tipo de GAN que incluye información auxiliar tanto para las redes generadora como discriminadora. Esta información adicional a menudo viene en forma de etiquetas, lo que permite que el proceso de generación de datos tenga en cuenta condiciones o características específicas.

En una GAN estándar, la red generadora toma un vector de ruido aleatorio como entrada y produce una instancia de datos sintéticos (por ejemplo, una imagen). La red discriminadora luego trata de clasificar si esta instancia de datos es real (de la distribución de datos verdadera) o falsa (generada por el generador). Las dos redes se entrenan juntas, con el generador tratando de engañar al discriminador y el discriminador tratando de clasificar correctamente las instancias reales frente a las falsas.

En una cGAN, el generador toma dos entradas: un vector de ruido aleatorio y una etiqueta. La etiqueta proporciona información adicional sobre qué tipo de instancia de datos debe producir el generador. Por ejemplo, si las etiquetas son dígitos del 0 al 9 y las instancias de datos son imágenes de dígitos escritos a mano, el generador podría estar condicionado a producir una imagen de un dígito específico.

El discriminador en una cGAN también toma dos entradas: una instancia de datos y una etiqueta. Tiene que determinar no solo si la instancia de datos es real o falsa, sino también si coincide con la etiqueta dada.

La ventaja de las cGANs es que pueden generar datos bajo condiciones específicas o con ciertas características, lo que puede ser muy útil en muchas aplicaciones. Por ejemplo, en la generación de imágenes, una cGAN podría generar imágenes de gatos, perros u otros objetos específicos según la etiqueta dada. En la mejora de datos, una cGAN podría generar datos adicionales para una clase específica que está subrepresentada en los datos de entrenamiento.

La implementación de una cGAN implica modificaciones tanto en la red generadora como en la discriminadora para aceptar y procesar la información de etiqueta adicional. Además, el procedimiento de entrenamiento necesita ajustarse para tener en cuenta la naturaleza condicional del proceso de generación de datos.

En general, las cGANs representan una extensión importante del marco estándar de GAN, permitiendo tareas de generación de datos más controladas y específicas.

Ejemplo: Implementación de una Conditional GAN

import tensorflow as tf
from tensorflow.keras.layers import Input, Embedding, multiply

# Conditional GAN Generator
def build_cgan_generator(latent_dim, num_classes):
    noise = Input(shape=(latent_dim,))
    label = Input(shape=(1,), dtype='int32')
    label_embedding = Flatten()(Embedding(num_classes, latent_dim)(label))
    model_input = multiply([noise, label_embedding])

    x = Dense(256 * 7 * 7, activation="relu")(model_input)
    x = Reshape((7, 7, 256))(x)
    x = BatchNormalization()(x)
    x = Conv2DTranspose(128, kernel_size=4, strides=2, padding='same')(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2DTranspose(64, kernel_size=4, strides=2, padding='same')(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=0.2)(x)
    output_img = Conv2DTranspose(1, kernel_size=4, strides=1, padding='same', activation='tanh')(x)

    return Model([noise, label], output_img)

# Conditional GAN Discriminator
def build_cgan_discriminator(img_shape, num_classes):
    img = Input(shape=img_shape)
    label = Input(shape=(1,), dtype='int32')
    label_embedding = Flatten()(Embedding(num_classes, np.prod(img_shape))(label))
    label_embedding = Reshape(img_shape)(label_embedding)
    model_input = multiply([img, label_embedding])

    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(model_input)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Flatten()(x)
    validity = Dense(1, activation='sigmoid')(x)

    return Model([img, label], validity)

# Build and compile the Conditional GAN
latent_dim = 100
num_classes = 10
img_shape = (28, 28, 1)

generator = build_cgan_generator(latent_dim, num_classes)
discriminator = build_cgan_discriminator(img_shape, num_classes)
discriminator.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
noise = Input(shape=(latent_dim,))
label = Input(shape=(1,), dtype='int32')
generated_img = generator([noise, label])
validity = discriminator([generated_img, label])
cgan = Model([noise, label], validity)
cgan.compile(optimizer='adam', loss='binary_crossentropy')

# Summary of the models
generator.summary()
discriminator.summary()
cgan.summary()

En este ejemplo:

El primer paso en el código es importar las bibliotecas necesarias. Se requiere la biblioteca TensorFlow para el aprendizaje automático, con su API de Keras utilizada para crear los modelos de redes neuronales. Las funciones Input, Embedding, Dense y multiply, entre otras, se importan del módulo de capas de Keras.

La siguiente parte del script define dos funciones, build_cgan_generator y build_cgan_discriminator. Estas dos funciones se utilizan para construir los modelos generador y discriminador del CGAN, respectivamente.

La función build_cgan_generator toma como entradas la dimensión latente (el tamaño del vector de ruido aleatorio) y el número de clases (el número de etiquetas). Dentro de esta función, se construye el modelo del generador. El generador toma un vector de ruido aleatorio y una etiqueta como entradas. El vector de ruido es un punto en el espacio latente, y la etiqueta es un vector codificado en one-hot que representa la clase deseada de la imagen generada. El ruido y la etiqueta se combinan y se pasan a través de una serie de capas Dense, Reshape, BatchNormalization, Conv2DTranspose y LeakyReLU para generar la imagen de salida final.

La función build_cgan_discriminator también toma como entradas la forma de la imagen y el número de clases. Dentro de esta función, se construye el modelo del discriminador. El discriminador toma una imagen y una etiqueta como entradas. La imagen es la generada (o real), y la etiqueta es la etiqueta verdadera de la imagen. La imagen y la etiqueta se combinan y se pasan a través de una serie de capas Conv2D, LeakyReLU, Flatten y Dense para producir un único valor que representa si la imagen es real o falsa.

Después de definir las funciones del generador y el discriminador, el script las utiliza para crear instancias de estos modelos. Luego, el modelo del discriminador se compila utilizando el optimizador Adam y la pérdida de entropía cruzada binaria como función de pérdida. También se especifica la métrica de precisión para medir el rendimiento del discriminador.

A continuación, el script establece el atributo trainable del discriminador a False. Esto se hace porque, al entrenar el CGAN, se desea entrenar el generador para engañar al discriminador, pero no entrenar al discriminador para mejorar su capacidad de detectar al generador. Por lo tanto, los pesos del discriminador se congelan durante el entrenamiento del CGAN.

Luego, se construye y compila el modelo CGAN. El modelo CGAN consta del generador seguido del discriminador. Un vector de ruido y una etiqueta se pasan al generador para producir una imagen generada. Esta imagen generada y la etiqueta se alimentan luego al discriminador para producir la validez de la imagen.

Finalmente, el script imprime un resumen de cada modelo. Esto proporciona una visión general de los modelos generador, discriminador y CGAN, incluyendo las capas en cada modelo, las formas de salida de estas capas y el número de parámetros en cada capa.

Este ejemplo proporciona una guía paso a paso sobre cómo implementar un CGAN en TensorFlow. Al proporcionar etiquetas como entrada adicional tanto al generador como al discriminador, un CGAN permite la generación de datos con características específicas deseadas.

3.5 Variaciones de las GANs

Desde la introducción de las innovadoras Redes Generativas Adversariales (GANs), se han desarrollado meticulosamente una gran cantidad de modificaciones y mejoras con el objetivo de abordar desafíos específicos que se encontraron y de expandir significativamente las capacidades del marco original de las GANs.

Estas variaciones son numerosas y diversas, incluyendo, pero no limitándose a, las GANs de Convolución Profunda (DCGANs), las innovadoras CycleGANs y las altamente versátiles StyleGANs, entre muchas otras.

Cada una de estas variaciones únicas introduce su propio conjunto de cambios arquitectónicos y técnicas de entrenamiento novedosas. Estas están cuidadosamente adaptadas para atender aplicaciones específicas o para mejorar el rendimiento. En esta sección en particular, profundizaremos en algunas de las variaciones de GANs más prominentes y reconocidas que han revolucionado el campo. Al hacerlo, proporcionaremos explicaciones detalladas que sean fáciles de entender, junto con código de ejemplo para ilustrar vívidamente su implementación práctica y uso en escenarios del mundo real.

3.5.1 GANs de Convolución Profunda (DCGANs)

Las GANs de Convolución Profunda (DCGANs) fueron introducidas por Radford et al. en 2015, y representan una mejora significativa sobre la arquitectura original de las GANs. Estas DCGANs aprovechan las capas convolucionales tanto en las redes del generador como del discriminador, lo cual es un cambio respecto al uso de capas totalmente conectadas. Esta adaptación es particularmente beneficiosa para manejar datos de imagen y conduce a un entrenamiento más estable y a imágenes generadas de mejor calidad.

Características clave de las DCGANs incluyen:

  • El uso de capas convolucionales en lugar de capas totalmente conectadas.
  • Sustitución de capas de pooling con convoluciones estratificadas en el discriminador y convoluciones transpuestas en el generador.
  • El uso de normalización por lotes (batch normalization) para estabilizar el entrenamiento.
  • El empleo de diferentes funciones de activación en el generador y el discriminador: activación ReLU en el generador y LeakyReLU en el discriminador.

Estas características contribuyen al rendimiento y la estabilidad mejorados de las DCGANs en comparación con las GANs originales. Al utilizar capas convolucionales, las DCGANs pueden aprender jerarquías espaciales de características de manera no supervisada, lo cual es altamente beneficioso para tareas que involucran imágenes.

En general, las DCGANs representan un hito significativo en el desarrollo de las GANs y han allanado el camino para numerosas variaciones y mejoras subsiguientes en la arquitectura de las GANs.

Ejemplo: Implementación de DCGAN con TensorFlow/Keras

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, LeakyReLU, BatchNormalization, Reshape, Dense, Flatten
from tensorflow.keras.models import Sequential
import numpy as np
import matplotlib.pyplot as plt

# DCGAN Generator
def build_dcgan_generator(latent_dim):
    model = Sequential([
        Dense(256 * 7 * 7, activation="relu", input_dim=latent_dim),
        Reshape((7, 7, 256)),
        BatchNormalization(),
        Conv2DTranspose(128, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2DTranspose(64, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2DTranspose(1, kernel_size=4, strides=1, padding='same', activation='tanh')
    ])
    return model

# DCGAN Discriminator
def build_dcgan_discriminator(img_shape):
    model = Sequential([
        Conv2D(64, kernel_size=4, strides=2, padding='same', input_shape=img_shape),
        LeakyReLU(alpha=0.2),
        Conv2D(128, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2D(256, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Flatten(),
        Dense(1, activation='sigmoid')
    ])
    return model

# Training the DCGAN
latent_dim = 100
img_shape = (28, 28, 1)

generator = build_dcgan_generator(latent_dim)
discriminator = build_dcgan_discriminator(img_shape)
discriminator.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
gan_input = tf.keras.Input(shape=(latent_dim,))
generated_img = generator(gan_input)
validity = discriminator(generated_img)
dcgan = tf.keras.Model(gan_input, validity)
dcgan.compile(optimizer='adam', loss='binary_crossentropy')

# Load and preprocess the MNIST dataset
(x_train, _), (_, _) = tf.keras.datasets.mnist.load_data()
x_train = (x_train.astype(np.float32) - 127.5) / 127.5  # Normalize to [-1, 1]
x_train = np.expand_dims(x_train, axis=-1)

# Training parameters
epochs = 10000
batch_size = 64
sample_interval = 1000

for epoch in range(epochs):
    # Train the discriminator
    idx = np.random.randint(0, x_train.shape[0], batch_size)
    real_images = x_train[idx]
    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    fake_images = generator.predict(noise)
    d_loss_real = discriminator.train_on_batch(real_images, np.ones((batch_size, 1)))
    d_loss_fake = discriminator.train_on_batch(fake_images, np.zeros((batch_size, 1)))
    d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)

    # Train the generator
    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    g_loss = dcgan.train_on_batch(noise, np.ones((batch_size, 1)))

    # Print progress
    if epoch % sample_interval == 0:
        print(f"{epoch} [D loss: {d_loss[0]}, acc.: {d_loss[1] * 100}%] [G loss: {g_loss}]")

        # Generate and save images
        noise = np.random.normal(0, 1, (10, latent_dim))
        generated_images = generator.predict(noise)
        fig, axs = plt.subplots(1, 10, figsize=(20, 2))
        for i, img in enumerate(generated_images):
            axs[i].imshow(img.squeeze(), cmap='gray')
            axs[i].axis('off')
        plt.show()

En este ejemplo:

El script comienza importando las bibliotecas necesarias, que incluyen TensorFlow, Keras, NumPy y Matplotlib. TensorFlow es una biblioteca de código abierto popular para el aprendizaje automático e inteligencia artificial, mientras que Keras es una API de redes neuronales de alto nivel escrita en Python y capaz de ejecutarse sobre TensorFlow. NumPy se usa para cálculos numéricos y Matplotlib se usa para generar gráficos.

El script luego define dos funciones, build_dcgan_generator y build_dcgan_discriminator, que crean los modelos del generador y del discriminador respectivamente. El modelo del generador toma una dimensión latente como entrada y produce una imagen, mientras que el discriminador toma una imagen como entrada y produce una probabilidad que indica si la imagen es real o falsa. El modelo del generador se construye usando una secuencia de capas densas, de reconfiguración, de normalización por lotes y de convolución transpuesta, mientras que el modelo del discriminador usa una secuencia de capas de convolución, de normalización por lotes, LeakyReLU, de aplanamiento y densas.

Después de definir los modelos, el script crea instancias del generador y del discriminador y compila el modelo del discriminador. El modelo del discriminador se compila con el optimizador Adam y la pérdida de entropía cruzada binaria. Durante el entrenamiento de la GAN, los parámetros del modelo del discriminador se configuran como no entrenables.

El script luego define el modelo de GAN, que toma un vector latente como entrada y da salida a la validez de la imagen generada según lo determine el discriminador. El modelo de GAN se compila con el optimizador Adam y la pérdida de entropía cruzada binaria.

A continuación, el script carga el conjunto de datos MNIST, que es una gran base de datos de dígitos escritos a mano que se utiliza comúnmente para entrenar varios sistemas de procesamiento de imágenes. Después de cargar el conjunto de datos, el script normaliza los datos de la imagen para que estén entre -1 y 1 y expande la dimensión del conjunto de datos.

El script luego establece los parámetros de entrenamiento, que incluyen el número de épocas, el tamaño del lote y el intervalo de muestreo. También inicializa matrices para almacenar las pérdidas y precisiones del discriminador y la pérdida del generador.

El script luego entra en el bucle de entrenamiento. Para cada época, el script selecciona un lote aleatorio de imágenes del conjunto de datos y genera un lote correspondiente de vectores de ruido. Utiliza el modelo del generador para generar un lote de imágenes falsas a partir de los vectores de ruido. El modelo del discriminador se entrena luego en las imágenes reales y falsas. El modelo del generador se entrena luego para generar imágenes que el modelo del discriminador considera reales.

Cada 1000 épocas, el script imprime el número de época, la pérdida y precisión del discriminador en las imágenes reales y falsas, y la pérdida del generador. También genera un lote de imágenes del modelo del generador usando un lote fijo de vectores de ruido y traza estas imágenes en una cuadrícula de 1 por 10.

3.5.2 CycleGAN

CycleGAN, introducida por Zhu et al. en 2017, es un tipo específico de Red Generativa Adversarial (GAN) que se centra en la traducción de imágenes a imágenes. Su característica distintiva principal es su capacidad para transformar imágenes de un dominio a otro sin necesidad de ejemplos de entrenamiento pareados. Este es un avance significativo sobre los modelos anteriores, ya que elimina la necesidad de un conjunto de datos que contenga pares de imágenes perfectamente emparejadas de los dominios fuente y destino.

Por ejemplo, si deseas convertir imágenes de caballos en imágenes de cebras, un modelo tradicional de traducción de imágenes a imágenes requeriría un conjunto de datos de imágenes de caballos y cebras emparejadas. CycleGAN, sin embargo, puede aprender esta transformación sin tal conjunto de datos. Esto es particularmente útil para tareas donde es difícil o imposible recopilar datos de entrenamiento pareados.

La arquitectura de CycleGAN incluye dos redes generadoras y dos redes discriminadoras. Las redes generadoras son responsables de la transformación de las imágenes entre los dos dominios. Un generador transforma del dominio fuente al dominio destino, mientras que el otro transforma en la dirección inversa. Las redes discriminadoras, por otro lado, se utilizan para imponer el realismo de las imágenes transformadas.

Además de las funciones de pérdida tradicionales de GAN, CycleGAN también introduce una función de pérdida de consistencia cíclica. Esta función asegura que una imagen que se transforma de un dominio a otro y luego de regreso al dominio original será la misma que la imagen original. Este proceso cíclico ayuda al modelo a aprender mapeos precisos y coherentes entre los dos dominios.

En general, CycleGAN ha sido fundamental en el campo de la traducción de imágenes y la transferencia de estilo, permitiendo transformaciones que anteriormente eran desafiantes o imposibles con GANs tradicionales. Se ha utilizado en una amplia variedad de aplicaciones, desde convertir pinturas en fotografías, cambiar estaciones en imágenes de paisajes, e incluso traducir imágenes de Google Maps a imágenes satelitales.

Resumen de Características Clave y Funcionalidades de CycleGAN:

  • CycleGAN hace uso de dos modelos generadores separados, cada uno designado para un dominio específico, así como dos modelos discriminadores individuales. Este enfoque, que implica vías duales, permite que el modelo aprenda y mapee las características de un dominio a otro.
  • Una característica única y crítica de CycleGAN es la introducción de lo que se conoce como pérdida de consistencia cíclica. Este mecanismo innovador impone el principio de que cuando una imagen se traduce de su dominio original al dominio objetivo, y luego se traduce de nuevo al dominio original, el modelo debe producir una imagen que refleje la imagen de entrada original. Este es un aspecto fundamental del diseño del modelo, ya que ayuda a asegurar la precisión de las traducciones entre dominios.

Ejemplo: Implementación de CycleGAN con TensorFlow/Keras

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, LeakyReLU, BatchNormalization, Input
from tensorflow.keras.models import Model
import numpy as np
import matplotlib.pyplot as plt

# CycleGAN Generator
def build_cyclegan_generator(img_shape):
    input_img = Input(shape=img_shape)
    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(input_img)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    x = Conv2DTranspose(64, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    output_img = Conv2DTranspose(3, kernel_size=4, strides=2, padding='same', activation='tanh')(x)
    return Model(input_img, output_img)

# CycleGAN Discriminator
def build_cyclegan_discriminator(img_shape):
    input_img = Input(shape=img_shape)
    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(input_img)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Flatten()(x)
    validity = Dense(1, activation='sigmoid')(x)
    return Model(input_img, validity)

# Build CycleGAN models
img_shape = (128, 128, 3)
G_AB = build_cyclegan_generator(img_shape)
G_BA = build_cyclegan_generator(img_shape)
D_A = build_cyclegan_discriminator(img_shape)
D_B = build_cyclegan_discriminator(img_shape)

D_A.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
D_B.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

# CycleGAN loss
def cycle_loss(y_true, y_pred):
    return tf.reduce_mean(tf.abs(y_true - y_pred))

# Full CycleGAN model
img_A = Input(shape=img_shape)
img_B = Input(shape=img_shape)

fake_B = G_AB(img_A)
reconstr_A = G_BA(fake_B)
fake_A = G_BA(img_B)
reconstr_B = G_AB(fake_A)

D_A.trainable = False
D_B.trainable = False

valid_A = D_A(fake_A)
valid_B = D_B(fake_B)

cycle_gan = Model(inputs=[img_A, img_B], outputs=[valid_A, valid_B, reconstr_A, reconstr_B])
cycle_gan.compile(optimizer='adam', loss=['binary_crossentropy', 'binary_crossentropy', cycle_loss, cycle_loss])

# Summary of the models
G_AB.summary()
G_BA.summary()
D_A.summary()
D_B.summary()
cycle_gan.summary()

En este ejemplo:

La primera parte del script importa las bibliotecas necesarias, que incluyen TensorFlow para el aprendizaje automático, Keras para la API de redes neuronales, numpy para cálculos numéricos y matplotlib para generar gráficos.

El script luego define dos funciones, build_cyclegan_generator y build_cyclegan_discriminator. Estas dos funciones se utilizan para construir los modelos generador y discriminador de la CycleGAN.

El modelo del generador está diseñado para transformar una imagen de un dominio a otro. El modelo comienza con una imagen de entrada y aplica una serie de capas convolucionales, de activación LeakyReLU y de normalización por lotes para procesar la imagen. La imagen procesada se pasa luego a través de un conjunto de capas de convolución transpuesta para generar la imagen de salida.

El modelo del discriminador es responsable de determinar si una imagen dada es real (del conjunto de datos) o falsa (generada por el generador). El modelo toma una imagen como entrada y aplica una serie de capas convolucionales y de activación LeakyReLU. La imagen procesada se aplana y se pasa a través de una capa densa para dar salida a un único valor que representa la probabilidad de que la imagen sea real.

Después de definir los modelos generador y discriminador, el script crea instancias de estos modelos para dos dominios de imagen, referidos como A y B. El script también compila los modelos discriminadores, especificando 'adam' como el optimizador, 'binary_crossentropy' como la función de pérdida y 'accuracy' como la métrica.

El script luego define una función de pérdida especial para la CycleGAN, llamada pérdida cíclica. Esta función mide la diferencia absoluta entre la imagen original y la imagen reconstruida (es decir, una imagen que ha sido transformada de un dominio a otro y luego de vuelta al dominio original). La pérdida cíclica anima a la CycleGAN a aprender mapeos capaces de reconstruir la imagen original con precisión.

A continuación, el script construye el modelo completo de CycleGAN. Este modelo toma dos imágenes como entrada (una del dominio A y una del dominio B), transforma cada imagen al otro dominio utilizando los generadores, y luego de vuelta al dominio original. El modelo también pasa las imágenes transformadas a través de los discriminadores para determinar su realismo. Las salidas del modelo incluyen la validez de las imágenes transformadas y las imágenes reconstruidas.

El modelo de CycleGAN se compila con el optimizador 'adam' y una lista de funciones de pérdida que incluyen la entropía cruzada binaria para las salidas de validez y la pérdida cíclica para las salidas de reconstrucción. Además, para asegurar que el entrenamiento de la CycleGAN se centre en mejorar los generadores, el script establece el atributo trainable de los discriminadores en False antes de compilar el modelo de CycleGAN.

Finalmente, el script imprime un resumen de cada modelo para proporcionar una visión general de sus arquitecturas. Esto incluye las capas en cada modelo, la forma de las salidas de cada capa y el número de parámetros en cada capa.

3.5.3 StyleGAN

StyleGAN, o Style Generative Adversarial Network, es un tipo avanzado de modelo GAN introducido por Karras et al. de NVIDIA en 2019. Este modelo representa un avance significativo en el campo de los modelos generativos debido a su capacidad para generar imágenes extremadamente realistas y de alta calidad.

La principal innovación en StyleGAN reside en su arquitectura única del generador basada en estilos. Esta nueva arquitectura permite un control detallado y específico del proceso de síntesis de imágenes, separando las influencias de atributos de alto nivel y la variación estocástica en las imágenes generadas. Con esto, es posible manipular aspectos específicos de las imágenes generadas de manera independiente, lo cual no era posible con modelos GAN anteriores.

La arquitectura de StyleGAN incluye una red de mapeo y una red de síntesis. La red de mapeo toma un código latente y lo mapea a un espacio latente intermedio, que controla los estilos de varios aspectos de la imagen generada. La red de síntesis toma esta representación intermedia y genera la imagen final.

Las características clave de StyleGAN incluyen el uso de normalización adaptativa de instancias (AdaIN) para la modulación de estilos, el crecimiento progresivo tanto del generador como del discriminador para un entrenamiento estable y una calidad mejorada, y una red de mapeo con inyección de estilo para controlar los atributos de la imagen.

Una de las aplicaciones más conocidas de StyleGAN es el sitio web 'This Person Does Not Exist', donde el modelo genera rostros humanos altamente realistas de personas que no existen. Otras aplicaciones incluyen la manipulación de características específicas de una imagen, como cambiar el color del cabello o la edad de una persona, y transferir el estilo de una imagen a otra, como cambiar una foto diurna a nocturna.

En conclusión, StyleGAN representa un avance significativo en el campo de los modelos generativos, abriendo nuevas posibilidades para la síntesis, manipulación y comprensión de imágenes.

Resumen de Características Clave de StyleGAN:

  • Utiliza una arquitectura de generador basada en estilos, que proporciona un enfoque único en cómo el generador maneja y procesa los vectores de ruido. Esta arquitectura se combina con la normalización adaptativa de instancias (AdaIN), una técnica que permite la transferencia de estilo desde las imágenes de estilo a las imágenes generadas.
  • Emplea una metodología de crecimiento progresivo tanto para el generador como para el discriminador. Esto significa que la red comienza entrenando con imágenes de baja resolución y luego aumenta progresivamente la resolución añadiendo más capas. Esta estrategia mejora significativamente la estabilidad del entrenamiento y permite que la red genere imágenes de alta calidad.
  • Proporciona la capacidad de controlar atributos específicos de la imagen, como el estilo y la estructura de las imágenes generadas. Esto se logra mediante el uso de una red de mapeo y la inyección de estilo. La red de mapeo permite que el modelo aprenda representaciones más separadas, y la inyección de estilo proporciona una forma de controlar el estilo en diferentes niveles de detalle.

Ejemplo: Uso de un Modelo StyleGAN Pre-entrenado

Para usar un modelo StyleGAN pre-entrenado, podemos aprovechar bibliotecas como stylegan2-pytorch para mayor simplicidad. Aquí hay un ejemplo:

import torch
from stylegan2_pytorch import ModelLoader
import matplotlib.pyplot as plt

# Load pre-trained StyleGAN2 model
model = ModelLoader(name='ffhq', load_model=True)

# Generate random latent vectors
num_images = 5
latent_vectors = torch.randn(num_images, 512)

# Generate images using the model
generated_images = model.generate(latent_vectors)

# Plot the generated images
fig, axs = plt.subplots(1, num_images, figsize=(15, 15))
for i, img in enumerate(generated_images):
    axs[i].imshow(img.permute(1, 2, 0).cpu().numpy())
    axs[i].axis('off')

plt.show()

Este ejemplo utiliza la biblioteca stylegan2-pytorch para generar imágenes a partir de un modelo preentrenado de StyleGAN2.

Aquí tienes un desglose de los pasos:

Importar Bibliotecas:

  • torch: La biblioteca PyTorch para el aprendizaje profundo.
  • from stylegan2_pytorch import ModelLoader: Importa la clase ModelLoader de la biblioteca stylegan2-pytorch. Esta clase ayuda a cargar y gestionar los modelos StyleGAN2.
  • matplotlib.pyplot as plt: Utilizado para trazar las imágenes generadas.

Cargar el Modelo Preentrenado:

  • model = ModelLoader(name='ffhq', load_model=True): Crea una instancia de ModelLoader llamada model.
    • name='ffhq': Especifica el nombre del modelo preentrenado, probablemente "ffhq", que se refiere al conjunto de datos Flickr-Faces-HQ, comúnmente utilizado para el entrenamiento de StyleGAN2.
    • load_model=True: Instruye a ModelLoader que cargue los parámetros del modelo preentrenado.

Generar Vectores Latentes Aleatorios:

  • num_images = 5: Define el número de imágenes a generar (establecido en 5 en este ejemplo).
  • latent_vectors = torch.randn(num_images, 512): Crea un tensor aleatorio llamado latent_vectors con dimensiones (num_images, 512). Este tensor representa el ruido latente utilizado para generar imágenes. La dimensionalidad específica (512 en este caso) depende de la arquitectura del modelo preentrenado.

Generar Imágenes:

  • generated_images = model.generate(latent_vectors): Esta línea utiliza la función model.generate para generar imágenes a partir de los vectores latentes proporcionados. Las imágenes generadas se almacenan en el tensor generated_images.

Trazar las Imágenes Generadas:

  • plt.subplots(1, num_images, figsize=(15, 15)): Crea una figura de Matplotlib con una sola fila y num_images columnas para mostrar las imágenes generadas. También establece el tamaño de la figura en 15x15 para una mejor visualización.
  • El bucle itera a través de cada imagen en generated_images:
    • axs[i].imshow(...): Esta línea muestra la imagen actual en una subtrama utilizando la función imshow de Matplotlib.
      • .permute(1, 2, 0).cpu().numpy(): Esta línea reorganiza las dimensiones del tensor de imagen del formato de PyTorch (canales primero) al formato de Matplotlib (canales al final) y lo convierte en un array de NumPy para la compatibilidad con imshow.
    • axs[i].axis('off'): Apaga las etiquetas de los ejes para una presentación más limpia.
  • plt.show(): Muestra las imágenes generadas en la pantalla.

En resumen, este ejemplo demuestra cómo generar imágenes con un modelo StyleGAN2 proporcionando ruido latente aleatorio como entrada y visualizando los resultados generados.

3.5.4 Otras Variaciones de GAN

1. Wasserstein GAN (WGAN):

Wasserstein GAN, a menudo abreviado como WGAN, es una variante de las Redes Generativas Antagónicas (GANs). Introducidas por Martin Arjovsky, Soumith Chintala y Léon Bottou en 2017, las WGANs representan un avance significativo en el campo de las GANs, abordando principalmente dos problemas críticos que a menudo afectan a las GANs tradicionales: la inestabilidad en el entrenamiento y el colapso de modos.

El nombre "Wasserstein" proviene del tipo de función de pérdida utilizada en estas GANs, conocida como la distancia Wasserstein o la distancia del "trasportador de tierra". Esta es una medida de la distancia entre dos distribuciones de probabilidad y se usa en lugar de las funciones de pérdida tradicionales de GAN, como la divergencia de Jensen-Shannon. Este cambio en la función de pérdida conduce a una superficie de pérdida más suave y significativa, lo que hace que el proceso de entrenamiento sea más estable.

Las WGANs también introducen una característica única conocida como recorte de pesos, que ayuda a garantizar que la función del discriminador (también conocida como el crítico en la terminología de WGAN) se encuentre dentro de un espacio compacto, facilitando el cálculo de la distancia Wasserstein.

La innovación de las WGANs ha tenido un impacto significativo en la mejora de la calidad y diversidad de las muestras generadas, así como en la estabilidad del proceso de entrenamiento de las GAN. Ha permitido procesos de entrenamiento más confiables, abriendo así nuevas posibilidades para la aplicación de las GAN en varios dominios.

Sin embargo, vale la pena señalar que, aunque las WGANs abordan algunos problemas en las GANs estándar, también tienen su propio conjunto de desafíos y limitaciones, como problemas con el recorte de pesos que conducen a comportamientos de función no deseados. Esto ha llevado a desarrollos y mejoras adicionales en el campo de las GAN, como la introducción de WGAN-GP (Wasserstein GAN con Penalización de Gradiente) que reemplaza el recorte de pesos con una penalización de gradiente para un entrenamiento más estable y eficiente.

2. BigGAN:

BigGAN, abreviatura de Big Generative Adversarial Network, es un tipo de modelo de aprendizaje automático que pertenece a la clase de Redes Generativas Antagónicas (GANs). Las GANs, introducidas por Ian Goodfellow y sus colegas en 2014, están diseñadas para generar nuevas instancias sintéticas de datos que puedan pasar por datos reales. Consisten en dos partes: un 'generador' que produce los datos sintéticos y un 'discriminador' que intenta diferenciar entre los datos generados y los datos reales.

En el contexto de BigGAN, el modelo está diseñado para producir imágenes de alta resolución y altamente realistas que a menudo pueden pasar como reales para el ojo inexperto. El término "big" se refiere a la naturaleza a gran escala del modelo, que emplea tamaños de lote grandes y conjuntos de datos de entrenamiento extensivos para crear estas imágenes de alta calidad.

El modelo BigGAN es una evolución en el campo de las GANs, con sus predecesores que incluyen el modelo GAN original, DCGAN, WGAN y otros. Cada evolución generalmente apunta a resolver algunos de los problemas enfrentados por los modelos anteriores o a mejorar la calidad de los datos generados. En el caso de BigGAN, el enfoque está en mejorar la resolución y el realismo de las imágenes generadas.

El uso de BigGAN y modelos similares se extiende más allá de solo generar imágenes de aspecto realista. Se utilizan en una amplia variedad de aplicaciones, incluyendo la mejora de imágenes, la transferencia de estilo, la traducción de imagen a imagen y más. Al mejorar continuamente la calidad y versatilidad de estos modelos, los investigadores están ampliando los límites de lo que es posible en el campo de la modelación generativa.

3. SRGAN (Super-Resolution GAN):

SRGAN, abreviatura de Super-Resolution Generative Adversarial Network, es una variante particular de las Redes Generativas Antagónicas (GANs) diseñadas específicamente para tareas de super-resolución de imágenes. Este tipo de GAN se utiliza principalmente para mejorar la resolución de imágenes de baja resolución, asegurando que las imágenes resultantes de alta resolución mantengan una alta calidad visual.

El término "super-resolución" se refiere al proceso de aumentar la resolución de una imagen, video u otro tipo de imagen. En el contexto de SRGAN, esto significa transformar una imagen de baja resolución en una versión de alta resolución que tenga más detalles y sea visualmente más atractiva.

La estructura básica de SRGAN, como otras GANs, consta de dos componentes principales: una red generadora y una red discriminadora. La red generadora tiene la tarea de tomar una imagen de baja resolución y generar una versión de alta resolución de la misma. La red discriminadora, por otro lado, tiene la tarea de determinar si una imagen de alta resolución dada proviene del conjunto de datos de imágenes de alta resolución reales o fue creada por el generador.

Una de las características clave de SRGAN que la distingue de otros métodos de super-resolución es su capacidad para recuperar detalles más finos en la imagen aumentada. Los métodos tradicionales a menudo producen imágenes de alta resolución que son más borrosas y carecen de algunos de los detalles texturales presentes en la imagen original. SRGAN supera esta limitación utilizando una función de pérdida perceptual que anima al generador a crear imágenes que no solo tengan los valores de píxeles correctos, sino que también tengan características de alto nivel que coincidan con las de la imagen original de alta resolución.

Como resultado de estas capacidades, SRGAN ha encontrado una amplia aplicación en campos donde la resolución de imagen de alta calidad es esencial. Estos incluyen imágenes médicas (por ejemplo, mejorando escaneos de MRI), imágenes satelitales y aéreas, gráficos de videojuegos y transmisión de video, entre otros.

SRGAN representa un avance importante en el campo de la super-resolución de imágenes, proporcionando una herramienta poderosa para mejorar la calidad de imágenes de baja resolución.

4. Conditional GAN (cGAN):

Las Redes Generativas Antagónicas Condicionales (cGANs) son un tipo de GAN que incluye información auxiliar tanto para las redes generadora como discriminadora. Esta información adicional a menudo viene en forma de etiquetas, lo que permite que el proceso de generación de datos tenga en cuenta condiciones o características específicas.

En una GAN estándar, la red generadora toma un vector de ruido aleatorio como entrada y produce una instancia de datos sintéticos (por ejemplo, una imagen). La red discriminadora luego trata de clasificar si esta instancia de datos es real (de la distribución de datos verdadera) o falsa (generada por el generador). Las dos redes se entrenan juntas, con el generador tratando de engañar al discriminador y el discriminador tratando de clasificar correctamente las instancias reales frente a las falsas.

En una cGAN, el generador toma dos entradas: un vector de ruido aleatorio y una etiqueta. La etiqueta proporciona información adicional sobre qué tipo de instancia de datos debe producir el generador. Por ejemplo, si las etiquetas son dígitos del 0 al 9 y las instancias de datos son imágenes de dígitos escritos a mano, el generador podría estar condicionado a producir una imagen de un dígito específico.

El discriminador en una cGAN también toma dos entradas: una instancia de datos y una etiqueta. Tiene que determinar no solo si la instancia de datos es real o falsa, sino también si coincide con la etiqueta dada.

La ventaja de las cGANs es que pueden generar datos bajo condiciones específicas o con ciertas características, lo que puede ser muy útil en muchas aplicaciones. Por ejemplo, en la generación de imágenes, una cGAN podría generar imágenes de gatos, perros u otros objetos específicos según la etiqueta dada. En la mejora de datos, una cGAN podría generar datos adicionales para una clase específica que está subrepresentada en los datos de entrenamiento.

La implementación de una cGAN implica modificaciones tanto en la red generadora como en la discriminadora para aceptar y procesar la información de etiqueta adicional. Además, el procedimiento de entrenamiento necesita ajustarse para tener en cuenta la naturaleza condicional del proceso de generación de datos.

En general, las cGANs representan una extensión importante del marco estándar de GAN, permitiendo tareas de generación de datos más controladas y específicas.

Ejemplo: Implementación de una Conditional GAN

import tensorflow as tf
from tensorflow.keras.layers import Input, Embedding, multiply

# Conditional GAN Generator
def build_cgan_generator(latent_dim, num_classes):
    noise = Input(shape=(latent_dim,))
    label = Input(shape=(1,), dtype='int32')
    label_embedding = Flatten()(Embedding(num_classes, latent_dim)(label))
    model_input = multiply([noise, label_embedding])

    x = Dense(256 * 7 * 7, activation="relu")(model_input)
    x = Reshape((7, 7, 256))(x)
    x = BatchNormalization()(x)
    x = Conv2DTranspose(128, kernel_size=4, strides=2, padding='same')(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2DTranspose(64, kernel_size=4, strides=2, padding='same')(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=0.2)(x)
    output_img = Conv2DTranspose(1, kernel_size=4, strides=1, padding='same', activation='tanh')(x)

    return Model([noise, label], output_img)

# Conditional GAN Discriminator
def build_cgan_discriminator(img_shape, num_classes):
    img = Input(shape=img_shape)
    label = Input(shape=(1,), dtype='int32')
    label_embedding = Flatten()(Embedding(num_classes, np.prod(img_shape))(label))
    label_embedding = Reshape(img_shape)(label_embedding)
    model_input = multiply([img, label_embedding])

    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(model_input)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Flatten()(x)
    validity = Dense(1, activation='sigmoid')(x)

    return Model([img, label], validity)

# Build and compile the Conditional GAN
latent_dim = 100
num_classes = 10
img_shape = (28, 28, 1)

generator = build_cgan_generator(latent_dim, num_classes)
discriminator = build_cgan_discriminator(img_shape, num_classes)
discriminator.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
noise = Input(shape=(latent_dim,))
label = Input(shape=(1,), dtype='int32')
generated_img = generator([noise, label])
validity = discriminator([generated_img, label])
cgan = Model([noise, label], validity)
cgan.compile(optimizer='adam', loss='binary_crossentropy')

# Summary of the models
generator.summary()
discriminator.summary()
cgan.summary()

En este ejemplo:

El primer paso en el código es importar las bibliotecas necesarias. Se requiere la biblioteca TensorFlow para el aprendizaje automático, con su API de Keras utilizada para crear los modelos de redes neuronales. Las funciones Input, Embedding, Dense y multiply, entre otras, se importan del módulo de capas de Keras.

La siguiente parte del script define dos funciones, build_cgan_generator y build_cgan_discriminator. Estas dos funciones se utilizan para construir los modelos generador y discriminador del CGAN, respectivamente.

La función build_cgan_generator toma como entradas la dimensión latente (el tamaño del vector de ruido aleatorio) y el número de clases (el número de etiquetas). Dentro de esta función, se construye el modelo del generador. El generador toma un vector de ruido aleatorio y una etiqueta como entradas. El vector de ruido es un punto en el espacio latente, y la etiqueta es un vector codificado en one-hot que representa la clase deseada de la imagen generada. El ruido y la etiqueta se combinan y se pasan a través de una serie de capas Dense, Reshape, BatchNormalization, Conv2DTranspose y LeakyReLU para generar la imagen de salida final.

La función build_cgan_discriminator también toma como entradas la forma de la imagen y el número de clases. Dentro de esta función, se construye el modelo del discriminador. El discriminador toma una imagen y una etiqueta como entradas. La imagen es la generada (o real), y la etiqueta es la etiqueta verdadera de la imagen. La imagen y la etiqueta se combinan y se pasan a través de una serie de capas Conv2D, LeakyReLU, Flatten y Dense para producir un único valor que representa si la imagen es real o falsa.

Después de definir las funciones del generador y el discriminador, el script las utiliza para crear instancias de estos modelos. Luego, el modelo del discriminador se compila utilizando el optimizador Adam y la pérdida de entropía cruzada binaria como función de pérdida. También se especifica la métrica de precisión para medir el rendimiento del discriminador.

A continuación, el script establece el atributo trainable del discriminador a False. Esto se hace porque, al entrenar el CGAN, se desea entrenar el generador para engañar al discriminador, pero no entrenar al discriminador para mejorar su capacidad de detectar al generador. Por lo tanto, los pesos del discriminador se congelan durante el entrenamiento del CGAN.

Luego, se construye y compila el modelo CGAN. El modelo CGAN consta del generador seguido del discriminador. Un vector de ruido y una etiqueta se pasan al generador para producir una imagen generada. Esta imagen generada y la etiqueta se alimentan luego al discriminador para producir la validez de la imagen.

Finalmente, el script imprime un resumen de cada modelo. Esto proporciona una visión general de los modelos generador, discriminador y CGAN, incluyendo las capas en cada modelo, las formas de salida de estas capas y el número de parámetros en cada capa.

Este ejemplo proporciona una guía paso a paso sobre cómo implementar un CGAN en TensorFlow. Al proporcionar etiquetas como entrada adicional tanto al generador como al discriminador, un CGAN permite la generación de datos con características específicas deseadas.

3.5 Variaciones de las GANs

Desde la introducción de las innovadoras Redes Generativas Adversariales (GANs), se han desarrollado meticulosamente una gran cantidad de modificaciones y mejoras con el objetivo de abordar desafíos específicos que se encontraron y de expandir significativamente las capacidades del marco original de las GANs.

Estas variaciones son numerosas y diversas, incluyendo, pero no limitándose a, las GANs de Convolución Profunda (DCGANs), las innovadoras CycleGANs y las altamente versátiles StyleGANs, entre muchas otras.

Cada una de estas variaciones únicas introduce su propio conjunto de cambios arquitectónicos y técnicas de entrenamiento novedosas. Estas están cuidadosamente adaptadas para atender aplicaciones específicas o para mejorar el rendimiento. En esta sección en particular, profundizaremos en algunas de las variaciones de GANs más prominentes y reconocidas que han revolucionado el campo. Al hacerlo, proporcionaremos explicaciones detalladas que sean fáciles de entender, junto con código de ejemplo para ilustrar vívidamente su implementación práctica y uso en escenarios del mundo real.

3.5.1 GANs de Convolución Profunda (DCGANs)

Las GANs de Convolución Profunda (DCGANs) fueron introducidas por Radford et al. en 2015, y representan una mejora significativa sobre la arquitectura original de las GANs. Estas DCGANs aprovechan las capas convolucionales tanto en las redes del generador como del discriminador, lo cual es un cambio respecto al uso de capas totalmente conectadas. Esta adaptación es particularmente beneficiosa para manejar datos de imagen y conduce a un entrenamiento más estable y a imágenes generadas de mejor calidad.

Características clave de las DCGANs incluyen:

  • El uso de capas convolucionales en lugar de capas totalmente conectadas.
  • Sustitución de capas de pooling con convoluciones estratificadas en el discriminador y convoluciones transpuestas en el generador.
  • El uso de normalización por lotes (batch normalization) para estabilizar el entrenamiento.
  • El empleo de diferentes funciones de activación en el generador y el discriminador: activación ReLU en el generador y LeakyReLU en el discriminador.

Estas características contribuyen al rendimiento y la estabilidad mejorados de las DCGANs en comparación con las GANs originales. Al utilizar capas convolucionales, las DCGANs pueden aprender jerarquías espaciales de características de manera no supervisada, lo cual es altamente beneficioso para tareas que involucran imágenes.

En general, las DCGANs representan un hito significativo en el desarrollo de las GANs y han allanado el camino para numerosas variaciones y mejoras subsiguientes en la arquitectura de las GANs.

Ejemplo: Implementación de DCGAN con TensorFlow/Keras

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, LeakyReLU, BatchNormalization, Reshape, Dense, Flatten
from tensorflow.keras.models import Sequential
import numpy as np
import matplotlib.pyplot as plt

# DCGAN Generator
def build_dcgan_generator(latent_dim):
    model = Sequential([
        Dense(256 * 7 * 7, activation="relu", input_dim=latent_dim),
        Reshape((7, 7, 256)),
        BatchNormalization(),
        Conv2DTranspose(128, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2DTranspose(64, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2DTranspose(1, kernel_size=4, strides=1, padding='same', activation='tanh')
    ])
    return model

# DCGAN Discriminator
def build_dcgan_discriminator(img_shape):
    model = Sequential([
        Conv2D(64, kernel_size=4, strides=2, padding='same', input_shape=img_shape),
        LeakyReLU(alpha=0.2),
        Conv2D(128, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2D(256, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Flatten(),
        Dense(1, activation='sigmoid')
    ])
    return model

# Training the DCGAN
latent_dim = 100
img_shape = (28, 28, 1)

generator = build_dcgan_generator(latent_dim)
discriminator = build_dcgan_discriminator(img_shape)
discriminator.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
gan_input = tf.keras.Input(shape=(latent_dim,))
generated_img = generator(gan_input)
validity = discriminator(generated_img)
dcgan = tf.keras.Model(gan_input, validity)
dcgan.compile(optimizer='adam', loss='binary_crossentropy')

# Load and preprocess the MNIST dataset
(x_train, _), (_, _) = tf.keras.datasets.mnist.load_data()
x_train = (x_train.astype(np.float32) - 127.5) / 127.5  # Normalize to [-1, 1]
x_train = np.expand_dims(x_train, axis=-1)

# Training parameters
epochs = 10000
batch_size = 64
sample_interval = 1000

for epoch in range(epochs):
    # Train the discriminator
    idx = np.random.randint(0, x_train.shape[0], batch_size)
    real_images = x_train[idx]
    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    fake_images = generator.predict(noise)
    d_loss_real = discriminator.train_on_batch(real_images, np.ones((batch_size, 1)))
    d_loss_fake = discriminator.train_on_batch(fake_images, np.zeros((batch_size, 1)))
    d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)

    # Train the generator
    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    g_loss = dcgan.train_on_batch(noise, np.ones((batch_size, 1)))

    # Print progress
    if epoch % sample_interval == 0:
        print(f"{epoch} [D loss: {d_loss[0]}, acc.: {d_loss[1] * 100}%] [G loss: {g_loss}]")

        # Generate and save images
        noise = np.random.normal(0, 1, (10, latent_dim))
        generated_images = generator.predict(noise)
        fig, axs = plt.subplots(1, 10, figsize=(20, 2))
        for i, img in enumerate(generated_images):
            axs[i].imshow(img.squeeze(), cmap='gray')
            axs[i].axis('off')
        plt.show()

En este ejemplo:

El script comienza importando las bibliotecas necesarias, que incluyen TensorFlow, Keras, NumPy y Matplotlib. TensorFlow es una biblioteca de código abierto popular para el aprendizaje automático e inteligencia artificial, mientras que Keras es una API de redes neuronales de alto nivel escrita en Python y capaz de ejecutarse sobre TensorFlow. NumPy se usa para cálculos numéricos y Matplotlib se usa para generar gráficos.

El script luego define dos funciones, build_dcgan_generator y build_dcgan_discriminator, que crean los modelos del generador y del discriminador respectivamente. El modelo del generador toma una dimensión latente como entrada y produce una imagen, mientras que el discriminador toma una imagen como entrada y produce una probabilidad que indica si la imagen es real o falsa. El modelo del generador se construye usando una secuencia de capas densas, de reconfiguración, de normalización por lotes y de convolución transpuesta, mientras que el modelo del discriminador usa una secuencia de capas de convolución, de normalización por lotes, LeakyReLU, de aplanamiento y densas.

Después de definir los modelos, el script crea instancias del generador y del discriminador y compila el modelo del discriminador. El modelo del discriminador se compila con el optimizador Adam y la pérdida de entropía cruzada binaria. Durante el entrenamiento de la GAN, los parámetros del modelo del discriminador se configuran como no entrenables.

El script luego define el modelo de GAN, que toma un vector latente como entrada y da salida a la validez de la imagen generada según lo determine el discriminador. El modelo de GAN se compila con el optimizador Adam y la pérdida de entropía cruzada binaria.

A continuación, el script carga el conjunto de datos MNIST, que es una gran base de datos de dígitos escritos a mano que se utiliza comúnmente para entrenar varios sistemas de procesamiento de imágenes. Después de cargar el conjunto de datos, el script normaliza los datos de la imagen para que estén entre -1 y 1 y expande la dimensión del conjunto de datos.

El script luego establece los parámetros de entrenamiento, que incluyen el número de épocas, el tamaño del lote y el intervalo de muestreo. También inicializa matrices para almacenar las pérdidas y precisiones del discriminador y la pérdida del generador.

El script luego entra en el bucle de entrenamiento. Para cada época, el script selecciona un lote aleatorio de imágenes del conjunto de datos y genera un lote correspondiente de vectores de ruido. Utiliza el modelo del generador para generar un lote de imágenes falsas a partir de los vectores de ruido. El modelo del discriminador se entrena luego en las imágenes reales y falsas. El modelo del generador se entrena luego para generar imágenes que el modelo del discriminador considera reales.

Cada 1000 épocas, el script imprime el número de época, la pérdida y precisión del discriminador en las imágenes reales y falsas, y la pérdida del generador. También genera un lote de imágenes del modelo del generador usando un lote fijo de vectores de ruido y traza estas imágenes en una cuadrícula de 1 por 10.

3.5.2 CycleGAN

CycleGAN, introducida por Zhu et al. en 2017, es un tipo específico de Red Generativa Adversarial (GAN) que se centra en la traducción de imágenes a imágenes. Su característica distintiva principal es su capacidad para transformar imágenes de un dominio a otro sin necesidad de ejemplos de entrenamiento pareados. Este es un avance significativo sobre los modelos anteriores, ya que elimina la necesidad de un conjunto de datos que contenga pares de imágenes perfectamente emparejadas de los dominios fuente y destino.

Por ejemplo, si deseas convertir imágenes de caballos en imágenes de cebras, un modelo tradicional de traducción de imágenes a imágenes requeriría un conjunto de datos de imágenes de caballos y cebras emparejadas. CycleGAN, sin embargo, puede aprender esta transformación sin tal conjunto de datos. Esto es particularmente útil para tareas donde es difícil o imposible recopilar datos de entrenamiento pareados.

La arquitectura de CycleGAN incluye dos redes generadoras y dos redes discriminadoras. Las redes generadoras son responsables de la transformación de las imágenes entre los dos dominios. Un generador transforma del dominio fuente al dominio destino, mientras que el otro transforma en la dirección inversa. Las redes discriminadoras, por otro lado, se utilizan para imponer el realismo de las imágenes transformadas.

Además de las funciones de pérdida tradicionales de GAN, CycleGAN también introduce una función de pérdida de consistencia cíclica. Esta función asegura que una imagen que se transforma de un dominio a otro y luego de regreso al dominio original será la misma que la imagen original. Este proceso cíclico ayuda al modelo a aprender mapeos precisos y coherentes entre los dos dominios.

En general, CycleGAN ha sido fundamental en el campo de la traducción de imágenes y la transferencia de estilo, permitiendo transformaciones que anteriormente eran desafiantes o imposibles con GANs tradicionales. Se ha utilizado en una amplia variedad de aplicaciones, desde convertir pinturas en fotografías, cambiar estaciones en imágenes de paisajes, e incluso traducir imágenes de Google Maps a imágenes satelitales.

Resumen de Características Clave y Funcionalidades de CycleGAN:

  • CycleGAN hace uso de dos modelos generadores separados, cada uno designado para un dominio específico, así como dos modelos discriminadores individuales. Este enfoque, que implica vías duales, permite que el modelo aprenda y mapee las características de un dominio a otro.
  • Una característica única y crítica de CycleGAN es la introducción de lo que se conoce como pérdida de consistencia cíclica. Este mecanismo innovador impone el principio de que cuando una imagen se traduce de su dominio original al dominio objetivo, y luego se traduce de nuevo al dominio original, el modelo debe producir una imagen que refleje la imagen de entrada original. Este es un aspecto fundamental del diseño del modelo, ya que ayuda a asegurar la precisión de las traducciones entre dominios.

Ejemplo: Implementación de CycleGAN con TensorFlow/Keras

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, LeakyReLU, BatchNormalization, Input
from tensorflow.keras.models import Model
import numpy as np
import matplotlib.pyplot as plt

# CycleGAN Generator
def build_cyclegan_generator(img_shape):
    input_img = Input(shape=img_shape)
    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(input_img)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    x = Conv2DTranspose(64, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    output_img = Conv2DTranspose(3, kernel_size=4, strides=2, padding='same', activation='tanh')(x)
    return Model(input_img, output_img)

# CycleGAN Discriminator
def build_cyclegan_discriminator(img_shape):
    input_img = Input(shape=img_shape)
    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(input_img)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Flatten()(x)
    validity = Dense(1, activation='sigmoid')(x)
    return Model(input_img, validity)

# Build CycleGAN models
img_shape = (128, 128, 3)
G_AB = build_cyclegan_generator(img_shape)
G_BA = build_cyclegan_generator(img_shape)
D_A = build_cyclegan_discriminator(img_shape)
D_B = build_cyclegan_discriminator(img_shape)

D_A.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
D_B.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

# CycleGAN loss
def cycle_loss(y_true, y_pred):
    return tf.reduce_mean(tf.abs(y_true - y_pred))

# Full CycleGAN model
img_A = Input(shape=img_shape)
img_B = Input(shape=img_shape)

fake_B = G_AB(img_A)
reconstr_A = G_BA(fake_B)
fake_A = G_BA(img_B)
reconstr_B = G_AB(fake_A)

D_A.trainable = False
D_B.trainable = False

valid_A = D_A(fake_A)
valid_B = D_B(fake_B)

cycle_gan = Model(inputs=[img_A, img_B], outputs=[valid_A, valid_B, reconstr_A, reconstr_B])
cycle_gan.compile(optimizer='adam', loss=['binary_crossentropy', 'binary_crossentropy', cycle_loss, cycle_loss])

# Summary of the models
G_AB.summary()
G_BA.summary()
D_A.summary()
D_B.summary()
cycle_gan.summary()

En este ejemplo:

La primera parte del script importa las bibliotecas necesarias, que incluyen TensorFlow para el aprendizaje automático, Keras para la API de redes neuronales, numpy para cálculos numéricos y matplotlib para generar gráficos.

El script luego define dos funciones, build_cyclegan_generator y build_cyclegan_discriminator. Estas dos funciones se utilizan para construir los modelos generador y discriminador de la CycleGAN.

El modelo del generador está diseñado para transformar una imagen de un dominio a otro. El modelo comienza con una imagen de entrada y aplica una serie de capas convolucionales, de activación LeakyReLU y de normalización por lotes para procesar la imagen. La imagen procesada se pasa luego a través de un conjunto de capas de convolución transpuesta para generar la imagen de salida.

El modelo del discriminador es responsable de determinar si una imagen dada es real (del conjunto de datos) o falsa (generada por el generador). El modelo toma una imagen como entrada y aplica una serie de capas convolucionales y de activación LeakyReLU. La imagen procesada se aplana y se pasa a través de una capa densa para dar salida a un único valor que representa la probabilidad de que la imagen sea real.

Después de definir los modelos generador y discriminador, el script crea instancias de estos modelos para dos dominios de imagen, referidos como A y B. El script también compila los modelos discriminadores, especificando 'adam' como el optimizador, 'binary_crossentropy' como la función de pérdida y 'accuracy' como la métrica.

El script luego define una función de pérdida especial para la CycleGAN, llamada pérdida cíclica. Esta función mide la diferencia absoluta entre la imagen original y la imagen reconstruida (es decir, una imagen que ha sido transformada de un dominio a otro y luego de vuelta al dominio original). La pérdida cíclica anima a la CycleGAN a aprender mapeos capaces de reconstruir la imagen original con precisión.

A continuación, el script construye el modelo completo de CycleGAN. Este modelo toma dos imágenes como entrada (una del dominio A y una del dominio B), transforma cada imagen al otro dominio utilizando los generadores, y luego de vuelta al dominio original. El modelo también pasa las imágenes transformadas a través de los discriminadores para determinar su realismo. Las salidas del modelo incluyen la validez de las imágenes transformadas y las imágenes reconstruidas.

El modelo de CycleGAN se compila con el optimizador 'adam' y una lista de funciones de pérdida que incluyen la entropía cruzada binaria para las salidas de validez y la pérdida cíclica para las salidas de reconstrucción. Además, para asegurar que el entrenamiento de la CycleGAN se centre en mejorar los generadores, el script establece el atributo trainable de los discriminadores en False antes de compilar el modelo de CycleGAN.

Finalmente, el script imprime un resumen de cada modelo para proporcionar una visión general de sus arquitecturas. Esto incluye las capas en cada modelo, la forma de las salidas de cada capa y el número de parámetros en cada capa.

3.5.3 StyleGAN

StyleGAN, o Style Generative Adversarial Network, es un tipo avanzado de modelo GAN introducido por Karras et al. de NVIDIA en 2019. Este modelo representa un avance significativo en el campo de los modelos generativos debido a su capacidad para generar imágenes extremadamente realistas y de alta calidad.

La principal innovación en StyleGAN reside en su arquitectura única del generador basada en estilos. Esta nueva arquitectura permite un control detallado y específico del proceso de síntesis de imágenes, separando las influencias de atributos de alto nivel y la variación estocástica en las imágenes generadas. Con esto, es posible manipular aspectos específicos de las imágenes generadas de manera independiente, lo cual no era posible con modelos GAN anteriores.

La arquitectura de StyleGAN incluye una red de mapeo y una red de síntesis. La red de mapeo toma un código latente y lo mapea a un espacio latente intermedio, que controla los estilos de varios aspectos de la imagen generada. La red de síntesis toma esta representación intermedia y genera la imagen final.

Las características clave de StyleGAN incluyen el uso de normalización adaptativa de instancias (AdaIN) para la modulación de estilos, el crecimiento progresivo tanto del generador como del discriminador para un entrenamiento estable y una calidad mejorada, y una red de mapeo con inyección de estilo para controlar los atributos de la imagen.

Una de las aplicaciones más conocidas de StyleGAN es el sitio web 'This Person Does Not Exist', donde el modelo genera rostros humanos altamente realistas de personas que no existen. Otras aplicaciones incluyen la manipulación de características específicas de una imagen, como cambiar el color del cabello o la edad de una persona, y transferir el estilo de una imagen a otra, como cambiar una foto diurna a nocturna.

En conclusión, StyleGAN representa un avance significativo en el campo de los modelos generativos, abriendo nuevas posibilidades para la síntesis, manipulación y comprensión de imágenes.

Resumen de Características Clave de StyleGAN:

  • Utiliza una arquitectura de generador basada en estilos, que proporciona un enfoque único en cómo el generador maneja y procesa los vectores de ruido. Esta arquitectura se combina con la normalización adaptativa de instancias (AdaIN), una técnica que permite la transferencia de estilo desde las imágenes de estilo a las imágenes generadas.
  • Emplea una metodología de crecimiento progresivo tanto para el generador como para el discriminador. Esto significa que la red comienza entrenando con imágenes de baja resolución y luego aumenta progresivamente la resolución añadiendo más capas. Esta estrategia mejora significativamente la estabilidad del entrenamiento y permite que la red genere imágenes de alta calidad.
  • Proporciona la capacidad de controlar atributos específicos de la imagen, como el estilo y la estructura de las imágenes generadas. Esto se logra mediante el uso de una red de mapeo y la inyección de estilo. La red de mapeo permite que el modelo aprenda representaciones más separadas, y la inyección de estilo proporciona una forma de controlar el estilo en diferentes niveles de detalle.

Ejemplo: Uso de un Modelo StyleGAN Pre-entrenado

Para usar un modelo StyleGAN pre-entrenado, podemos aprovechar bibliotecas como stylegan2-pytorch para mayor simplicidad. Aquí hay un ejemplo:

import torch
from stylegan2_pytorch import ModelLoader
import matplotlib.pyplot as plt

# Load pre-trained StyleGAN2 model
model = ModelLoader(name='ffhq', load_model=True)

# Generate random latent vectors
num_images = 5
latent_vectors = torch.randn(num_images, 512)

# Generate images using the model
generated_images = model.generate(latent_vectors)

# Plot the generated images
fig, axs = plt.subplots(1, num_images, figsize=(15, 15))
for i, img in enumerate(generated_images):
    axs[i].imshow(img.permute(1, 2, 0).cpu().numpy())
    axs[i].axis('off')

plt.show()

Este ejemplo utiliza la biblioteca stylegan2-pytorch para generar imágenes a partir de un modelo preentrenado de StyleGAN2.

Aquí tienes un desglose de los pasos:

Importar Bibliotecas:

  • torch: La biblioteca PyTorch para el aprendizaje profundo.
  • from stylegan2_pytorch import ModelLoader: Importa la clase ModelLoader de la biblioteca stylegan2-pytorch. Esta clase ayuda a cargar y gestionar los modelos StyleGAN2.
  • matplotlib.pyplot as plt: Utilizado para trazar las imágenes generadas.

Cargar el Modelo Preentrenado:

  • model = ModelLoader(name='ffhq', load_model=True): Crea una instancia de ModelLoader llamada model.
    • name='ffhq': Especifica el nombre del modelo preentrenado, probablemente "ffhq", que se refiere al conjunto de datos Flickr-Faces-HQ, comúnmente utilizado para el entrenamiento de StyleGAN2.
    • load_model=True: Instruye a ModelLoader que cargue los parámetros del modelo preentrenado.

Generar Vectores Latentes Aleatorios:

  • num_images = 5: Define el número de imágenes a generar (establecido en 5 en este ejemplo).
  • latent_vectors = torch.randn(num_images, 512): Crea un tensor aleatorio llamado latent_vectors con dimensiones (num_images, 512). Este tensor representa el ruido latente utilizado para generar imágenes. La dimensionalidad específica (512 en este caso) depende de la arquitectura del modelo preentrenado.

Generar Imágenes:

  • generated_images = model.generate(latent_vectors): Esta línea utiliza la función model.generate para generar imágenes a partir de los vectores latentes proporcionados. Las imágenes generadas se almacenan en el tensor generated_images.

Trazar las Imágenes Generadas:

  • plt.subplots(1, num_images, figsize=(15, 15)): Crea una figura de Matplotlib con una sola fila y num_images columnas para mostrar las imágenes generadas. También establece el tamaño de la figura en 15x15 para una mejor visualización.
  • El bucle itera a través de cada imagen en generated_images:
    • axs[i].imshow(...): Esta línea muestra la imagen actual en una subtrama utilizando la función imshow de Matplotlib.
      • .permute(1, 2, 0).cpu().numpy(): Esta línea reorganiza las dimensiones del tensor de imagen del formato de PyTorch (canales primero) al formato de Matplotlib (canales al final) y lo convierte en un array de NumPy para la compatibilidad con imshow.
    • axs[i].axis('off'): Apaga las etiquetas de los ejes para una presentación más limpia.
  • plt.show(): Muestra las imágenes generadas en la pantalla.

En resumen, este ejemplo demuestra cómo generar imágenes con un modelo StyleGAN2 proporcionando ruido latente aleatorio como entrada y visualizando los resultados generados.

3.5.4 Otras Variaciones de GAN

1. Wasserstein GAN (WGAN):

Wasserstein GAN, a menudo abreviado como WGAN, es una variante de las Redes Generativas Antagónicas (GANs). Introducidas por Martin Arjovsky, Soumith Chintala y Léon Bottou en 2017, las WGANs representan un avance significativo en el campo de las GANs, abordando principalmente dos problemas críticos que a menudo afectan a las GANs tradicionales: la inestabilidad en el entrenamiento y el colapso de modos.

El nombre "Wasserstein" proviene del tipo de función de pérdida utilizada en estas GANs, conocida como la distancia Wasserstein o la distancia del "trasportador de tierra". Esta es una medida de la distancia entre dos distribuciones de probabilidad y se usa en lugar de las funciones de pérdida tradicionales de GAN, como la divergencia de Jensen-Shannon. Este cambio en la función de pérdida conduce a una superficie de pérdida más suave y significativa, lo que hace que el proceso de entrenamiento sea más estable.

Las WGANs también introducen una característica única conocida como recorte de pesos, que ayuda a garantizar que la función del discriminador (también conocida como el crítico en la terminología de WGAN) se encuentre dentro de un espacio compacto, facilitando el cálculo de la distancia Wasserstein.

La innovación de las WGANs ha tenido un impacto significativo en la mejora de la calidad y diversidad de las muestras generadas, así como en la estabilidad del proceso de entrenamiento de las GAN. Ha permitido procesos de entrenamiento más confiables, abriendo así nuevas posibilidades para la aplicación de las GAN en varios dominios.

Sin embargo, vale la pena señalar que, aunque las WGANs abordan algunos problemas en las GANs estándar, también tienen su propio conjunto de desafíos y limitaciones, como problemas con el recorte de pesos que conducen a comportamientos de función no deseados. Esto ha llevado a desarrollos y mejoras adicionales en el campo de las GAN, como la introducción de WGAN-GP (Wasserstein GAN con Penalización de Gradiente) que reemplaza el recorte de pesos con una penalización de gradiente para un entrenamiento más estable y eficiente.

2. BigGAN:

BigGAN, abreviatura de Big Generative Adversarial Network, es un tipo de modelo de aprendizaje automático que pertenece a la clase de Redes Generativas Antagónicas (GANs). Las GANs, introducidas por Ian Goodfellow y sus colegas en 2014, están diseñadas para generar nuevas instancias sintéticas de datos que puedan pasar por datos reales. Consisten en dos partes: un 'generador' que produce los datos sintéticos y un 'discriminador' que intenta diferenciar entre los datos generados y los datos reales.

En el contexto de BigGAN, el modelo está diseñado para producir imágenes de alta resolución y altamente realistas que a menudo pueden pasar como reales para el ojo inexperto. El término "big" se refiere a la naturaleza a gran escala del modelo, que emplea tamaños de lote grandes y conjuntos de datos de entrenamiento extensivos para crear estas imágenes de alta calidad.

El modelo BigGAN es una evolución en el campo de las GANs, con sus predecesores que incluyen el modelo GAN original, DCGAN, WGAN y otros. Cada evolución generalmente apunta a resolver algunos de los problemas enfrentados por los modelos anteriores o a mejorar la calidad de los datos generados. En el caso de BigGAN, el enfoque está en mejorar la resolución y el realismo de las imágenes generadas.

El uso de BigGAN y modelos similares se extiende más allá de solo generar imágenes de aspecto realista. Se utilizan en una amplia variedad de aplicaciones, incluyendo la mejora de imágenes, la transferencia de estilo, la traducción de imagen a imagen y más. Al mejorar continuamente la calidad y versatilidad de estos modelos, los investigadores están ampliando los límites de lo que es posible en el campo de la modelación generativa.

3. SRGAN (Super-Resolution GAN):

SRGAN, abreviatura de Super-Resolution Generative Adversarial Network, es una variante particular de las Redes Generativas Antagónicas (GANs) diseñadas específicamente para tareas de super-resolución de imágenes. Este tipo de GAN se utiliza principalmente para mejorar la resolución de imágenes de baja resolución, asegurando que las imágenes resultantes de alta resolución mantengan una alta calidad visual.

El término "super-resolución" se refiere al proceso de aumentar la resolución de una imagen, video u otro tipo de imagen. En el contexto de SRGAN, esto significa transformar una imagen de baja resolución en una versión de alta resolución que tenga más detalles y sea visualmente más atractiva.

La estructura básica de SRGAN, como otras GANs, consta de dos componentes principales: una red generadora y una red discriminadora. La red generadora tiene la tarea de tomar una imagen de baja resolución y generar una versión de alta resolución de la misma. La red discriminadora, por otro lado, tiene la tarea de determinar si una imagen de alta resolución dada proviene del conjunto de datos de imágenes de alta resolución reales o fue creada por el generador.

Una de las características clave de SRGAN que la distingue de otros métodos de super-resolución es su capacidad para recuperar detalles más finos en la imagen aumentada. Los métodos tradicionales a menudo producen imágenes de alta resolución que son más borrosas y carecen de algunos de los detalles texturales presentes en la imagen original. SRGAN supera esta limitación utilizando una función de pérdida perceptual que anima al generador a crear imágenes que no solo tengan los valores de píxeles correctos, sino que también tengan características de alto nivel que coincidan con las de la imagen original de alta resolución.

Como resultado de estas capacidades, SRGAN ha encontrado una amplia aplicación en campos donde la resolución de imagen de alta calidad es esencial. Estos incluyen imágenes médicas (por ejemplo, mejorando escaneos de MRI), imágenes satelitales y aéreas, gráficos de videojuegos y transmisión de video, entre otros.

SRGAN representa un avance importante en el campo de la super-resolución de imágenes, proporcionando una herramienta poderosa para mejorar la calidad de imágenes de baja resolución.

4. Conditional GAN (cGAN):

Las Redes Generativas Antagónicas Condicionales (cGANs) son un tipo de GAN que incluye información auxiliar tanto para las redes generadora como discriminadora. Esta información adicional a menudo viene en forma de etiquetas, lo que permite que el proceso de generación de datos tenga en cuenta condiciones o características específicas.

En una GAN estándar, la red generadora toma un vector de ruido aleatorio como entrada y produce una instancia de datos sintéticos (por ejemplo, una imagen). La red discriminadora luego trata de clasificar si esta instancia de datos es real (de la distribución de datos verdadera) o falsa (generada por el generador). Las dos redes se entrenan juntas, con el generador tratando de engañar al discriminador y el discriminador tratando de clasificar correctamente las instancias reales frente a las falsas.

En una cGAN, el generador toma dos entradas: un vector de ruido aleatorio y una etiqueta. La etiqueta proporciona información adicional sobre qué tipo de instancia de datos debe producir el generador. Por ejemplo, si las etiquetas son dígitos del 0 al 9 y las instancias de datos son imágenes de dígitos escritos a mano, el generador podría estar condicionado a producir una imagen de un dígito específico.

El discriminador en una cGAN también toma dos entradas: una instancia de datos y una etiqueta. Tiene que determinar no solo si la instancia de datos es real o falsa, sino también si coincide con la etiqueta dada.

La ventaja de las cGANs es que pueden generar datos bajo condiciones específicas o con ciertas características, lo que puede ser muy útil en muchas aplicaciones. Por ejemplo, en la generación de imágenes, una cGAN podría generar imágenes de gatos, perros u otros objetos específicos según la etiqueta dada. En la mejora de datos, una cGAN podría generar datos adicionales para una clase específica que está subrepresentada en los datos de entrenamiento.

La implementación de una cGAN implica modificaciones tanto en la red generadora como en la discriminadora para aceptar y procesar la información de etiqueta adicional. Además, el procedimiento de entrenamiento necesita ajustarse para tener en cuenta la naturaleza condicional del proceso de generación de datos.

En general, las cGANs representan una extensión importante del marco estándar de GAN, permitiendo tareas de generación de datos más controladas y específicas.

Ejemplo: Implementación de una Conditional GAN

import tensorflow as tf
from tensorflow.keras.layers import Input, Embedding, multiply

# Conditional GAN Generator
def build_cgan_generator(latent_dim, num_classes):
    noise = Input(shape=(latent_dim,))
    label = Input(shape=(1,), dtype='int32')
    label_embedding = Flatten()(Embedding(num_classes, latent_dim)(label))
    model_input = multiply([noise, label_embedding])

    x = Dense(256 * 7 * 7, activation="relu")(model_input)
    x = Reshape((7, 7, 256))(x)
    x = BatchNormalization()(x)
    x = Conv2DTranspose(128, kernel_size=4, strides=2, padding='same')(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2DTranspose(64, kernel_size=4, strides=2, padding='same')(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=0.2)(x)
    output_img = Conv2DTranspose(1, kernel_size=4, strides=1, padding='same', activation='tanh')(x)

    return Model([noise, label], output_img)

# Conditional GAN Discriminator
def build_cgan_discriminator(img_shape, num_classes):
    img = Input(shape=img_shape)
    label = Input(shape=(1,), dtype='int32')
    label_embedding = Flatten()(Embedding(num_classes, np.prod(img_shape))(label))
    label_embedding = Reshape(img_shape)(label_embedding)
    model_input = multiply([img, label_embedding])

    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(model_input)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Flatten()(x)
    validity = Dense(1, activation='sigmoid')(x)

    return Model([img, label], validity)

# Build and compile the Conditional GAN
latent_dim = 100
num_classes = 10
img_shape = (28, 28, 1)

generator = build_cgan_generator(latent_dim, num_classes)
discriminator = build_cgan_discriminator(img_shape, num_classes)
discriminator.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
noise = Input(shape=(latent_dim,))
label = Input(shape=(1,), dtype='int32')
generated_img = generator([noise, label])
validity = discriminator([generated_img, label])
cgan = Model([noise, label], validity)
cgan.compile(optimizer='adam', loss='binary_crossentropy')

# Summary of the models
generator.summary()
discriminator.summary()
cgan.summary()

En este ejemplo:

El primer paso en el código es importar las bibliotecas necesarias. Se requiere la biblioteca TensorFlow para el aprendizaje automático, con su API de Keras utilizada para crear los modelos de redes neuronales. Las funciones Input, Embedding, Dense y multiply, entre otras, se importan del módulo de capas de Keras.

La siguiente parte del script define dos funciones, build_cgan_generator y build_cgan_discriminator. Estas dos funciones se utilizan para construir los modelos generador y discriminador del CGAN, respectivamente.

La función build_cgan_generator toma como entradas la dimensión latente (el tamaño del vector de ruido aleatorio) y el número de clases (el número de etiquetas). Dentro de esta función, se construye el modelo del generador. El generador toma un vector de ruido aleatorio y una etiqueta como entradas. El vector de ruido es un punto en el espacio latente, y la etiqueta es un vector codificado en one-hot que representa la clase deseada de la imagen generada. El ruido y la etiqueta se combinan y se pasan a través de una serie de capas Dense, Reshape, BatchNormalization, Conv2DTranspose y LeakyReLU para generar la imagen de salida final.

La función build_cgan_discriminator también toma como entradas la forma de la imagen y el número de clases. Dentro de esta función, se construye el modelo del discriminador. El discriminador toma una imagen y una etiqueta como entradas. La imagen es la generada (o real), y la etiqueta es la etiqueta verdadera de la imagen. La imagen y la etiqueta se combinan y se pasan a través de una serie de capas Conv2D, LeakyReLU, Flatten y Dense para producir un único valor que representa si la imagen es real o falsa.

Después de definir las funciones del generador y el discriminador, el script las utiliza para crear instancias de estos modelos. Luego, el modelo del discriminador se compila utilizando el optimizador Adam y la pérdida de entropía cruzada binaria como función de pérdida. También se especifica la métrica de precisión para medir el rendimiento del discriminador.

A continuación, el script establece el atributo trainable del discriminador a False. Esto se hace porque, al entrenar el CGAN, se desea entrenar el generador para engañar al discriminador, pero no entrenar al discriminador para mejorar su capacidad de detectar al generador. Por lo tanto, los pesos del discriminador se congelan durante el entrenamiento del CGAN.

Luego, se construye y compila el modelo CGAN. El modelo CGAN consta del generador seguido del discriminador. Un vector de ruido y una etiqueta se pasan al generador para producir una imagen generada. Esta imagen generada y la etiqueta se alimentan luego al discriminador para producir la validez de la imagen.

Finalmente, el script imprime un resumen de cada modelo. Esto proporciona una visión general de los modelos generador, discriminador y CGAN, incluyendo las capas en cada modelo, las formas de salida de estas capas y el número de parámetros en cada capa.

Este ejemplo proporciona una guía paso a paso sobre cómo implementar un CGAN en TensorFlow. Al proporcionar etiquetas como entrada adicional tanto al generador como al discriminador, un CGAN permite la generación de datos con características específicas deseadas.

3.5 Variaciones de las GANs

Desde la introducción de las innovadoras Redes Generativas Adversariales (GANs), se han desarrollado meticulosamente una gran cantidad de modificaciones y mejoras con el objetivo de abordar desafíos específicos que se encontraron y de expandir significativamente las capacidades del marco original de las GANs.

Estas variaciones son numerosas y diversas, incluyendo, pero no limitándose a, las GANs de Convolución Profunda (DCGANs), las innovadoras CycleGANs y las altamente versátiles StyleGANs, entre muchas otras.

Cada una de estas variaciones únicas introduce su propio conjunto de cambios arquitectónicos y técnicas de entrenamiento novedosas. Estas están cuidadosamente adaptadas para atender aplicaciones específicas o para mejorar el rendimiento. En esta sección en particular, profundizaremos en algunas de las variaciones de GANs más prominentes y reconocidas que han revolucionado el campo. Al hacerlo, proporcionaremos explicaciones detalladas que sean fáciles de entender, junto con código de ejemplo para ilustrar vívidamente su implementación práctica y uso en escenarios del mundo real.

3.5.1 GANs de Convolución Profunda (DCGANs)

Las GANs de Convolución Profunda (DCGANs) fueron introducidas por Radford et al. en 2015, y representan una mejora significativa sobre la arquitectura original de las GANs. Estas DCGANs aprovechan las capas convolucionales tanto en las redes del generador como del discriminador, lo cual es un cambio respecto al uso de capas totalmente conectadas. Esta adaptación es particularmente beneficiosa para manejar datos de imagen y conduce a un entrenamiento más estable y a imágenes generadas de mejor calidad.

Características clave de las DCGANs incluyen:

  • El uso de capas convolucionales en lugar de capas totalmente conectadas.
  • Sustitución de capas de pooling con convoluciones estratificadas en el discriminador y convoluciones transpuestas en el generador.
  • El uso de normalización por lotes (batch normalization) para estabilizar el entrenamiento.
  • El empleo de diferentes funciones de activación en el generador y el discriminador: activación ReLU en el generador y LeakyReLU en el discriminador.

Estas características contribuyen al rendimiento y la estabilidad mejorados de las DCGANs en comparación con las GANs originales. Al utilizar capas convolucionales, las DCGANs pueden aprender jerarquías espaciales de características de manera no supervisada, lo cual es altamente beneficioso para tareas que involucran imágenes.

En general, las DCGANs representan un hito significativo en el desarrollo de las GANs y han allanado el camino para numerosas variaciones y mejoras subsiguientes en la arquitectura de las GANs.

Ejemplo: Implementación de DCGAN con TensorFlow/Keras

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, LeakyReLU, BatchNormalization, Reshape, Dense, Flatten
from tensorflow.keras.models import Sequential
import numpy as np
import matplotlib.pyplot as plt

# DCGAN Generator
def build_dcgan_generator(latent_dim):
    model = Sequential([
        Dense(256 * 7 * 7, activation="relu", input_dim=latent_dim),
        Reshape((7, 7, 256)),
        BatchNormalization(),
        Conv2DTranspose(128, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2DTranspose(64, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2DTranspose(1, kernel_size=4, strides=1, padding='same', activation='tanh')
    ])
    return model

# DCGAN Discriminator
def build_dcgan_discriminator(img_shape):
    model = Sequential([
        Conv2D(64, kernel_size=4, strides=2, padding='same', input_shape=img_shape),
        LeakyReLU(alpha=0.2),
        Conv2D(128, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Conv2D(256, kernel_size=4, strides=2, padding='same'),
        BatchNormalization(),
        LeakyReLU(alpha=0.2),
        Flatten(),
        Dense(1, activation='sigmoid')
    ])
    return model

# Training the DCGAN
latent_dim = 100
img_shape = (28, 28, 1)

generator = build_dcgan_generator(latent_dim)
discriminator = build_dcgan_discriminator(img_shape)
discriminator.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
gan_input = tf.keras.Input(shape=(latent_dim,))
generated_img = generator(gan_input)
validity = discriminator(generated_img)
dcgan = tf.keras.Model(gan_input, validity)
dcgan.compile(optimizer='adam', loss='binary_crossentropy')

# Load and preprocess the MNIST dataset
(x_train, _), (_, _) = tf.keras.datasets.mnist.load_data()
x_train = (x_train.astype(np.float32) - 127.5) / 127.5  # Normalize to [-1, 1]
x_train = np.expand_dims(x_train, axis=-1)

# Training parameters
epochs = 10000
batch_size = 64
sample_interval = 1000

for epoch in range(epochs):
    # Train the discriminator
    idx = np.random.randint(0, x_train.shape[0], batch_size)
    real_images = x_train[idx]
    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    fake_images = generator.predict(noise)
    d_loss_real = discriminator.train_on_batch(real_images, np.ones((batch_size, 1)))
    d_loss_fake = discriminator.train_on_batch(fake_images, np.zeros((batch_size, 1)))
    d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)

    # Train the generator
    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    g_loss = dcgan.train_on_batch(noise, np.ones((batch_size, 1)))

    # Print progress
    if epoch % sample_interval == 0:
        print(f"{epoch} [D loss: {d_loss[0]}, acc.: {d_loss[1] * 100}%] [G loss: {g_loss}]")

        # Generate and save images
        noise = np.random.normal(0, 1, (10, latent_dim))
        generated_images = generator.predict(noise)
        fig, axs = plt.subplots(1, 10, figsize=(20, 2))
        for i, img in enumerate(generated_images):
            axs[i].imshow(img.squeeze(), cmap='gray')
            axs[i].axis('off')
        plt.show()

En este ejemplo:

El script comienza importando las bibliotecas necesarias, que incluyen TensorFlow, Keras, NumPy y Matplotlib. TensorFlow es una biblioteca de código abierto popular para el aprendizaje automático e inteligencia artificial, mientras que Keras es una API de redes neuronales de alto nivel escrita en Python y capaz de ejecutarse sobre TensorFlow. NumPy se usa para cálculos numéricos y Matplotlib se usa para generar gráficos.

El script luego define dos funciones, build_dcgan_generator y build_dcgan_discriminator, que crean los modelos del generador y del discriminador respectivamente. El modelo del generador toma una dimensión latente como entrada y produce una imagen, mientras que el discriminador toma una imagen como entrada y produce una probabilidad que indica si la imagen es real o falsa. El modelo del generador se construye usando una secuencia de capas densas, de reconfiguración, de normalización por lotes y de convolución transpuesta, mientras que el modelo del discriminador usa una secuencia de capas de convolución, de normalización por lotes, LeakyReLU, de aplanamiento y densas.

Después de definir los modelos, el script crea instancias del generador y del discriminador y compila el modelo del discriminador. El modelo del discriminador se compila con el optimizador Adam y la pérdida de entropía cruzada binaria. Durante el entrenamiento de la GAN, los parámetros del modelo del discriminador se configuran como no entrenables.

El script luego define el modelo de GAN, que toma un vector latente como entrada y da salida a la validez de la imagen generada según lo determine el discriminador. El modelo de GAN se compila con el optimizador Adam y la pérdida de entropía cruzada binaria.

A continuación, el script carga el conjunto de datos MNIST, que es una gran base de datos de dígitos escritos a mano que se utiliza comúnmente para entrenar varios sistemas de procesamiento de imágenes. Después de cargar el conjunto de datos, el script normaliza los datos de la imagen para que estén entre -1 y 1 y expande la dimensión del conjunto de datos.

El script luego establece los parámetros de entrenamiento, que incluyen el número de épocas, el tamaño del lote y el intervalo de muestreo. También inicializa matrices para almacenar las pérdidas y precisiones del discriminador y la pérdida del generador.

El script luego entra en el bucle de entrenamiento. Para cada época, el script selecciona un lote aleatorio de imágenes del conjunto de datos y genera un lote correspondiente de vectores de ruido. Utiliza el modelo del generador para generar un lote de imágenes falsas a partir de los vectores de ruido. El modelo del discriminador se entrena luego en las imágenes reales y falsas. El modelo del generador se entrena luego para generar imágenes que el modelo del discriminador considera reales.

Cada 1000 épocas, el script imprime el número de época, la pérdida y precisión del discriminador en las imágenes reales y falsas, y la pérdida del generador. También genera un lote de imágenes del modelo del generador usando un lote fijo de vectores de ruido y traza estas imágenes en una cuadrícula de 1 por 10.

3.5.2 CycleGAN

CycleGAN, introducida por Zhu et al. en 2017, es un tipo específico de Red Generativa Adversarial (GAN) que se centra en la traducción de imágenes a imágenes. Su característica distintiva principal es su capacidad para transformar imágenes de un dominio a otro sin necesidad de ejemplos de entrenamiento pareados. Este es un avance significativo sobre los modelos anteriores, ya que elimina la necesidad de un conjunto de datos que contenga pares de imágenes perfectamente emparejadas de los dominios fuente y destino.

Por ejemplo, si deseas convertir imágenes de caballos en imágenes de cebras, un modelo tradicional de traducción de imágenes a imágenes requeriría un conjunto de datos de imágenes de caballos y cebras emparejadas. CycleGAN, sin embargo, puede aprender esta transformación sin tal conjunto de datos. Esto es particularmente útil para tareas donde es difícil o imposible recopilar datos de entrenamiento pareados.

La arquitectura de CycleGAN incluye dos redes generadoras y dos redes discriminadoras. Las redes generadoras son responsables de la transformación de las imágenes entre los dos dominios. Un generador transforma del dominio fuente al dominio destino, mientras que el otro transforma en la dirección inversa. Las redes discriminadoras, por otro lado, se utilizan para imponer el realismo de las imágenes transformadas.

Además de las funciones de pérdida tradicionales de GAN, CycleGAN también introduce una función de pérdida de consistencia cíclica. Esta función asegura que una imagen que se transforma de un dominio a otro y luego de regreso al dominio original será la misma que la imagen original. Este proceso cíclico ayuda al modelo a aprender mapeos precisos y coherentes entre los dos dominios.

En general, CycleGAN ha sido fundamental en el campo de la traducción de imágenes y la transferencia de estilo, permitiendo transformaciones que anteriormente eran desafiantes o imposibles con GANs tradicionales. Se ha utilizado en una amplia variedad de aplicaciones, desde convertir pinturas en fotografías, cambiar estaciones en imágenes de paisajes, e incluso traducir imágenes de Google Maps a imágenes satelitales.

Resumen de Características Clave y Funcionalidades de CycleGAN:

  • CycleGAN hace uso de dos modelos generadores separados, cada uno designado para un dominio específico, así como dos modelos discriminadores individuales. Este enfoque, que implica vías duales, permite que el modelo aprenda y mapee las características de un dominio a otro.
  • Una característica única y crítica de CycleGAN es la introducción de lo que se conoce como pérdida de consistencia cíclica. Este mecanismo innovador impone el principio de que cuando una imagen se traduce de su dominio original al dominio objetivo, y luego se traduce de nuevo al dominio original, el modelo debe producir una imagen que refleje la imagen de entrada original. Este es un aspecto fundamental del diseño del modelo, ya que ayuda a asegurar la precisión de las traducciones entre dominios.

Ejemplo: Implementación de CycleGAN con TensorFlow/Keras

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, Conv2DTranspose, LeakyReLU, BatchNormalization, Input
from tensorflow.keras.models import Model
import numpy as np
import matplotlib.pyplot as plt

# CycleGAN Generator
def build_cyclegan_generator(img_shape):
    input_img = Input(shape=img_shape)
    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(input_img)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    x = Conv2DTranspose(64, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = BatchNormalization()(x)
    output_img = Conv2DTranspose(3, kernel_size=4, strides=2, padding='same', activation='tanh')(x)
    return Model(input_img, output_img)

# CycleGAN Discriminator
def build_cyclegan_discriminator(img_shape):
    input_img = Input(shape=img_shape)
    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(input_img)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Flatten()(x)
    validity = Dense(1, activation='sigmoid')(x)
    return Model(input_img, validity)

# Build CycleGAN models
img_shape = (128, 128, 3)
G_AB = build_cyclegan_generator(img_shape)
G_BA = build_cyclegan_generator(img_shape)
D_A = build_cyclegan_discriminator(img_shape)
D_B = build_cyclegan_discriminator(img_shape)

D_A.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
D_B.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

# CycleGAN loss
def cycle_loss(y_true, y_pred):
    return tf.reduce_mean(tf.abs(y_true - y_pred))

# Full CycleGAN model
img_A = Input(shape=img_shape)
img_B = Input(shape=img_shape)

fake_B = G_AB(img_A)
reconstr_A = G_BA(fake_B)
fake_A = G_BA(img_B)
reconstr_B = G_AB(fake_A)

D_A.trainable = False
D_B.trainable = False

valid_A = D_A(fake_A)
valid_B = D_B(fake_B)

cycle_gan = Model(inputs=[img_A, img_B], outputs=[valid_A, valid_B, reconstr_A, reconstr_B])
cycle_gan.compile(optimizer='adam', loss=['binary_crossentropy', 'binary_crossentropy', cycle_loss, cycle_loss])

# Summary of the models
G_AB.summary()
G_BA.summary()
D_A.summary()
D_B.summary()
cycle_gan.summary()

En este ejemplo:

La primera parte del script importa las bibliotecas necesarias, que incluyen TensorFlow para el aprendizaje automático, Keras para la API de redes neuronales, numpy para cálculos numéricos y matplotlib para generar gráficos.

El script luego define dos funciones, build_cyclegan_generator y build_cyclegan_discriminator. Estas dos funciones se utilizan para construir los modelos generador y discriminador de la CycleGAN.

El modelo del generador está diseñado para transformar una imagen de un dominio a otro. El modelo comienza con una imagen de entrada y aplica una serie de capas convolucionales, de activación LeakyReLU y de normalización por lotes para procesar la imagen. La imagen procesada se pasa luego a través de un conjunto de capas de convolución transpuesta para generar la imagen de salida.

El modelo del discriminador es responsable de determinar si una imagen dada es real (del conjunto de datos) o falsa (generada por el generador). El modelo toma una imagen como entrada y aplica una serie de capas convolucionales y de activación LeakyReLU. La imagen procesada se aplana y se pasa a través de una capa densa para dar salida a un único valor que representa la probabilidad de que la imagen sea real.

Después de definir los modelos generador y discriminador, el script crea instancias de estos modelos para dos dominios de imagen, referidos como A y B. El script también compila los modelos discriminadores, especificando 'adam' como el optimizador, 'binary_crossentropy' como la función de pérdida y 'accuracy' como la métrica.

El script luego define una función de pérdida especial para la CycleGAN, llamada pérdida cíclica. Esta función mide la diferencia absoluta entre la imagen original y la imagen reconstruida (es decir, una imagen que ha sido transformada de un dominio a otro y luego de vuelta al dominio original). La pérdida cíclica anima a la CycleGAN a aprender mapeos capaces de reconstruir la imagen original con precisión.

A continuación, el script construye el modelo completo de CycleGAN. Este modelo toma dos imágenes como entrada (una del dominio A y una del dominio B), transforma cada imagen al otro dominio utilizando los generadores, y luego de vuelta al dominio original. El modelo también pasa las imágenes transformadas a través de los discriminadores para determinar su realismo. Las salidas del modelo incluyen la validez de las imágenes transformadas y las imágenes reconstruidas.

El modelo de CycleGAN se compila con el optimizador 'adam' y una lista de funciones de pérdida que incluyen la entropía cruzada binaria para las salidas de validez y la pérdida cíclica para las salidas de reconstrucción. Además, para asegurar que el entrenamiento de la CycleGAN se centre en mejorar los generadores, el script establece el atributo trainable de los discriminadores en False antes de compilar el modelo de CycleGAN.

Finalmente, el script imprime un resumen de cada modelo para proporcionar una visión general de sus arquitecturas. Esto incluye las capas en cada modelo, la forma de las salidas de cada capa y el número de parámetros en cada capa.

3.5.3 StyleGAN

StyleGAN, o Style Generative Adversarial Network, es un tipo avanzado de modelo GAN introducido por Karras et al. de NVIDIA en 2019. Este modelo representa un avance significativo en el campo de los modelos generativos debido a su capacidad para generar imágenes extremadamente realistas y de alta calidad.

La principal innovación en StyleGAN reside en su arquitectura única del generador basada en estilos. Esta nueva arquitectura permite un control detallado y específico del proceso de síntesis de imágenes, separando las influencias de atributos de alto nivel y la variación estocástica en las imágenes generadas. Con esto, es posible manipular aspectos específicos de las imágenes generadas de manera independiente, lo cual no era posible con modelos GAN anteriores.

La arquitectura de StyleGAN incluye una red de mapeo y una red de síntesis. La red de mapeo toma un código latente y lo mapea a un espacio latente intermedio, que controla los estilos de varios aspectos de la imagen generada. La red de síntesis toma esta representación intermedia y genera la imagen final.

Las características clave de StyleGAN incluyen el uso de normalización adaptativa de instancias (AdaIN) para la modulación de estilos, el crecimiento progresivo tanto del generador como del discriminador para un entrenamiento estable y una calidad mejorada, y una red de mapeo con inyección de estilo para controlar los atributos de la imagen.

Una de las aplicaciones más conocidas de StyleGAN es el sitio web 'This Person Does Not Exist', donde el modelo genera rostros humanos altamente realistas de personas que no existen. Otras aplicaciones incluyen la manipulación de características específicas de una imagen, como cambiar el color del cabello o la edad de una persona, y transferir el estilo de una imagen a otra, como cambiar una foto diurna a nocturna.

En conclusión, StyleGAN representa un avance significativo en el campo de los modelos generativos, abriendo nuevas posibilidades para la síntesis, manipulación y comprensión de imágenes.

Resumen de Características Clave de StyleGAN:

  • Utiliza una arquitectura de generador basada en estilos, que proporciona un enfoque único en cómo el generador maneja y procesa los vectores de ruido. Esta arquitectura se combina con la normalización adaptativa de instancias (AdaIN), una técnica que permite la transferencia de estilo desde las imágenes de estilo a las imágenes generadas.
  • Emplea una metodología de crecimiento progresivo tanto para el generador como para el discriminador. Esto significa que la red comienza entrenando con imágenes de baja resolución y luego aumenta progresivamente la resolución añadiendo más capas. Esta estrategia mejora significativamente la estabilidad del entrenamiento y permite que la red genere imágenes de alta calidad.
  • Proporciona la capacidad de controlar atributos específicos de la imagen, como el estilo y la estructura de las imágenes generadas. Esto se logra mediante el uso de una red de mapeo y la inyección de estilo. La red de mapeo permite que el modelo aprenda representaciones más separadas, y la inyección de estilo proporciona una forma de controlar el estilo en diferentes niveles de detalle.

Ejemplo: Uso de un Modelo StyleGAN Pre-entrenado

Para usar un modelo StyleGAN pre-entrenado, podemos aprovechar bibliotecas como stylegan2-pytorch para mayor simplicidad. Aquí hay un ejemplo:

import torch
from stylegan2_pytorch import ModelLoader
import matplotlib.pyplot as plt

# Load pre-trained StyleGAN2 model
model = ModelLoader(name='ffhq', load_model=True)

# Generate random latent vectors
num_images = 5
latent_vectors = torch.randn(num_images, 512)

# Generate images using the model
generated_images = model.generate(latent_vectors)

# Plot the generated images
fig, axs = plt.subplots(1, num_images, figsize=(15, 15))
for i, img in enumerate(generated_images):
    axs[i].imshow(img.permute(1, 2, 0).cpu().numpy())
    axs[i].axis('off')

plt.show()

Este ejemplo utiliza la biblioteca stylegan2-pytorch para generar imágenes a partir de un modelo preentrenado de StyleGAN2.

Aquí tienes un desglose de los pasos:

Importar Bibliotecas:

  • torch: La biblioteca PyTorch para el aprendizaje profundo.
  • from stylegan2_pytorch import ModelLoader: Importa la clase ModelLoader de la biblioteca stylegan2-pytorch. Esta clase ayuda a cargar y gestionar los modelos StyleGAN2.
  • matplotlib.pyplot as plt: Utilizado para trazar las imágenes generadas.

Cargar el Modelo Preentrenado:

  • model = ModelLoader(name='ffhq', load_model=True): Crea una instancia de ModelLoader llamada model.
    • name='ffhq': Especifica el nombre del modelo preentrenado, probablemente "ffhq", que se refiere al conjunto de datos Flickr-Faces-HQ, comúnmente utilizado para el entrenamiento de StyleGAN2.
    • load_model=True: Instruye a ModelLoader que cargue los parámetros del modelo preentrenado.

Generar Vectores Latentes Aleatorios:

  • num_images = 5: Define el número de imágenes a generar (establecido en 5 en este ejemplo).
  • latent_vectors = torch.randn(num_images, 512): Crea un tensor aleatorio llamado latent_vectors con dimensiones (num_images, 512). Este tensor representa el ruido latente utilizado para generar imágenes. La dimensionalidad específica (512 en este caso) depende de la arquitectura del modelo preentrenado.

Generar Imágenes:

  • generated_images = model.generate(latent_vectors): Esta línea utiliza la función model.generate para generar imágenes a partir de los vectores latentes proporcionados. Las imágenes generadas se almacenan en el tensor generated_images.

Trazar las Imágenes Generadas:

  • plt.subplots(1, num_images, figsize=(15, 15)): Crea una figura de Matplotlib con una sola fila y num_images columnas para mostrar las imágenes generadas. También establece el tamaño de la figura en 15x15 para una mejor visualización.
  • El bucle itera a través de cada imagen en generated_images:
    • axs[i].imshow(...): Esta línea muestra la imagen actual en una subtrama utilizando la función imshow de Matplotlib.
      • .permute(1, 2, 0).cpu().numpy(): Esta línea reorganiza las dimensiones del tensor de imagen del formato de PyTorch (canales primero) al formato de Matplotlib (canales al final) y lo convierte en un array de NumPy para la compatibilidad con imshow.
    • axs[i].axis('off'): Apaga las etiquetas de los ejes para una presentación más limpia.
  • plt.show(): Muestra las imágenes generadas en la pantalla.

En resumen, este ejemplo demuestra cómo generar imágenes con un modelo StyleGAN2 proporcionando ruido latente aleatorio como entrada y visualizando los resultados generados.

3.5.4 Otras Variaciones de GAN

1. Wasserstein GAN (WGAN):

Wasserstein GAN, a menudo abreviado como WGAN, es una variante de las Redes Generativas Antagónicas (GANs). Introducidas por Martin Arjovsky, Soumith Chintala y Léon Bottou en 2017, las WGANs representan un avance significativo en el campo de las GANs, abordando principalmente dos problemas críticos que a menudo afectan a las GANs tradicionales: la inestabilidad en el entrenamiento y el colapso de modos.

El nombre "Wasserstein" proviene del tipo de función de pérdida utilizada en estas GANs, conocida como la distancia Wasserstein o la distancia del "trasportador de tierra". Esta es una medida de la distancia entre dos distribuciones de probabilidad y se usa en lugar de las funciones de pérdida tradicionales de GAN, como la divergencia de Jensen-Shannon. Este cambio en la función de pérdida conduce a una superficie de pérdida más suave y significativa, lo que hace que el proceso de entrenamiento sea más estable.

Las WGANs también introducen una característica única conocida como recorte de pesos, que ayuda a garantizar que la función del discriminador (también conocida como el crítico en la terminología de WGAN) se encuentre dentro de un espacio compacto, facilitando el cálculo de la distancia Wasserstein.

La innovación de las WGANs ha tenido un impacto significativo en la mejora de la calidad y diversidad de las muestras generadas, así como en la estabilidad del proceso de entrenamiento de las GAN. Ha permitido procesos de entrenamiento más confiables, abriendo así nuevas posibilidades para la aplicación de las GAN en varios dominios.

Sin embargo, vale la pena señalar que, aunque las WGANs abordan algunos problemas en las GANs estándar, también tienen su propio conjunto de desafíos y limitaciones, como problemas con el recorte de pesos que conducen a comportamientos de función no deseados. Esto ha llevado a desarrollos y mejoras adicionales en el campo de las GAN, como la introducción de WGAN-GP (Wasserstein GAN con Penalización de Gradiente) que reemplaza el recorte de pesos con una penalización de gradiente para un entrenamiento más estable y eficiente.

2. BigGAN:

BigGAN, abreviatura de Big Generative Adversarial Network, es un tipo de modelo de aprendizaje automático que pertenece a la clase de Redes Generativas Antagónicas (GANs). Las GANs, introducidas por Ian Goodfellow y sus colegas en 2014, están diseñadas para generar nuevas instancias sintéticas de datos que puedan pasar por datos reales. Consisten en dos partes: un 'generador' que produce los datos sintéticos y un 'discriminador' que intenta diferenciar entre los datos generados y los datos reales.

En el contexto de BigGAN, el modelo está diseñado para producir imágenes de alta resolución y altamente realistas que a menudo pueden pasar como reales para el ojo inexperto. El término "big" se refiere a la naturaleza a gran escala del modelo, que emplea tamaños de lote grandes y conjuntos de datos de entrenamiento extensivos para crear estas imágenes de alta calidad.

El modelo BigGAN es una evolución en el campo de las GANs, con sus predecesores que incluyen el modelo GAN original, DCGAN, WGAN y otros. Cada evolución generalmente apunta a resolver algunos de los problemas enfrentados por los modelos anteriores o a mejorar la calidad de los datos generados. En el caso de BigGAN, el enfoque está en mejorar la resolución y el realismo de las imágenes generadas.

El uso de BigGAN y modelos similares se extiende más allá de solo generar imágenes de aspecto realista. Se utilizan en una amplia variedad de aplicaciones, incluyendo la mejora de imágenes, la transferencia de estilo, la traducción de imagen a imagen y más. Al mejorar continuamente la calidad y versatilidad de estos modelos, los investigadores están ampliando los límites de lo que es posible en el campo de la modelación generativa.

3. SRGAN (Super-Resolution GAN):

SRGAN, abreviatura de Super-Resolution Generative Adversarial Network, es una variante particular de las Redes Generativas Antagónicas (GANs) diseñadas específicamente para tareas de super-resolución de imágenes. Este tipo de GAN se utiliza principalmente para mejorar la resolución de imágenes de baja resolución, asegurando que las imágenes resultantes de alta resolución mantengan una alta calidad visual.

El término "super-resolución" se refiere al proceso de aumentar la resolución de una imagen, video u otro tipo de imagen. En el contexto de SRGAN, esto significa transformar una imagen de baja resolución en una versión de alta resolución que tenga más detalles y sea visualmente más atractiva.

La estructura básica de SRGAN, como otras GANs, consta de dos componentes principales: una red generadora y una red discriminadora. La red generadora tiene la tarea de tomar una imagen de baja resolución y generar una versión de alta resolución de la misma. La red discriminadora, por otro lado, tiene la tarea de determinar si una imagen de alta resolución dada proviene del conjunto de datos de imágenes de alta resolución reales o fue creada por el generador.

Una de las características clave de SRGAN que la distingue de otros métodos de super-resolución es su capacidad para recuperar detalles más finos en la imagen aumentada. Los métodos tradicionales a menudo producen imágenes de alta resolución que son más borrosas y carecen de algunos de los detalles texturales presentes en la imagen original. SRGAN supera esta limitación utilizando una función de pérdida perceptual que anima al generador a crear imágenes que no solo tengan los valores de píxeles correctos, sino que también tengan características de alto nivel que coincidan con las de la imagen original de alta resolución.

Como resultado de estas capacidades, SRGAN ha encontrado una amplia aplicación en campos donde la resolución de imagen de alta calidad es esencial. Estos incluyen imágenes médicas (por ejemplo, mejorando escaneos de MRI), imágenes satelitales y aéreas, gráficos de videojuegos y transmisión de video, entre otros.

SRGAN representa un avance importante en el campo de la super-resolución de imágenes, proporcionando una herramienta poderosa para mejorar la calidad de imágenes de baja resolución.

4. Conditional GAN (cGAN):

Las Redes Generativas Antagónicas Condicionales (cGANs) son un tipo de GAN que incluye información auxiliar tanto para las redes generadora como discriminadora. Esta información adicional a menudo viene en forma de etiquetas, lo que permite que el proceso de generación de datos tenga en cuenta condiciones o características específicas.

En una GAN estándar, la red generadora toma un vector de ruido aleatorio como entrada y produce una instancia de datos sintéticos (por ejemplo, una imagen). La red discriminadora luego trata de clasificar si esta instancia de datos es real (de la distribución de datos verdadera) o falsa (generada por el generador). Las dos redes se entrenan juntas, con el generador tratando de engañar al discriminador y el discriminador tratando de clasificar correctamente las instancias reales frente a las falsas.

En una cGAN, el generador toma dos entradas: un vector de ruido aleatorio y una etiqueta. La etiqueta proporciona información adicional sobre qué tipo de instancia de datos debe producir el generador. Por ejemplo, si las etiquetas son dígitos del 0 al 9 y las instancias de datos son imágenes de dígitos escritos a mano, el generador podría estar condicionado a producir una imagen de un dígito específico.

El discriminador en una cGAN también toma dos entradas: una instancia de datos y una etiqueta. Tiene que determinar no solo si la instancia de datos es real o falsa, sino también si coincide con la etiqueta dada.

La ventaja de las cGANs es que pueden generar datos bajo condiciones específicas o con ciertas características, lo que puede ser muy útil en muchas aplicaciones. Por ejemplo, en la generación de imágenes, una cGAN podría generar imágenes de gatos, perros u otros objetos específicos según la etiqueta dada. En la mejora de datos, una cGAN podría generar datos adicionales para una clase específica que está subrepresentada en los datos de entrenamiento.

La implementación de una cGAN implica modificaciones tanto en la red generadora como en la discriminadora para aceptar y procesar la información de etiqueta adicional. Además, el procedimiento de entrenamiento necesita ajustarse para tener en cuenta la naturaleza condicional del proceso de generación de datos.

En general, las cGANs representan una extensión importante del marco estándar de GAN, permitiendo tareas de generación de datos más controladas y específicas.

Ejemplo: Implementación de una Conditional GAN

import tensorflow as tf
from tensorflow.keras.layers import Input, Embedding, multiply

# Conditional GAN Generator
def build_cgan_generator(latent_dim, num_classes):
    noise = Input(shape=(latent_dim,))
    label = Input(shape=(1,), dtype='int32')
    label_embedding = Flatten()(Embedding(num_classes, latent_dim)(label))
    model_input = multiply([noise, label_embedding])

    x = Dense(256 * 7 * 7, activation="relu")(model_input)
    x = Reshape((7, 7, 256))(x)
    x = BatchNormalization()(x)
    x = Conv2DTranspose(128, kernel_size=4, strides=2, padding='same')(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2DTranspose(64, kernel_size=4, strides=2, padding='same')(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=0.2)(x)
    output_img = Conv2DTranspose(1, kernel_size=4, strides=1, padding='same', activation='tanh')(x)

    return Model([noise, label], output_img)

# Conditional GAN Discriminator
def build_cgan_discriminator(img_shape, num_classes):
    img = Input(shape=img_shape)
    label = Input(shape=(1,), dtype='int32')
    label_embedding = Flatten()(Embedding(num_classes, np.prod(img_shape))(label))
    label_embedding = Reshape(img_shape)(label_embedding)
    model_input = multiply([img, label_embedding])

    x = Conv2D(64, kernel_size=4, strides=2, padding='same')(model_input)
    x = LeakyReLU(alpha=0.2)(x)
    x = Conv2D(128, kernel_size=4, strides=2, padding='same')(x)
    x = LeakyReLU(alpha=0.2)(x)
    x = Flatten()(x)
    validity = Dense(1, activation='sigmoid')(x)

    return Model([img, label], validity)

# Build and compile the Conditional GAN
latent_dim = 100
num_classes = 10
img_shape = (28, 28, 1)

generator = build_cgan_generator(latent_dim, num_classes)
discriminator = build_cgan_discriminator(img_shape, num_classes)
discriminator.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
noise = Input(shape=(latent_dim,))
label = Input(shape=(1,), dtype='int32')
generated_img = generator([noise, label])
validity = discriminator([generated_img, label])
cgan = Model([noise, label], validity)
cgan.compile(optimizer='adam', loss='binary_crossentropy')

# Summary of the models
generator.summary()
discriminator.summary()
cgan.summary()

En este ejemplo:

El primer paso en el código es importar las bibliotecas necesarias. Se requiere la biblioteca TensorFlow para el aprendizaje automático, con su API de Keras utilizada para crear los modelos de redes neuronales. Las funciones Input, Embedding, Dense y multiply, entre otras, se importan del módulo de capas de Keras.

La siguiente parte del script define dos funciones, build_cgan_generator y build_cgan_discriminator. Estas dos funciones se utilizan para construir los modelos generador y discriminador del CGAN, respectivamente.

La función build_cgan_generator toma como entradas la dimensión latente (el tamaño del vector de ruido aleatorio) y el número de clases (el número de etiquetas). Dentro de esta función, se construye el modelo del generador. El generador toma un vector de ruido aleatorio y una etiqueta como entradas. El vector de ruido es un punto en el espacio latente, y la etiqueta es un vector codificado en one-hot que representa la clase deseada de la imagen generada. El ruido y la etiqueta se combinan y se pasan a través de una serie de capas Dense, Reshape, BatchNormalization, Conv2DTranspose y LeakyReLU para generar la imagen de salida final.

La función build_cgan_discriminator también toma como entradas la forma de la imagen y el número de clases. Dentro de esta función, se construye el modelo del discriminador. El discriminador toma una imagen y una etiqueta como entradas. La imagen es la generada (o real), y la etiqueta es la etiqueta verdadera de la imagen. La imagen y la etiqueta se combinan y se pasan a través de una serie de capas Conv2D, LeakyReLU, Flatten y Dense para producir un único valor que representa si la imagen es real o falsa.

Después de definir las funciones del generador y el discriminador, el script las utiliza para crear instancias de estos modelos. Luego, el modelo del discriminador se compila utilizando el optimizador Adam y la pérdida de entropía cruzada binaria como función de pérdida. También se especifica la métrica de precisión para medir el rendimiento del discriminador.

A continuación, el script establece el atributo trainable del discriminador a False. Esto se hace porque, al entrenar el CGAN, se desea entrenar el generador para engañar al discriminador, pero no entrenar al discriminador para mejorar su capacidad de detectar al generador. Por lo tanto, los pesos del discriminador se congelan durante el entrenamiento del CGAN.

Luego, se construye y compila el modelo CGAN. El modelo CGAN consta del generador seguido del discriminador. Un vector de ruido y una etiqueta se pasan al generador para producir una imagen generada. Esta imagen generada y la etiqueta se alimentan luego al discriminador para producir la validez de la imagen.

Finalmente, el script imprime un resumen de cada modelo. Esto proporciona una visión general de los modelos generador, discriminador y CGAN, incluyendo las capas en cada modelo, las formas de salida de estas capas y el número de parámetros en cada capa.

Este ejemplo proporciona una guía paso a paso sobre cómo implementar un CGAN en TensorFlow. Al proporcionar etiquetas como entrada adicional tanto al generador como al discriminador, un CGAN permite la generación de datos con características específicas deseadas.