Menu iconMenu icon
Aprendizaje Profundo Generativo Edición Actualizada

Capítulo 4: Generación de Rostros de Proyectos con GANs

4.4 Generación de Nuevas Caras

Después de entrenar nuestro modelo GAN, el siguiente paso emocionante es generar nuevas caras. Esta sección te guiará a través del proceso de generar nuevas imágenes utilizando el modelo generador entrenado. Cubriremos cómo generar imágenes a partir de ruido aleatorio, cómo guardar estas imágenes y cómo ajustar el generador para mejorar la calidad de las caras generadas.

4.4.1 Generación de Imágenes a partir de Ruido Aleatorio

El modelo generador, una vez entrenado, puede tomar un vector de ruido aleatorio como entrada y transformarlo en una imagen facial realista. Este vector de ruido, a menudo llamado vector latente, se toma de una distribución normal estándar. El proceso de generar nuevas caras implica muestrear múltiples vectores latentes y pasarlos a través del generador.

Ejemplo: Código para Generar Imágenes

Aquí te mostramos cómo puedes generar y visualizar nuevas imágenes faciales utilizando el modelo generador entrenado:

import numpy as np
import matplotlib.pyplot as plt

# Function to generate and plot new faces
def generate_and_plot_faces(generator, latent_dim, n_samples=10):
    noise = np.random.normal(0, 1, (n_samples, latent_dim))
    generated_images = generator.predict(noise)
    generated_images = (generated_images * 127.5 + 127.5).astype(np.uint8)  # Rescale to [0, 255]

    plt.figure(figsize=(20, 2))
    for i in range(n_samples):
        plt.subplot(1, n_samples, i + 1)
        plt.imshow(generated_images[i])
        plt.axis('off')
    plt.show()

# Generate and plot new faces
latent_dim = 100
generate_and_plot_faces(generator, latent_dim, n_samples=10)

La función 'generate_and_plot_faces' toma un generador (presumiblemente un modelo entrenado, como una Red Generativa Adversaria), una dimensión latente dada y un número específico de muestras.

La función genera 'ruido' siguiendo una distribución normal, que luego se introduce en el modelo generador para crear las 'imágenes generadas'. Estas imágenes se reescalan de un rango [-1, 1] a [0, 255] para que coincidan con la escala RGB estándar.

Luego, las imágenes se trazan en una cuadrícula utilizando matplotlib. Cada imagen se muestra como un subgráfico en una sola fila. La variable 'latent_dim' se establece en 100 y se llama a la función para generar y trazar 10 nuevas caras.

4.4.2 Guardar Imágenes Generadas

Para guardar las imágenes generadas para su uso posterior o compartirlas, podemos utilizar bibliotecas de procesamiento de imágenes como PIL (Python Imaging Library). Esto nos permite guardar las imágenes generadas en varios formatos, como PNG o JPEG.

Ejemplo: Código para Guardar Imágenes

Aquí te mostramos cómo puedes guardar las imágenes generadas en disco:

from PIL import Image

# Function to generate and save new faces
def generate_and_save_faces(generator, latent_dim, n_samples=10, save_dir='generated_faces'):
    noise = np.random.normal(0, 1, (n_samples, latent_dim))
    generated_images = generator.predict(noise)
    generated_images = (generated_images * 127.5 + 127.5).astype(np.uint8)  # Rescale to [0, 255]

    for i in range(n_samples):
        img = Image.fromarray(generated_images[i])
        img.save(f'{save_dir}/face_{i}.png')

# Generate and save new faces
generate_and_save_faces(generator, latent_dim, n_samples=10)

La función generate_and_save_faces toma un modelo generador, un tamaño de dimensión latente, un número de muestras y un directorio para guardar las imágenes. Genera vectores de ruido aleatorios, los usa como entrada para el generador para crear nuevas imágenes, escala los valores de los píxeles de las imágenes generadas para que estén entre 0 y 255, y luego guarda las imágenes como archivos .png en el directorio especificado.

4.4.3 Ajuste Fino del Generador

Aunque nuestro generador ya puede producir resultados impresionantes, siempre hay formas de ajustar y mejorar la calidad de las imágenes generadas. El ajuste fino puede implicar la modificación de la arquitectura del modelo, los hiperparámetros o el proceso de entrenamiento. Aquí hay algunas estrategias:

  1. Ajuste de Hiperparámetros:
    • Experimenta con diferentes tasas de aprendizaje, tamaños de lote y configuraciones de optimizadores para encontrar la mejor combinación para tu conjunto de datos.
  2. Aumento de Datos:
    • Aumenta la diversidad de los datos de entrenamiento aplicando diversas técnicas de aumento como rotación, zoom y cambios de color.
  3. Mejoras Arquitectónicas:
    • Experimenta con diferentes arquitecturas de generadores y discriminadores, como agregar más capas, usar diferentes tipos de capas o ajustar los tamaños de las capas.
  4. Entrenamiento Prolongado:
    • Entrena el modelo durante más épocas o usa parada temprana con puntos de control para asegurar que se guarde el mejor modelo.
  5. Crecimiento Progresivo:
    • Comienza con una resolución más baja y aumenta gradualmente la resolución de las imágenes durante el entrenamiento. Esta técnica puede ayudar al modelo a aprender más eficazmente a cada escala.

Ejemplo: Código para Ajuste Fino

Aquí te mostramos cómo puedes ajustar la tasa de aprendizaje y volver a entrenar el modelo por épocas adicionales:

# Adjust the learning rate and recompile the models
learning_rate = 0.0002
generator_optimizer = tf.keras.optimizers.Adam(learning_rate, beta_1=0.5)
discriminator_optimizer = tf.keras.optimizers.Adam(learning_rate, beta_1=0.5)

discriminator.compile(optimizer=discriminator_optimizer, loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
gan_input = tf.keras.Input(shape=(latent_dim,))
generated_img = generator(gan_input)
gan_output = discriminator(generated_img)
gan = tf.keras.Model(gan_input, gan_output)
gan.compile(optimizer=generator_optimizer, loss='binary_crossentropy')

# Continue training with the adjusted learning rate
for epoch in range(epochs, epochs + 5000):
    idx = np.random.randint(0, train_images.shape[0], batch_size)
    real_images = train_images[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, real)
    d_loss_fake = discriminator.train_on_batch(fake_images, fake)
    d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)

    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    g_loss = gan.train_on_batch(noise, real)

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

    if epoch % 1000 == 0:
        generator.save(f'generator_epoch_{epoch}.h5')
        discriminator.save(f'discriminator_epoch_{epoch}.h5')

Comienza ajustando la tasa de aprendizaje a 0.0002 y recompilando los modelos con esta nueva tasa de aprendizaje. Luego, se establece la capacidad de entrenamiento del discriminador en False para congelar sus pesos cuando se entrene la GAN.

En el bucle de entrenamiento, se seleccionan imágenes reales del conjunto de entrenamiento y se generan imágenes falsas mediante el generador. El discriminador se entrena con estas imágenes reales y falsas. Luego, el generador se entrena para engañar al discriminador utilizando el modelo GAN.

Cada pocas épocas (definidas por 'sample_interval'), se imprimen las pérdidas del discriminador y del generador, y la precisión del discriminador. También se trazan las imágenes generadas por el generador.

Cada 1000 épocas, se guardan los modelos actuales del generador y del discriminador. Esto permite continuar el proceso de entrenamiento más tarde a partir de estos modelos o utilizar estos modelos para generar nuevos datos.

4.4.4 Evaluación de las Caras Generadas

Una vez que hayas generado caras, es importante evaluar su calidad tanto cuantitativamente como cualitativamente. La evaluación cuantitativa se puede realizar utilizando métricas como la Inception Score (IS) y la Fréchet Inception Distance (FID), como se cubrió en secciones anteriores. La evaluación cualitativa implica inspeccionar visualmente las imágenes para evaluar su realismo y diversidad.

Ejemplo: Código de Evaluación

Aquí tienes un breve resumen de cómo evaluar utilizando Inception Score y FID:

# Calculate Inception Score
is_mean, is_std = calculate_inception_score(generated_images)
print(f"Inception Score: {is_mean} ± {is_std}")

# Calculate FID Score
real_images = x_train[np.random.choice(x_train.shape[0], 1000, replace=False)]
fid_score = calculate_fid(real_images, generated_images)
print(f"FID Score: {fid_score}")

La primera parte calcula el Inception Score de las imágenes generadas, que mide tanto la calidad como la diversidad de las imágenes. La puntuación y su desviación estándar se imprimen en la consola.

La segunda parte calcula la puntuación FID entre las imágenes generadas y un conjunto de imágenes reales seleccionadas aleatoriamente del conjunto de entrenamiento. La puntuación FID mide la similitud entre los dos conjuntos de imágenes; una FID más baja indica que las distribuciones de las imágenes generadas y reales están más cerca una de la otra. La puntuación FID calculada se imprime en la consola.

Siguiendo estos pasos, podrás generar caras realistas y de alta calidad utilizando tu modelo GAN entrenado. El ajuste fino del modelo y la evaluación de las caras generadas son cruciales para lograr los mejores resultados posibles.

4.4 Generación de Nuevas Caras

Después de entrenar nuestro modelo GAN, el siguiente paso emocionante es generar nuevas caras. Esta sección te guiará a través del proceso de generar nuevas imágenes utilizando el modelo generador entrenado. Cubriremos cómo generar imágenes a partir de ruido aleatorio, cómo guardar estas imágenes y cómo ajustar el generador para mejorar la calidad de las caras generadas.

4.4.1 Generación de Imágenes a partir de Ruido Aleatorio

El modelo generador, una vez entrenado, puede tomar un vector de ruido aleatorio como entrada y transformarlo en una imagen facial realista. Este vector de ruido, a menudo llamado vector latente, se toma de una distribución normal estándar. El proceso de generar nuevas caras implica muestrear múltiples vectores latentes y pasarlos a través del generador.

Ejemplo: Código para Generar Imágenes

Aquí te mostramos cómo puedes generar y visualizar nuevas imágenes faciales utilizando el modelo generador entrenado:

import numpy as np
import matplotlib.pyplot as plt

# Function to generate and plot new faces
def generate_and_plot_faces(generator, latent_dim, n_samples=10):
    noise = np.random.normal(0, 1, (n_samples, latent_dim))
    generated_images = generator.predict(noise)
    generated_images = (generated_images * 127.5 + 127.5).astype(np.uint8)  # Rescale to [0, 255]

    plt.figure(figsize=(20, 2))
    for i in range(n_samples):
        plt.subplot(1, n_samples, i + 1)
        plt.imshow(generated_images[i])
        plt.axis('off')
    plt.show()

# Generate and plot new faces
latent_dim = 100
generate_and_plot_faces(generator, latent_dim, n_samples=10)

La función 'generate_and_plot_faces' toma un generador (presumiblemente un modelo entrenado, como una Red Generativa Adversaria), una dimensión latente dada y un número específico de muestras.

La función genera 'ruido' siguiendo una distribución normal, que luego se introduce en el modelo generador para crear las 'imágenes generadas'. Estas imágenes se reescalan de un rango [-1, 1] a [0, 255] para que coincidan con la escala RGB estándar.

Luego, las imágenes se trazan en una cuadrícula utilizando matplotlib. Cada imagen se muestra como un subgráfico en una sola fila. La variable 'latent_dim' se establece en 100 y se llama a la función para generar y trazar 10 nuevas caras.

4.4.2 Guardar Imágenes Generadas

Para guardar las imágenes generadas para su uso posterior o compartirlas, podemos utilizar bibliotecas de procesamiento de imágenes como PIL (Python Imaging Library). Esto nos permite guardar las imágenes generadas en varios formatos, como PNG o JPEG.

Ejemplo: Código para Guardar Imágenes

Aquí te mostramos cómo puedes guardar las imágenes generadas en disco:

from PIL import Image

# Function to generate and save new faces
def generate_and_save_faces(generator, latent_dim, n_samples=10, save_dir='generated_faces'):
    noise = np.random.normal(0, 1, (n_samples, latent_dim))
    generated_images = generator.predict(noise)
    generated_images = (generated_images * 127.5 + 127.5).astype(np.uint8)  # Rescale to [0, 255]

    for i in range(n_samples):
        img = Image.fromarray(generated_images[i])
        img.save(f'{save_dir}/face_{i}.png')

# Generate and save new faces
generate_and_save_faces(generator, latent_dim, n_samples=10)

La función generate_and_save_faces toma un modelo generador, un tamaño de dimensión latente, un número de muestras y un directorio para guardar las imágenes. Genera vectores de ruido aleatorios, los usa como entrada para el generador para crear nuevas imágenes, escala los valores de los píxeles de las imágenes generadas para que estén entre 0 y 255, y luego guarda las imágenes como archivos .png en el directorio especificado.

4.4.3 Ajuste Fino del Generador

Aunque nuestro generador ya puede producir resultados impresionantes, siempre hay formas de ajustar y mejorar la calidad de las imágenes generadas. El ajuste fino puede implicar la modificación de la arquitectura del modelo, los hiperparámetros o el proceso de entrenamiento. Aquí hay algunas estrategias:

  1. Ajuste de Hiperparámetros:
    • Experimenta con diferentes tasas de aprendizaje, tamaños de lote y configuraciones de optimizadores para encontrar la mejor combinación para tu conjunto de datos.
  2. Aumento de Datos:
    • Aumenta la diversidad de los datos de entrenamiento aplicando diversas técnicas de aumento como rotación, zoom y cambios de color.
  3. Mejoras Arquitectónicas:
    • Experimenta con diferentes arquitecturas de generadores y discriminadores, como agregar más capas, usar diferentes tipos de capas o ajustar los tamaños de las capas.
  4. Entrenamiento Prolongado:
    • Entrena el modelo durante más épocas o usa parada temprana con puntos de control para asegurar que se guarde el mejor modelo.
  5. Crecimiento Progresivo:
    • Comienza con una resolución más baja y aumenta gradualmente la resolución de las imágenes durante el entrenamiento. Esta técnica puede ayudar al modelo a aprender más eficazmente a cada escala.

Ejemplo: Código para Ajuste Fino

Aquí te mostramos cómo puedes ajustar la tasa de aprendizaje y volver a entrenar el modelo por épocas adicionales:

# Adjust the learning rate and recompile the models
learning_rate = 0.0002
generator_optimizer = tf.keras.optimizers.Adam(learning_rate, beta_1=0.5)
discriminator_optimizer = tf.keras.optimizers.Adam(learning_rate, beta_1=0.5)

discriminator.compile(optimizer=discriminator_optimizer, loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
gan_input = tf.keras.Input(shape=(latent_dim,))
generated_img = generator(gan_input)
gan_output = discriminator(generated_img)
gan = tf.keras.Model(gan_input, gan_output)
gan.compile(optimizer=generator_optimizer, loss='binary_crossentropy')

# Continue training with the adjusted learning rate
for epoch in range(epochs, epochs + 5000):
    idx = np.random.randint(0, train_images.shape[0], batch_size)
    real_images = train_images[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, real)
    d_loss_fake = discriminator.train_on_batch(fake_images, fake)
    d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)

    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    g_loss = gan.train_on_batch(noise, real)

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

    if epoch % 1000 == 0:
        generator.save(f'generator_epoch_{epoch}.h5')
        discriminator.save(f'discriminator_epoch_{epoch}.h5')

Comienza ajustando la tasa de aprendizaje a 0.0002 y recompilando los modelos con esta nueva tasa de aprendizaje. Luego, se establece la capacidad de entrenamiento del discriminador en False para congelar sus pesos cuando se entrene la GAN.

En el bucle de entrenamiento, se seleccionan imágenes reales del conjunto de entrenamiento y se generan imágenes falsas mediante el generador. El discriminador se entrena con estas imágenes reales y falsas. Luego, el generador se entrena para engañar al discriminador utilizando el modelo GAN.

Cada pocas épocas (definidas por 'sample_interval'), se imprimen las pérdidas del discriminador y del generador, y la precisión del discriminador. También se trazan las imágenes generadas por el generador.

Cada 1000 épocas, se guardan los modelos actuales del generador y del discriminador. Esto permite continuar el proceso de entrenamiento más tarde a partir de estos modelos o utilizar estos modelos para generar nuevos datos.

4.4.4 Evaluación de las Caras Generadas

Una vez que hayas generado caras, es importante evaluar su calidad tanto cuantitativamente como cualitativamente. La evaluación cuantitativa se puede realizar utilizando métricas como la Inception Score (IS) y la Fréchet Inception Distance (FID), como se cubrió en secciones anteriores. La evaluación cualitativa implica inspeccionar visualmente las imágenes para evaluar su realismo y diversidad.

Ejemplo: Código de Evaluación

Aquí tienes un breve resumen de cómo evaluar utilizando Inception Score y FID:

# Calculate Inception Score
is_mean, is_std = calculate_inception_score(generated_images)
print(f"Inception Score: {is_mean} ± {is_std}")

# Calculate FID Score
real_images = x_train[np.random.choice(x_train.shape[0], 1000, replace=False)]
fid_score = calculate_fid(real_images, generated_images)
print(f"FID Score: {fid_score}")

La primera parte calcula el Inception Score de las imágenes generadas, que mide tanto la calidad como la diversidad de las imágenes. La puntuación y su desviación estándar se imprimen en la consola.

La segunda parte calcula la puntuación FID entre las imágenes generadas y un conjunto de imágenes reales seleccionadas aleatoriamente del conjunto de entrenamiento. La puntuación FID mide la similitud entre los dos conjuntos de imágenes; una FID más baja indica que las distribuciones de las imágenes generadas y reales están más cerca una de la otra. La puntuación FID calculada se imprime en la consola.

Siguiendo estos pasos, podrás generar caras realistas y de alta calidad utilizando tu modelo GAN entrenado. El ajuste fino del modelo y la evaluación de las caras generadas son cruciales para lograr los mejores resultados posibles.

4.4 Generación de Nuevas Caras

Después de entrenar nuestro modelo GAN, el siguiente paso emocionante es generar nuevas caras. Esta sección te guiará a través del proceso de generar nuevas imágenes utilizando el modelo generador entrenado. Cubriremos cómo generar imágenes a partir de ruido aleatorio, cómo guardar estas imágenes y cómo ajustar el generador para mejorar la calidad de las caras generadas.

4.4.1 Generación de Imágenes a partir de Ruido Aleatorio

El modelo generador, una vez entrenado, puede tomar un vector de ruido aleatorio como entrada y transformarlo en una imagen facial realista. Este vector de ruido, a menudo llamado vector latente, se toma de una distribución normal estándar. El proceso de generar nuevas caras implica muestrear múltiples vectores latentes y pasarlos a través del generador.

Ejemplo: Código para Generar Imágenes

Aquí te mostramos cómo puedes generar y visualizar nuevas imágenes faciales utilizando el modelo generador entrenado:

import numpy as np
import matplotlib.pyplot as plt

# Function to generate and plot new faces
def generate_and_plot_faces(generator, latent_dim, n_samples=10):
    noise = np.random.normal(0, 1, (n_samples, latent_dim))
    generated_images = generator.predict(noise)
    generated_images = (generated_images * 127.5 + 127.5).astype(np.uint8)  # Rescale to [0, 255]

    plt.figure(figsize=(20, 2))
    for i in range(n_samples):
        plt.subplot(1, n_samples, i + 1)
        plt.imshow(generated_images[i])
        plt.axis('off')
    plt.show()

# Generate and plot new faces
latent_dim = 100
generate_and_plot_faces(generator, latent_dim, n_samples=10)

La función 'generate_and_plot_faces' toma un generador (presumiblemente un modelo entrenado, como una Red Generativa Adversaria), una dimensión latente dada y un número específico de muestras.

La función genera 'ruido' siguiendo una distribución normal, que luego se introduce en el modelo generador para crear las 'imágenes generadas'. Estas imágenes se reescalan de un rango [-1, 1] a [0, 255] para que coincidan con la escala RGB estándar.

Luego, las imágenes se trazan en una cuadrícula utilizando matplotlib. Cada imagen se muestra como un subgráfico en una sola fila. La variable 'latent_dim' se establece en 100 y se llama a la función para generar y trazar 10 nuevas caras.

4.4.2 Guardar Imágenes Generadas

Para guardar las imágenes generadas para su uso posterior o compartirlas, podemos utilizar bibliotecas de procesamiento de imágenes como PIL (Python Imaging Library). Esto nos permite guardar las imágenes generadas en varios formatos, como PNG o JPEG.

Ejemplo: Código para Guardar Imágenes

Aquí te mostramos cómo puedes guardar las imágenes generadas en disco:

from PIL import Image

# Function to generate and save new faces
def generate_and_save_faces(generator, latent_dim, n_samples=10, save_dir='generated_faces'):
    noise = np.random.normal(0, 1, (n_samples, latent_dim))
    generated_images = generator.predict(noise)
    generated_images = (generated_images * 127.5 + 127.5).astype(np.uint8)  # Rescale to [0, 255]

    for i in range(n_samples):
        img = Image.fromarray(generated_images[i])
        img.save(f'{save_dir}/face_{i}.png')

# Generate and save new faces
generate_and_save_faces(generator, latent_dim, n_samples=10)

La función generate_and_save_faces toma un modelo generador, un tamaño de dimensión latente, un número de muestras y un directorio para guardar las imágenes. Genera vectores de ruido aleatorios, los usa como entrada para el generador para crear nuevas imágenes, escala los valores de los píxeles de las imágenes generadas para que estén entre 0 y 255, y luego guarda las imágenes como archivos .png en el directorio especificado.

4.4.3 Ajuste Fino del Generador

Aunque nuestro generador ya puede producir resultados impresionantes, siempre hay formas de ajustar y mejorar la calidad de las imágenes generadas. El ajuste fino puede implicar la modificación de la arquitectura del modelo, los hiperparámetros o el proceso de entrenamiento. Aquí hay algunas estrategias:

  1. Ajuste de Hiperparámetros:
    • Experimenta con diferentes tasas de aprendizaje, tamaños de lote y configuraciones de optimizadores para encontrar la mejor combinación para tu conjunto de datos.
  2. Aumento de Datos:
    • Aumenta la diversidad de los datos de entrenamiento aplicando diversas técnicas de aumento como rotación, zoom y cambios de color.
  3. Mejoras Arquitectónicas:
    • Experimenta con diferentes arquitecturas de generadores y discriminadores, como agregar más capas, usar diferentes tipos de capas o ajustar los tamaños de las capas.
  4. Entrenamiento Prolongado:
    • Entrena el modelo durante más épocas o usa parada temprana con puntos de control para asegurar que se guarde el mejor modelo.
  5. Crecimiento Progresivo:
    • Comienza con una resolución más baja y aumenta gradualmente la resolución de las imágenes durante el entrenamiento. Esta técnica puede ayudar al modelo a aprender más eficazmente a cada escala.

Ejemplo: Código para Ajuste Fino

Aquí te mostramos cómo puedes ajustar la tasa de aprendizaje y volver a entrenar el modelo por épocas adicionales:

# Adjust the learning rate and recompile the models
learning_rate = 0.0002
generator_optimizer = tf.keras.optimizers.Adam(learning_rate, beta_1=0.5)
discriminator_optimizer = tf.keras.optimizers.Adam(learning_rate, beta_1=0.5)

discriminator.compile(optimizer=discriminator_optimizer, loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
gan_input = tf.keras.Input(shape=(latent_dim,))
generated_img = generator(gan_input)
gan_output = discriminator(generated_img)
gan = tf.keras.Model(gan_input, gan_output)
gan.compile(optimizer=generator_optimizer, loss='binary_crossentropy')

# Continue training with the adjusted learning rate
for epoch in range(epochs, epochs + 5000):
    idx = np.random.randint(0, train_images.shape[0], batch_size)
    real_images = train_images[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, real)
    d_loss_fake = discriminator.train_on_batch(fake_images, fake)
    d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)

    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    g_loss = gan.train_on_batch(noise, real)

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

    if epoch % 1000 == 0:
        generator.save(f'generator_epoch_{epoch}.h5')
        discriminator.save(f'discriminator_epoch_{epoch}.h5')

Comienza ajustando la tasa de aprendizaje a 0.0002 y recompilando los modelos con esta nueva tasa de aprendizaje. Luego, se establece la capacidad de entrenamiento del discriminador en False para congelar sus pesos cuando se entrene la GAN.

En el bucle de entrenamiento, se seleccionan imágenes reales del conjunto de entrenamiento y se generan imágenes falsas mediante el generador. El discriminador se entrena con estas imágenes reales y falsas. Luego, el generador se entrena para engañar al discriminador utilizando el modelo GAN.

Cada pocas épocas (definidas por 'sample_interval'), se imprimen las pérdidas del discriminador y del generador, y la precisión del discriminador. También se trazan las imágenes generadas por el generador.

Cada 1000 épocas, se guardan los modelos actuales del generador y del discriminador. Esto permite continuar el proceso de entrenamiento más tarde a partir de estos modelos o utilizar estos modelos para generar nuevos datos.

4.4.4 Evaluación de las Caras Generadas

Una vez que hayas generado caras, es importante evaluar su calidad tanto cuantitativamente como cualitativamente. La evaluación cuantitativa se puede realizar utilizando métricas como la Inception Score (IS) y la Fréchet Inception Distance (FID), como se cubrió en secciones anteriores. La evaluación cualitativa implica inspeccionar visualmente las imágenes para evaluar su realismo y diversidad.

Ejemplo: Código de Evaluación

Aquí tienes un breve resumen de cómo evaluar utilizando Inception Score y FID:

# Calculate Inception Score
is_mean, is_std = calculate_inception_score(generated_images)
print(f"Inception Score: {is_mean} ± {is_std}")

# Calculate FID Score
real_images = x_train[np.random.choice(x_train.shape[0], 1000, replace=False)]
fid_score = calculate_fid(real_images, generated_images)
print(f"FID Score: {fid_score}")

La primera parte calcula el Inception Score de las imágenes generadas, que mide tanto la calidad como la diversidad de las imágenes. La puntuación y su desviación estándar se imprimen en la consola.

La segunda parte calcula la puntuación FID entre las imágenes generadas y un conjunto de imágenes reales seleccionadas aleatoriamente del conjunto de entrenamiento. La puntuación FID mide la similitud entre los dos conjuntos de imágenes; una FID más baja indica que las distribuciones de las imágenes generadas y reales están más cerca una de la otra. La puntuación FID calculada se imprime en la consola.

Siguiendo estos pasos, podrás generar caras realistas y de alta calidad utilizando tu modelo GAN entrenado. El ajuste fino del modelo y la evaluación de las caras generadas son cruciales para lograr los mejores resultados posibles.

4.4 Generación de Nuevas Caras

Después de entrenar nuestro modelo GAN, el siguiente paso emocionante es generar nuevas caras. Esta sección te guiará a través del proceso de generar nuevas imágenes utilizando el modelo generador entrenado. Cubriremos cómo generar imágenes a partir de ruido aleatorio, cómo guardar estas imágenes y cómo ajustar el generador para mejorar la calidad de las caras generadas.

4.4.1 Generación de Imágenes a partir de Ruido Aleatorio

El modelo generador, una vez entrenado, puede tomar un vector de ruido aleatorio como entrada y transformarlo en una imagen facial realista. Este vector de ruido, a menudo llamado vector latente, se toma de una distribución normal estándar. El proceso de generar nuevas caras implica muestrear múltiples vectores latentes y pasarlos a través del generador.

Ejemplo: Código para Generar Imágenes

Aquí te mostramos cómo puedes generar y visualizar nuevas imágenes faciales utilizando el modelo generador entrenado:

import numpy as np
import matplotlib.pyplot as plt

# Function to generate and plot new faces
def generate_and_plot_faces(generator, latent_dim, n_samples=10):
    noise = np.random.normal(0, 1, (n_samples, latent_dim))
    generated_images = generator.predict(noise)
    generated_images = (generated_images * 127.5 + 127.5).astype(np.uint8)  # Rescale to [0, 255]

    plt.figure(figsize=(20, 2))
    for i in range(n_samples):
        plt.subplot(1, n_samples, i + 1)
        plt.imshow(generated_images[i])
        plt.axis('off')
    plt.show()

# Generate and plot new faces
latent_dim = 100
generate_and_plot_faces(generator, latent_dim, n_samples=10)

La función 'generate_and_plot_faces' toma un generador (presumiblemente un modelo entrenado, como una Red Generativa Adversaria), una dimensión latente dada y un número específico de muestras.

La función genera 'ruido' siguiendo una distribución normal, que luego se introduce en el modelo generador para crear las 'imágenes generadas'. Estas imágenes se reescalan de un rango [-1, 1] a [0, 255] para que coincidan con la escala RGB estándar.

Luego, las imágenes se trazan en una cuadrícula utilizando matplotlib. Cada imagen se muestra como un subgráfico en una sola fila. La variable 'latent_dim' se establece en 100 y se llama a la función para generar y trazar 10 nuevas caras.

4.4.2 Guardar Imágenes Generadas

Para guardar las imágenes generadas para su uso posterior o compartirlas, podemos utilizar bibliotecas de procesamiento de imágenes como PIL (Python Imaging Library). Esto nos permite guardar las imágenes generadas en varios formatos, como PNG o JPEG.

Ejemplo: Código para Guardar Imágenes

Aquí te mostramos cómo puedes guardar las imágenes generadas en disco:

from PIL import Image

# Function to generate and save new faces
def generate_and_save_faces(generator, latent_dim, n_samples=10, save_dir='generated_faces'):
    noise = np.random.normal(0, 1, (n_samples, latent_dim))
    generated_images = generator.predict(noise)
    generated_images = (generated_images * 127.5 + 127.5).astype(np.uint8)  # Rescale to [0, 255]

    for i in range(n_samples):
        img = Image.fromarray(generated_images[i])
        img.save(f'{save_dir}/face_{i}.png')

# Generate and save new faces
generate_and_save_faces(generator, latent_dim, n_samples=10)

La función generate_and_save_faces toma un modelo generador, un tamaño de dimensión latente, un número de muestras y un directorio para guardar las imágenes. Genera vectores de ruido aleatorios, los usa como entrada para el generador para crear nuevas imágenes, escala los valores de los píxeles de las imágenes generadas para que estén entre 0 y 255, y luego guarda las imágenes como archivos .png en el directorio especificado.

4.4.3 Ajuste Fino del Generador

Aunque nuestro generador ya puede producir resultados impresionantes, siempre hay formas de ajustar y mejorar la calidad de las imágenes generadas. El ajuste fino puede implicar la modificación de la arquitectura del modelo, los hiperparámetros o el proceso de entrenamiento. Aquí hay algunas estrategias:

  1. Ajuste de Hiperparámetros:
    • Experimenta con diferentes tasas de aprendizaje, tamaños de lote y configuraciones de optimizadores para encontrar la mejor combinación para tu conjunto de datos.
  2. Aumento de Datos:
    • Aumenta la diversidad de los datos de entrenamiento aplicando diversas técnicas de aumento como rotación, zoom y cambios de color.
  3. Mejoras Arquitectónicas:
    • Experimenta con diferentes arquitecturas de generadores y discriminadores, como agregar más capas, usar diferentes tipos de capas o ajustar los tamaños de las capas.
  4. Entrenamiento Prolongado:
    • Entrena el modelo durante más épocas o usa parada temprana con puntos de control para asegurar que se guarde el mejor modelo.
  5. Crecimiento Progresivo:
    • Comienza con una resolución más baja y aumenta gradualmente la resolución de las imágenes durante el entrenamiento. Esta técnica puede ayudar al modelo a aprender más eficazmente a cada escala.

Ejemplo: Código para Ajuste Fino

Aquí te mostramos cómo puedes ajustar la tasa de aprendizaje y volver a entrenar el modelo por épocas adicionales:

# Adjust the learning rate and recompile the models
learning_rate = 0.0002
generator_optimizer = tf.keras.optimizers.Adam(learning_rate, beta_1=0.5)
discriminator_optimizer = tf.keras.optimizers.Adam(learning_rate, beta_1=0.5)

discriminator.compile(optimizer=discriminator_optimizer, loss='binary_crossentropy', metrics=['accuracy'])

discriminator.trainable = False
gan_input = tf.keras.Input(shape=(latent_dim,))
generated_img = generator(gan_input)
gan_output = discriminator(generated_img)
gan = tf.keras.Model(gan_input, gan_output)
gan.compile(optimizer=generator_optimizer, loss='binary_crossentropy')

# Continue training with the adjusted learning rate
for epoch in range(epochs, epochs + 5000):
    idx = np.random.randint(0, train_images.shape[0], batch_size)
    real_images = train_images[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, real)
    d_loss_fake = discriminator.train_on_batch(fake_images, fake)
    d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)

    noise = np.random.normal(0, 1, (batch_size, latent_dim))
    g_loss = gan.train_on_batch(noise, real)

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

    if epoch % 1000 == 0:
        generator.save(f'generator_epoch_{epoch}.h5')
        discriminator.save(f'discriminator_epoch_{epoch}.h5')

Comienza ajustando la tasa de aprendizaje a 0.0002 y recompilando los modelos con esta nueva tasa de aprendizaje. Luego, se establece la capacidad de entrenamiento del discriminador en False para congelar sus pesos cuando se entrene la GAN.

En el bucle de entrenamiento, se seleccionan imágenes reales del conjunto de entrenamiento y se generan imágenes falsas mediante el generador. El discriminador se entrena con estas imágenes reales y falsas. Luego, el generador se entrena para engañar al discriminador utilizando el modelo GAN.

Cada pocas épocas (definidas por 'sample_interval'), se imprimen las pérdidas del discriminador y del generador, y la precisión del discriminador. También se trazan las imágenes generadas por el generador.

Cada 1000 épocas, se guardan los modelos actuales del generador y del discriminador. Esto permite continuar el proceso de entrenamiento más tarde a partir de estos modelos o utilizar estos modelos para generar nuevos datos.

4.4.4 Evaluación de las Caras Generadas

Una vez que hayas generado caras, es importante evaluar su calidad tanto cuantitativamente como cualitativamente. La evaluación cuantitativa se puede realizar utilizando métricas como la Inception Score (IS) y la Fréchet Inception Distance (FID), como se cubrió en secciones anteriores. La evaluación cualitativa implica inspeccionar visualmente las imágenes para evaluar su realismo y diversidad.

Ejemplo: Código de Evaluación

Aquí tienes un breve resumen de cómo evaluar utilizando Inception Score y FID:

# Calculate Inception Score
is_mean, is_std = calculate_inception_score(generated_images)
print(f"Inception Score: {is_mean} ± {is_std}")

# Calculate FID Score
real_images = x_train[np.random.choice(x_train.shape[0], 1000, replace=False)]
fid_score = calculate_fid(real_images, generated_images)
print(f"FID Score: {fid_score}")

La primera parte calcula el Inception Score de las imágenes generadas, que mide tanto la calidad como la diversidad de las imágenes. La puntuación y su desviación estándar se imprimen en la consola.

La segunda parte calcula la puntuación FID entre las imágenes generadas y un conjunto de imágenes reales seleccionadas aleatoriamente del conjunto de entrenamiento. La puntuación FID mide la similitud entre los dos conjuntos de imágenes; una FID más baja indica que las distribuciones de las imágenes generadas y reales están más cerca una de la otra. La puntuación FID calculada se imprime en la consola.

Siguiendo estos pasos, podrás generar caras realistas y de alta calidad utilizando tu modelo GAN entrenado. El ajuste fino del modelo y la evaluación de las caras generadas son cruciales para lograr los mejores resultados posibles.