Variational Autoencoders (VAEs; 変分オートエンコーダ) (理論)

# **あ**

今だにちょくちょくこの記事を参考にしていただけるのですが、次の記事にもうちょっと推敲して書き直したのでこちらを参照していただけると幸いです.

[Variational Autoencoders (VAEs)](http://cympfh.cc/paper/VAE.html)

(この記事自体を書きなおせばいいじゃんってのはナシで. Qiita でこれ以上ものを書きたくないので)

# 応用例

ちょっとググると次のようなものがヒットします

- [Variational Autoencoderでアルバムジャケットの生成 - Use At Your Own Risk](http://ryotakatoh.hatenablog.com/entry/2015/09/01/075301)
- [chainer-Variational-AutoEncoderを使ってみた - studylog/北の雲](http://studylog.hateblo.jp/entry/2015/09/21/103835)

すごいですね！

# 応用はいいから理論を教えて！

## 参考文献

1. Tutorial to Variational Autoencoders: [https://arxiv.org/pdf/1606.05908v2.pdf](https://arxiv.org/pdf/1606.05908v2.pdf)
1. Variational Auto-Encoders and Extensions: [http://dpkingma.com/wordpress/wp-content/uploads/2015/12/talk_nips_workshop_2015.pdf](http://dpkingma.com/wordpress/wp-content/uploads/2015/12/talk_nips_workshop_2015.pdf)
1. Variational Autoencoders Explained: [http://kvfrans.com/variational-autoencoders-explained/](http://kvfrans.com/variational-autoencoders-explained/)
1. Introduction to variational autoencoders: [https://home.zhaw.ch/~dueo/bbs/files/vae.pdf](https://home.zhaw.ch/~dueo/bbs/files/vae.pdf)

上から読むべき順

## (古典的) Autoencoder

現実世界のデータには冗長性があります. 線形数学の言葉で比喩すると線形従属です.
例えば写真なら、あるピクセルは周辺のピクセルによって割りとよい精度で補完されます.
そう考えるとそのピクセルが抜けていても元の画像を復元でき、ピクセルが抜けた写真は元の写真と同じだけの情報量を尚も保存しているわけです.
Autoencoder はこれと似たことを実際に行ってみせます.

形式的に記述すると、次の式を満たす関数 $f, g$ の2つ組が Autoencoder です.

- $t = f(x)$
- $x = g(t)$

合成関数 $g \circ f$ は恒等関数です.
ここで $\dim(t) \lt \dim(x)$ としましょう.
一見すると $t$ は $x$ に比べて次元が落ちているので情報量が落ちているようですが、$g$ によって元の $x$ を復元できているということは、情報量が保存されていることを示唆します.
$x$ からこのような $t$ を作る操作を一般的に (ニューラルネットワークの文脈に限らず) 「次元圧縮」と呼びます.
$x$ が何千次元なのに $\dim(t)=10$ で上を満たす $f, g$ が存在するなら、$x$ のランクは 10 以下でしょう (きっと).

普通オートエンコーダはニューラルネットワークで構成します.
即ち、関数 $f, g$ それぞれを多層パーセプトロンで構成します.
最後の出力と入力が出来るだけ (例えば最小自乗誤差という意味で) 近くなるように学習します.

> $t$ の次元を $x$ の次元以上にするとか、或いは $x$ にノイズを乗せるだとか、亜種はいくらでもある.

## Variational Autoencoder (VAE)

実データ $x$ の生成モデル自体を学習する方法です. 上に書いた Autoencoder の原理とは全く違いそうです.

### 生成モデル

データ $x$ が $n$ 次元の実ベクトルだとする ($x \in R^n$).
しかしながらデータに関して何かしらの制約 (顔写真に限定している) があるので、任意の点がデータになるわけではない.
何が言いたいのかと言えば、あり得るデータの空間 $\mathcal{X} \subset R^n$ がある.
生成モデルでは何かしらパラメータの下でデータ $x$ が生成されることを仮定する.

固定のパラメータ $\theta$ と、潜在変数 (latent variable) $z \in R^m$ があって $x$ が生成されるのだとする:

$$\mathcal{X} = \\{ x = f(z; \theta) : z \in R^m \\} \subset R^n.$$

いきなりデータ $x$ が天から降ってくるわけではなく、$z$ が確率 $P(z)$ で降ってくるのであって、これによって $x$ が自然に決まる.
では $x$ が得られる確率 $P(x)$ はというと、ここはベイジアン的にこう記述できる:

$$P(x) = \int dz P(x|z;\theta) P(z)$$

(確率の周辺化).

わざわざこのようなひと手間を加えるのは思うに、$x$ 特有の複雑さを $f$ に担わせることで $z$ 自体は単純化するできるからである.

$$z \sim \mathcal{N}(0, I)$$

という仮定を置いた生成モデルを仮定する.
従って $P(z) = \mathcal{N}(z | 0, I)$ です.

> $\mathcal{N}$ は正規分布のことである. 自然界のものは大体これに従っている (と言われる) が、恐らく $x$ 自体は正規分布でもなんでもないだろう.
> 平均をゼロにしているがこれは特に問題はない. $f$ でどうとでもできることだからである.
> また、$I$ は単位行列. これも強い単純化である.

### (古典的) Autoencoder との比較

古典的なAutoencoderの学習を擬似コードで書くと次のようになります:

```haskell
t = Encoder x
x' = Decoder t
loss = (x - x') ** 2
```

この $t$ を潜在変数 $z$ に置き換えてみましょう.
Decoder とは潜在変数から観測値を生成するモデルそのものであり、条件付き確率 $P(x|z)$ と言えます.
Encoder はちょうどその逆で、観測値から潜在変数を予測するモデル $P(z|x)$ です.

そう考えると、古典的なAutoencoderも生成モデルを学習していると主張できそうです.
しかし今回はそれにさらに制約を強く儲けています. 一つは先述した $P(z)$ がある正規分布に従っているという仮定です.
それ以外にも $X$ に関する条件付きの確率分布も正規分布だとします.

1. $P(z) = \mathcal{N}(z|0, I)$
1. $P(z|X) = \mathcal{N}(z|\mu(X), \Sigma(X))$

Encoder が $x$ から一つの潜在変数 $z$ を予測するだけだとしたら、その分布が確かに正規分布であることをどうやって確認するか.
Encoder は $x$ から直接正規分布を出力すればいい. 実際には2つのパラメータを予測すれば十分だから.
それから Decoder については、復元が十分であることを確認しさえすればいい.
確かに正規分布であることは、分布同士の比較だから、KL距離がある.
復元が十分であることは古典的なAutoencoder同様に自乗誤差がある.
ただこの損失関数については次章で詳細に述べる.

```haskell
(mu, sigma) = Encoder x
z <- Norm mu sigma
x' = Decoder z
loss = ...
```

### 損失関数 (目的関数)

Encoder は観測データ $x$ からそれを生成するであろう $z$ に関する分布 $P(z|x)$ を予測する.
真の確率 $P(z|x)$ に対してEncoderによる予測を $Q(z|x)$ と書くことにする.
この2つの分布の距離をKL距離によって測る.

- $\mathcal{D}_{KL}\left[Q(z|x) || P(z|x)\right]$
- $= \mathcal{E}_{z \sim Q(z|x)} \left[ \log Q(z|x) - \log P(z|x) \right]$
- $= \mathcal{E}_z \left[ \log Q(z|x) - \log P(x|z) - \log P(z) \right] + \log P(x)$
- $= \mathcal{D}_{KL}\left[Q(z|x)||P(z) \right]$
    - $- \mathcal{E}_z \left[ \log P(x|z) \right] + \log P(x)$

$\iff$

- $(\mathcal{L}=) ~ \log P(x) - \mathcal{D}_{KL}\left[ Q(z|x) || P(z|x) \right]$
- $= \mathcal{E}_z \left[\log P(x|z)\right]$
    - $- \mathcal{D}_{KL}\left[ Q(z|x) || P(z) \right]$

この式こそがVAEの根幹を為すものである.

左辺を改めて見てみる.

1. $Q(z|x)$, $P(z|x)$ は近いほうが良い
    - KL距離は確率分布が完全に一致するときのみゼロでそれ以外では正
    - なのでここでは小さくゼロに近いほど良い
1. $P(x)$ はそのまま観測確率である
    - 高くて然るべきである

右辺に解釈を与える.

1. $P(x|z)$ を与えられた $z$ から $x$ を生成するDecoder だとする
1. $Q(z|x)$ は与えられた $x$ から $z$ の分布を予測する Encoder だとする
1. $P(z)$ は先程言ったように $\mathcal{N}(z|0,I)$ である

右辺の2項目目は直接計算することができる:

- $\mathcal{D}_{KL}\left[ Q(z|X) || P(z) \right]$
- $= \mathcal{D}_{KL}\left[ \mathcal{N}(z|\mu(X), \Sigma(X)) || \mathcal{N}(z|0, I) \right]$
- $= (1/2) \left[ tr \Sigma(X) + \mu(X)^T \mu(X) - k - \log ~ \det \Sigma(X) \right]$


ここで $k$ は $z$ の次元.

では一項目の $\mathcal{E}\left[ \ldots \right]$ はどうするか.
素直に計算するならば、Encoder が予測した分布に従って $z$ をサンプリングしたものを Decoder して平均をとることになる.
問題は大きく2つある. 一つはサンプリングに関する問題だが、これは次章 (Reparameterization trick) で、一つは Decoder 部分は与えられた $x, z$ に関して $P(x|z) \in \mathbb{R}$ を予測するものではなく、
$z$ から入力 $x$ を復元するような $x'$ を生成するものであってほしい. これは Autoencoder という枠組みから来る要請である.

$\log P(x|z)$ を $- (x - x')^2$ で誤魔化すことにする.

$z$ から入力 $x$ が生成される確率が低いとき $\log P(x|z) \ll 0$ で、Decoder による復元 $x'$ も $x$ から十分離れるため $- (x - x')^2 \ll 0$ である.
逆に (極端に) $z$ から入力 $x$ がいつも生成されるなら $\log P(x|z) = 0$ で Decoder による復元も完璧になるから $- (x - x') = 0$ である.

以上から、損失関数としては次がふさわしい (次を最小化したい)

$$\mathcal{L}' = (x' - x)^2 + \mathcal{D}_{KL}\left[ Q(z|x) || P(z) \right]$$

以上を行う計算グラフを記述すると次のようになる.
ここで実践による矢印は通常のニューラルネットワークにおける順伝播であるが、点線は分布からのサンプリングである.

![vae0.png](https://qiita-image-store.s3.amazonaws.com/0/17022/abc73e5c-a2ac-2035-b44a-e01855f66213.png)


### Reparameterization trick

先ほどの計算グラフを見れば分かるように順伝播は途中で途切れている.
従って $x'$ から計算した損失を Encoder まで逆伝播させることができない.
サンプリングという行為の為である.
Reparameterization trick と呼ばれるテクによって伝播を繋げることが可能.

つまり、

$$\mathcal{N}(\mu, \Sigma) = \mu + \Sigma^{1/2} \cdot \mathcal{N}(0, I)$$

を使えば、サンプリングするのは $\epsilon \sim \mathcal{N}(0, I)$ として、$z$ を生成することができる.
計算グラフは次のようになり、逆伝播が可能.

![vae1.png](https://qiita-image-store.s3.amazonaws.com/0/17022/44667e70-e4c4-3cee-02c1-f2f4329c1d56.png)


# 理論はいいから実装

- https://github.com/cympfh/vae-icons

実装するだけならぶっちゃけめっちゃ簡単.
普通のAutoencoderにKL距離をロスに加えるだけ.
chainer ならN(0,1) とのKL距離を計算するためだけの関数もある.