アラカン"BOKU"のITな日常

文系システムエンジニアの”BOKU”が勉強したこと、経験したこと、日々思うこと。

NNabla(Neural Network Libraries)のDCGANのサンプルでフェイク画像の生成をやってみる

GAN(Generative Adversarial Network)という技術があります。

 

生成モデルの一種です。

 

生成モデルというのは、訓練データで学習して、それらと似たようなデータを生成させようというものです。

 

よく顔写真とか絵の画像データなんかを学習させて、それっぽい画像(フェイク画像)を生成させたデモなんかがネットで紹介されているアレです。

 

そのGANをCNNを使って実現するモデルの一つがDCGAN(Deep Convolutional GAN)で、おそらく、一番名前が通っているのもこれです。

 

NNabla(Neural Network Libraries)にも、このDCGANのサンプルがあります。

 

こちらの、dcgan.pyというのがそうです。

github.com

 

ですが、ドキュメントが英語しかなく、かつ、あっさりしか説明してくれてないのもあって、あまり話題に登りません。

 

なので、軽く紹介だけでもしてみようかなと思います。

 

まずはGANの構造をざっくりと

 

まずは、GANの動作原理をざっくりと整理しておきます。

 

そこがイメージできないと、ソース見ても、意味わからないと思いますので。

 

GANは、generator(生成器)とdiscriminator(弁別器)という2つのネットワークを使って処理をします。

 

generator(生成器)が、フェイク画像を生成する役割。

 

discriminator(弁別器)が、本物(オリジナル)かgenerator(生成器)が生成した偽物(フェイク)かを識別しようとする役割。

 

その両方がお互いに学習をして、generator(生成器)はdiscriminator(弁別器)をだませるように、より精度の高いフェイクを生成し、discriminator(弁別器)は精度のあがったフェイクにだまされないよう識別精度をあげていく。

 

そんな感じで、どんどん精度をあげていくわけです。

 

関係の概念図でいくと、こんな感じですかね。

f:id:arakan_no_boku:20171220233059j:plain

 

ちなみに、DCGANの場合、generator(生成器)とdiscriminator(弁別器)を、それぞれニューラルネットワークで実現するわけです。

 

もっとも、ニューラルネットワークといっても。

 

discriminator(弁別器)の方は、convolutionを使ってるわけですが、Max Poolingを使わないで、ストライド2の畳み込み(convolution)に置き換える・・とか。

 

generator(生成器)の方は、対して、deconvolutionで構成されているとか。

 

普通のCNNとかとは、だいぶ構成が違いますけど。

 

サンプルを動かすのは簡単だが、時間がかかります

 

サンプルプログラムをそのまま動かすなら、以下の3つのファイルを適当なフォルダにコピーして実行すれば良いだけです。

  • args.py
  • dcgan.py
  • mnist_data.py

 

サンプルは、MNISTを学習して、0から9までの手書き数字のフェイク画像をタイルで生成します。

 

でも、めちゃくちゃ時間がかかります。

 

自分のPC(1コアの非常にプアなスペックですが)で試しに実行したところ、6時間でmax_iter=20000回(デフォルト)中、2000回少々しか終わってなくて、強制終了しました。

 

単純計算で60時間弱(2日半くらい!)かかるってことなので。

 

これはしんどいです。

 

時間短縮のためにちょっとだけ手を加えます。

 

なんとなく学習に使うデータを減らしたくなりますが、そううまく行きません。

 

実際に、一つの数字だけに絞って、データ量を半分にしてみたりしましたが、学習のスピードはあまり速くなりませんでした。

 

今回は雰囲気だけ味わってみるということにして、ちょっとだけ、ソースを修正して実行します。 

 

変更するのは、「dcgan.py」です。

 

まず、最後の方のこの部分を変更します。

args = get_args(monitor_path=monitor_path, model_save_path=monitor_path,
max_iter=20000, learning_rate=0.0002, batch_size=64,
weight_decay=0.0001)

 

ここを以下のようにします。(変更部分は赤字)

args = get_args(monitor_path=monitor_path, model_save_path=monitor_path,
max_iter=3000, learning_rate=0.0002, batch_size=32,
weight_decay=0.0001)

 

max_iterを3000に減らしたのと、batch_sizeを半分の32にしています。

 

雰囲気だけを味わうことにしたので、一回のバッチサイズを小さくして速度をあげて、繰り返し回数も減らしたということです。

 

あと、生成される画像の状況を見ながら、適当なところで止められるように以下も修正しておきます。

monitor_fake = M.MonitorImageTile(
"Fake images", monitor,  normalize_method=lambda x: x + 1 / 2.)

 

ここが画像を書き出している部分ですが、デフォルトだと1000回に1回しかファイルを作成しません。

 

そこをもう少し、ちょこちょことチェックしたいのに、「 interval=100」を付け加えて、100回ごとに画像ファイルを作るようにします。

monitor_fake = M.MonitorImageTile(
"Fake images", monitor, interval=100, normalize_method=lambda x: x + 1 / 2.) 

 

これで実行してみます。

 

こんな感じで生成されていきます

 

生成した画像は、ソースコードをおいたフォルダの「tmp.monitor.dcgan\Fake-images」の下に、「000799.png」のようなファイル名でできていきます。

 

上の図でもある通り、最初はノイズだけです。

f:id:arakan_no_boku:20171221215237p:plain

 

これが200回くらい学習すると、ちょっと形が見えてきます。

f:id:arakan_no_boku:20171221215449p:plain

 

1000回目くらいになると」、だいぶ手書き文字っぽくなってきます。

f:id:arakan_no_boku:20171221215552p:plain

 

3000回目ではこんな感じ。

f:id:arakan_no_boku:20171221232922p:plain

 

わずかずつですが、生成される画像の精度があがってきている雰囲気はわかります。

 

今回は、4時間程度しか動かすつもりがなかったので、このあたりできってます。

 

この調子で20000回も繰り返すと、かなり、元画像に近いものが生成されるようになるという雰囲気はわかります。

 

でも、それを味わうには、GPUが使えるマシンか、AWSとかのクラウドを利用できないと、ちょっときついかな。

 

面白い技術であるのは、間違いないんですけどね。

 

先立つものが・・・。

 

関連情報

NNabla(Neural Network Libraries)の関連記事の一覧はこちらです。

arakan-pgm-ai.hatenablog.com

 

ニューラルネットワークコンソールの関連記事の一覧はこちらです。

arakan-pgm-ai.hatenablog.com

f:id:arakan_no_boku:20170910161122j:plain