TFGANでFashion MNISTのGANをさくっと試す

これは[TensorFlow Advent Calendar 2017](https://qiita.com/advent-calendar/2017/tensorflow)の22日目の記事です。

12/12にGoogleから[TFGAN](https://research.googleblog.com/2017/12/tfgan-lightweight-library-for.html)がリリースされた。TFGANはTensorFlowで[Generative Adversarial Networks (GAN)](https://elix-tech.github.io/ja/2017/02/06/gan.html)を手軽に使えるライブラリ。さっそく触ってみたので、お手軽に試す手順を紹介したい。おそらく30〜60分ほどでこんなふうにFashion MNISTの画像が徐々に生成されていく様子が確認できるはず。

![GAN_with_fashion_MNIST.gif](https://qiita-image-store.s3.amazonaws.com/0/38290/d93abeb7-dd00-76ea-3ec1-331635d59ad5.gif)
TFGANで生成したFashion MNIST画像

## GANって何？

GANについては、[アイドル顔画像生成](http://memo.sugyan.com/entry/2016/10/12/084751)や[いらすとや画像生成](http://yusuke-ujitoko.hatenablog.com/entry/2017/05/20/145924)などの事例で目にしたことのある人も多いはず。いわゆる**生成モデル**に分類される技法で、既存のデータを投入して学習すると、**そのデータの特徴を捉えた新しいデータの生成**を行える。2014年にIan Goodfellow他が考案したモデルだ。

最近ではNVIDIAからGANによる高精細の[セレブ画像生成事例](https://youtu.be/XOxxPcy5Gr4?t=38s)が紹介され、もはやリアル画像か生成画像か見分けが付かないクオリティに達している。

<img width="639" alt="Screen Shot 2017-12-22 at 10.54.28 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/38290/ec3bbeb9-601f-6445-3d60-ff0a1f221e75.png">
GANで生成された非実在セレブの皆さん（From: [Progressive Growing of GANs for Improved Quality, Stability, and Variation](https://youtu.be/XOxxPcy5Gr4?t=38s)）

単純な画像生成にかぎらず、動画のウマをシマウマに変えちゃったり（CycleGANによるスタイル変換）、

<img width="639" alt="Screen Shot 2017-12-22 at 11.01.17 AM.png" src="https://qiita-image-store.s3.amazonaws.com/0/38290/d2e2bf68-d8f5-c647-e08e-78fe3adacf1e.png">
From: [Turning a horse video into a zebra video (by CycleGAN)](https://www.youtube.com/watch?v=9reHvktowLY)

線画やラベル画像、文章からそれっぽい画像を生成したり（pix2pix／StackGAN）、

![](https://phillipi.github.io/pix2pix/images/teaser_v3.png)
From: [Image-to-Image Translation with Conditional Adversarial Nets
](https://phillipi.github.io/pix2pix/)

その他、低解像画像から高解像画像を生成する超解像（super resolution）、データ圧縮等々、幅広い応用が可能だ。

応用の対象は画像に限定されるわけではなく、今後は画像以外の様々な用途でGANが応用されていくはず。例えば、開発現場でのテストデータの自動生成やシミュレーションなどがすぐに思いつく。音楽のコード進行を与えるとそれっぽい旋律を生成する事例（MidiNet）もある。
![](https://i2.wp.com/createwith.ai/wp-content/uploads/2017/07/midinet_result.png?zoom=2&fit=840%2C287)

From: [GANで音楽生成](http://createwith.ai/paper/20170709/863)

## GANの仕組み

GANの仕組みについては、日本語による良質な解説記事がいくつか公開されているので、詳しくはそちらを見ていただきたい。

- [はじめてのGAN](https://elix-tech.github.io/ja/2017/02/06/gan.html)
- [Generative Adversarial Networks (GAN) の学習方法進展・画像生成・教師なし画像変換](https://www.slideshare.net/hamadakoichi/gan-training-techniques)
- [Generative Adversarial Networks(GAN)を勉強して、kerasで手書き文字生成する](http://yusuke-ujitoko.hatenablog.com/entry/2017/05/08/010314)
- [タカハシ春の GAN 祭り！〜 一日一GAN(๑•̀ㅂ•́)و✧ 〜](http://tech-blog.abeja.asia/entry/everyday_gan)
- [NIPS 2016 Tutorial: Generative Adversarial Networks](https://arxiv.org/pdf/1701.00160.pdf)：Ian Goodfellowによるチュートリアル

ここでは、サンプルコードの理解に必要となるおおざっぱな仕組みだけかいつまんで説明しよう。

### GeneratorとDiscriminator

GANの基本的なアイディアはそれほど複雑ではない。GANでは、**Generator**と**Discriminator**と呼ばれる2つのニューラルネットワークを組み合わせて学習を行う。

![](https://sthalles.github.io/assets/dcgan/GANs.png)

From: [A Short Introduction to Generative Adversarial Networks](https://sthalles.github.io/intro-to-gans/)

それぞれ、以下の目標に向けて学習が行われる。

- Discriminatorの目標：本物データと生成データを見分けること
- Generatorの目標：Discriminatorが本物データと見間違うような生成データを作ること

この両者を同時に学習させていくと、Discriminatorはデータのより細かな特徴を見つけて本物データと生成データの違いを判別可能になる。一方、Generatorは、Discriminatorをだませるよう、より本物に近い特徴を備えたデータを生成できるようになる。

## TFGANのGANEstimatorでお手軽W-GAN

TFGANでは、このGANを簡単に構成できるAPIとして、[`GANEstimator`](https://www.tensorflow.org/versions/master/api_docs/python/tf/contrib/gan/estimator/GANEstimator)を提供しており、[サンプルコード](https://github.com/tensorflow/models/blob/master/research/gan/tutorial.ipynb)では以下のようにさくっとGANが簡潔に記述されている。

```Python
gan_estimator = tfgan.estimator.GANEstimator(
    generator_fn=generator_fn,         # Generatorの指定
    discriminator_fn=discriminator_fn, # Distriminatorの指定
    generator_loss_fn=tfgan.losses.wasserstein_generator_loss,
    discriminator_loss_fn=tfgan.losses.wasserstein_discriminator_loss,
    generator_optimizer=tf.train.AdamOptimizer(0.001, 0.5),
    discriminator_optimizer=tf.train.AdamOptimizer(0.0001, 0.5),
    add_summaries=tfgan.estimator.SummaryType.IMAGES)
```

ここで、`generator_fn`と`discriminator_fn`にはそれぞれGeneratorとDiscriminatorのCNN構成を返す関数を渡す。`generator_loss_fn`と`discriminator_loss_fn`（GeneratorとDiscriminatorの学習に用いる損失関数）としては、Wasserstein metric（後述）による損失関数を指定している。またオプティマイザーとしてはAdamを利用する。

これまでGANを試されたことのある方ならお分かりの通り、従来のGANは学習が安定しないという問題があった。確かに、ネット上にはGANの学習がうまくいかない〜ってお悩みのブログが散見される。GANの学習を成功させるべく、オプティマイザーにはAdamを使うべし、活性化関数にはLeakyReLUを使うべし等々、[GANをうまく学習するためのテクニック](https://qiita.com/underfitting/items/a0cbb035568dea33b2d7)が集約されてきた。

そうしたGAN研究の最新成果のひとつが[Wasserstein GAN (W-GAN)](https://arxiv.org/abs/1701.07875)だ。正直、W-GANの[解説記事](https://www.slideshare.net/DeepLearningJP2016/dlwasserstein-gantowards-principled-methods-for-training-generative-adversarial-networks?next_slideshow=1)を読んでも私には理解し難いのだが、とりあえずWasserstein metricsを損失関数として用いると、その低次元多様体間距離やらリプシッツ連続性やらの**よーわからんがいい感じの数学的特性によってGANの学習が安定する**という。

このようにTFGANでは、W-GANの詳細を知らなくても簡単にそのメリットを享受できる。つまり、これまでのGAN研究のノウハウに基づいたAPIであるため、**つまづきにくく初心者にやさしいGANライブラリ**と言える。サンプルコードをいろいろ試してる分には安定した学習が可能になっている。

## Cloud DatalabでTFGANを動かす

では実際にTFGANを動かしてみよう。今回は、Google Cloudに統合されたJupyter Notebook環境である[Cloud Datalab](https://cloud.google.com/datalab/)上でTFGANに付属のサンプルコードを試してみる。

クラウド上のJupyterと言えばGoogle Researchが公開する[Colaboratory (Colab)](https://colab.research.google.com/)もお手軽だが、Colabは無償サービスのためGPUが使えない。重いGANの学習にGPUを使いたくなったときのことを考え、今回は商用サービスであるDatalabを選択した。Datalabであれば、Tesla K80やP100を使った学習も可能だ。ちなみに、DatalabでのGPU利用方法については[こちら](https://qiita.com/kazunori279/items/b17d16a2bfbec5e72984)を参考のこと。

<img width="594" alt="Screen Shot 2017-12-22 at 6.42.45 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/38290/b09e17b3-b4a4-026e-023d-442b895817a7.png">

まずは、Datalabの[Quickstart](https://cloud.google.com/datalab/docs/quickstart)を参考に、Datalabインスタンスを作成する。ただしGANの計算は重いので、デフォルトの`n1-standard-1`ではサンプルコードの学習でも長時間を要してしまうだろう。お財布に余裕があれば、[この記述](https://cloud.google.com/datalab/docs/how-to/machine-type)を参考に、4個や8個のCPUを割り当てておきたい。[インスタンスのコスト](https://cloud.google.com/compute/pricing#machinetype)は4個のvCPUで1時間$0.19だ（2017年12月現在）。


### TensorFlowを1.4にアップデート

DatalabのデフォルトではTensorFlow 1.2がインストールされるので、まずはTensorFlowを1.4にアップデートしよう。Datalabをブラウザで開いたら`notebooks`フォルダを開き、`Notebook`をクリックして新規Notebookを作成する。そこで、以下のコマンドを入力して実行する（GPU利用時は`tensorflow`の代わりに`tensorflow-GPU`を指定）。

```
!pip install -U tensorflow
```

つづいて、画面右上にある`Reset Session`をクリックし、Datalabセッションをリセットする。その後、以下のコードを実行してTensorFlowのバージョンを確認する。

```Python
import tensorflow as tf
print(tf.__version__)
```

この時、以下のように1.4以降のバージョン番号が表示されればOKだ。

<img width="337" alt="Screen Shot 2017-12-22 at 6.41.08 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/38290/ec7c0e75-62e1-6a30-0be8-f52f89a25f41.png">

### modelsリポジトリをclone

つづいて、TFGANが含まれる[modelsリポジトリ](https://github.com/tensorflow/models)全体をDatalabにcloneする。

```
!git clone https://github.com/tensorflow/models.git
```

するとリポジトリがcloneされ、`notebooks`フォルダには`models`フォルダが作成される。

### Fashion MNISTのURLを指定

TFGANのサンプルコードは、`notebooks/models/research/gan`フォルダにある`tutorial.ipynb`だ。これをクリックして開く。

このままNotebookをポチポチしていけばすぐにMNIST画像の生成サンプルが動くのだが、今回は[Fashion MNIST](https://github.com/zalandoresearch/fashion-mnist)を代わりに使ってみよう。

Fashion MNISTはMNISTとフォーマット互換の学習データで、手書き数字の代わりにファッションアイテムが並んでいる。ファイルフォーマットやファイル名すべてMNISTと同じにしてあり、世の中にたくさんあるMNISTベースのサンプルコードで動作できるように工夫されている。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/38290/a4182e81-41e5-a135-4ba2-ea2ff0987179.png)

このFashion MNISTでTFGANを試すには、`models/research/slim/datasets`フォルダにある`download_and_convert_mnist.py`をクリックして開き、`_DATA_URL`を以下のURLで差し替える。

```Python
_DATA_URL = 'http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/'
```

これでOK。ファイルを保存したら、`tutorial.ipynb`に戻って上からポチポチ実行していこう。Fashion MNISTのデータファイルをダウンロードする部分で時間がかかり、DatalabのUIがフリーズしてしまうが、じっとこらえて放置しておけば2〜3分でダウンロードと変換が完了する。

### TFGANの学習

ダウンロードと変換が完了したあとは、さらにポチポチしていくことでTFGANによる学習を開始できる。こんな感じで、学習の過程が確認できる。

<img width="437" alt="Screen Shot 2017-12-22 at 7.09.05 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/38290/9c383de6-2df5-af03-601d-a1f748e2ea8e.png">


サンプルコードにある800ステップの学習が完了するまでには、4個のvCPUを持つDatalabインスタンスでおよそ10分がかかる。サンプルコードに記されたコメントによると、GPUインスタンスにすることで、この学習が5倍の速さで完了するとのこと。GANEstimatorでW-GANによる2000ステップの学習を行った場合は、以下のようなクオリティの画像が生成される。

![gan_final.png](https://qiita-image-store.s3.amazonaws.com/0/38290/11cffee0-34ae-b0b7-0bcd-9b879cc4d6af.png)

お手軽さの割には、なかなか悪くない！ 学習も安定している様子。

というわけで、私のように「GANってなんだか大変そうだな〜」と敬遠しがちだった皆さま、TFGANでGANデビューしてみてはいかが。

-----
Disclaimer この記事は個人的なものです｡ここで述べられていることは私の個人的な意見に基づくものであり､私の雇用者には関係はありません｡