Capítulo 4: Generación de Rostros de Proyectos con GANs
4.6 Mejorando la Generación de Rostros con StyleGAN
StyleGAN representa un avance significativo en el campo de las Redes Generativas Antagónicas (GANs), proporcionando una arquitectura novedosa que permite un control detallado sobre las imágenes generadas. Esta sección profundizará en las complejidades de StyleGAN, explicando su arquitectura, el generador basado en estilos y cómo usarlo para generar imágenes de rostros de alta calidad. También incluiremos ejemplos de código para ayudarte a implementar y experimentar con StyleGAN.
4.6.1 Introducción a StyleGAN
StyleGAN, introducido por investigadores de NVIDIA, mejora las GANs tradicionales incorporando una arquitectura de generador basada en estilos. Esta arquitectura permite la separación de atributos de alto nivel (estilos) de los detalles de bajo nivel, permitiendo un control más preciso sobre el proceso de generación. StyleGAN utiliza la normalización adaptativa de instancias (AdaIN) para inyectar estilos en diferentes capas del generador, resultando en imágenes con una amplia gama de variaciones y características detalladas.
Características Clave de StyleGAN:
- Generador basado en estilos: Modula estilos en varias capas del generador para controlar aspectos específicos de la imagen.
- Crecimiento progresivo: Entrena el modelo incrementando progresivamente la resolución de las imágenes generadas, mejorando la estabilidad y calidad.
- Inyección de ruido: Añade variación estocástica a las imágenes inyectando ruido en múltiples capas, mejorando la diversidad de muestras generadas.
4.6.2 Arquitectura del Generador basado en Estilos
El generador en StyleGAN consiste en una red de mapeo y una red de síntesis. La red de mapeo transforma el vector latente de entrada en un espacio latente intermedio, que luego es utilizado por la red de síntesis para generar imágenes.
Red de Mapeo:
- Consiste en varias capas totalmente conectadas.
- Mapea el vector latente de entrada z a un espacio latente intermedio w.
Red de Síntesis:
- Utiliza el vector latente intermedio w para controlar los estilos en cada capa.
- Emplea la normalización adaptativa de instancias (AdaIN) para modular los mapas de características basados en los estilos.
- Añade ruido a los mapas de características en varias capas para introducir variación estocástica.
Ejemplo: Código del Generador basado en Estilos
import tensorflow as tf
from tensorflow.keras.layers import Dense, Reshape, Conv2D, Conv2DTranspose, Input, LeakyReLU, Layer
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.initializers import RandomNormal
# Custom layer for Adaptive Instance Normalization (AdaIN)
class AdaIN(Layer):
def __init__(self):
super(AdaIN, self).__init__()
def call(self, inputs):
content, style = inputs
mean, variance = tf.nn.moments(content, axes=[1, 2], keepdims=True)
std_dev = tf.sqrt(variance + 1e-8)
norm_content = (content - mean) / std_dev
style_mean, style_std_dev = tf.nn.moments(style, axes=[1, 2], keepdims=True)
return norm_content * style_std_dev + style_mean
# Mapping network to map latent vector z to intermediate latent space w
def build_mapping_network(latent_dim):
model = Sequential()
for _ in range(8):
model.add(Dense(latent_dim, activation='relu'))
return model
# Synthesis network to generate images
def build_synthesis_network(img_shape, latent_dim):
init = RandomNormal(mean=0.0, stddev=1.0)
inputs = Input(shape=(latent_dim,))
x = Dense(4 * 4 * 512, activation='relu', kernel_initializer=init)(inputs)
x = Reshape((4, 4, 512))(x)
for filters in [512, 256, 128, 64]:
x = Conv2DTranspose(filters, kernel_size=4, strides=2, padding='same', kernel_initializer=init)(x)
style_input = Input(shape=(latent_dim,))
x = AdaIN()([x, style_input])
x = LeakyReLU(alpha=0.2)(x)
x = Conv2D(filters, kernel_size=3, padding='same', kernel_initializer=init)(x)
x = AdaIN()([x, style_input])
x = LeakyReLU(alpha=0.2)(x)
outputs = Conv2D(3, kernel_size=3, padding='same', activation='tanh')(x)
return Model(inputs=[inputs, style_input], outputs=outputs)
# Build StyleGAN generator
latent_dim = 100
mapping_network = build_mapping_network(latent_dim)
synthesis_network = build_synthesis_network((64, 64, 3), latent_dim)
mapping_network.summary()
synthesis_network.summary()
En este ejemplo:
- Importar las bibliotecas y módulos necesarios.
- Definir una capa personalizada de TensorFlow (AdaIN o Normalización Adaptativa de Instancias) que normaliza las características de contenido según las características de estilo.
- Definir una red de mapeo. Esta es una parte de la arquitectura de StyleGAN que transforma el vector latente de entrada en un espacio latente intermedio.
- Definir una red de síntesis. Esta toma la salida de la red de mapeo y genera la imagen final. La red de síntesis utiliza capas Conv2DTranspose para escalar hacia arriba, con la capa AdaIN utilizada para aplicar características de estilo en cada escala.
- Construir el generador de StyleGAN creando instancias de las redes de mapeo y síntesis y resumiendo sus arquitecturas.
4.6.3 Entrenamiento de StyleGAN
Entrenar StyleGAN implica dos fases: preentrenar la red de mapeo y luego entrenar todo el modelo StyleGAN utilizando el crecimiento progresivo. El crecimiento progresivo comienza con imágenes de baja resolución y aumenta gradualmente la resolución, estabilizando el proceso de entrenamiento y mejorando la calidad de las imágenes generadas.
Ejemplo: Bucle de Entrenamiento con Crecimiento Progresivo
Así es como puedes implementar el bucle de entrenamiento con crecimiento progresivo:
# Define progressive growing parameters
initial_resolution = 4
final_resolution = 64
num_steps_per_resolution = 10000
batch_size = 64
# Function to train at a given resolution
def train_at_resolution(generator, discriminator, gan, resolution, steps):
for step in range(steps):
# Generate real and fake images
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, noise])
# Train discriminator
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 generator
noise = np.random.normal(0, 1, (batch_size, latent_dim))
g_loss = gan.train_on_batch([noise, noise], np.ones((batch_size, 1)))
# Print progress
if step % 100 == 0:
print(f"Resolution {resolution}x{resolution}, Step {step}/{steps}, D loss: {d_loss[0]}, G loss: {g_loss}")
# Save models periodically
if step % 1000 == 0:
generator.save(f'generator_res_{resolution}_step_{step}.h5')
discriminator.save(f'discriminator_res_{resolution}_step_{step}.h5')
# Initialize and compile models
generator = build_synthesis_network((initial_resolution, initial_resolution, 3), latent_dim)
discriminator = build_discriminator((initial_resolution, initial_resolution, 3))
gan_input = Input(shape=(latent_dim,))
gan_output = discriminator(generator([gan_input, gan_input]))
gan = Model(gan_input, gan_output)
generator.compile(optimizer='adam', loss='binary_crossentropy')
discriminator.compile(optimizer='adam', loss='binary_crossentropy')
gan.compile(optimizer='adam', loss='binary_crossentropy')
# Train progressively
for resolution in [4, 8, 16, 32, 64]:
train_at_resolution(generator, discriminator, gan, resolution, num_steps_per_resolution)
El código define parámetros para el crecimiento progresivo del GAN, como las resoluciones inicial y final y el número de pasos de entrenamiento por resolución. También define una función para entrenar el GAN a una resolución dada.
Esta función itera sobre un número especificado de pasos, generando lotes de imágenes reales y falsas, entrenando al discriminador con estas imágenes y luego entrenando al generador. Periódicamente se imprimen métricas de rendimiento y se guardan los modelos en ciertos intervalos.
Los modelos GAN se inicializan y compilan, y la función de entrenamiento se llama para cada resolución en un rango especificado, permitiendo que la red crezca progresivamente a medida que se entrena.
4.6.4 Ajuste Fino y Evaluación de StyleGAN
Después de entrenar StyleGAN, es esencial ajustar y evaluar el modelo para asegurar la generación de imágenes de alta calidad. Esto implica:
- Ajuste Fino: Ajustar hiperparámetros, agregar pasos de entrenamiento adicionales y usar técnicas como el enfriamiento del aprendizaje para refinar el modelo.
- Evaluación: Usar métodos cualitativos y cuantitativos como la inspección visual, el Inception Score (IS) y la Fréchet Inception Distance (FID) para evaluar la calidad de las imágenes generadas.
Ejemplo: Código de Ajuste Fino
# Adjust learning rate and recompile models for fine-tuning
fine_tune_learning_rate = 0.0001
generator.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
discriminator.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
gan.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
# Fine-tuning loop
fine_tune_steps = 5000
train_at_resolution(generator, discriminator, gan, final_resolution, fine_tune_steps)
Primero, se define una nueva tasa de aprendizaje para el ajuste fino, y los modelos del generador, el discriminador y el GAN se vuelven a compilar con esta tasa de aprendizaje utilizando el optimizador Adam y la función de pérdida de entropía cruzada binaria.
Luego, se define un número específico de pasos de ajuste fino, y el modelo GAN se entrena a una resolución especificada durante este número de pasos.
4.6.5 Generación y Evaluación de Imágenes Finales
Una vez que el modelo se ha ajustado, genera imágenes finales y evalúa su calidad.
Ejemplo: Generación de Imágenes Finales
# Generate final images using the fine-tuned model
def generate_final_images(generator, latent_dim, n_samples=10):
noise = np.random.normal(0, 1, (n_samples, latent_dim))
generated_images = generator.predict([noise, 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 final images
generate_final_images(generator, latent_dim, n_samples=10)
Esta función se utiliza para generar y trazar imágenes finales utilizando un modelo generador que ha sido afinado. La función toma tres argumentos: el modelo generador, el tamaño de la dimensión latente y el número de muestras a generar (que por defecto es 10 si no se especifica).
Primero, genera una entrada de ruido aleatorio para el modelo generador utilizando una distribución normal. Luego, el modelo generador predice las imágenes generadas. Estas imágenes generadas se reescalan para que caigan dentro del rango de [0, 255] para coincidir con el rango típico de valores de píxeles en una imagen.
Se crea una trama con un subtrama para cada imagen generada. Las imágenes se trazan sin ejes. Finalmente, se muestra la trama.
Mejorar la generación de rostros con StyleGAN proporciona mejoras significativas en la calidad y el control de las imágenes generadas. Al aprovechar la arquitectura del generador basada en estilos, el entrenamiento con crecimiento progresivo y las técnicas de afinamiento, puedes lograr imágenes de rostros de alta calidad, diversas y realistas. Evaluar el modelo utilizando métodos cualitativos y cuantitativos asegura que las imágenes generadas cumplan con los estándares deseados.
A medida que continúas explorando las capacidades de StyleGAN, puedes experimentar con diferentes estilos, resoluciones y estrategias de afinamiento para mejorar aún más tus proyectos de modelado generativo. Esta poderosa técnica abre nuevas posibilidades para aplicaciones creativas, investigación e implementaciones prácticas en diversos dominios.
4.6 Mejorando la Generación de Rostros con StyleGAN
StyleGAN representa un avance significativo en el campo de las Redes Generativas Antagónicas (GANs), proporcionando una arquitectura novedosa que permite un control detallado sobre las imágenes generadas. Esta sección profundizará en las complejidades de StyleGAN, explicando su arquitectura, el generador basado en estilos y cómo usarlo para generar imágenes de rostros de alta calidad. También incluiremos ejemplos de código para ayudarte a implementar y experimentar con StyleGAN.
4.6.1 Introducción a StyleGAN
StyleGAN, introducido por investigadores de NVIDIA, mejora las GANs tradicionales incorporando una arquitectura de generador basada en estilos. Esta arquitectura permite la separación de atributos de alto nivel (estilos) de los detalles de bajo nivel, permitiendo un control más preciso sobre el proceso de generación. StyleGAN utiliza la normalización adaptativa de instancias (AdaIN) para inyectar estilos en diferentes capas del generador, resultando en imágenes con una amplia gama de variaciones y características detalladas.
Características Clave de StyleGAN:
- Generador basado en estilos: Modula estilos en varias capas del generador para controlar aspectos específicos de la imagen.
- Crecimiento progresivo: Entrena el modelo incrementando progresivamente la resolución de las imágenes generadas, mejorando la estabilidad y calidad.
- Inyección de ruido: Añade variación estocástica a las imágenes inyectando ruido en múltiples capas, mejorando la diversidad de muestras generadas.
4.6.2 Arquitectura del Generador basado en Estilos
El generador en StyleGAN consiste en una red de mapeo y una red de síntesis. La red de mapeo transforma el vector latente de entrada en un espacio latente intermedio, que luego es utilizado por la red de síntesis para generar imágenes.
Red de Mapeo:
- Consiste en varias capas totalmente conectadas.
- Mapea el vector latente de entrada z a un espacio latente intermedio w.
Red de Síntesis:
- Utiliza el vector latente intermedio w para controlar los estilos en cada capa.
- Emplea la normalización adaptativa de instancias (AdaIN) para modular los mapas de características basados en los estilos.
- Añade ruido a los mapas de características en varias capas para introducir variación estocástica.
Ejemplo: Código del Generador basado en Estilos
import tensorflow as tf
from tensorflow.keras.layers import Dense, Reshape, Conv2D, Conv2DTranspose, Input, LeakyReLU, Layer
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.initializers import RandomNormal
# Custom layer for Adaptive Instance Normalization (AdaIN)
class AdaIN(Layer):
def __init__(self):
super(AdaIN, self).__init__()
def call(self, inputs):
content, style = inputs
mean, variance = tf.nn.moments(content, axes=[1, 2], keepdims=True)
std_dev = tf.sqrt(variance + 1e-8)
norm_content = (content - mean) / std_dev
style_mean, style_std_dev = tf.nn.moments(style, axes=[1, 2], keepdims=True)
return norm_content * style_std_dev + style_mean
# Mapping network to map latent vector z to intermediate latent space w
def build_mapping_network(latent_dim):
model = Sequential()
for _ in range(8):
model.add(Dense(latent_dim, activation='relu'))
return model
# Synthesis network to generate images
def build_synthesis_network(img_shape, latent_dim):
init = RandomNormal(mean=0.0, stddev=1.0)
inputs = Input(shape=(latent_dim,))
x = Dense(4 * 4 * 512, activation='relu', kernel_initializer=init)(inputs)
x = Reshape((4, 4, 512))(x)
for filters in [512, 256, 128, 64]:
x = Conv2DTranspose(filters, kernel_size=4, strides=2, padding='same', kernel_initializer=init)(x)
style_input = Input(shape=(latent_dim,))
x = AdaIN()([x, style_input])
x = LeakyReLU(alpha=0.2)(x)
x = Conv2D(filters, kernel_size=3, padding='same', kernel_initializer=init)(x)
x = AdaIN()([x, style_input])
x = LeakyReLU(alpha=0.2)(x)
outputs = Conv2D(3, kernel_size=3, padding='same', activation='tanh')(x)
return Model(inputs=[inputs, style_input], outputs=outputs)
# Build StyleGAN generator
latent_dim = 100
mapping_network = build_mapping_network(latent_dim)
synthesis_network = build_synthesis_network((64, 64, 3), latent_dim)
mapping_network.summary()
synthesis_network.summary()
En este ejemplo:
- Importar las bibliotecas y módulos necesarios.
- Definir una capa personalizada de TensorFlow (AdaIN o Normalización Adaptativa de Instancias) que normaliza las características de contenido según las características de estilo.
- Definir una red de mapeo. Esta es una parte de la arquitectura de StyleGAN que transforma el vector latente de entrada en un espacio latente intermedio.
- Definir una red de síntesis. Esta toma la salida de la red de mapeo y genera la imagen final. La red de síntesis utiliza capas Conv2DTranspose para escalar hacia arriba, con la capa AdaIN utilizada para aplicar características de estilo en cada escala.
- Construir el generador de StyleGAN creando instancias de las redes de mapeo y síntesis y resumiendo sus arquitecturas.
4.6.3 Entrenamiento de StyleGAN
Entrenar StyleGAN implica dos fases: preentrenar la red de mapeo y luego entrenar todo el modelo StyleGAN utilizando el crecimiento progresivo. El crecimiento progresivo comienza con imágenes de baja resolución y aumenta gradualmente la resolución, estabilizando el proceso de entrenamiento y mejorando la calidad de las imágenes generadas.
Ejemplo: Bucle de Entrenamiento con Crecimiento Progresivo
Así es como puedes implementar el bucle de entrenamiento con crecimiento progresivo:
# Define progressive growing parameters
initial_resolution = 4
final_resolution = 64
num_steps_per_resolution = 10000
batch_size = 64
# Function to train at a given resolution
def train_at_resolution(generator, discriminator, gan, resolution, steps):
for step in range(steps):
# Generate real and fake images
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, noise])
# Train discriminator
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 generator
noise = np.random.normal(0, 1, (batch_size, latent_dim))
g_loss = gan.train_on_batch([noise, noise], np.ones((batch_size, 1)))
# Print progress
if step % 100 == 0:
print(f"Resolution {resolution}x{resolution}, Step {step}/{steps}, D loss: {d_loss[0]}, G loss: {g_loss}")
# Save models periodically
if step % 1000 == 0:
generator.save(f'generator_res_{resolution}_step_{step}.h5')
discriminator.save(f'discriminator_res_{resolution}_step_{step}.h5')
# Initialize and compile models
generator = build_synthesis_network((initial_resolution, initial_resolution, 3), latent_dim)
discriminator = build_discriminator((initial_resolution, initial_resolution, 3))
gan_input = Input(shape=(latent_dim,))
gan_output = discriminator(generator([gan_input, gan_input]))
gan = Model(gan_input, gan_output)
generator.compile(optimizer='adam', loss='binary_crossentropy')
discriminator.compile(optimizer='adam', loss='binary_crossentropy')
gan.compile(optimizer='adam', loss='binary_crossentropy')
# Train progressively
for resolution in [4, 8, 16, 32, 64]:
train_at_resolution(generator, discriminator, gan, resolution, num_steps_per_resolution)
El código define parámetros para el crecimiento progresivo del GAN, como las resoluciones inicial y final y el número de pasos de entrenamiento por resolución. También define una función para entrenar el GAN a una resolución dada.
Esta función itera sobre un número especificado de pasos, generando lotes de imágenes reales y falsas, entrenando al discriminador con estas imágenes y luego entrenando al generador. Periódicamente se imprimen métricas de rendimiento y se guardan los modelos en ciertos intervalos.
Los modelos GAN se inicializan y compilan, y la función de entrenamiento se llama para cada resolución en un rango especificado, permitiendo que la red crezca progresivamente a medida que se entrena.
4.6.4 Ajuste Fino y Evaluación de StyleGAN
Después de entrenar StyleGAN, es esencial ajustar y evaluar el modelo para asegurar la generación de imágenes de alta calidad. Esto implica:
- Ajuste Fino: Ajustar hiperparámetros, agregar pasos de entrenamiento adicionales y usar técnicas como el enfriamiento del aprendizaje para refinar el modelo.
- Evaluación: Usar métodos cualitativos y cuantitativos como la inspección visual, el Inception Score (IS) y la Fréchet Inception Distance (FID) para evaluar la calidad de las imágenes generadas.
Ejemplo: Código de Ajuste Fino
# Adjust learning rate and recompile models for fine-tuning
fine_tune_learning_rate = 0.0001
generator.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
discriminator.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
gan.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
# Fine-tuning loop
fine_tune_steps = 5000
train_at_resolution(generator, discriminator, gan, final_resolution, fine_tune_steps)
Primero, se define una nueva tasa de aprendizaje para el ajuste fino, y los modelos del generador, el discriminador y el GAN se vuelven a compilar con esta tasa de aprendizaje utilizando el optimizador Adam y la función de pérdida de entropía cruzada binaria.
Luego, se define un número específico de pasos de ajuste fino, y el modelo GAN se entrena a una resolución especificada durante este número de pasos.
4.6.5 Generación y Evaluación de Imágenes Finales
Una vez que el modelo se ha ajustado, genera imágenes finales y evalúa su calidad.
Ejemplo: Generación de Imágenes Finales
# Generate final images using the fine-tuned model
def generate_final_images(generator, latent_dim, n_samples=10):
noise = np.random.normal(0, 1, (n_samples, latent_dim))
generated_images = generator.predict([noise, 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 final images
generate_final_images(generator, latent_dim, n_samples=10)
Esta función se utiliza para generar y trazar imágenes finales utilizando un modelo generador que ha sido afinado. La función toma tres argumentos: el modelo generador, el tamaño de la dimensión latente y el número de muestras a generar (que por defecto es 10 si no se especifica).
Primero, genera una entrada de ruido aleatorio para el modelo generador utilizando una distribución normal. Luego, el modelo generador predice las imágenes generadas. Estas imágenes generadas se reescalan para que caigan dentro del rango de [0, 255] para coincidir con el rango típico de valores de píxeles en una imagen.
Se crea una trama con un subtrama para cada imagen generada. Las imágenes se trazan sin ejes. Finalmente, se muestra la trama.
Mejorar la generación de rostros con StyleGAN proporciona mejoras significativas en la calidad y el control de las imágenes generadas. Al aprovechar la arquitectura del generador basada en estilos, el entrenamiento con crecimiento progresivo y las técnicas de afinamiento, puedes lograr imágenes de rostros de alta calidad, diversas y realistas. Evaluar el modelo utilizando métodos cualitativos y cuantitativos asegura que las imágenes generadas cumplan con los estándares deseados.
A medida que continúas explorando las capacidades de StyleGAN, puedes experimentar con diferentes estilos, resoluciones y estrategias de afinamiento para mejorar aún más tus proyectos de modelado generativo. Esta poderosa técnica abre nuevas posibilidades para aplicaciones creativas, investigación e implementaciones prácticas en diversos dominios.
4.6 Mejorando la Generación de Rostros con StyleGAN
StyleGAN representa un avance significativo en el campo de las Redes Generativas Antagónicas (GANs), proporcionando una arquitectura novedosa que permite un control detallado sobre las imágenes generadas. Esta sección profundizará en las complejidades de StyleGAN, explicando su arquitectura, el generador basado en estilos y cómo usarlo para generar imágenes de rostros de alta calidad. También incluiremos ejemplos de código para ayudarte a implementar y experimentar con StyleGAN.
4.6.1 Introducción a StyleGAN
StyleGAN, introducido por investigadores de NVIDIA, mejora las GANs tradicionales incorporando una arquitectura de generador basada en estilos. Esta arquitectura permite la separación de atributos de alto nivel (estilos) de los detalles de bajo nivel, permitiendo un control más preciso sobre el proceso de generación. StyleGAN utiliza la normalización adaptativa de instancias (AdaIN) para inyectar estilos en diferentes capas del generador, resultando en imágenes con una amplia gama de variaciones y características detalladas.
Características Clave de StyleGAN:
- Generador basado en estilos: Modula estilos en varias capas del generador para controlar aspectos específicos de la imagen.
- Crecimiento progresivo: Entrena el modelo incrementando progresivamente la resolución de las imágenes generadas, mejorando la estabilidad y calidad.
- Inyección de ruido: Añade variación estocástica a las imágenes inyectando ruido en múltiples capas, mejorando la diversidad de muestras generadas.
4.6.2 Arquitectura del Generador basado en Estilos
El generador en StyleGAN consiste en una red de mapeo y una red de síntesis. La red de mapeo transforma el vector latente de entrada en un espacio latente intermedio, que luego es utilizado por la red de síntesis para generar imágenes.
Red de Mapeo:
- Consiste en varias capas totalmente conectadas.
- Mapea el vector latente de entrada z a un espacio latente intermedio w.
Red de Síntesis:
- Utiliza el vector latente intermedio w para controlar los estilos en cada capa.
- Emplea la normalización adaptativa de instancias (AdaIN) para modular los mapas de características basados en los estilos.
- Añade ruido a los mapas de características en varias capas para introducir variación estocástica.
Ejemplo: Código del Generador basado en Estilos
import tensorflow as tf
from tensorflow.keras.layers import Dense, Reshape, Conv2D, Conv2DTranspose, Input, LeakyReLU, Layer
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.initializers import RandomNormal
# Custom layer for Adaptive Instance Normalization (AdaIN)
class AdaIN(Layer):
def __init__(self):
super(AdaIN, self).__init__()
def call(self, inputs):
content, style = inputs
mean, variance = tf.nn.moments(content, axes=[1, 2], keepdims=True)
std_dev = tf.sqrt(variance + 1e-8)
norm_content = (content - mean) / std_dev
style_mean, style_std_dev = tf.nn.moments(style, axes=[1, 2], keepdims=True)
return norm_content * style_std_dev + style_mean
# Mapping network to map latent vector z to intermediate latent space w
def build_mapping_network(latent_dim):
model = Sequential()
for _ in range(8):
model.add(Dense(latent_dim, activation='relu'))
return model
# Synthesis network to generate images
def build_synthesis_network(img_shape, latent_dim):
init = RandomNormal(mean=0.0, stddev=1.0)
inputs = Input(shape=(latent_dim,))
x = Dense(4 * 4 * 512, activation='relu', kernel_initializer=init)(inputs)
x = Reshape((4, 4, 512))(x)
for filters in [512, 256, 128, 64]:
x = Conv2DTranspose(filters, kernel_size=4, strides=2, padding='same', kernel_initializer=init)(x)
style_input = Input(shape=(latent_dim,))
x = AdaIN()([x, style_input])
x = LeakyReLU(alpha=0.2)(x)
x = Conv2D(filters, kernel_size=3, padding='same', kernel_initializer=init)(x)
x = AdaIN()([x, style_input])
x = LeakyReLU(alpha=0.2)(x)
outputs = Conv2D(3, kernel_size=3, padding='same', activation='tanh')(x)
return Model(inputs=[inputs, style_input], outputs=outputs)
# Build StyleGAN generator
latent_dim = 100
mapping_network = build_mapping_network(latent_dim)
synthesis_network = build_synthesis_network((64, 64, 3), latent_dim)
mapping_network.summary()
synthesis_network.summary()
En este ejemplo:
- Importar las bibliotecas y módulos necesarios.
- Definir una capa personalizada de TensorFlow (AdaIN o Normalización Adaptativa de Instancias) que normaliza las características de contenido según las características de estilo.
- Definir una red de mapeo. Esta es una parte de la arquitectura de StyleGAN que transforma el vector latente de entrada en un espacio latente intermedio.
- Definir una red de síntesis. Esta toma la salida de la red de mapeo y genera la imagen final. La red de síntesis utiliza capas Conv2DTranspose para escalar hacia arriba, con la capa AdaIN utilizada para aplicar características de estilo en cada escala.
- Construir el generador de StyleGAN creando instancias de las redes de mapeo y síntesis y resumiendo sus arquitecturas.
4.6.3 Entrenamiento de StyleGAN
Entrenar StyleGAN implica dos fases: preentrenar la red de mapeo y luego entrenar todo el modelo StyleGAN utilizando el crecimiento progresivo. El crecimiento progresivo comienza con imágenes de baja resolución y aumenta gradualmente la resolución, estabilizando el proceso de entrenamiento y mejorando la calidad de las imágenes generadas.
Ejemplo: Bucle de Entrenamiento con Crecimiento Progresivo
Así es como puedes implementar el bucle de entrenamiento con crecimiento progresivo:
# Define progressive growing parameters
initial_resolution = 4
final_resolution = 64
num_steps_per_resolution = 10000
batch_size = 64
# Function to train at a given resolution
def train_at_resolution(generator, discriminator, gan, resolution, steps):
for step in range(steps):
# Generate real and fake images
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, noise])
# Train discriminator
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 generator
noise = np.random.normal(0, 1, (batch_size, latent_dim))
g_loss = gan.train_on_batch([noise, noise], np.ones((batch_size, 1)))
# Print progress
if step % 100 == 0:
print(f"Resolution {resolution}x{resolution}, Step {step}/{steps}, D loss: {d_loss[0]}, G loss: {g_loss}")
# Save models periodically
if step % 1000 == 0:
generator.save(f'generator_res_{resolution}_step_{step}.h5')
discriminator.save(f'discriminator_res_{resolution}_step_{step}.h5')
# Initialize and compile models
generator = build_synthesis_network((initial_resolution, initial_resolution, 3), latent_dim)
discriminator = build_discriminator((initial_resolution, initial_resolution, 3))
gan_input = Input(shape=(latent_dim,))
gan_output = discriminator(generator([gan_input, gan_input]))
gan = Model(gan_input, gan_output)
generator.compile(optimizer='adam', loss='binary_crossentropy')
discriminator.compile(optimizer='adam', loss='binary_crossentropy')
gan.compile(optimizer='adam', loss='binary_crossentropy')
# Train progressively
for resolution in [4, 8, 16, 32, 64]:
train_at_resolution(generator, discriminator, gan, resolution, num_steps_per_resolution)
El código define parámetros para el crecimiento progresivo del GAN, como las resoluciones inicial y final y el número de pasos de entrenamiento por resolución. También define una función para entrenar el GAN a una resolución dada.
Esta función itera sobre un número especificado de pasos, generando lotes de imágenes reales y falsas, entrenando al discriminador con estas imágenes y luego entrenando al generador. Periódicamente se imprimen métricas de rendimiento y se guardan los modelos en ciertos intervalos.
Los modelos GAN se inicializan y compilan, y la función de entrenamiento se llama para cada resolución en un rango especificado, permitiendo que la red crezca progresivamente a medida que se entrena.
4.6.4 Ajuste Fino y Evaluación de StyleGAN
Después de entrenar StyleGAN, es esencial ajustar y evaluar el modelo para asegurar la generación de imágenes de alta calidad. Esto implica:
- Ajuste Fino: Ajustar hiperparámetros, agregar pasos de entrenamiento adicionales y usar técnicas como el enfriamiento del aprendizaje para refinar el modelo.
- Evaluación: Usar métodos cualitativos y cuantitativos como la inspección visual, el Inception Score (IS) y la Fréchet Inception Distance (FID) para evaluar la calidad de las imágenes generadas.
Ejemplo: Código de Ajuste Fino
# Adjust learning rate and recompile models for fine-tuning
fine_tune_learning_rate = 0.0001
generator.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
discriminator.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
gan.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
# Fine-tuning loop
fine_tune_steps = 5000
train_at_resolution(generator, discriminator, gan, final_resolution, fine_tune_steps)
Primero, se define una nueva tasa de aprendizaje para el ajuste fino, y los modelos del generador, el discriminador y el GAN se vuelven a compilar con esta tasa de aprendizaje utilizando el optimizador Adam y la función de pérdida de entropía cruzada binaria.
Luego, se define un número específico de pasos de ajuste fino, y el modelo GAN se entrena a una resolución especificada durante este número de pasos.
4.6.5 Generación y Evaluación de Imágenes Finales
Una vez que el modelo se ha ajustado, genera imágenes finales y evalúa su calidad.
Ejemplo: Generación de Imágenes Finales
# Generate final images using the fine-tuned model
def generate_final_images(generator, latent_dim, n_samples=10):
noise = np.random.normal(0, 1, (n_samples, latent_dim))
generated_images = generator.predict([noise, 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 final images
generate_final_images(generator, latent_dim, n_samples=10)
Esta función se utiliza para generar y trazar imágenes finales utilizando un modelo generador que ha sido afinado. La función toma tres argumentos: el modelo generador, el tamaño de la dimensión latente y el número de muestras a generar (que por defecto es 10 si no se especifica).
Primero, genera una entrada de ruido aleatorio para el modelo generador utilizando una distribución normal. Luego, el modelo generador predice las imágenes generadas. Estas imágenes generadas se reescalan para que caigan dentro del rango de [0, 255] para coincidir con el rango típico de valores de píxeles en una imagen.
Se crea una trama con un subtrama para cada imagen generada. Las imágenes se trazan sin ejes. Finalmente, se muestra la trama.
Mejorar la generación de rostros con StyleGAN proporciona mejoras significativas en la calidad y el control de las imágenes generadas. Al aprovechar la arquitectura del generador basada en estilos, el entrenamiento con crecimiento progresivo y las técnicas de afinamiento, puedes lograr imágenes de rostros de alta calidad, diversas y realistas. Evaluar el modelo utilizando métodos cualitativos y cuantitativos asegura que las imágenes generadas cumplan con los estándares deseados.
A medida que continúas explorando las capacidades de StyleGAN, puedes experimentar con diferentes estilos, resoluciones y estrategias de afinamiento para mejorar aún más tus proyectos de modelado generativo. Esta poderosa técnica abre nuevas posibilidades para aplicaciones creativas, investigación e implementaciones prácticas en diversos dominios.
4.6 Mejorando la Generación de Rostros con StyleGAN
StyleGAN representa un avance significativo en el campo de las Redes Generativas Antagónicas (GANs), proporcionando una arquitectura novedosa que permite un control detallado sobre las imágenes generadas. Esta sección profundizará en las complejidades de StyleGAN, explicando su arquitectura, el generador basado en estilos y cómo usarlo para generar imágenes de rostros de alta calidad. También incluiremos ejemplos de código para ayudarte a implementar y experimentar con StyleGAN.
4.6.1 Introducción a StyleGAN
StyleGAN, introducido por investigadores de NVIDIA, mejora las GANs tradicionales incorporando una arquitectura de generador basada en estilos. Esta arquitectura permite la separación de atributos de alto nivel (estilos) de los detalles de bajo nivel, permitiendo un control más preciso sobre el proceso de generación. StyleGAN utiliza la normalización adaptativa de instancias (AdaIN) para inyectar estilos en diferentes capas del generador, resultando en imágenes con una amplia gama de variaciones y características detalladas.
Características Clave de StyleGAN:
- Generador basado en estilos: Modula estilos en varias capas del generador para controlar aspectos específicos de la imagen.
- Crecimiento progresivo: Entrena el modelo incrementando progresivamente la resolución de las imágenes generadas, mejorando la estabilidad y calidad.
- Inyección de ruido: Añade variación estocástica a las imágenes inyectando ruido en múltiples capas, mejorando la diversidad de muestras generadas.
4.6.2 Arquitectura del Generador basado en Estilos
El generador en StyleGAN consiste en una red de mapeo y una red de síntesis. La red de mapeo transforma el vector latente de entrada en un espacio latente intermedio, que luego es utilizado por la red de síntesis para generar imágenes.
Red de Mapeo:
- Consiste en varias capas totalmente conectadas.
- Mapea el vector latente de entrada z a un espacio latente intermedio w.
Red de Síntesis:
- Utiliza el vector latente intermedio w para controlar los estilos en cada capa.
- Emplea la normalización adaptativa de instancias (AdaIN) para modular los mapas de características basados en los estilos.
- Añade ruido a los mapas de características en varias capas para introducir variación estocástica.
Ejemplo: Código del Generador basado en Estilos
import tensorflow as tf
from tensorflow.keras.layers import Dense, Reshape, Conv2D, Conv2DTranspose, Input, LeakyReLU, Layer
from tensorflow.keras.models import Model, Sequential
from tensorflow.keras.initializers import RandomNormal
# Custom layer for Adaptive Instance Normalization (AdaIN)
class AdaIN(Layer):
def __init__(self):
super(AdaIN, self).__init__()
def call(self, inputs):
content, style = inputs
mean, variance = tf.nn.moments(content, axes=[1, 2], keepdims=True)
std_dev = tf.sqrt(variance + 1e-8)
norm_content = (content - mean) / std_dev
style_mean, style_std_dev = tf.nn.moments(style, axes=[1, 2], keepdims=True)
return norm_content * style_std_dev + style_mean
# Mapping network to map latent vector z to intermediate latent space w
def build_mapping_network(latent_dim):
model = Sequential()
for _ in range(8):
model.add(Dense(latent_dim, activation='relu'))
return model
# Synthesis network to generate images
def build_synthesis_network(img_shape, latent_dim):
init = RandomNormal(mean=0.0, stddev=1.0)
inputs = Input(shape=(latent_dim,))
x = Dense(4 * 4 * 512, activation='relu', kernel_initializer=init)(inputs)
x = Reshape((4, 4, 512))(x)
for filters in [512, 256, 128, 64]:
x = Conv2DTranspose(filters, kernel_size=4, strides=2, padding='same', kernel_initializer=init)(x)
style_input = Input(shape=(latent_dim,))
x = AdaIN()([x, style_input])
x = LeakyReLU(alpha=0.2)(x)
x = Conv2D(filters, kernel_size=3, padding='same', kernel_initializer=init)(x)
x = AdaIN()([x, style_input])
x = LeakyReLU(alpha=0.2)(x)
outputs = Conv2D(3, kernel_size=3, padding='same', activation='tanh')(x)
return Model(inputs=[inputs, style_input], outputs=outputs)
# Build StyleGAN generator
latent_dim = 100
mapping_network = build_mapping_network(latent_dim)
synthesis_network = build_synthesis_network((64, 64, 3), latent_dim)
mapping_network.summary()
synthesis_network.summary()
En este ejemplo:
- Importar las bibliotecas y módulos necesarios.
- Definir una capa personalizada de TensorFlow (AdaIN o Normalización Adaptativa de Instancias) que normaliza las características de contenido según las características de estilo.
- Definir una red de mapeo. Esta es una parte de la arquitectura de StyleGAN que transforma el vector latente de entrada en un espacio latente intermedio.
- Definir una red de síntesis. Esta toma la salida de la red de mapeo y genera la imagen final. La red de síntesis utiliza capas Conv2DTranspose para escalar hacia arriba, con la capa AdaIN utilizada para aplicar características de estilo en cada escala.
- Construir el generador de StyleGAN creando instancias de las redes de mapeo y síntesis y resumiendo sus arquitecturas.
4.6.3 Entrenamiento de StyleGAN
Entrenar StyleGAN implica dos fases: preentrenar la red de mapeo y luego entrenar todo el modelo StyleGAN utilizando el crecimiento progresivo. El crecimiento progresivo comienza con imágenes de baja resolución y aumenta gradualmente la resolución, estabilizando el proceso de entrenamiento y mejorando la calidad de las imágenes generadas.
Ejemplo: Bucle de Entrenamiento con Crecimiento Progresivo
Así es como puedes implementar el bucle de entrenamiento con crecimiento progresivo:
# Define progressive growing parameters
initial_resolution = 4
final_resolution = 64
num_steps_per_resolution = 10000
batch_size = 64
# Function to train at a given resolution
def train_at_resolution(generator, discriminator, gan, resolution, steps):
for step in range(steps):
# Generate real and fake images
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, noise])
# Train discriminator
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 generator
noise = np.random.normal(0, 1, (batch_size, latent_dim))
g_loss = gan.train_on_batch([noise, noise], np.ones((batch_size, 1)))
# Print progress
if step % 100 == 0:
print(f"Resolution {resolution}x{resolution}, Step {step}/{steps}, D loss: {d_loss[0]}, G loss: {g_loss}")
# Save models periodically
if step % 1000 == 0:
generator.save(f'generator_res_{resolution}_step_{step}.h5')
discriminator.save(f'discriminator_res_{resolution}_step_{step}.h5')
# Initialize and compile models
generator = build_synthesis_network((initial_resolution, initial_resolution, 3), latent_dim)
discriminator = build_discriminator((initial_resolution, initial_resolution, 3))
gan_input = Input(shape=(latent_dim,))
gan_output = discriminator(generator([gan_input, gan_input]))
gan = Model(gan_input, gan_output)
generator.compile(optimizer='adam', loss='binary_crossentropy')
discriminator.compile(optimizer='adam', loss='binary_crossentropy')
gan.compile(optimizer='adam', loss='binary_crossentropy')
# Train progressively
for resolution in [4, 8, 16, 32, 64]:
train_at_resolution(generator, discriminator, gan, resolution, num_steps_per_resolution)
El código define parámetros para el crecimiento progresivo del GAN, como las resoluciones inicial y final y el número de pasos de entrenamiento por resolución. También define una función para entrenar el GAN a una resolución dada.
Esta función itera sobre un número especificado de pasos, generando lotes de imágenes reales y falsas, entrenando al discriminador con estas imágenes y luego entrenando al generador. Periódicamente se imprimen métricas de rendimiento y se guardan los modelos en ciertos intervalos.
Los modelos GAN se inicializan y compilan, y la función de entrenamiento se llama para cada resolución en un rango especificado, permitiendo que la red crezca progresivamente a medida que se entrena.
4.6.4 Ajuste Fino y Evaluación de StyleGAN
Después de entrenar StyleGAN, es esencial ajustar y evaluar el modelo para asegurar la generación de imágenes de alta calidad. Esto implica:
- Ajuste Fino: Ajustar hiperparámetros, agregar pasos de entrenamiento adicionales y usar técnicas como el enfriamiento del aprendizaje para refinar el modelo.
- Evaluación: Usar métodos cualitativos y cuantitativos como la inspección visual, el Inception Score (IS) y la Fréchet Inception Distance (FID) para evaluar la calidad de las imágenes generadas.
Ejemplo: Código de Ajuste Fino
# Adjust learning rate and recompile models for fine-tuning
fine_tune_learning_rate = 0.0001
generator.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
discriminator.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
gan.compile(optimizer=tf.keras.optimizers.Adam(fine_tune_learning_rate), loss='binary_crossentropy')
# Fine-tuning loop
fine_tune_steps = 5000
train_at_resolution(generator, discriminator, gan, final_resolution, fine_tune_steps)
Primero, se define una nueva tasa de aprendizaje para el ajuste fino, y los modelos del generador, el discriminador y el GAN se vuelven a compilar con esta tasa de aprendizaje utilizando el optimizador Adam y la función de pérdida de entropía cruzada binaria.
Luego, se define un número específico de pasos de ajuste fino, y el modelo GAN se entrena a una resolución especificada durante este número de pasos.
4.6.5 Generación y Evaluación de Imágenes Finales
Una vez que el modelo se ha ajustado, genera imágenes finales y evalúa su calidad.
Ejemplo: Generación de Imágenes Finales
# Generate final images using the fine-tuned model
def generate_final_images(generator, latent_dim, n_samples=10):
noise = np.random.normal(0, 1, (n_samples, latent_dim))
generated_images = generator.predict([noise, 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 final images
generate_final_images(generator, latent_dim, n_samples=10)
Esta función se utiliza para generar y trazar imágenes finales utilizando un modelo generador que ha sido afinado. La función toma tres argumentos: el modelo generador, el tamaño de la dimensión latente y el número de muestras a generar (que por defecto es 10 si no se especifica).
Primero, genera una entrada de ruido aleatorio para el modelo generador utilizando una distribución normal. Luego, el modelo generador predice las imágenes generadas. Estas imágenes generadas se reescalan para que caigan dentro del rango de [0, 255] para coincidir con el rango típico de valores de píxeles en una imagen.
Se crea una trama con un subtrama para cada imagen generada. Las imágenes se trazan sin ejes. Finalmente, se muestra la trama.
Mejorar la generación de rostros con StyleGAN proporciona mejoras significativas en la calidad y el control de las imágenes generadas. Al aprovechar la arquitectura del generador basada en estilos, el entrenamiento con crecimiento progresivo y las técnicas de afinamiento, puedes lograr imágenes de rostros de alta calidad, diversas y realistas. Evaluar el modelo utilizando métodos cualitativos y cuantitativos asegura que las imágenes generadas cumplan con los estándares deseados.
A medida que continúas explorando las capacidades de StyleGAN, puedes experimentar con diferentes estilos, resoluciones y estrategias de afinamiento para mejorar aún más tus proyectos de modelado generativo. Esta poderosa técnica abre nuevas posibilidades para aplicaciones creativas, investigación e implementaciones prácticas en diversos dominios.