Ricostruzione delle immagini MNIST utilizzando un autoencoder

Ricostruzione immagini MNIST con autoencoder

Introduzione

Con così tante informazioni su Internet, ricercatori e scienziati stanno cercando di sviluppare metodi di trasferimento dati più efficienti e sicuri. Gli autoencoder sono emersi come strumenti preziosi a questo scopo grazie alla loro architettura semplice ed intuitiva. Di solito, dopo che l’autoencoder è addestrato, i pesi dell’encoder possono essere inviati al mittente e i pesi del decoder al destinatario. Ciò consente al mittente di inviare i dati in formato codificato, risparmiando tempo e costi, mentre il destinatario può ricevere dati compressi. Questo articolo esplora l’appassionante applicazione degli autoencoder nella ricostruzione di immagini MNIST, in particolare utilizzando il database numerico MNIST e il framework PyTorch in Python.

Obiettivi di apprendimento

  • Questo articolo si concentra sulla costruzione di un autoencoder TensorFlow in grado di codificare immagini MNIST.
  • Implementeremo funzioni per caricare e elaborare database e creare trasformazioni dinamiche dei punti dati.
  • Genereremo un autoencoder con architettura encoder-decoder utilizzando immagini rumorose e reali come input.
  • Esploreremo l’importanza degli autoencoder nell’apprendimento profondo, i principi di applicazione e il loro potenziale per migliorare le prestazioni del modello.

Questo articolo è stato pubblicato come parte del Data Science Blogathon.

L’architettura degli autoencoder

Gli autoencoder possono essere divisi in tre componenti principali:

Encoder: questo modulo prende i dati di input dal set di addestramento-validazione-test e li comprime in una rappresentazione codificata. Di solito, i dati delle immagini codificate sono più piccoli dei dati di input.

Bottleneck: il modulo bottleneck mantiene la rappresentazione della conoscenza compressa e la rende una parte critica della rete. La dimensione dei dati diventa una barriera decrescente.

Decoder: il modulo decoder è fondamentale nel ripristinare la rappresentazione dei dati nella sua forma originale “decomprimendola”. L’output risultante del decoder viene quindi confrontato con il ground truth o con i dati di input iniziali.

Il modulo decoder aiuta a “decomprimere” la visualizzazione dei dati e a ricostruirla nella sua forma codificata. L’output del decoder viene quindi confrontato con il ground truth o con i dati di input originali.

La relazione tra l’encoder, il bottleneck e il decoder

Encoder

L’encoder svolge un ruolo significativo nella compressione dei dati di input attraverso il modulo pooling e il blocco convoluzionale. Questa compressione produce un’immagine compatta chiamata blocco.

Dopo un certo intervallo di tempo, entra in gioco il decoder. Esso è composto da moduli di alto livello che restituiscono caratteristiche compressate nel formato dell’immagine originale. Negli autoencoder di base, il decoder mira a ricostruire l’output in modo simile all’input, indipendentemente dalla riduzione del rumore.

Tuttavia, nel caso degli autoencoder variabili, l’input non è una ricostruzione dell’input. Invece, crea un’immagine completamente nuova basata sui dati di input forniti al modello. Questa differenza consente agli autoencoder variabili di avere un certo controllo sull’immagine risultante e di produrre risultati diversi.

Bottleneck

Sebbene il bottleneck sia la parte più piccola del sistema nervoso, è molto importante. Agisce come un elemento critico che limita il flusso di dati dall’encoder al decoder, consentendo solo il passaggio dei dati più critici. Limitando il flusso, la barriera garantisce che le proprietà cruciali siano preservate e utilizzate nel ripristino.

Questo rappresenta il tipo di conoscenza di input progettando ostacoli per estrarre il massimo delle informazioni dall’immagine. La struttura encoder-decoder consente l’estrazione di informazioni preziose dalle immagini e la creazione di connessioni significative tra vari input nella rete.

Questa forma compressa di elaborazione impedisce al sistema nervoso di memorizzare l’input e di sovraccaricarsi di informazioni. Come linea guida generale, più piccola è la barriera, minore è il rischio di eccesso.

Tuttavia, buffer molto piccoli possono limitare la quantità di dati memorizzati, aumentando la probabilità che dati essenziali vengano persi attraverso il livello di pooling dell’encoder.

Decoder

Un decoder è composto da un blocco di uplink e convoluzione che ricostruisce interruzioni di output.

Una volta che l’input raggiunge il decoder, che riceve la rappresentazione compressa, diventa un “decompressore”. Il ruolo del decoder è quello di ricostruire l’immagine basandosi sulle proprietà nascoste estratte dall’immagine compressa. Utilizzando questa proprietà nascosta, il decoder ricostruisce efficacemente l’immagine invertendo il processo di compressione eseguito dall’encoder.

Come Allenare gli Autoencoder?

Prima di impostare l’autoencoder, ci sono quattro iperparametri importanti:

  • Dimensione del codice: La dimensione del codice, nota anche come dimensione del blocco, è un iperparametro essenziale nella taratura dell’autoencoder. Specifica il livello di compressione dei dati. Inoltre, la dimensione del codice può agire come termine di regolarizzazione.
  • Diverse strati: Come le altre reti neurali, la profondità dell’encoder e del decoder è un iperparametro vitale degli autoencoder. Aumentare la profondità aggiunge complessità al modello, mentre diminuire la profondità aumenta la velocità di elaborazione.
  • Numero di punti in ogni strato: Il numero di punti in ogni strato determina il peso utilizzato in ogni strato. Tipicamente, il numero di punti diminuisce man mano che si procede al livello successivo nell’autoencoder, indicando che l’input sta diminuendo.
  • Ripristino della perdita: La scelta della funzione di perdita per allenare l’autoencoder dipende dall’adattamento desiderato input-output. Quando si lavora con dati di immagine, le funzioni di perdita popolari per la ricostruzione includono la perdita di errore quadratico medio (MSE) e la perdita L1. L’entropia incrociata binaria può anche essere utilizzata come perdita di ricostruzione se gli input e gli output sono nell’intervallo [0,1], ad esempio con MNIST.

Requisiti

Abbiamo bisogno di questa libreria e delle funzioni di supporto per creare un Autoencoder in Tensorflow.

Tensorflow: Per iniziare, dovremmo importare la libreria Tensorflow e tutti i componenti necessari per creare il nostro modello, consentendogli di leggere e generare immagini MNIST.

NumPy: Successivamente, importiamo NumPy, una potente libreria per l’elaborazione di numeri, che utilizzeremo per la preelaborazione e la riorganizzazione del database.

Matplotlib: Utilizzeremo la libreria di pianificazione matplotlib per visualizzare e valutare le prestazioni del modello.

  • La funzione data_proc(dat) prende la funzione di supporto come dati e li ridimensiona alle dimensioni richieste dal modello.
  • La funzione di supporto gen_noise(dat) è progettata per accettare un array come input, applicare rumore gaussiano e garantire che i valori risultanti rientrino nell’intervallo (0,1).
  • Two Arrays è una funzione di supporto per la visualizzazione (dat1, dat2) che prende un array di input e un array di immagini previste e li inserisce in due righe.

Costruzione dell’AutoEncoder

Nella parte successiva, impareremo come creare un semplice Autoencoder utilizzando TensorFlow e allenarlo utilizzando immagini MNIST. Innanzitutto, delineeremo i passaggi per caricare e elaborare i dati MNIST per soddisfare i nostri requisiti. Una volta che i dati sono formattati correttamente, costruiamo e alleniamo il modello.

L’architettura della rete è composta da tre componenti principali: Encoder, Bottleneck e Decoder. L’encoder è responsabile della compressione dell’immagine di input preservando le informazioni preziose. Il bottleneck determina quali caratteristiche sono essenziali per passare attraverso il decoder. Infine, il Decoder utilizza il risultato del Bottleneck per ricostruire l’immagine. Durante questo processo di ricostruzione, l’Autoencoder mira a imparare la posizione nascosta dei dati.

Dobbiamo importare alcune librerie e scrivere alcune funzioni per creare un modello per leggere e creare immagini MNIST. Utilizzare la libreria TensorFlow per importarla con altri componenti correlati. Importare anche la libreria di elaborazione numerica NumPy e la libreria di grafici Matplotlib. Questa libreria ci aiuterà a eseguire alcune operazioni e visualizzare i risultati.

Importa Libreria

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

from tensorflow.keras.layers import *
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Model

Inoltre, abbiamo bisogno dell’implementazione di alcune funzioni ausiliarie. La funzione di inizializzazione è responsabile per ricevere un array come input e modificare la dimensione alla dimensione richiesta per il modello.

def data_proc(dat):
    larr = len(dat)
    return np.reshape(dat.astype("float32") /255.0 , (larr, 28,28,1))

Dobbiamo anche aggiungere una seconda funzione di supporto che opera sull’array. Questa funzione aggiunge rumore gaussiano all’array e assicura che il valore risultante sia compreso tra 0 e 1.

def gen_noise(dat):
    return np.clip(dat + 0.4 * np.random.normal(loc=0.0, scale=1.0, size=dat.shape), 0.0, 1.0)

Valutare le prestazioni del modello

Per valutare le prestazioni del nostro modello, è importante visualizzare un gran numero di immagini. A tal fine, possiamo utilizzare una funzione di input che prende due array, un insieme di immagini proiettate e una terza funzione che le mette in due righe.

def display(dat1, dat2):
    ind = np.random.randint(len(dat1), size=10)
    im1 = dat1[ind, :]
    im2 = dat2[ind, :]
    for i, (a, b) in enumerate(zip(im1, im2)):
        plt_axis = plt.subplot(2, n, i + 1)
        plt.imshow(a.reshape(28, 28))
        plt.gray()
        plt_axis.get_xaxis().set_visible(False)
        plt_axis.get_yaxis().set_visible(False)
        
        plt_axis = plt.subplot(2, n, i + 1 + n)
        plt.imshow(b.reshape(28, 28))
        plt.gray()
        plt_axis.get_xaxis().set_visible(False)
        plt_axis.get_yaxis().set_visible(False)
    plt.show()

Preparazione del dataset

Il dataset MNIST è stato fornito in TensorFlow, diviso in set di dati di addestramento e test. Possiamo caricare direttamente questo database e utilizzare le funzioni di elaborazione predefinite definite in precedenza. Inoltre, generiamo una versione rumorosa dell’immagine MNIST originale per la seconda metà dei dati di input utilizzando la funzione gen_noise definita precedentemente. Va notato che il livello di rumore di input influisce sulla distorsione dell’immagine, rendendo difficile ottenere una buona ricostruzione del modello. Immagineremo l’immagine originale e il rumore come parte del processo.

(ds_train, _), (ds_test, _) = mnist.load_data()
ds_train,ds_test = data_proc(ds_train), data_proc(ds_test)
noisy_ds_train, noisy_ds_test = gen_noise(ds_train), gen_noise(ds_test)
display(ds_train, noisy_ds_train)

Definizione dell’encoder

La parte dell’encoder della rete utilizza livelli di convoluzione e pooling massimo con attivazione ReLU. L’obiettivo è raffreddare i dati di input prima di inviarli alla rete. L’output desiderato da questo passaggio è una versione compressa dei dati originali. Dato che l’immagine MNIST ha un’immagine 28x28x1, creiamo un input con una certa forma.

inps = Input(shape=(28, 28, 1))


x = Conv2D(32, (3, 3), activation="relu", padding="same")(inps)
x = MaxPooling2D((2, 2), padding="same")(x)
x = Conv2D(32, (3, 3), activation="relu", padding="same")(x)
x = MaxPooling2D((2, 2), padding="same")(x)

Definizione del bottleneck

A differenza degli altri elementi, il bottleneck non richiede una programmazione esplicita. Poiché il livello di encoder del pooling massimo produce un output finale altamente compresso, il decoder è addestrato a ricostruire l’immagine utilizzando questa rappresentazione compressa. L’architettura del bottleneck può essere modificata in un’implementazione più complessa di autoencoder.

Definizione del decoder

Il decoder è composto da convoluzioni trasposte con uno stride di 2. L’ultimo strato del modello utilizza una semplice convoluzione 2D con la funzione di attivazione sigmoide. Lo scopo di questo componente è ricostruire le immagini dalla rappresentazione compressa. La convoluzione trasposta viene utilizzata per l’upsampling, consentendo passi più grandi e riducendo il numero di passi necessari per l’upsampling delle immagini.

x = Conv2DTranspose(32, (3, 3),activation="relu", padding="same", strides=2)(x)
x = Conv2DTranspose(32, (3, 3),activation="relu", padding="same", strides=2)(x)
x = Conv2D(1, (3, 3), activation="sigmoid", padding="same")(x)

Allenamento del modello

Dopo aver definito il modello, deve essere configurato con l’ottimizzatore e le funzioni di perdita. In questo articolo, utilizzeremo l’ottimizzatore Adam e selezioneremo la funzione di perdita Binary Cross Entropy per l’addestramento.

conv_autoenc_model = Model(inps, x)
conv_autoenc_model.compile(optimizer="adam", loss="binary_crossentropy")
conv_autoenc_model.summary()

Output

Una volta che il modello è costruito, possiamo addestrarlo utilizzando le immagini MNIST modificate create in precedenza nell’articolo. Il processo di addestramento prevede l’esecuzione del modello per 50 epoche con una dimensione del batch di 128. Inoltre, forniamo dati di validazione per il modello.

conv_autoenc_model.fit(
    x=ds_train,
    y=ds_train,
    epochs=50,
    batch_size=128,
    shuffle=True,
    validation_data=(ds_test, ds_test),
)

Ricostruzione delle immagini

Una volta addestrato il modello, possiamo generare previsioni e ricostruire le immagini. Possiamo utilizzare la funzione precedentemente definita per visualizzare l’immagine risultante.

preds = conv_autoenc_model.predict(ds_test)
display(ds_test, preds)

Conclusioni

Un autoencoder è una rete neurale artificiale che puoi utilizzare per apprendere la codifica dei dati non supervisionata. L’obiettivo principale è ottenere una rappresentazione a bassa dimensione, spesso chiamata codifica, per dati ad alta dimensione al fine di ridurre la dimensione. Le griglie consentono una rappresentazione e un’analisi efficienti dei dati per catturare le caratteristiche o le caratteristiche più importanti dell’immagine di input.

Punti principali

  • Gli autoencoder sono tecniche di apprendimento non supervisionato utilizzate nelle reti neurali. Sono progettati per apprendere una rappresentazione efficiente dei dati (codifica) addestrando la rete a filtrare il rumore di segnale indesiderato.
  • Gli autoencoder hanno una varietà di applicazioni, tra cui immagini, compressione delle immagini e, in alcuni casi, anche generazione di immagini.
  • Anche se gli autoencoder sembrano semplici a prima vista a causa della loro base teorica semplice, insegnare loro a imparare rappresentazioni significative dei dati di input può essere sfidante.
  • Gli autoencoder hanno diverse applicazioni, come l’analisi delle componenti principali (PCA), una tecnica di riduzione della dimensionalità, la rappresentazione delle immagini e molti altri compiti.

Domande frequenti

I media mostrati in questo articolo non sono di proprietà di Analytics Vidhya e sono utilizzati a discrezione dell’autore.