sábado, 22 de mayo de 2021

GANs Convolucionales profundas DCGAN

Las características principales de las GANs convolucionales profundas son las siguientes:

Reemplazan cualquier capa de agrupación con convoluciones de paso (en el discriminador) y convoluciones traspuestas (en el generador)

Utilizan Normalización Batch en el generador y en el discriminador, excepto en la capa de salida del generador y en la capa de entrada del discriminador.

Elimina todas las capas ocultas completamente conectadas para arquitecturas más profundas.

Utiliza activación ReLU en el generador para todas las capas excepto la capa de salida la cual debe utilizar tanh.

Utiliza activación leaky ReLU en todas las capas del discriminador.

Estas características se utilizan en muchos casos, pero no siempre. Debemos poder experimentar con diferentes hiperparámetros, cambindo la semilla aleatoria y probando el modelo una y otra vez.

El siguiente ejemplo de DCGAN funciona razonablemente bien con eldataset de moda MNIST.

tf.random.set_seed(42)

np.random.seed(42)

codings_size = 100

generator = keras.models.Sequential([

    keras.layers.Dense(7 * 7 * 128, input_shape=[codings_size]),

    keras.layers.Reshape([7, 7, 128]),

    keras.layers.BatchNormalization(),

    keras.layers.Conv2DTranspose(64, kernel_size=5, strides=2, padding="SAME",

                                 activation="selu"),

    keras.layers.BatchNormalization(),

    keras.layers.Conv2DTranspose(1, kernel_size=5, strides=2, padding="SAME",

                                 activation="tanh"),

])

discriminator = keras.models.Sequential([

    keras.layers.Conv2D(64, kernel_size=5, strides=2, padding="SAME",

                        activation=keras.layers.LeakyReLU(0.2),

                        input_shape=[28, 28, 1]),

    keras.layers.Dropout(0.4),

    keras.layers.Conv2D(128, kernel_size=5, strides=2, padding="SAME",

                        activation=keras.layers.LeakyReLU(0.2)),

    keras.layers.Dropout(0.4),

    keras.layers.Flatten(),

    keras.layers.Dense(1, activation="sigmoid")

])

gan = keras.models.Sequential([generator, discriminator])

El generador toma codificaciones (codings) de tamaño 100 y las proyecta a 6272 dimensiones 7*7*28 y cambia la forma del resultado a un tensor de 7x7x128. Este tensor utiliza normalización por lotes y alimenta a una capa convolucional traspuesta con un paso de 2, la cual ensancha las muestras de 7x7  a 14x14 y reduce su profundidad de 128 a 64. El resultado se normaliza por lotes de nuevo y alimenta otr capa convolucional traspuesta con un paso de 2 la cual se ensancha de nuevo de 14x14 a 28x28 y reduce su profundidad de 64 a 1 esta capa utiliza la función de activación tanh con salidas en el rango -1 a 1 por esta razón antes de entrenar la GAN necesitamos reescalar el set de entrenamiento y ponerlo en el mismo rango. También necesitamos cambiarle la forma para añadirle un canal de dimensión.

discriminator.compile(loss="binary_crossentropy", optimizer="rmsprop")

discriminator.trainable = False

gan.compile(loss="binary_crossentropy", optimizer="rmsprop")

X_train_dcgan = X_train.reshape(-1, 28, 28, 1) * 2. - 1. # cambia la forma y la escala

El discriminador se parece mucho a una CNN regular para clasificación binaria pero en vez de utilizar capas de agrupación max para reducir la muestra de la imagen usa convoluciones de paso 2. Hay que notar también que utiliza la función de activación Leaky ReLU.

Respecto a las líneas marcadas al principio para las DCGAN hemos sustituido las capas de normalización por lotas por capas de Dropout en el discriminador y se ha reemplazado ReLU por SELU en el generador. Hay que sentirse libre para cambiar la arquitectura especialmente los relativos a las tasas de aprendizaje de ambas redes neuronales.

Finalmente construimos el dataset, entrenamos y compilamos el modelo.

batch_size = 32

dataset = tf.data.Dataset.from_tensor_slices(X_train_dcgan)

dataset = dataset.shuffle(1000)

dataset = dataset.batch(batch_size, drop_remainder=True).prefetch(1)

train_gan(gan, dataset, batch_size, codings_size)

tf.random.set_seed(42)

np.random.seed(42)

noise = tf.random.normal(shape=[batch_size, codings_size])

generated_images = generator(noise)

plot_multiple_images(generated_images, 8)

save_fig("dcgan_generated_images_plot", tight_layout=False)

Después de 50 épocas el modelo será capaz de genera imágenes como las de abajo.

GANs Convolucionales profundas DCGAN


 Traducido del capítulo 17 de “Hands-On Machine Learning with Scikit-Learn, Keras and Tensorflow, 2nd Edition by Aurelien Géron (O’Reilly). Copyright 2019 Kiwisoft S.A.S., 978-1-492-03264-9”


sábado, 15 de mayo de 2021

AWS in a nutshell 16. Soluciones de Resolución de Nombres. Route 53

Utilizaremos los servicios de AWS adecuados para diseñar e implementar aplicaciones que cumplan con los requisitos dados, migrar aplicaciones complejas en AWS, diseñar e implementar operaciones escalables en toda la empresa en AWS e implementar estrategias de control de costos. Exploraremos cómo configurar las opciones de resolución de nombres de AWS utilizando Amazon Route 53, incluidas las zonas alojadas y las políticas de enrutamiento de registros DNS. 

16.1 Route 53 

Amazon Route 53 es un servicio DNS administrado. Esto significa que no tenemos que aprovisionar manualmente un servidor y configurar el software DNS en él. Solo necesitamos configurar los detalles para la resolución de nombres DNS.

 

AWS Ruta 53

Menú de Route 53

Tecleamos Route 53 en el buscador de la página principal de AWS y nos muestra este menú


Menú de Route 53

16.2 Route 53 Politicas de Enrutamiento

Route 53 admite una serie de políticas de enrutamiento cuando creamos un conjunto de registros DNS. El propósito general es reducir la cantidad de tiempo que le lleva a un cliente conectarse a un recurso. Eso sucede cuando proporcionamos acceso a una dirección IP con la menor cantidad de latencia de red y mediante el uso de  comprobaciones de estado de DNS para evitar el enrutamiento de las solicitudes de los clientes a los servidores backend que no funcionan correctamente o no responden.

16.3 Políticas de ponderadas de route 53

Este es un tipo de configuración para un registro DNS, donde tenemos múltiples registros DNS que usan el mismo FQDN. Sin embargo, cada uno de ellos está configurado con un valor de peso numérico diferente. Y si tenemos uno con un valor de 100 y otro registro con un valor de 200, el mismo nombre, diferentes IP. El que tiene el valor de 200 se usa el doble de veces para devolver esa dirección IP al cliente, que el mismo FDQN con el valor de peso de solo 100.


sábado, 8 de mayo de 2021

Redes Generativas Adversarias (GAN)

Las Redes Generativas Adversarias se componen de un generador y un discriminador.

Generador

Toma a su entrada una distribución aleatoria, suele ser Gaussiana y devuelve a la salida los datos que suelen ser imágenes. Podemos pensar en las entradas aleatorias como en las imágenes latentes que serán generadas. Como se puede ver, el generador ofrece la misma funcionalidad que en un autoencoder variacional y se puede utilizar para generar nuevas imágenes, alimentado por ruido Gaussiano de donde saca las nuevas imágenes.

Discriminador

Toma como entrada una imagen falsa generada por el Generador y otra del dataset de entrenamiento, entonces trata de averiguar cual es la generada y la del dataset. 

Durante el entrenamiento, el generador y el discriminador tiene objetivos opuestos, el discriminador intenta distinguir la imágenes falsas de las auténticas, mientras el generador intenta producir imágenes tan realistas que el discriminador no la distinga de las imágenes del dataset. Como una GAN está compuesta por dos redes con diferentes objetivos, no se puede entrenar como una red neuronal convencional, cada iteracción en el entrenamiento está dividida en dos fases:

En la primera fase, entrenamos el dicriminador. Introducimos un lote de imágenes generadas por el generador y otrode imágenes del dataset y etiquetamos con 0 las del generador y con 1 las del dataset y entrenamos al discriminador con este nuevo dataset utilizando entropía cruzada binaria. Durante esta fase sólo se actualizan los pesos del discriminador.

La segunda fase consiste en entrenar al generador. Para ello, producimos otro lote de imágenes falsas generadas por el generador y utilizamos de nuevo al discriminador para etiquetar las falsas de las reales. Pero esta vez no añadimos imágenes reales en el lote y todas las imágenes son etiquetadas como reales (ponemos 1). Lo que queremos es que el discriminador etiquete erróneamente imágenes falsas como verdaderas. En este paso congelamos los pesos del discriminador, pues lo que nos interesa es entranar al generador.

Vamos a construir una GAN con nuestro dataset de moda MNIST. Para ello construimos el generador y el discriminador. El generador se´ra similar a un decodificador de un autoencoder, y el discriminador es un clasificador binario regular. Toma una imagen de entrada y termina con una capa densa conteniendo una sola neurona con una función de activación sigmoide. En la segunda fase para cada iteracción de entrenamiento necesitamos el modelo GAN completo conteniendo el generador seguido por el discriminador.

np.random.seed(42)

tf.random.set_seed(42)

codings_size = 30

generator = keras.models.Sequential([

    keras.layers.Dense(100, activation="selu", input_shape=[codings_size]),

    keras.layers.Dense(150, activation="selu"),

    keras.layers.Dense(28 * 28, activation="sigmoid"),

    keras.layers.Reshape([28, 28])

])

discriminator = keras.models.Sequential([

    keras.layers.Flatten(input_shape=[28, 28]),

    keras.layers.Dense(150, activation="selu"),

    keras.layers.Dense(100, activation="selu"),

    keras.layers.Dense(1, activation="sigmoid")

])

gan = keras.models.Sequential([generator, discriminator])

Ahora necesitamos compilar estos modelos. Como el discriminador es un clasificador binario podemos utilizar la pérdida binaria de entropía cruzada. El generador sólo será entrenado a través del modelo gan así que no necesitamos compilarlo. El modelo gan también es un clasificador binario, luego también podemos utilizar la pérdida binaria de entropía cruzada. Es importante no entrenar el discriminador durante la segunda fase, así que lo hacemos no entrenable antes de compilar el modelo gan.

discriminator.compile(loss="binary_crossentropy", optimizer="rmsprop")

discriminator.trainable = False

gan.compile(loss="binary_crossentropy", optimizer="rmsprop")

Durante el entrenamiento no debemos utilizar el método fit() en su lugar podemos escribir un bucle de entrenamiento personalizado, para esto necesitamos crear un Dataset para iterar a través de las imágenes.

batch_size = 32

dataset = tf.data.Dataset.from_tensor_slices(X_train).shuffle(1000)

dataset = dataset.batch(batch_size, drop_remainder=True).prefetch(1)

Con esto ya estamos preparados para el entrenamiento. Lo vamos a envolver en una función que llamaremos train_gan().

def train_gan(gan, dataset, batch_size, codings_size, n_epochs=50):

    generator, discriminator = gan.layers

    for epoch in range(n_epochs):

        print("Epoch {}/{}".format(epoch + 1, n_epochs))                      for X_batch in dataset:

            # fase 1 entrenamos el discriminador

            noise = tf.random.normal(shape=[batch_size, codings_size])

            generated_images = generator(noise)

            X_fake_and_real = tf.concat([generated_images, X_batch], axis=0)

            y1 = tf.constant([[0.]] * batch_size + [[1.]] * batch_size)

            discriminator.trainable = True

            discriminator.train_on_batch(X_fake_and_real, y1)

            # fase 2 – entrenamos el generador

            noise = tf.random.normal(shape=[batch_size, codings_size])

            y2 = tf.constant([[1.]] * batch_size)

            discriminator.trainable = False

            gan.train_on_batch(noise, y2)

        plot_multiple_images(generated_images, 8)                    

        plt.show()                                                

Como se ha indicado antes, podemos ver dos fases en cada iteracción.

En la fase uno alimentamos con ruido Gaussiano el generador, para producir imágenes falsas y completamos el lote concatenando un número igual de imágenes reales. A las imágenes reales y1 las ponemos la etiqueta 1 y a las falsas la etiqueta 0. También ponemos el atributo trainable del discriminador como true, esto es solo para evitar que salga una advertencia de Keras cuando el atributo es ahora false y anteriormente era true o viceversa.

En la fase 2 alimentamos la GAN con algo de ruido gausiano. Su generador debe producir imágenes falsas y el discriminador debe averiguar si las imágenes son generadas o del dataset. Nosotros queremos que el discriminador crea que las imágenes falsas sean reales. Así que los objetivos y2 son puestos a 1. Ponemos el atributo trainable del discriminador a False una vez más para evitar el Warning.

Desafortunadamente las imágenes nunca serán mucho mejores que estas, incluso si entrenamos la red más épocas la GAN parece olvidar lo aprendido.

tf.random.set_seed(42)

np.random.seed(42)

noise = tf.random.normal(shape=[batch_size, codings_size])

generated_images = generator(noise)

plot_multiple_images(generated_images, 8)

save_fig("gan_generated_images_plot", tight_layout=False)

train_gan(gan, dataset, batch_size, codings_size)

Redes Generativas Adversarias (GAN)

Dificultades de entrenar GANs

Cuando el generador produce imágenes perfectamente realistas  y el discriminador es forzado a adivinar el 50% falsas y el 50 % verdaderas se debería alcanzar el equilibrio de Nash 

Consideramos que si entrenamos una GAN un tiempo suficiente, esta alcanzará dicho equilibrio, teniendo de este modo un generador perfecto, pero no hay nada que nos garantice que se alcanzará dicho equilibrio.

La principal dificultad se llama modo colapso. Consiste en que el generador cada vez saca imágenes menos diversas. Pues si consigue engañar al discriminador mejor con zapatos que con otras prendas, tratará de generar zapatos más amenudo. Gradualmente olvidará genera otras prendas y generará solo zapatos. Del mismo modo el discriminador olvidará cómo discriminar otras prendas que no sean zapatos con lo que forzará al generador a moverse hacia otras prendas pero ambos olvidarán los zapatos, de modo que irán rotando por diferentes prendas y olvidando las anteriores con lo entra en un bucle cerrado del que no saldrá ninguna mejora de la red.

Además como el generador y el discriminador están constantemente luchando uno contra otro, sus parámetros pueden acabar oscilando y haciéndose inestables. Con lo que de repente pueden comenzar a diverger sin razón aparente. Po resto las GAN son muy sensibles a los hiperparámetros y es necesario un gran esfuerzo en ajustarlas convenientemente.

Traducido del capítulo 17 de “Hands-On Machine Learning with Scikit-Learn, Keras and Tensorflow, 2nd Edition by Aurelien Géron (O’Reilly). Copyright 2019 Kiwisoft S.A.S., 978-1-492-03264-9”


sábado, 1 de mayo de 2021

AWS in a nutshell 15. VPCs

En este post, exploraremos la creación y configuración de VPC, direcciones IP elásticas y la configuración de emparejamiento de VPC para alinearlas con las necesidades del negocio. 

15.1 VPC  

En Amazon Web Services, una Virtual Private Cloud o VPC es una definición de red que creamos en el entorno de la nube para acomodar los recursos que se ejecutarán en esa red.  Tendremos automáticamente VPC predeterminados, uno específicamente para cada región de AWS.

El propósito de esto es que facilita el lanzamiento de recursos como instancias EC2 de inmediato, sin tener que crear una VPC. Pero si utilizamos a gran escala AWS, querremos configurar nuestros propios VPC para satisfacer nuestros propios requisitos de red. Una VPC, puede ser configurarla con un bloque CIDR IPv4 o un bloque CIDR IPv6. 

AWS VPC


15.2 Creación de una VPC por GUI

Desde la consola de AWS tecleamos  → VPC →  y pulsamos en el botón Launch VPC Wizard

Creación de una VPC por GUI


podemos ver las VPCs creadas desde Consola → VPC → your VPCs

También se pueden crear por comandos de texto desde el CLI y desde PowerShell

15.3 Opciones de DHCP de VPC

Un conjunto de opciones de DHCP es una configuración que se asocia con una VPC.

En la consola de administración de VPC, tenemos que seleccionar una VPC existente.  debajo de la pestaña Descripción, podemos ver que hay un enlace, un hipervínculo, para el conjunto de opciones de DHCP asociado con esta VPC en particular. Y si hacemos clic en él, cambia a la vista Conjuntos de opciones de DHCP, donde se filtra en la parte superior para la ID del conjunto de opciones de DHCP que seleccionamos.

AWS Opciones de DHCP de VPC


15.4 Configuración de DNS de VPC

La resolución de nombres DNS es importante porque permite una forma fácil de comunicación entre  dispositivos a través de una red utilizando un nombre DNS, en lugar de la dirección IP más difícil de recordar.

Consola → EC2 → instances  dentro de una instancia pestaña Description y abajo aparece VPC ID con un enlace  pulsamos sobre el enlace y Pestaña Actions donde elegiremos Edit DNS resolution donde elegiremos Edit DNS resolution

AWS Configuración de DNS de VPC


15.5 Direcciones IP elásticas

Las direcciones IP elásticas o EIP son recursos independientes de AWS que nos permiten tener un elemento separado que tiene una dirección IP que luego podemos asociar a una instancia EC2.

Servicios de AWS donde se enumeran varios servicios, como EC2, Amazon Forecast, etc.

Consola –> VPC  → elastic Ips   y pulsamos el botón allocate new adress

15.6 Direccionamiento de IP pública de subred

Una de las muchas opciones que podemos especificar al iniciar una nueva instancia EC2 es si tiene o no una dirección IP pública.

Consola →  EC2 → clic en la opción Instancias para abrir la página Instancias.   Y Launch instance y  elegimos una AMI

17.7 VPC Peering

La interconexión de VPC vincula los VPC directamente entre sí. Podemos hacer esto entre diferentes cuentas de AWS o dentro de una cuenta de AWS, incluso entre regiones de AWS donde cada VPC podría estar en una región diferente. VPC Peering está diseñado para que tengamos instancias EC2, por ejemplo, en cualquiera de las VPC que se comuniquen entre sí, como si estuvieran en la misma red individual aunque no lo estén.

AWS VPC Peering


15.8 Configurar el emparejamiento VPC

Para configurar una subred determinamos si una dirección IP pública se habilita automáticamente para las instancias de EC2 iniciadas en esa subred.

Consola → VPC → sunets