DCGANによるポケモン生成


#DCGANでポケモン生成
今回はkaggelで配布されているデータセット　[https://www.kaggle.com/kvpratama/pokemon-images-dataset](https://www.kaggle.com/kvpratama/pokemon-images-dataset/version/1)　を教師データ(正解画像)として用います。
実際のコードは以下からダウンロードできます。
https://github.com/Kohey1480/pokemon_dcgan
　同じ階層にデータセットを用意しimagechange.py->pokemon_dcgan.pyの順で実行してください。
#教師データについて
配布されているポケモンデータセットは第7世代721体のポケモンのメガシンカやフォルムチェンジを含んだの819枚画像で、256(pixel)×256(pixel)×3(channel)になっています。メモリのオーバーフローを避けるため今回使うデータは64(pixel)×64(pixel)×3(channel)に圧縮しました。
#DCGANの簡単な説明
詳しくは[論文](https://arxiv.org/abs/1511.06434) に書いてありますが、DCGANは以下のように構成されています。
<img width="1141" alt="スクリーンショット 2019-07-18 1.48.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/460724/c993b019-8e06-daab-2aa7-1d772b92d288.png">
　大まかに言うとGeneratorとDiscriminatorで構成されていて、ランダムに生成されたノイズからGenerator部分で画像を生成し、
Discriminator部分では実際の画像であるかgeneratorであるかを判別するようにできていて、Discriminator正しく判断し、generatorは学習されたDisciminatorをだませるように学習を行っていくという構成です。
#実装
　まず、Generatorについては、UpSampling2Dという関数を用いて、畳み込みの逆方向の操作を行うことで画像を生成していきます。また、
　・ 出力層の活性化関数はtanhを用いる 
　・ バッチノルムを用いる。
といったテクニックがあるようです。
![001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/460724/121fed17-858b-d020-478a-b034aa9d5928.jpeg)

今回実装したGenerator部分のニューラルネットワークは以下のコードで構成されています。

    def generator(self):
        noise_shape = (self.z_dim,)

        model = Sequential()
        model.add(Dense(128 * 16 * 16, activation="relu", input_shape=noise_shape))
        model.add(Reshape((16, 16, 128)))
        model.add(BatchNormalization(momentum=0.8))
        model.add(UpSampling2D())
        model.add(Conv2D(128, kernel_size=3, padding="same"))
        model.add(Activation("relu"))
        model.add(BatchNormalization(momentum=0.8))
        model.add(UpSampling2D())
        model.add(Conv2D(64, kernel_size=3, padding="same"))
        model.add(Activation("relu"))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Conv2D(3, kernel_size=3, padding="same"))
        model.add(Activation("tanh"))
        model.summary()

        return model

　Discminatorについては畳み込みニューラルネットワーク(CNN)で構成されていて出力層については、正解画像か生成された画像であるか生成された画像であるかの2クラス問題であるため、出力層のノードは1個か2個でもどちらでもよく、1個で設定されているものが一般的であるようであるが、直感的にわかりやすくするために今回は出力層のノードを2個で構成しました。

　また、DCGANに限ってはDiscmininatorは
　　・ pooling層ではなくストライド幅を大きくした畳み込み層を用いること
　　・ 全結合層を用いないこと(層が深ければ深いほど用いないほうが良い)
　　・ 活性化関数はLeakyReLUを用いること
　　・ バッチノルム用いること
などといったテクニックがあるようです。

    def build_discriminator(self):
        img_shape = (self.img_rows, self.img_cols, self.channels)

        model = Sequential()
        model.add(Conv2D(32, kernel_size=3, strides=2, input_shape=img_shape, padding="same"))
        model.add(LeakyReLU(alpha=0.2))
        model.add(Dropout(0.25))
        model.add(Conv2D(64, kernel_size=3, strides=2, padding="same"))
        #model.add(ZeroPadding2D(padding=((0, 1), (0, 1))))
        model.add(LeakyReLU(alpha=0.2))
        model.add(Dropout(0.25))
        model.add(BatchNormalization(momentum=0.8))
        model.add(Conv2D(128, kernel_size=3, strides=2, padding="same"))
        model.add(LeakyReLU(alpha=0.2))
        model.add(Dropout(0.25))
        model.add(GlobalAveragePooling2D())
        model.add(Dense(2, activation='sigmoid'))
        model.summary()

        return model
#結果
以下100000epoch学習した推移です。
![poke_gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/460724/3052f1b9-b76a-3330-4688-ec00bf47416f.gif)
↓100000epoch学習後の出力です。
![pokemon90000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/460724/194b1da1-a851-e79b-7a82-b785fa295e45.png)


ポケモンっぽい...??
(これでもパラメーターやネットワークのチューニングに数日かかりました。)