6.9 KiB
video consigliato prima di leggere: https://www.youtube.com/watch?v=hZ4a4NgM3u0
Un autoencoder è una rete neurale feed-forward: !
L'obiettivo di un autoencoder è ricostruire esattamente l'input x (prende x in input e restituisce una cosa molto simile ad x in output, che chiameremo x_{hat}
).
Nell'immagine, l'hidden layer ha una dimensionalità decisamente inferiore rispetto all'input. Questo costringe il modello ad imparare le feature principali dall'input, per poterlo ricostruire nel modo più simile possibile. Quell'hidden layer viene detto latent space.
L'errore nella ricostruzione x_{hat}
di x
è il classico Mean Squared Error (MSE), che useremo come loss function.
Questa roba si può usare per tante cose:
- si può usare per estrarre feature (un po' come fa il PCA), in questo caso dopo il training mi interessa considerare la parte di encoding
- nei modelli generativi viene invece usata anche parte di decoding, ad esempio un possibile utilizzo è un modello che rimuove il rumore dalle immagini: imparerà ad estrarre i pattern importanti dell'immagine (non il rumore), e poi sulla base di questi ricostruire un'immagine più clean.
Possibili impieghi:
- riduzione della dimensionalità
- compressione dei dati mantenendo le informazioni importanti
- imparare feature per altri task
- utilizzare dati senza label: il training è unsupervised, non servono label. Ci sono scenari in cui non si hanno a disposizione le label, o magari le si hanno solo per un piccolo sottoinsieme dei dati. In quest'ultimo caso posso fare un training iniziale con un autoencoder, poi sostituisco il decoder con dei layer di classificazione (es. linear layer + softmax) e faccio fine tuning con i dati con label a disposizione.
Autoencoder lineari
- un solo hidden layer, con activation function lineari
- possiamo esprimere
x_{hat}
come una trasformazione lineare dix
!Pasted image 20241129144016.pngx_{hat} = UVx
Hey, sembra molto simile al PCA questa cosa... Esatto, perché questo è letteralmente il PCA! Se invece di fare training utilizziamo PCA, V (la matrice dei pesi del layer di encoding) non sarà altro che l'autovettore del PCA. U (matrice di pesi del layer di decoding) sarà la trasposta di V.
Eigenfaces
Le eigenfaces sono le componenti principali di un grosso insieme di facce (immagini di volti), e possono essere usate in task di face recognition. Come?
- si appiattiscono le facce, passando da 2D a 1D (classico flattening di una matrice)
- si centrano tutte le facce
- si calcola il valore medio di tutte le facce e lo si sottrae a ogni faccia, in modo che i dati siano centrati attorno lo zero. Praticamente è una normalizzazione, ma "normalizziamo solo la media" e non la varianza
- si applica PCA all'insieme di facce e si tengono le
k
facce che catturano la maggior parte della varianza. Gli autovettori che otterremo si chiamano eigenfaces - qualsiasi faccia può essere rappresentata come combinazione lineare di queste eigenfaces
- per vedere se due facce sono simili mi basterà usare una metrica di distanza tipo la distanza euclidea, o la cosine similarity ecc.
Limitazioni:
- sensibile a variazioni PIE
- il dataset di train deve includere molta diversità
- non riesce a catturare le variazioni non lineari di una faccia, dal momento che PCA è lineare!
Deep autoencoders
Ecco, ora arriva la parte interessante. Invece di proiettare i dati su un sottospazio, i deep autoencoders lo fanno su un manifold non lineare: !Pasted image 20241129145900.png
Stacked autoencoders
Si possono usare più layer di encoding? Certo! !Pasted image 20241129150041.png
E non solo... Posso anche semplificare il training trainando un pezzettino per volta: !Pasted image 20241129150144.png
Dimensione hidden layer
Undercomplete autoencoders:
- quelli la cui dimensione degli hidden layer è inferiore alla dimensione di input e output
- riduzione dimensionalità (il latent space ha dimensionalità minore appunto)
- forza il modello a imparare rappresentazioni sensate dei dati, assicurandosi che non vada semplicemente a memorizzarli
- ma potrebbe perdere informazioni utili se i dati in input sono molto complessi o la loro dimensionalità è alta
Overcomplete autoencoders:
- l'opposto, letteralmente. Gli hidden layers sono più grandi
- può catturare una rappresentazione più ricca dei dati
- ma... senza opportuni vincoli, memorizzerà i dati in input e basta :/
- La soluzione sono gli sparse autoencoders, che introducono vincoli.
Sparse autoencoders
Si vuole aggiungere un vincolo che forza l'attivazione solo di alcuni neuroni per volta.
- Aiuta a ottenere rappresentazioni più interpretabili, in cui ogni neurone rappresenta una caratteristica specifica.
- Riduce il rischio di overfitting, poiché forza il modello a rappresentare i dati in modo più compatto.
- È ispirato al funzionamento biologico del cervello, dove solo poche regioni neurali si attivano contemporaneamente.
Come? Introducendo un meccanismo di penalizzazione, per cui la loss diventerà: L = ||X - \hat{X}||^2 + \lambda \cdot \text{Penalty}(s)
Si possono usare due penalty mechanism:
Regolarizzazione L1
La regolarizzazione L1 penalizza direttamente i valori assoluti delle attivazioni dell'hidden layer aggiungendo un termine proporzionale alla loro somma nella loss function. In pratica, incoraggia molte attivazioni a essere esattamente zero, ottenendo una rappresentazione più sparsa. La loss function sarà:
L = \text{MSE} + \lambda \sum_{i,j} |z_j^{(i)}|
Dove z_{j}^i
è il valore di attivazione del neurone j per il campione i
(p.s. per attivazione si intende il valore numerico prodotto in output dal neurone)
KL Divergence
La KL Divergence misura la "distanza" tra due distribuzioni di probabilità. Negli sparse autoencoders, viene utilizzata per confrontare la distribuzione delle attivazioni dei neuroni nell'hidden layer con una distribuzione desiderata che promuova la sparsità.
Ad esempio, se sceglo di avere una sparsità di 0.05
KL(ρ∣∣a^j)=rhologρa^j+(1−ρ)log1−ρ1−a^jKL(\rho || \hat{a}_j) = \rho \log \frac{\rho}{\hat{a}_j} + (1 - \rho) \log \frac{1 - \rho}{1 - \hat{a}_j}
\rho
: valore desiderato di sparsità (es. 0.05).\hat{a}_j
: attivazione media del neurone jj calcolata su tutto il dataset.
In questo modo penalizziamo sia i neuroni che si attivano troppo, sia quelli che si attivano troppo poco. Questo forza l'autoencoder a trovare rappresentazioni latenti che coinvolgano pochi neuroni attivi, garantendo una maggiore efficienza e interpretabilità.
- Vantaggi:
- Rende le rappresentazioni più interpretabili.
- Riduce il rischio di overfitting.
- Può aiutare nella separazione delle caratteristiche nei dati.
- Considerazioni:
- La scelta di ρ e β è cruciale: valori troppo grandi possono rendere il training instabile.
- La penalizzazione introdotta dalla KL Divergence può rendere l'ottimizzazione più lenta.