sábado, 13 de marzo de 2021

Autoencoders apilados I: Reducción de dimensionalidad

Los autoencoders, al igual que otras redes neuronales pueden tener múltiples capas ocultas. En este caso los llamamos autoencoders apilados o autoencoders profundos. Añadir más capas ayuda al autoencoder a aprender codificaciones más complejas. Pero hay que ser cuidadoso de no implementar un autoencoder más potente de lo que necesitamos. Imaginamos por ejemplo un codificador tan potente que es capaz de mapear cada número individual de forma arbitraria y un decodificar que hace el mapeo inverso. Obviamente tal autoencoder debería ser capaz de reconstruir los datos de entrenamiento perfectamente, pero no sería capaz de aprender ninguna representación útil de los datos en el proceso (y esto no es útil para generalización de nuevas instancias).

La arquitectura de un autoencoder apilado es tipicamente simétrica con respecto a la capa oculta central (la capa de codificación). Por ejemplo para codificar el dataset de moda MINST 

Debería tener 784 entradas seguidas por una capa oculta de 100 neuronas , luego una capa central de 30 neuronas y otra capa oculta de 100 neuronas, finalmente una capa de salida de 784 salidas.

 

Autoencoders apilados I: Reducción de dimensionalidad

Vamos a construir un autoencoder apilado para trabajar con el dataset MNIST, utilizaremos activación SELU.

Cargamos el dataset MNIST

(X_train_full, y_train_full), (X_test, y_test) = keras.datasets.fashion_mnist.load_data()

X_train_full = X_train_full.astype(np.float32) / 255

X_test = X_test.astype(np.float32) / 255

X_train, X_valid = X_train_full[:-5000], X_train_full[-5000:]

y_train, y_valid = y_train_full[:-5000], y_train_full[-5000:]

Construimos un Autoencoder apilado con 3 capas ocultas y 1 capa de salida (es decir, 2 Autoencoders apilados).

def rounded_accuracy(y_true, y_pred):

    return keras.metrics.binary_accuracy(tf.round(y_true), tf.round(y_pred))

tf.random.set_seed(42)

np.random.seed(42)

 

stacked_encoder = keras.models.Sequential([

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

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

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

])

stacked_decoder = keras.models.Sequential([

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

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

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

])

stacked_ae = keras.models.Sequential([stacked_encoder, stacked_decoder])

stacked_ae.compile(loss="binary_crossentropy",

                   optimizer=keras.optimizers.SGD(lr=1.5), metrics=[rounded_accuracy])

history = stacked_ae.fit(X_train, X_train, epochs=20,

                         validation_data=(X_valid, X_valid))

Echemos un vistazo al código: el modelo de autoencoder se divide en dos submodelos, el codificador y el decodificador.

El codificador toma imágenes en escala de grises de 28x28 pixels, las aplana de tal forma que cada imagen es metida en un vector de 784 posiciones, entonces procesa tales vectores a través de dos capas densas de tamaños que van disminuyendo (primero a 100 unidades y después a 30), ambas capas utilizan la función de activación SELU. Para cada imagen de entrada, el codificador genera un vector de 30 posiciones.

El decodificador toma este vector de 30 posiciones (que es la salida del codificador) y lo procesa a través de dos capas densas incrementando sus tañamos desde 100 unidades hasta 784 y reconstruye el vector final como una imagen de escala de grises de 28x28 pixels con lo que la salida tiene el mismo tamaño que la entrada del codificador.

Cuando compilamos el autoencoder apilado utilizamos pérdida de entropía cruzada binaria en vez del error cuadrático medio. Estamos tratando esta  tarea de reconstrucción como un problema de clasificación binaria múltiple: cada intensidad de pixel representa la probabilidad de que el pixel sea negro. Enmarcando este problema más bien como un problema de regresión, lo que hace que el modelo tienda a converger más rápidamente.

Finalmente entrenamos el modelo utilizando X_train como entradas y como objetivos, y similarmente utilizamos X_valid como entradas de validación y como objetivos.

Visualizando las reconstrucciones

Una forma de asegurarnos de que en autoencoder es entrenado apropiadamente es comparar las entradas con las salidas. Las diferencias no deberían ser demasiado significativas. Vamos a mostrar algunas imágenes de entrada junto con sus correspondientes salidas.

def show_reconstructions(model, images=X_valid, n_images=5):

    reconstructions = model.predict(images[:n_images])

    fig = plt.figure(figsize=(n_images * 1.5, 3))

    for image_index in range(n_images):

        plt.subplot(2, n_images, 1 + image_index)

        plot_image(images[image_index])

        plt.subplot(2, n_images, 1 + n_images + image_index)

        plot_image(reconstructions[image_index])

        show_reconstructions(stacked_ae)

save_fig("reconstruction_plot")


Autoencoders apilados
Las recostrucciones son reconocibles pero con un poco de pérdida. Necesitamos un entrenamiento más largo para el modelo o construir un codificador-decodificador más profundo. Pero tenemos una red neuronal bastante potente, podemos gestionarla para hacer reconstrucciones perfectas sin que aprenda ningún patrón útil en los datos.

Visualizando el dataset de moda MNIST

Ahora que hemos entrenado nuestro autoencoder apilado, podemos utilizarlo para reducir la dimensionalidad del dataset. Para visualización no devolverá grandes resultados comparado con otros algoritmos de reducción de dimensionalidad, pero una de las grandes ventajas de los autoencoders es que pueden manejar datasets grandes con muchas instancias y muchas características. De este modo, una estrategia es utilizar un autoencoder para reducir la dimensionalidad hasta un nivel razonable, y entonces utilizar otro algoritmo de reducción de dimensionalidad para visualización. Utilizaremos esta estrategia para visualizar el dataset de moda MNIST. Primero utilizaremos el codificador de nuestro autoencoder apilado para reducir la dimensionalidad por debajo de 30, y luego utilizaremos la implementación de Scikit-Learn de un algoritmo t-SNE  para reducir la dimensionalidad a 2 para visualizarlo.

np.random.seed(42)

from sklearn.manifold import TSNE

X_valid_compressed = stacked_encoder.predict(X_valid)

tsne = TSNE()

X_valid_2D = tsne.fit_transform(X_valid_compressed)

X_valid_2D = (X_valid_2D - X_valid_2D.min()) / (X_valid_2D.max() - X_valid_2D.min())

plt.scatter(X_valid_2D[:, 0], X_valid_2D[:, 1], c=y_valid, s=10, cmap="tab10")

plt.axis("off")

plt.show()

El diagrama no es muy bonito, si queremos hacer un poco más vistoso hacemos:

# adaptado de https://scikit-learn.org/stable/auto_examples/manifold/plot_lle_digits.html

plt.figure(figsize=(10, 8))

cmap = plt.cm.tab10

plt.scatter(X_valid_2D[:, 0], X_valid_2D[:, 1], c=y_valid, s=10, cmap=cmap)

image_positions = np.array([[1., 1.]])

for index, position in enumerate(X_valid_2D):

    dist = np.sum((position - image_positions) ** 2, axis=1)

    if np.min(dist) > 0.02: # si está más lejos de otras imágenes

        image_positions = np.r_[image_positions, [position]]

        imagebox = mpl.offsetbox.AnnotationBbox(

            mpl.offsetbox.OffsetImage(X_valid[index], cmap="binary"),

            position, bboxprops={"edgecolor": cmap(y_valid[index]), "lw": 2})

        plt.gca().add_artist(imagebox)

plt.axis("off")

save_fig("visualizacion_mnist_moda")

plt.show()

Esto devuelve como resultado un gráfico más amplio y con algunas imágenes como ejemplo. El algoritmo t-SNE identifica varios grupos razonablemente bien, representa cada clase con un color diferente.

Visualizando el dataset de moda MNIST
De este modo los autoencoders pueden ser utilizados para reducción de dimensionalidad. Otra aplicación es para preentrenamientp no supervisado.

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, 6 de marzo de 2021

AWS in a nutshell 11: Alta disponibilidad

11.1 Configuración de Amazon S3 Glacier 

Podemos configurar el almacenamiento de bajo costo a largo plazo con Amazon S3 Glacier.

Una forma de hacerlo es marcar elementos específicos almacenados actualmente en S3 para usar una clase de almacenamiento diferente en forma de depósito Glacier, y otra forma es configurar una regla de ciclo de vida en el depósito para migrar automáticamente los datos más antiguos a Glacier. 

Desde la Consola de AWS tecleamos → S3 → (elegimos un bucket S3) 

Amazon S3 Glacier

11.2 Tipos de balanceo de carga de AWS

El balanceador de carga de Amazon Elastic, o ELB, es una consideración importante cuando planeamos el uso de aplicaciones en AWS. Una de las razones es que podemos mejorar el rendimiento y otra razón es que podemos aumentar la alta disponibilidad. Esto se debe a que hay varios contenedores backend o instancias EC2 que admiten una aplicación y, por lo tanto, se mejora el rendimiento o se logra una alta disponibilidad. Porque si una instancia de backend, por ejemplo, falla, otras están disponibles para tomar el relevo. ELB también es escalable.

11.3 Implementación del equilibrador de carga de red

Un balanceador de carga de red está diseñado para aumentar la disponibilidad de una aplicación, porque las solicitudes pasan por la interfaz del balanceador de carga y hay un grupo de servidores backend separado en la aplicación. Incluso si una aplicación deja de funcionar, otros servidores o instancias pueden manejar la solicitud. Por lo tanto, aumenta la alta disponibilidad y también el rendimiento. Tenemos más jobs esencialmente sirviendo la aplicación.

Consola → EC2 → (panel izquerdo) Load Balancer → (botón) create Load Balancer

11.4 Grupos de ubicación

En Amazon Web Services, se puede especificar un grupo de ubicación cuando se lanza una nueva instancia, y también se puede cambiar después del hecho, como usar la AWS CLI.  Cuando creamos un grupo de ubicación, lo hacemos para poder determinar cómo se distribuyen varias máquinas virtuales o instancias EC2, por ejemplo, en el hardware de los centros de datos de AWS.

Consola → EC2 → (panel izquerdo) Placement Groups→ (Botón) create Placement Group

11.5 Replicación entre regiones de S3 

Podemos lograr una alta disponibilidad con el contenido almacenado en un bucket de S3 habilitando la replicación entre regiones, también conocida como CRR.

Para comenzar, desde la Consola de administración de AWS, tecleamos S3 para iniciar la Consola de administración de S3, donde luego vemos una lista de buckets. 

Consola → S3 → (elegimos un bucket S3) → Management → replication



Replicación entre regiones de S3

11.6 Gateway de almacenamiento

AWS Storage Gateway es una solución de almacenamiento híbrida. Los servicios locales que podemos tener en ejecución pueden comunicarse con el dispositivo de almacenamiento de AWS e incluso pueden comunicarse con el almacenamiento de AWS a través del dispositivo para acceder a almacenamiento adicional en la nube. Por lo que se puede utilizar como una solución de copia de seguridad en la nube. También es una solución de emulación de cinta en la nube, por lo que parece un dispositivo de cinta para los hosts locales que podrían necesitar realizar una copia de seguridad, cuando en realidad es la puerta de enlace de almacenamiento de AWS la que a su vez almacena esas copias de seguridad en la nube. 

Por lo tanto, también podemos usar recursos compartidos de archivos locales respaldados en la nube.

Consola → Storage Gateway → get started

AWS Gateway de almacenamiento

11.7 Réplicas de bases de datos MySQL

En la Consola de administración de AWS, podemos realizar una réplica de una implementación de MySQL existente.

Podríamos hacer esto para implementar nuestra réplica de solo lectura en una ubicación alternativa donde habrá mucho acceso de lectura, como consultas, pero al mismo tiempo significa que también tenemos una copia adicional de los datos replicados actualizados. 

Consola → RDS → databases

AWS Réplicas de bases de datos MySQL

AWS Réplicas de bases de datos MySQL

11.8 Copia de seguridad de AWS (AWS Backup) 

La solución de respaldo de AWS se basa en el uso de instantáneas, que se toman de una variedad de fuentes diferentes, ya sean locales o en la nube. Y estas instantáneas sirven como copias de seguridad. Las fuentes de respaldo incluyen una variedad de elementos disponibles en AWS, así como aplicaciones locales. La ubicación de almacenamiento predeterminada para los elementos respaldados por AWS se encuentra dentro de los buckets de S3. Los servicios de AWS que se pueden respaldar incluyen volúmenes de EBS, bases de datos RDS, DynamoDB, Amazon EFS y también el volumen de AWS Storage Gateway podemos hacer que los elementos locales estén disponibles para respaldo utilizando AWS Backup para almacenamiento en la nube.

Copia de seguridad de AWS (AWS Backup)
Consola → AWS Backup → Backup vaults → (botón ) Create Backup vault

Copia de seguridad de AWS (AWS Backup)

11.9 Copias de seguridad bajo demanda

Una vez que hayamos configurado los planes de copia de seguridad en la copia de seguridad de AWS, que normalmente se programan, podemos, por supuesto, realizar una copia de seguridad bajo demanda en cualquier momento. 

Consola → AWS Backup → Backup plans

11.10 Restauración de copia de seguridad de AWS

Con el Backup de AWS, podemos crear un plan de respaldo para programar backups de recursos de AWS, podemos copiarlos en regiones alternativas y podemos realizar respaldos bajo demanda.

Consola → AWS Backup → Protected resources

Restauración de copia de seguridad de AWS

11.11 Instantáneas de la base de datos MySQL

Al igual que podemos tomar una instantánea de un volumen de EBS para su custodia, de modo que podemos volver a usarlo en caso de corrupción o eliminación de datos, podemos hacer lo mismo con una base de datos MySQL: podemos crear una instantánea de la misma.

Consola → RDS → Databases 

AWS Instantáneas de la base de datos MySQL

11.12 Restauración de instantáneas de base de datos

Si hemos tomado instantáneas de bases de datos, podemos restaurarlas en caso de que surja un problema con la base de datos de origen.

AWS Restauración de instantáneas de base de datos

12.13 Instantáneas de volumen

Es posible utilizar la Consola de administración de AWS para crear una instantánea de volumen de EBS.  ¿para qué haríamos esto? Pues por seguridad. En el caso de que haya algún tipo de corrupción o problema en el volumen de EBS de origen, tenemos una instantánea a la que básicamente podríamos volver.

Incluso podríamos usar esa instantánea como un punto de partida de origen para crear otros volúmenes de EBS, incluso si no hay ningún problema con el volumen de origen. 

Consola → EC2 → (menu izqud) Elastic Block store → volumes