Variational Autoencoder (VAE)
Una forma avanzata di autoencoder che genera nuove osservazioni campionando da una distribuzione continua.
Definizione di Variational Autoencoder (VAE)
Un Variational Autoencoder (VAE) è un tipo di rete neurale utilizzata per l'apprendimento non supervisionato e la generazione di nuovi dati simili ai dati di addestramento.È una forma avanzata di autoencoder che, a differenza degli autoencoder tradizionali, genera nuove osservazioni campionando da una distribuzione continua.
Un VAE apprende una rappresentazione latente probabilistica dei dati che può essere utilizzata per generare nuovi campioni verosimili.
Codice Completo per Addestrare un VAE su MNIST
Importazione delle Librerie
import numpy as np
import tensorflow as tf
from tensorflow.keras import layers, Model
import matplotlib.pyplot as plt
Definizione delle Dimensioni
input_dim = (28, 28, 1)
latent_dim = 2
- `input_dim`: Dimensione dell'input (28x28 con 1 canale per immagini in scala di grigi).
- `latent_dim`: Dimensione dello spazio latente, qui impostata a 2.
Encoder
inputs = layers.Input(shape=input_dim)
x = layers.Conv2D(32, 3, activation='relu', strides=2, padding='same')(inputs)
x = layers.Conv2D(64, 3, activation='relu', strides=2, padding='same')(x)
x = layers.Flatten()(x)
x = layers.Dense(16, activation='relu')(x)
z_mean = layers.Dense(latent_dim)(x)
z_log_var = layers.Dense(latent_dim)(x)
- Input Layer: Definisce l'input del modello con la dimensione specificata.
- Convolutional Layers: Due strati convoluzionali con 32 e 64 filtri, rispettivamente, con kernel 3x3, funzione di attivazione ReLU, stride di 2 e padding "same".
- Flatten: Appiattisce l'output del secondo strato convoluzionale in un vettore 1D.
- Dense Layer: Strato completamente connesso con 16 unità e attivazione ReLU.
- z_mean e z_log_var: Due strati densi che producono i parametri della distribuzione latente (media e logaritmo della varianza).
Campionamento dallo Spazio Latente
def sampling(args):
z_mean, z_log_var = args
batch = tf.shape(z_mean)[0]
dim = tf.shape(z_mean)[1]
epsilon = tf.keras.backend.random_normal(shape=(batch, dim))
return z_mean + tf.exp(0.5 * z_log_var) * epsilon
z = layers.Lambda(sampling)([z_mean, z_log_var])
Funzione di Campionamento
Campiona dallo spazio latente utilizzando la reparametrizzazione.- `epsilon` è un rumore gaussiano.
- `z = z_mean + exp(0.5 * z_log_var) * epsilon` applica la reparametrizzazione per ottenere un campione dalla distribuzione latente.
- Lambda Layer Layer Lambda per eseguire la funzione di campionamento.
Decoder
decoder_inputs = layers.Input(shape=(latent_dim,))
x = layers.Dense(7 * 7 * 64, activation='relu')(decoder_inputs)
x = layers.Reshape((7, 7, 64))(x)
x = layers.Conv2DTranspose(64, 3, activation='relu', strides=2, padding='same')(x)
x = layers.Conv2DTranspose(32, 3, activation='relu', strides=2, padding='same')(x)
outputs = layers.Conv2DTranspose(1, 3, activation='sigmoid', padding='same')(x)
- Input del Decoder: Input layer per il decoder con dimensione latente.
- Dense Layer: Strato completamente connesso che mappa lo spazio latente a 7x7x64.
- Reshape: Riformatta l'output del dense layer a una forma 7x7x64.
- Conv2DTranspose Layers: Tre strati di convoluzione trasposta per ricostruire l'immagine originale. Il primo e il secondo hanno 64 e 32 filtri rispettivamente, con kernel 3x3, attivazione ReLU e stride di 2. Il terzo ha 1 filtro con kernel 3x3, attivazione sigmoid e padding "same".
Costruzione dei Modelli
encoder = Model(inputs, [z_mean, z_log_var, z], name='encoder')
decoder = Model(decoder_inputs, outputs, name='decoder')
outputs = decoder(encoder(inputs)[2])
vae = Model(inputs, outputs, name='vae')
- Encoder Model: Modello che mappa l'input ai parametri della distribuzione latente e al campione latente.
- Decoder Model: Modello che mappa i campioni latenti alle immagini ricostruite.
- VAE Model: Modello complessivo che collega encoder e decoder.
Funzione di Costo
reconstruction_loss = tf.keras.losses.binary_crossentropy(tf.keras.backend.flatten(inputs), tf.keras.backend.flatten(outputs))
reconstruction_loss *= input_dim[0] * input_dim[1]
kl_loss = 1 + z_log_var - tf.square(z_mean) - tf.exp(z_log_var)
kl_loss = tf.reduce_sum(kl_loss, axis=-1)
kl_loss *= -0.5
vae_loss = tf.reduce_mean(reconstruction_loss + kl_loss)
- Ricostruzione Loss: Utilizza la binary crossentropy tra l'input originale e l'output ricostruito.
- KL Divergence: Calcola la divergenza KL tra la distribuzione latente appresa e una distribuzione normale standard.
- VAE Loss: Somma della ricostruzione loss e della KL divergence.
Compilazione del Modello
vae.add_loss(vae_loss)
vae.compile(optimizer='adam')
- Aggiunta della Funzione di Costo: Aggiunge la funzione di costo al modello VAE.
- Compilazione: Compila il modello VAE con l'ottimizzatore Adam.
Caricamento e Preprocessamento dei Dati
from tensorflow.keras.datasets import mnist
# Carica il dataset MNIST
(x_train, _), (x_test, _) = mnist.load_data()
# Normalizza i valori dei pixel a [0, 1] e aggiungi una dimensione per il canale
x_train = np.expand_dims(x_train, -1).astype("float32") / 255
x_test = np.expand_dims(x_test, -1).astype("float32") / 255
Addestramento del VAE
vae.fit(x_train, epochs=50, batch_size=128, validation_data=(x_test, None))
Generazione di Nuove Immagini
# Funzione per visualizzare le immagini generate
def plot_generated_images(decoded_imgs, n=10):
plt.figure(figsize=(20, 4))
for i in range(n):
ax = plt.subplot(2, n, i + 1)
plt.imshow(decoded_imgs[i].reshape(28, 28), cmap='gray')
plt.axis('off')
plt.show()
# Campiona dallo spazio latente
n_samples = 10
random_latent_vectors = np.random.normal(size=(n_samples, latent_dim))
# Genera nuove immagini
generated_images = decoder.predict(random_latent_vectors)
# Visualizza le immagini generate
plot_generated_images(generated_images, n_samples)
Passi in dettaglio
Importazione delle Librerie
- `numpy`: Libreria per il calcolo numerico.- `tensorflow` e `keras`: Librerie per costruire e addestrare reti neurali.
- `matplotlib`: Libreria per visualizzare le immagini.
Definizione delle Dimensioni
- `input_dim` specifica la dimensione dell'input (28x28 con 1 canale per immagini in scala di grigi).- `latent_dim` definisce la dimensione dello spazio latente (2 dimensioni).
Costruzione dell'Encoder
- L'encoder prende l'immagine di input e la passa attraverso strati convoluzionali e un denso per ottenere i parametri della distribuzione latente (z_mean e z_log_var).Campionamento dallo Spazio Latente
- La funzione di campionamento utilizza la reparametrizzazione per campionare dallo spazio latente, aggiungendo rumore gaussiano.Costruzione del Decoder
- Il decoder prende i campioni latenti e li passa attraverso strati completamente connessi e strati di convoluzione trasposta per ricostruire l'immagine originale.Costruzione dei Modelli
- Il modello encoder mappa l'input ai parametri della distribuzione latente e al campione latente.- Il modello decoder mappa i campioni latenti alle immagini ricostruite.
- Il modello VAE collega encoder e decoder.
Definizione della Funzione di Costo
- La funzione di costo è la somma della ricostruzione loss (binary crossentropy) e della divergenza KL.Compilazione del Modello
- Aggiunta della funzione di costo e compilazione del modello con l'ottimizzatore Adam.Caricamento e Preprocessamento dei Dati
- Caricamento del dataset MNIST e normalizzazione dei valori dei pixel.Addestramento del VAE
- Addestramento del modello VAE per 50 epoche con batch size di 128.Generazione di Nuove Immagini
- Campionamento dallo spazio latente e utilizzo del decoder per generare nuove immagini.- Visualizzazione delle immagini generate usando Matplotlib.
Generazione delle Immagini
Il comando chiave per generare nuove immagini è:
random_latent_vectors = np.random.normal(size=(n_samples, latent_dim))
generated_images = decoder.predict(random_latent_vectors)
Campionamento: `np.random.normal(size=(n_samples, latent_dim))` campiona vettori latenti casuali da una distribuzione normale standard. Generazione: `decoder.predict(random_latent_vectors)` utilizza il decoder per generare immagini dai vettori latenti campionati.