7.4 KiB
Visione fortemente consigliata: https://www.youtube.com/watch?v=qJeaCHQ1k2w
La differenza è che se un autoencoder "normale", durante l'encoding mi genera un vettore dello spazio latente, un variational autoencoder mi genererà una distribuzione di probabilità (in termini di media e varianza di una distribuzione normale). Prendendo campioni da questa distribuzione e mandandoli in input al decoder, otterrò immagini simili.
Le distribuzioni
(p.s. supporrò che i vettori x siano immagini)
p(x)
: la vera distribuzione di x, ovvero la distribuzione del dataset. NON LA SI CONOSCE, altrimenti sarebbe tutto bello.
Esempio: ipotizzando di avere un dataset con immagini di numeri, un'immagine che rappresenta il numero "1" avrà un valore alto di p(x)
, un'immagine che rappresenta un cazzo curvo avrà un valore basso di p(x)
.
p(z)
la distribuzione della variabile latente. Solitamente si usa una gaussiana N(0, I)
, dove I è la matrice identità. La dimensione della matrice è la dimensione dello spazio latente z: ogni z_{i}
ha valore medio 0 e varianza 1.
p(z|x)
: distribuzione condizionale associata all'encoder, non la conosciamo. Possiamo anche vederla come la likelihood di z per un certo x ("qual è la probabilità di generare questo vettore z dato che l'immagine in input è x?")
p(x|z)
: distribuzione condizionale associata al decoder ("qual è la probabilità di generare l'immagine x, dato che il vettore nello spazio latente è z?")
Non conoscendo p(z|x)
, usiamo un encoder parametrizzato con \phi
come "proxy": $$(\mu, \sigma^2) = Encoder_{\phi}(x) \to q_{\phi}(z|x)=N(z|\mu,\sigma^2I)$$ma non conosciamo ancora i parametri \mu
e \sigma
, dobbiamo impararli.
Non conoscendo p(x|z)
, usiamo un decoder parametrizzato con \theta
come "proxy": f_{\theta}(z) = Decoder_{\theta}(z) \to p_{\theta}(x|z)=N(x,|f_{\theta}(z),\sigma²I)
p.s. \phi
e \theta
rappresentano i parametri dell'encoder e del decoder (sono quindi i weight e i bias).
Massimizzare la likelihood
Il nostro obiettivo è di massimizzare log\ p(x)
. Perché log? Per i soliti motivi: calcoli più semplici e meno numerical instabilities (divisioni per 0 ecc.).
È difficile, anzi impossibile visto che è intrattabile, ma wait, perché è intrattabile? Facciamo un passo indietro:
- sappiamo cosa sono
p(x)
ep(z)
- consideriamo ora la joint distribution
p(x, z)
: probabilità di osservare l'immagine x e il vettore z nel latent space - possiamo dire usando la formula di Bayes che
p(x,z)=p(x∣z)p(z)
, ovvero chep(x, z)
è la probabilità di generare l'immagine x dato il vettore z, per la probabilità di osservare il vettore z. - allora si ha che
p(x) = \int p(x \mid z) p(z) \, dz
(se mi interessa la probabilità di x, integro per tutti gli z)
A questo punto io vorrei massimizzare \log\ p(x) = \log\ \int p(x,z) \, dz
ma come faccio se non posso calcolare l'integrale esatto (mica conosco quelle distribuzioni) e non posso semplificarlo ulteriormente? Posso provare a definire un lower bound (un qualcosa che è sempre minore di log\ p(x)
e che però posso calcolarlo).
Posso usare un trick e moltiplicare \frac{q_\phi(z \mid x)}{q_\phi(z \mid x)} = 1
dentro l'integrale: \log p(x) = \log \int p(x,z) \frac{q_\phi(z \mid x)}{q_\phi(z \mid x)} \, dz
Interpretandola notiamo che \int q_\phi(z \mid x)\ dz
non è altro che il valore atteso di quella distribuzione: log\ p(x) = \log \mathbb{E}_{{q_{\phi}(z|x)}}\left[ \frac{p(x, z)}{q_{\phi}(z|x)} \right]
Usando la disuguaglianza di Jensen, sposto il log dentro e ottengo: log\ p(x) \geq \mathbb{E}_{{q_{\phi}(z|x)}}\left[\log \frac{p(x, z)}{q_{\phi}(z|x)} \right]
Ora uso la formula di Bayes per sostituire p(x,z)
come descritto prima: log\ p(x) \geq \mathbb{E}_{{q_{\phi}(z|x)}}\left[\log \frac{p(x∣z)p(z)}{q_{\phi}(z|x)} \right]
Ora splitto in due il logaritmo (uso le proprietà solite dei logaritmi): log\ p(x) \geq \mathbb{E}_{{q_{\phi}(z|x)}}\left[\log p(x∣z) + \log \frac{p(z)}{q_{\phi}(z|x)} \right]
= \mathbb{E}_{{q_{\phi}(z|x)}}\left[\log p(x∣z)\right] + \mathbb{E}_{{q_{\phi}(z|x)}}\left[\log \frac{p(z)}{q_{\phi}(z|x)} \right]
Ma hey, la seconda parte è la formula della KL divergenza! = \mathbb{E}_{{q_{\phi}(z|x)}}\left[\log p(x∣z)\right] + D_{KL}(q_{\phi}(x|z)||p(z))
Ora possiamo usare questa come funzione loss. La prima parte ci indica quanto bene il modello (decoder) genera l'immagine x dato il vettore z nello spazio latente, è quindi una misura della qualità della ricostruzione dei dati, dovrà essere ottimizzata per migliorare la capacità del modello di ricostruire correttamente gli input x.
La seconda parte viene usata come termine di penalizzazione: penalizza il modello se la distribuzione approssimativa q_{\phi}(z|x)
si discosta troppo dalla reale p(z)
(che conosciamo, è una gaussiana con media 0 e varianza 1, come detto inizialmente).
Backpropagation
Il problema resta che ok, possiamo calcolare la loss, ma possiamo anche fare la backpropagation?
Dovremmo poter derivare la loss (quindi l'ELBO nel nostro caso), si può? No.
Perché non si può derivare? Non lo so, erano più di due pagine per calcolare una derivata e ho scelto un CdL in computer science, mica in matematica, però fidatevi, l'ELBO sebbene risulta derivabile per \theta
, non lo è però per \phi
, quindi è impossibile calcolare il suo gradiente.
Possiamo risolvere questo problema usando un trick, il reparametrization trick:
Reparametrization trick
Trick che risolve questo problema. Invece di prendere campioni direttamente da q_{\phi}(z∣x)
, introduciamo una variabile aleatoria \epsilon
per poter gestire la randomness "esternamente".
Anziché campionare z direttamente da q_\phi(z|x)
, possiamo scrivere z come:
z = \mu_{\phi}(x) + \sigma_{\phi}(x) \cdot \epsilon
dove:
\mu_{\phi}(x)
e\sigma_{\phi}(x)
sono rispettivamente la media e la deviazione standard diq_\phi(z|x)
, sono i valori restituiti dal modello encoder che ha preso x in input\epsilon
è una variabile casuale campionata da una distribuzione gaussiana standard\epsilon \sim \mathcal{N}(0, I)
.
Con questo trick sgravatissimo ho che \epsilon
non dipende più da \phi
e quindi non ho problemi a fare la derivata, yeee.
La nostra funzione di penalizzazione, che ricordiamo essere definita come: D_{KL}(q_{\phi}(x|z)||p(z))
, diventa: D_{KL}(q_{\phi}(g(\epsilon)|z)||p(z))
, e se la espandiamo con la formula della KL-divergenza per una distribuzione normale, dopo semplificazioni varie esce fuori: -\frac{1}{2}(1+\log \sigma_{\phi}(x)^2-\mu_{\phi}(x)^2-\sigma_{\phi}(x)^2)
Rimane una cosa da capire, come calcolo la parte a sinistra dell'ELBO?$$= \mathbb{E}{{q{\phi}(z|x)}}\left[\log p(x∣z)\right]
La risposta in realtà è semplice, guardiamola bene... È il valore medio della probabilità, sotto la distribuzione
q_{\phi}(z|x)
, di osservare l'immagine generata x, dato che il vettore nello spazio latente è z
(ci riferiamo quindi al decoder).
In pratica, se il decoder genera un'immagine molto simile a x, questo valore sarà alto! Se genera un'immagine che non c'entra una sega, sarà molto basso! Per cui è letteralmente la log likelihood! E la possiamo calcolare quindi come già sappiamo fare! Possiamo banalmente fare il mean squared error tra l'immagine originale e quella generata.
Così posso finalmente fare la backpropagation e trainare quindi il modello come una normalissima rete neurale, usando un optimizer qualsiasi come ad es. Adam.