論文まとめ Triple Generative Adversarial Nets

#はじめに

NIPS2017から C. Li らの Triple Generative Adversarial Nets をまとめてみた。

論文はこちら
[1] http://papers.nips.cc/paper/6997-triple-generative-adversarial-nets.pdf

著者らのコードはこちら。
[2] https://github.com/zhenxuan00/triple-gan

定理の証明やモデルの詳細等はこちら
[3] http://papers.nips.cc/paper/6997-triple-generative-adversarial-nets-supplemental.zip

#要点
一般的なGANsモデルは２つの問題点を抱えている。１つは Generator と Discriminator を同時に学習できない点、もう１つは Generator で生成されるサンプルの意味をコントロールできない点である。

この問題点は Discriminator が偽物のサンプルを見分けると同時にそのラベルを予測するという矛盾した役割をし、結果ラベルを考慮することなくデータを推定するところからきている。

この問題にとりくむため Generator と discriminator に加えて Classifier を用いた。

Generator と Classifier は画像とそのラベル間の条件付き確率分布を特徴化し、Discriminator は偽物の（画像ーラベルの）ペアか否かを判断する。

この仕組みにより state-of-the-art な分類性能を達成した。

#モデルのアーキテクチャ
モデルの全体図は以下。

<img width="823" alt="スクリーンショット 2018-01-07 21.28.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/116706/d9805b04-59ac-6878-810e-da31fb33bfa0.png">

【図１　Triple-GANsのアーキテクチャ　[1]のFigure 1より】

一様乱数などに従うノイズ $Z_g \sim p_z(Z)$ とそのラベル $Y_g \sim p(Y)$ を Generator に入れると (X, Y) のペア $(X_g, Y_g) \sim p_g (X, Y)$ が生成される。

この X を Classifier に入れて Y との交差エントロピーを取ることで Classifier を学習させる。

また実際の画像とそのラベルのペア $(X_l, Y_l) \sim p(X, Y)$ のうちの X もclassifer に入れ、Y との交差エントロピーを取ることで、やはり Classifier を学習させる。

一方で Classifier にはラベルのない画像 $X_c \sim p(X)$ も入れ、ラベルを推定させる。

Discriminator には１） $(X_g, Y_g) \sim p_g (X, Y)$ 、２） $(X_l, Y_l) \sim p(X, Y)$ 、３）$X_c \sim p(X)$ を入れ、画像とラベルのペアが正しい（accceptance）か否か（reject）かを判断させる。

###min max な式
GANs の min max な式は以下

```math
\min_{C,G} \max_D U(C,G,D) = E_{(x,y) \sim p(x,y)}[\log D(x,y)] + \alpha E_{(x,y) \sim p_c (x,y)}[\log (1-D(x,y))]\\ + (1 - \alpha)E_{(x,y) \sim (p_g (x,y)} [\log (1-D(G(y,z),y))] + \mathcal{R_L}
```

第１項目が正しい画像とラベルのペア。第２項目が classifier で推測されたラベルと画像のペア。第３項目が generator で生成された画像とラベルのペア。第４項目が正しいペアによる classifier の学習部分。

#勾配
###Discriminator の勾配
Discriminator の勾配は入ってくる $(x,y) \sim p(x,y)$ を 正解ペア（acceptance）と判断し、$(x,y) \sim p_c (x,y)$ と $(x,y) \sim (p_g (x,y)$ を不正解ペア（rejecttion）と判定するよう学習するので以下の adversarial な部分のみ。

```math
\nabla_{\theta_d} \left[ \frac{1}{m_d}(\sum_{(x_d,y_d)} \log D(x_d,y_d) ) + \frac{\alpha}{m_c}(\sum_{(x_c,y_c)} \log(1- D(x_c,y_c) ) + \frac{1 - \alpha}{m_g}(\sum_{(x_g,y_g)} \log(1- D(x_g,y_g)) \right]
```

これを勾配上昇法で学習させる。

###Generator の勾配
Generator の勾配も Adversarial な部分のみ。

```math
\nabla_{\theta_g} \left[ \frac{1 - \alpha}{m_g} \sum_{(x_g,y_g)} \log (1 - D(x_g,y_g) ) \right]
```

###Classifier の勾配
一方で Classifier の場合は adversarial な勾配だけではうまくいかない可能性が考えられる。

$p(x,y) = p_g(x,y) = p_c(x,y)$ としたいわけだが、この収束値に向かわないかもしれない。

そこで

```math
\mathcal{R_L}=E_{(x,y) \sim (x,y)}[- \log p_c (y|x)]
```

として実際のデータで Classifier を教師あり学習させる項が１つ。これにより $p(x,y) = p_c(x,y)$ を狙う。さらに

```math
\mathcal{R_P}=E_{(x,y) \sim (x_g,y_g)}[- \log p_c (y|x)]
```

として Generator で生成された画像とラベルの擬似的なペアで教師あり学習させる項が１つ。これにより $p_g(x,y) = p_c(x,y)$ を狙う。

以上と adversarial な部分を用いて classifier の勾配は以下のようになる。

```math
\nabla_{\theta_c} \left[ \frac{\alpha}{m_c} \sum_{(x_c,y_c)} p_c(y_c|x_c) \log (1-D(x_c,y_c)) + \mathcal{R_L} + \alpha_{\mathcal{P}} \mathcal{R_P} \right]
```

#実験と結果
MNIST、SVHN、CIFAR10のデータセットで実験した。

###classifier の実験結果
学習後の Classifier の性能は以下。

<img width="847" alt="スクリーンショット 2018-01-07 21.28.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/116706/79f76150-32a8-750b-4c31-ac02b28b3c70.png">

【図２ 学習後 classifier の Error rate の比較】

いずれのデータセットにおいても高い性能を発揮している。

###generator の実験結果
以下の画像が学習後 generator により生成された画像
<img width="845" alt="スクリーンショット 2018-01-07 21.28.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/116706/a1b4c60b-b6ed-2aec-17c4-d167cf7fd45d.png">

【図３　学習後 generator で生成された画像】

いい感じで生成されている

#サンプルコード
chainerを用いたコードとtensorflowを用いたコードを作りました。

###chainerを用いたコード
chainerを用いたコードはGitHub上のこちらにUPしました。
https://github.com/masataka46/tripleGAN_chainer

chainerはVer.3系を使ってますが、trainerとか最近の仕組みはよくわからないので、古い書き方をしてます。

またgaussian noiseの実装方法がわからないので、その部分は書いてないです。

###tensorflowを用いたコード
tensorflowを用いたコードはGitHub上のこちらにUPしました。
https://github.com/masataka46/tripleGAN

一部にバグがあると思います。（Genertorに異なるラベルを入れたにも関わらず、同じタイプの画像が出力される症状が学習進行後も改善されません）

tensorflowのコードに関しては別のデータセットを用いたサンプルが既に存在します。そちらもご参考下さい。
https://github.com/taki0112/TripleGAN-Tensorflow

#Generatorからの出力結果
以下は作成したchainerコードによる出力結果です。Generatorに10種類のノイズ x 及び10種類のラベルを入力し、その出力を表示させています。

画像の横方向がノイズのパターン、縦方向がラベル（数字）となります。

学習１回
![resultImage_0.png](https://qiita-image-store.s3.amazonaws.com/0/116706/56b8b02f-6490-f5d6-eb42-e13a1ad4bad1.png)

学習１０回
![resultImage_10.png](https://qiita-image-store.s3.amazonaws.com/0/116706/01e4a346-3726-0c97-7d09-83e578d1dafd.png)

学習１００回
![resultImage_100.png](https://qiita-image-store.s3.amazonaws.com/0/116706/3dfdf8e0-8e80-2cd6-1e84-7c186ae0a181.png)

学習５００回
![resultImage_580.png](https://qiita-image-store.s3.amazonaws.com/0/116706/6059faf5-511f-b19f-c5d7-fc30e7bc36b9.png)