---
# System prepended metadata

title: VAE (Variation Autoencoder)
tags: [Encoder, KL Divergence, CNN, Decoder]

---

# VAE (Variation Autoencoder)

[TOC]


**Github Code** : https://github.com/jason19990305/VAE.git

## Introduction


**Auto-Encoder** 代表這個 **Neural Networ** 有 **Encoder** 和 **Decoder** 兩個過程，Input 的大小會壓縮的很小，變成 **Code**，然後 **Decoder** 透過這個 **Code** 計算出 **Output**，這個 Output 要跟 **Input** 的資料越接近越好，這邊的 **NN** 也可以用 **CNN**，拿 **MNIST** 手寫數字這個資料集來描述，大致流程如下


1. **Conv2d、MaxPooling** : `1x28x28` -> `16x14x14`
2. **Conv2d、MaxPooling** : `16x14x14` -> `32x7x7`
3. **Flatten** : `32x7x7=1568`
4. **Linear** : `1568 -> 10`

這個部分就是 **Encoder**，最後會 **Output** 出維度為 **10** 的 **Vector**

**Decoder** 則負責從向量恢復成原來的樣子，也就是變成原來的手寫數字
1. **Linear** : `10 -> 1568`
2. **Reshape** : `1568 -> 32x7x7`
3. **ConvTranspose2d** : `32x7x7` -> `16x14x14`
4. **ConvTranspose2d** : `16x14x14` -> `1x28x28`

**ConvTranspose2d** : 
![image](https://hackmd.io/_uploads/BJVR0LqBWg.png)

這樣就可以用來訓練能恢復原本圖片的 **Neural Network**







## VAE


![image](https://hackmd.io/_uploads/HkV4RW9SZe.png)

**VAE (Variational Auto-Encoder)** 與 **Auto-Encoder** 的差異，就是將 **Encoder** 的 **Output Code**，變成用 $\mu$ 和 $\sigma$ 來描述，其實也就是用 **Probability Distribution** 來描述一張圖，並透過重參數化技巧(**Reparameterize**)，在訓練期間加入雜訊，然後 **Decoder** 一樣用來恢復圖片，**VAE** 對於生成圖片的效果並沒有到很好，生成的圖片通常不構銳利，基本上都是蠻模糊的，但他在 **Encoder** 的部分卻有很多用處，因為訓練時帶入雜訊，所以抗噪能力強，不會死記硬背，能夠較好的學習圖片的相似度，所以他會是一個很 **General** 的降維、提取特徵 **Model**。



## Forward


**Encoder** : 
1. **Conv2d、MaxPooling** : `1x28x28` -> `16x14x14`
2. **Conv2d、MaxPooling** : `16x14x14` -> `32x7x7`
3. **Flatten** : `32x7x7=1568`
4. **mu,logvar** : `1568 -> 10`，**10** 是可設定的 **Latent Size**，用一個 **Linear Layer** 分別產生 $\mu$ 和 $\log\sigma^2$
5. **Reparameterize** : $z=\mu + \sigma\epsilon$

**Decoder** : 
1. **Linear** : `10 -> 1568`，恢復大小
2. **Reshape** : `1568 -> 32x7x7`
3. **ConvTranspose2d** : `32x7x7` -> `16x14x14`
4. **ConvTranspose2d** : `16x14x14` -> `1x28x28` 恢復原圖


## Reparameterize


**VAE** 的算法，就是要在 **Encoder** 的 **Output** 加入雜訊，雜訊生成的方式會讓 **Encoder** 自己決定，生成雜訊的參數都是 **Encoder** 自己產生，但是還要搭配 **Normal Distribution**， $z\sim\mathcal{N}(\mu,\sigma)$，但是為了讓訓練能正確傳遞 **Gradient** 而產生的，寫法會變成 $z=\mu + \sigma \epsilon$


那為什麼要對 **Code** 加入雜訊? **Encoder** 的輸出就像一個數字如 0~9，而 **Decoder** 就像查表一樣去恢復這個數字

## KL Divergence


**Neural Network** 為了讓訓練效果變好，在 **Training** 的過程中可能會希望雜訊越小越好，然後把 $\sigma$ 調整的非常低，但這樣就失去我們要的效果了，所以我們會在 **Loss Function** 動手腳，用來限制 $\sigma$ 不要太小，**VAE** 用的方法就是讓 **KL Divergence** 計算 **Distribution** $Q(z)$ 和 $\mathcal{N}(0,I)$ 之間的不相似度，目的就是讓 $Q(z)$ 可以越接近 $\mathcal{N}(0,I)$ 越好，因為 **KL Divergence** 用來當作 **Loss**，**Training** 過程會讓不相似度降低，所以 $\sigma$ 會接近 **1**


**KL Divergence** 定義 : 
$$
KL(Q||P)=\int Q(z)\cdot\log(\frac{Q(z)}{P(z)})dz
$$

可以用來評估 **Distribution** $Q(z)$ 和 $P(z)$ 之間的不相似度，數值越大代表差距越大，實際計算方式

$$
\int \mathcal{N}(\mu,\sigma^2)\cdot(\frac{\mathcal{N}(\mu,\sigma^2)}{\mathcal{N}(0,I)})
$$


![image](https://hackmd.io/_uploads/rkOZ3uqHbx.png)

最右邊的顏色深度，代表左邊兩個 Distribution 的差異度，顏色越深代表差越多，所以可以發現重疊的部分深度是較低的，因為機率相似，但 KL Divergence 最後是只吐出一個數值，不會像圖片那樣

**Normal Distribution PDF** : $f(x) = \frac{1}{\sqrt{2\pi}\sigma} e^{-\frac{(x-\mu)^2}{2\sigma^2}}$

帶入並簡化後就變成 : 

$$
-0.5\sum(1+\log(\sigma^2)-\mu^2-\sigma^2)
$$

簡化流程可參考 : https://tomohiroliu22.medium.com/%E6%B7%B1%E5%BA%A6%E5%AD%B8%E7%BF%92paper%E7%B3%BB%E5%88%97-04-variational-autoencoder-vae-a7fbc67f0a2

然後恢復圖片的 **Loss** 就直接用 **MSE(Mean Square Error)** 來算圖片間的差異就好，或是可以用 **BCE(Binary Crocc-Entropy)** 來算也沒問題



## Result


訓練完成後要生成圖片時，就直接給 **Latent Size** 的數字，然後直接 **Call Decoder**，不通過 **Encoder** 和 **Reparameterize**，等於直接用無雜訊的 $\mu$ 來生成

![image](https://hackmd.io/_uploads/SJMDSt9rWe.png)


VAE 的問題就是生成圖片很模糊，但後來 **Stable-Diffusion** 其實還是有使用，但不會拿來做為生成圖片的 **Decoder**


