[最新論文]MirrorGANをKerasで実装した話

# MirrorGANとは
先月（２０１９年３月）に発表された、GANを使ったテキストから画像を生成する（text to image）研究の論文です。現在、CVPR2019にも承認されているようです。

[MirrorGANの本家論文](https://arxiv.org/abs/1903.05854)
[実装したコードはこちらです！](https://github.com/komiya-m/MirrorGAN)
<img width="1110" alt="スクリーンショット 2019-04-27 17.12.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/20b809cd-8ad0-575f-7065-c6b2b677c74d.png">
 インプットのテキストと生成された画像
## ミラー構造
MirrorGANはT2I(text to image)とI2T（image to text)の両方を統合することによってミラー構造となっています。
文章からGANで画像を出力し、それを元に文章を再生成することでT2I生成を学ぶという仕組みです。

![2019-03-20-143455.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/00469c67-f8ba-8594-1b5d-2d8a9b830fbf.jpeg)
![2019-03-20-143136.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/71a2893b-7d2d-ee87-dabc-6fad0aa158cc.jpeg)
# MirrorGANの3つのコアモジュールの構造
MirrorGANは、「テキストから画像への再記述学習生成」という3つのモジュールからなリます。
・ セマンティックテキスト埋め込みモジュール（STEM）
・ カスケード画像生成グローバル - ローカル共同注意モジュール（GLAM）
・ セマンティックテキストの再生成および整列モジュール（STREAM）

## セマンティックテキスト埋め込みモジュール STEM
Embedding（埋め込み）を行い、RNNを通しています。
RNNの$h_t$（つまりシーケンスごとの出力）がword_feature_w（ワードごとの特徴）。
最終の出力がsentence_feature_s（文章全体の特徴）となります。
今回の実装では、Embeddingレイヤーと双方向GRUを使用しました。

<img width="248" alt="スクリーンショット 2019-04-27 18.00.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/180cf699-7f2b-bccf-2b3b-7194d12e1dd3.png">

## カスケード画像生成グローバル - ローカル共同注意モジュール GLAM
ここがGANで画像生成する部分になります。
図ではわかりにくいのですが、実はGANが３層構造になっています。
Generator=$G_i$
$G_0$で64x64サイズの$f_0$を出力→$G_1$で128x128サイズの$f_1$を出力→$G_2$で256x256サイズの画像を出力という形です。各Gに対応するDiscriminatorもそれぞれ3つ存在しています。
これはいきなり256x256のサイズでトレーニングしてもうまくいかないからです。$G_0$だけでまずトレーニングを始めることになるので階層になっています。
<img width="534" alt="スクリーンショット 2019-04-27 18.01.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/962467e0-eae7-0356-5f97-79198b24da13.png">

まず、sentence_feature_s（文章全体の特徴）をconditioning augmentationします。

テキストのエンコードは非線形の変換となるため、Generatorへの入力となる潜在変数は偏りが生じることがわかっていて、この問題を解決するために、conditioning augmentationを行なっています。
conditioning augmentationすることで多様性を維持することができ、少ない入力テキスト表現から幅広い分布を生成することができるようです。詳しくは[StackGAN](https://arxiv.org/abs/1612.03242)の論文をみてみてください。

<img width="174" alt="スクリーンショット 2019-04-27 18.30.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/66df0562-ea30-2fcc-aa12-b07a63f25fc6.png">
<img width="332" alt="スクリーンショット 2019-04-27 19.30.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/3693080c-47dc-185c-44ae-572cd060ce6e.png">
conditioning augmentationの実装。
<img width="608" alt="スクリーンショット 2019-04-30 11.06.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/b9048dfb-83c5-df33-d793-d01ba5be3f14.png">


そして$Sca$と$Z$をconcatします。これが最初のGenerater($G_0$)の入力になります。
$I_i$は出力された画像。
<img width="178" alt="スクリーンショット 2019-04-27 19.37.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/5dce4cff-85b2-e553-df2a-3bb4030550fd.png">
<img width="393" alt="スクリーンショット 2019-04-27 19.41.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/bc572877-bd88-a082-e80d-dc389deaa494.png">


# Attention
Source-Target-Attentionで
word_feture_wと$Sca$の情報を前のGeneratorからの出力である$f_{i-1}$とconcatします。
concat後の特徴マップが$f_i$となります。
${Target}$が$f_{i-1}$　${Source}$がword_feture_w もしくは $Sca$ です。

[アテンションに関してはこちらの記事が詳しいです](https://qiita.com/halhorn/items/c91497522be27bde17ce)


<img width="594" alt="スクリーンショット 2019-04-27 20.11.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/9870c562-7b1b-bedb-eb73-6af86eeeeb5c.png">
<img width="602" alt="スクリーンショット 2019-04-27 18.31.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/fa815e56-2a8b-dd14-8155-5369770745b6.png">
<img width="560" alt="スクリーンショット 2019-04-27 18.31.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/dedc40d3-1502-b3a5-3953-c91d49ca34b7.png">




# セマンティックテキストの再生成および整列モジュール（STREAM）
CNNはInceptionV3をimagenetの重みを凍結して使用します。
実装ではCNNの出力(global_averege_pooliingまで)とembeddingを通したテキストデータをシーケンス方向にconcatしました。
論文でSTREAMを事前にトレーニングしないとうまくいかないと書かれていましたので、
２日ほどpretrainingしています。

<img width="290" alt="スクリーンショット 2019-04-27 18.01.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/8a752983-a93e-e37c-cd9b-1cf3a1e91a1d.png">
実装。Gの出力サイズがそれぞれ違うため、まず入力画像に対して、
Lambdaレイヤーとtf.image.resize_imagesを使ってInceptionV3の標準入力である299x299にサイズ変更をかけています。
<img width="650" alt="スクリーンショット 2019-04-27 20.27.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/f8fad325-1fa0-a1e2-9c82-66f981dc67e3.png">

# 損失関数
左の項普通のGのロス
右の項 sをIに加えている
<img width="392" alt="スクリーンショット 2019-04-27 20.35.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/3730c1de-79d2-2363-3b01-c041d2e6ebd5.png">
実装。I (h_code)のshapeが(batch x 4 x 4 x c), s(sent_emb)のshapeが(batch x c)
Iとsのshapeが合わないため、Reshapeで軸を増やした後にrepeat_elementsでテンソルをコピーして合わせています。
<img width="637" alt="スクリーンショット 2019-04-27 20.50.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/f39fac47-333e-1060-d1f8-d35abfcbf7be.png">

streamのロス　普通のカテゴリカルクロスエントロピー 
<img width="393" alt="スクリーンショット 2019-04-27 20.35.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/2a142858-093f-c7bf-2487-d158cd14203c.png">
Gの統合されたloss
<img width="330" alt="スクリーンショット 2019-04-27 20.35.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/51369752-ef52-bf77-b636-0e9d60be109b.png">

Dのloss
<img width="458" alt="スクリーンショット 2019-04-27 20.35.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/838ae04e-b005-9b9a-38c6-0da1c190b512.png">

# 途中経過
鳥っぽい何かが出力されています。まだまだトレーニングが足りなそうですね。
現在64x64サイズでトレーニング中です。
![ダウンロード (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339671/3f93c664-8667-9fec-0c3f-63efac44dbd7.png)