TensorFlow: Técnicas avanzadas

Explora arquitecturas neuronales avanzadas con TensorFlow: redes generativas adversarias (GANs), autoencoders para reducción de dimensionalidad, y modelos transformer para procesamiento de lenguaje y visión. Implementa estas potentes técnicas en proyectos

Aprende TensorFlow GRATIS y certifícate

El mundo de las redes neuronales avanzadas representa la vanguardia del aprendizaje profundo, donde las arquitecturas más sofisticadas permiten crear modelos capaces no solo de clasificar o detectar patrones, sino también de generar contenido nuevo y comprender complejas relaciones contextuales. En este módulo exploraremos tres familias de arquitecturas que han revolucionado la inteligencia artificial: los modelos generativos, los autoencoders y los transformers.

Estas arquitecturas avanzadas abren posibilidades que eran inimaginables hace apenas unos años, desde la creación de rostros que no existen hasta sistemas capaces de mantener conversaciones coherentes o traducir entre idiomas con una precisión sin precedentes.

Modelos Generativos

Los modelos generativos constituyen una clase especial de redes neuronales con la capacidad de generar nuevos datos similares a aquellos con los que fueron entrenados. A diferencia de los modelos discriminativos (como los clasificadores convencionales), que aprenden a distinguir entre clases, los generativos capturan la distribución probabilística subyacente de los datos.

Redes Generativas Adversarias (GANs)

Introducidas por Ian Goodfellow en 2014, las GANs (Generative Adversarial Networks) representan uno de los avances más significativos en el campo generativo. Su funcionamiento se basa en dos redes que compiten entre sí:

  • Generador: Red que intenta crear datos falsos que parezcan reales
  • Discriminador: Red que intenta distinguir entre datos reales y generados

Esta arquitectura de competencia mutua funciona como un juego de suma cero donde la mejora de una red impulsa la mejora de la otra, llevando a generaciones cada vez más realistas.

Veamos la implementación de una GAN básica con TensorFlow para generar dígitos MNIST:

import tensorflow as tf
from tensorflow.keras import layers, models
import numpy as np
import matplotlib.pyplot as plt

# Parámetros
latent_dim = 100  # Dimensión del espacio latente
batch_size = 128

# Arquitectura del generador
def build_generator():
    model = models.Sequential()
    
    # Capa densa inicial y reshape
    model.add(layers.Dense(7*7*256, use_bias=False, input_shape=(latent_dim,)))
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU(alpha=0.2))
    model.add(layers.Reshape((7, 7, 256)))
    
    # Primera capa de convolución transpuesta
    model.add(layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU(alpha=0.2))
    
    # Segunda capa de convolución transpuesta
    model.add(layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
    model.add(layers.BatchNormalization())
    model.add(layers.LeakyReLU(alpha=0.2))
    
    # Capa de salida
    model.add(layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
    
    return model

# Arquitectura del discriminador
def build_discriminator():
    model = models.Sequential()
    
    # Primera capa convolucional
    model.add(layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[28, 28, 1]))
    model.add(layers.LeakyReLU(alpha=0.2))
    model.add(layers.Dropout(0.3))
    
    # Segunda capa convolucional
    model.add(layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'))
    model.add(layers.LeakyReLU(alpha=0.2))
    model.add(layers.Dropout(0.3))
    
    # Capas densas finales
    model.add(layers.Flatten())
    model.add(layers.Dense(1))  # Salida sin activación para loss from_logits=True
    
    return model

# Función de pérdida y optimizadores
cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)

def discriminator_loss(real_output, fake_output):
    real_loss = cross_entropy(tf.ones_like(real_output), real_output)
    fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output)
    return real_loss + fake_loss

def generator_loss(fake_output):
    return cross_entropy(tf.ones_like(fake_output), fake_output)

# Optimizadores
generator_optimizer = tf.keras.optimizers.Adam(1e-4)
discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)

# Creación de modelos
generator = build_generator()
discriminator = build_discriminator()

# Función de entrenamiento para un paso
@tf.function
def train_step(images):
    # Generar ruido aleatorio para el generador
    noise = tf.random.normal([batch_size, latent_dim])
    
    with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
        # Generar imágenes falsas
        generated_images = generator(noise, training=True)
        
        # Clasificar imágenes reales y falsas
        real_output = discriminator(images, training=True)
        fake_output = discriminator(generated_images, training=True)
        
        # Calcular pérdidas
        gen_loss = generator_loss(fake_output)
        disc_loss = discriminator_loss(real_output, fake_output)
    
    # Calcular gradientes
    gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)
    gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)
    
    # Aplicar gradientes
    generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))
    discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))
    
    return gen_loss, disc_loss

# Función para generar y guardar imágenes durante el entrenamiento
def generate_and_save_images(model, epoch, test_input):
    predictions = model(test_input, training=False)
    
    plt.figure(figsize=(10, 10))
    for i in range(25):
        plt.subplot(5, 5, i+1)
        plt.imshow(predictions[i, :, :, 0] * 0.5 + 0.5, cmap='gray')
        plt.axis('off')
    
    plt.savefig(f'epoch_{epoch:04d}.png')
    plt.close()

# Código de entrenamiento
def train(dataset, epochs):
    # Semilla fija para visualización
    seed = tf.random.normal([25, latent_dim])
    
    for epoch in range(epochs):
        for batch in dataset:
            gen_loss, disc_loss = train_step(batch)
        
        # Generar y guardar imágenes
        if (epoch + 1) % 10 == 0:
            generate_and_save_images(generator, epoch + 1, seed)
            print(f'Epoch {epoch+1}, Gen Loss: {gen_loss:.4f}, Disc Loss: {disc_loss:.4f}')
    
    # Guardar el modelo final
    generator.save('gan_generator.h5')
    discriminator.save('gan_discriminator.h5')

# Preparación del dataset
def prepare_mnist():
    (train_images, _), (_, _) = tf.keras.datasets.mnist.load_data()
    train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32')
    # Normalizar a [-1, 1], rango de la función tanh
    train_images = (train_images - 127.5) / 127.5 
    
    # Crear dataset
    train_dataset = tf.data.Dataset.from_tensor_slices(train_images)
    train_dataset = train_dataset.shuffle(60000).batch(batch_size)
    
    return train_dataset

# Ejecutar entrenamiento completo
train_dataset = prepare_mnist()
train(train_dataset, epochs=50)

En esta implementación, el generador transforma vectores de ruido aleatorio en imágenes de 28×28 píxeles, mientras que el discriminador intenta distinguir estas imágenes generadas de las reales. Con cada iteración, ambas redes mejoran: el generador produce imágenes más convincentes y el discriminador se vuelve más astuto en detectar falsificaciones.

Variantes y Aplicaciones Avanzadas de GANs

El concepto básico de GANs ha evolucionado hacia arquitecturas especializadas que abordan limitaciones específicas:

  • DCGANs (Deep Convolutional GANs): Utilizan capas convolucionales profundas para mejorar la calidad y estabilidad.
  • CycleGANs: Permiten la traducción entre dominios de imágenes sin necesidad de pares de entrenamiento emparejados.
  • StyleGANs: Proporcionan control sobre distintos aspectos estilísticos de las imágenes generadas.
  • Pix2Pix: Realizan traducciones de imagen a imagen con pares supervisados.

Veamos una implementación de StyleGAN para generación de rostros con mayor control:

import tensorflow as tf
from tensorflow.keras import layers, models

# Implementación simplificada de componentes de StyleGAN
# Capa de modulación adaptativa
class AdaIN(layers.Layer):
    def __init__(self, channels):
        super(AdaIN, self).__init__()
        self.channels = channels
        self.style_scale = layers.Dense(channels)
        self.style_bias = layers.Dense(channels)
        
    def call(self, inputs, style):
        # Obtener escala y sesgo del vector de estilo
        scale = self.style_scale(style)[:, None, None, :]
        bias = self.style_bias(style)[:, None, None, :]
        
        # Normalizar la entrada
        mean, var = tf.nn.moments(inputs, axes=[1, 2], keepdims=True)
        normalized = (inputs - mean) / tf.sqrt(var + 1e-8)
        
        # Aplicar modulación de estilo
        return normalized * scale + bias

# Bloque de generación con control de estilo
class StyleBlock(layers.Layer):
    def __init__(self, filters, kernel_size=3):
        super(StyleBlock, self).__init__()
        self.conv = layers.Conv2D(filters, kernel_size, padding='same', use_bias=False)
        self.adain = AdaIN(filters)
        self.activation = layers.LeakyReLU(0.2)
        
    def call(self, inputs, style):
        x = self.conv(inputs)
        x = self.adain(x, style)
        return self.activation(x)

# Generador de código latente a estilo
class MappingNetwork(models.Model):
    def __init__(self, style_dim=512, depth=8):
        super(MappingNetwork, self).__init__()
        self.layers_list = []
        
        for i in range(depth):
            self.layers_list.append(layers.Dense(style_dim, activation='relu'))
            
    def call(self, inputs):
        x = inputs
        for layer in self.layers_list:
            x = layer(x)
        re
Empezar curso de TensorFlow

Lecciones de este módulo de TensorFlow

Lecciones de programación del módulo Técnicas avanzadas del curso de TensorFlow.