sábado, 24 de abril de 2021

Autoencoders IV: Autoencoders variacionales

 Los autoencoders variacionales son bastante diferentes a los autoencoders vistos previamente, en particular en estas dos características:

-       Son autoencoders probabilísticos, es decir sus salidas son parcialmente determinadas aleatoriamente, incluso después de su entrenamiento

-       Son autoencoders generativos. Es decir pueden generar nuevas instancias similares a sus datos de entrenamiento.

Ejecutan una inferencia Bayesana. Son similares al resto de los autoencoders, solo que para cada entrada dada producen una codificación media y una desviación estándar. La codificación real es entonces modificada aleatoriamente con una distribución Gaussiana con la codificación media m y la desviación estándar s después el decodificador decodifica la muestra normalmente   .

El codificador genera m y s y lo codifica de forma aleatoria, luego lo decodifica y el resultado es una instancia aleatoria pero similar a las de la entrada.   

La estructura del autoencoder se puede ver en la siguiente figura.

Autoencoders variacionales


Aunque las entradas tengan una distribución muy compleja, un autoencoder variacional tiende a producir codificaciones (codings) similares a la distribución Gaussiana simple de las muestras de entrada. Durante el entrenamiento la función de costo empuja a los codings a migrar gradualmente dentro del espacio del coding (también llamado espacio latente) hasta acabar pareciéndose a una nube de puntos Gaussianos. Una gran consecuencia es que después de entrenar un autoencoder variacional podemos fácilmente generar nuevas instancias simplemente eligiendo un punto aleatorio dentro de nuestro espacio Gaussiano.

Es cuanto a la función de costo, está compuesta por dos partes. La primera es la típica reconstrucción de pérdida que empuja al autoencoder a reproducir sus entradas. Podemos utilizar entropía cruzada para esta parte. La segunda parte es la perdida latente que empuja al autoencoder a tener codings similares a las muestras de su distribución Gaussiana: esto es la divergencia KL entre la distribución objetivo (la distribución Gaussiana) y la distribución real del coding.

Vamos a comenzar construyendo un autoencoder variacional para el dataset de moda MNIST. Lo primero que necesitamos es una capa personalizada para los codings.

class Sampling(keras.layers.Layer):

    def call(self, inputs):

        mean, log_var = inputs

        return K.random_normal(tf.shape(log_var)) * K.exp(log_var / 2) + mean

Esta capa de muestreo toma dos entradas, la means (m) y la log_var(g). Utiliza la función K.random_normal() para muestrear u vector aleatorio en el mismo espacio de g con una media de 0 y una desviación estándar de 1donde luego lo multiplica por exp(g \2) lo que lo convierte en s, y finalmente le añade m y retorna el resultado.

Lo siguiente es crear el codificador utilizando una API funcional ya que el modelo no es completamente secuencial.

tf.random.set_seed(42)

np.random.seed(42)

codings_size = 10

inputs = keras.layers.Input(shape=[28, 28])

z = keras.layers.Flatten()(inputs)

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

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

codings_mean = keras.layers.Dense(codings_size)(z)

codings_log_var = keras.layers.Dense(codings_size)(z)

codings = Sampling()([codings_mean, codings_log_var])

variational_encoder = keras.models.Model(

    inputs=[inputs], outputs=[codings_mean, codings_log_var, codings])

Nótese  que las capas densas que sacan codings_mean(m) y codings_log_var(g) tienen las mismas entradas (las salidas de la segunda capa densa) entonces se pasan ambas a la capa Sampling. Finalmente el modelo variational_encoder tiene tres salidas.

A continuación el decodificador.

decoder_inputs = keras.layers.Input(shape=[codings_size])

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

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

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

outputs = keras.layers.Reshape([28, 28])(x)

variational_decoder = keras.models.Model(inputs=[decoder_inputs], outputs=[outputs])

Para este decodificador hemos utilizado la API Secuencial en vez de la API Funcional, pues es más sencilla, una simple pila de capas.

Finalmente construimos el modelo de autoencoder variacional.

_, _, codings = variational_encoder(inputs)

reconstructions = variational_decoder(codings)

variational_ae = keras.models.Model(inputs=[inputs], outputs=[reconstructions])

 

Nótese que hemos ignorado las dos primeras salidas del codificador (pues sólo queremos alimentar los codings del decodificador). Finalmente debemos añadir la pérdida latente y la reconstrucción de pérdida.

 

latent_loss = -0.5 * K.sum(

    1 + codings_log_var - K.exp(codings_log_var) - K.square(codings_mean),

    axis=-1)

variational_ae.add_loss(K.mean(latent_loss) / 784.)

variational_ae.compile(loss="binary_crossentropy", optimizer="rmsprop", metrics=[rounded_accuracy])

 

Primero calcula la pérdida latent para cada instancia, luego calcula la pérdida media sobre todas las instancias y divide el resultado entre 784 para asegurarse que tiene una escala apropiada comparada con la recosntrucción de pérdida. Verdaderamente la reconstrucción de pérdida del autodencoder variacional se supone como la suma de los errores de reconstrucción de los pixels, pero cuando Keras calcula la pérdida binary_crossentropy, lo hace sobre la media de los 784 pixels más bien que con su suma.De modo  que la reconstrucción de la pérdida es 784 veces más pequeña de lo que necesitamos. Para ello, definimos una pérdida personalizada que calcula la suma en vez de la media. Para ello utilizamos el optimizador RMSprop que funciona bien para este caso, y finalmente entrenamos el modelo.

history = variational_ae.fit(X_train, X_train, epochs=25, batch_size=128,

                       validation_data=(X_valid, X_valid))

Generando imágenes de moda MNIST

Vamos a utilizar este codificador variacional para generar imágenes similares a las que contiene el dataset MNIST. Lo único que necesitamos son codings aleatorios procedentes de una distribución Gaussiana y decodificarlos.

def plot_multiple_images(images, n_cols=None):

    n_cols = n_cols or len(images)

    n_rows = (len(images) - 1) // n_cols + 1

    if images.shape[-1] == 1:

        images = np.squeeze(images, axis=-1)

    plt.figure(figsize=(n_cols, n_rows))

    for index, image in enumerate(images):

        plt.subplot(n_rows, n_cols, index + 1)

        plt.imshow(image, cmap="binary")

        plt.axis("off")

Vamos a generar algunas codificaciones aleatorias, decodificarlas y mostrar las imágenes resultantes:

tf.random.set_seed(42)

codings = tf.random.normal(shape=[12, codings_size])

images = variational_decoder(codings).numpy()

plot_multiple_images(images, 4)

save_fig("vae_generated_images_plot", tight_layout=False)

Autoencoders variacionales

La mayor parte de estas imágenes parecen bastante convincentes, aunque son un poco borrosas. Vamos a ajustar un poco mejor el autoencoder para hacerlas mejor.

Los autoencoders variacionales, permiten ejecutar la interpolación semántica , en vez de interpolar dos imágenes a nivel de pixel (lo qu emostrarís dos imágenes solapadas) puede hacer la interpolación a nivel de coding. Tomamos dos imágenes interpolamos sus codings y los decodificamos obteniendo una imagen final similar a cualquier otra del dataset MNIST.

A continuación tomaremos 12 codings y los organizaremos en una matriz de 3X4, utilizando la función  tf.image.resize() de TensorFlow para redimensionar esta matriz a una de 5X7 . Por defecto la función resize() realiza interpolación linear de modo que cada imagen adicional contendrá codings interpolados, finalmente decodificamos los codings para obtener las imágenes.

tf.random.set_seed(42)

np.random.seed(42)

 

codings_grid = tf.reshape(codings, [1, 3, 4, codings_size])

larger_grid = tf.image.resize(codings_grid, size=[5, 7])

interpolated_codings = tf.reshape(larger_grid, [-1, codings_size])

images = variational_decoder(interpolated_codings).numpy()

 

plt.figure(figsize=(7, 5))

for index, image in enumerate(images):

    plt.subplot(5, 7, index + 1)

    if index%7%2==0 and index//7%2==0:

        plt.gca().get_xaxis().set_visible(False)

        plt.gca().get_yaxis().set_visible(False)

    else:

        plt.axis("off")

    plt.imshow(image, cmap="binary")

save_fig("semantic_interpolation_plot", tight_layout=False)

La imagen inferior muestra las imágenes resultantes. Las originales están enmarcadas y el resto son el resultado de la interpolación semántica entre sus imágenes cercanas. Nótese por ejemplo como el zapato de la cuarta fila es una interpolación entre los que tiene encima y debajo.

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, 17 de abril de 2021

AWS in a nutshell 14. Administración de Amazon S3

Amazon Simple Storage Service (Amazon S3)  es un servicio de almacenamiento de objetos que permite escalabilidad, disponibilidad de datos, seguridad y rendimiento. Almacena y protege cualquier volumen de datos para cualquier utilidad como lagos de datos, sitios web, aplicaciones móviles, procesos de copia de seguridad y restauración, operaciones de archivado, aplicaciones empresariales, dispositivos IoT y análisis de big data. Amazon S3 proporciona características de administración fáciles de utilizar que permiten organizar los datos y configurar sofisticados controles de acceso. 

14.1 Replicación de S3 

Podemos habilitar la replicación entre regiones de bucket S3, o CRR, para una mayor redundancia. Esencialmente para sincronizar el contenido de un depósito S3, o para filtrar qué objetos se replican en un sitio alternativo. 

Para gestionarlo desde la consola de AWS escribimos  S3 y nos sale



AWS Administración de Amazon S3



14.2 versionado de S3  

El control de versiones de S3 es el tipo de característica que podemos esperar en una solución de administración de documentos, donde se retienen varias versiones de documentos individuales. 

Desde la consola ponemos  S3 y vamos a Bucket Projects → Versioning

14.3 Creación de un bucket S3

Utilizaremos la GUI de la consola de administración de AWS para crear un cubo (bucket) de S3. Antes de nada necesitamos saber el propósito de este cubo. ¿para alojar un sitio web? ¿Se utilizará para almacenar archivos de productividad de la oficina, como hojas de cálculo y documentos, y diapositivas para los usuarios? ¿Se usará para almacenar copias de seguridad? Y consideraremos cómo configurar el nivel de almacenamiento para el archivado a largo plazo.

Tecleamos S3 en la consola

AWS Creación de un bucket S3

14.4 Administración del ciclo de vida de S3

La administración del ciclo de vida del bucket de Amazon S3 utiliza las llamadas reglas de transición para migrar datos de un nivel de almacenamiento a otro, de manera automatizada. Como puede ser coger los datos a los que no se ha accedido en mucho tiempo y moverlos a la clase de almacenamiento Glacier. 

Para comenzar con la gestión del ciclo de vida, hay que abrir un cubo. 

Desde la consola ponemos Amazon S3 y vamos a Bucket Projects pulsamos sobre el botón Management y luego sobre el botón Add lifecycle rule

AWS Administración del ciclo de vida de S3


14.5  Niveles de almacenamiento S3 (Bucket Storage Tiers)

Podemos usar la Consola de administración S3 para ver y cambiar los niveles de almacenamiento S3 o las clases de almacenamiento para los objetos que hemos almacenado en S3.

Desde la Consola de administración S3 elegimos S3 Bucket 

14.6 Clases de almacenamiento S3

Para decidir una clase de almacenamiento, tenemos que considerar cosas como la cantidad de datos que se almacenarán en S3. La frecuencia con la que se necesita acceder a los datos,  la clase de almacenamiento y su redundancia, si necesitamos múltiples copias. Hay varias clases diferentes de almacenamiento S3.

AWS Clases de almacenamiento S3

14.7 Amazon S3 Glacier 

Amazon S3 Glacier es una solución de archivos en la nube de AWS, la recuperación de datos de un archivo Glacier puede llevar de minutos a horas. Podemos especificar recuperaciones aceleradas como opción. Podemos acceder a los datos entre uno a cinco minutos en función de una cierta tasa de la cantidad de datos que se recuperan. Se considera un medio de almacenamiento económico para los datos a los que se accede con frecuencia en la nube. Es la opción que elegiremos si necesitamos acceder a los datos una o dos veces al año y nos da igual necesitar entre 12 y 48 horas para la recuperación de estos.

AWS Amazon S3 Glacier

14.8 Aceleración de transferencia S3 

Como su nombre lo indica, el uso de la aceleración de transferencia S3 acelera las transferencias de archivos a un depósito S3. Esto se logra aprovechando la red de entrega de contenido de Amazon CloudFronto CDN, donde los datos se copian o almacenan en caché en diferentes puntos finales geográficos de todo el mundo.

hacemos clic en un cubo existente  en la Consola de administración S3.

14.9. Volúmenes de la almacenamiento de bloques elásticos  (Elastic Block Store Volumes.) 

Los volúmenes de Elastic Block Store o EBS 

son similares a los discos duros virtuales que pueden asociarse con máquinas virtuales.

Para comenzar a crear un volumen EBS, en la consola de administración de AWS, tecleamos EC2, y en Todos los servicios -> Computar.

Se abre una página web llamada "Consola de administración EC2". Se divide en dos partes: panel de navegación y panel de contenido. 

14.10 Adjuntar volúmenes a instancias EC2

Después de crear un volumen EBS, podemos adjuntarlo a una instancia EC2.

Se abre la Consola de administración EC2 en la que se abre la página Volúmenes. 

En la Consola de administración EC2, navegamos hasta la vista de volúmenes de Elastic Block Store.

14.11 Configurar el sistema de archivos elástico

En Amazon Web Services, Elastic File System, o EFS, 

es esencialmente una carpeta compartida en la nube a la que puede conectarse desde dispositivos locales o desde instancias EC2 que se ejecutan en la nube de AWS. Lo que es, es un recurso compartido NFS al que nos conectamos, por ejemplo, incluso desde un host Linux, usando el comando mount.

Buscamos EFS en la consola elegimos un resultado en la lista de búsqueda. Y pulsamos el botón Crear sistema de archivos.

Depués hacemos clic en el botón "Crear sistema de archivos" y se muestra su asistente correspondiente. 

Amazon Web Services, Elastic File System