ここでは画像生成の手法を自分の手で実装していきます。とりあえずPyTorch, Tensorflow, Keras, Chainer全部で実装してください。 ネットワークを作ったら、学習率やイテレーションを変えて、テストデータセット ../Dataset/test/images でテストしてみてください。 画像生成では学習データの数が非常に重要になってきます。なので、データ拡張をできる限り多く使って下さい、もしくはMNISTやCIFAR10のデータセットを使った方がいいかもしれません。ここではイモリのものとcifar10のものの解答を載せます。
まずは基本的なAuto encoderから。これは画像の表現方法をモデルに学習させること、特徴の次元圧縮を目的に行われます。
AEはよく2層ネットワークで表される。入力層、中間層(Encoder・エンコーダー)、出力層(Decoder・デコーダー)であり、出力が入力画像と同じになるように学習が行われます。中間層のユニット数は入力、出力のものよりずっと小さく、砂時計型である。これが特徴表現の次元圧縮を実現してます。
ここでは次の構造を取る。
input=64, width=64, channel=3 とする。
- Input = (height, width, channel)
- MLP(64)
- MLP(height x width x channel)
画像を[-1, 1]に正規化する。出力層には活性化関数を使わず、LossはMeanSquaredErrorとする。最適化はAdamで学習率は0.001、イテレーション回数は1000としてKerasを使った例はこんな感じ。なんとなく色味を見た感じ復元できているように思えます。よくAutoEncoderでググるとMNISTを使った例がよく出るんだけど、MNISTは0, 1の値だけで構成されているので分散が小さくタスクとして簡単です。一方イモリの画像は値がいろいろあって分散が大きい難しいタスクであるので、結果が微妙に見えてしまいます。
answer_ae_keras_akahara_0009.png | answer_ae_keras_akahara_0009.png |
---|---|
答え
- Pytorch answers/ae_pytorch.py
- Tensorflow answers/ae_tensorflow_slim.py
- Keras answers/ae_keras.py
- Chainer answers/ae_chainer.py
- Pytorch answers/ae_cifar10_pytorch.py
- Tensorflow answers/ae_cifar10_tensorflow_slim.py
- Keras answers/ae_cifar10_keras.py
- Chainer answers/ae_cifar10_chainer.py
AEはMLPのみの構成だったが、ここではConvolutoinとTransposed convolutionでAEを行う。SemaSegの時と似たようなネットワーク構造をとります。
モデル構成は、
- Input = (height, width, channel)
- Conv(kernel_num=32, kernel_size=3, padding=1, strfide=1)
- Conv(kernel_num=16, kernel_size=3, padding=1, strfide=1)
- TransposedConv(kernel_num=32, kernel_size=2, padding=0, strfide=2)
- TransposedConv(kernel_num=channel, kernel_size=2, padding=0, strfide=2)
answer_convae_pytorch_akahara_0011.png | answer_convae_pytorch_madara_0011.png |
---|---|
答え
- Pytorch answers/convae_pytorch.py
- Tensorflow answers/convae_tensorflow_slim.py
- Keras answers/convae_keras.py
- Chainer answers/convae_chainer.py
- Pytorch answers/convae_cifar10_pytorch.py
- Tensorflow answers/convae_cifar10_tensorflow_slim.py
- Keras answers/convae_cifar10_keras.py
- Chainer answers/convae_cifar10_chainer.py
答え
- Pytorch answers/vae_mnist_pytorch.py
論文 >> https://arxiv.org/abs/1406.2661
GAN とはGenerateive Adversarial Networks の略です。最近はこのGANをベースにした手法だらけです。GANはGeneratorとDiscreminatorの2つが敵対(adverse)するのでこんな名前がついています。Generatoirは画像を生成するネットワーク、Discreminatorは画像がGeneratorが作ったか否かを分類するネットワークになっています。つまり GANは画像を生成するニューラルネットワーク です。
学習手法は、
- Generatorが生成した画像にラベル0、生成したい画像にラベル1を割り当てる
- 1のミニバッチでDiscriminatorを学習させる (Discriminatorだけの学習、Generatorは学習させない)
- Generatoir + Discriminatorにノイズを入力して、ラベル1を割り当てる
- 3でGeneratorを学習させる これを1イテレーション毎に行います。これによってDisciminatorはGeneratorが生成した画像が否かを学習できるようになっています。
テスト時はGeneratorにノイズを入力して、生成した画像を得ることができます。つまり、GANの目的は、適当なノイズから作りたい画像を得ることです。学習データは画像を容易するだけでいいので、教師なし学習の一種とみなせるようです。
GANはピクセルごとにLossを取るAutoEncoderとは違い、画像を非間接的にGeneratorに学習させるところが大きく違っていて、これが精度よくできるので、ものすごく注目されてます。なんできれいな画像ができるかが、論文中の数式で証明されています。(詳しくはわかりませんでしたが、どうやら生成したい画像の確率分布を学習できます的なことが書いてあるようでした。)今ではGANの派生として、pix2pixやBigGANなどきれいな画像をすごくきれいに生成できる手法があります。最近(2019.3.1)だと存在しない人の顔を作るサイトなんかもかなり話題になりました。
なぜかGANの構造が論文に記載されていなくて、いろいろな人の実装を見るとこんな感じでした。生成したい画像サイズの縦をheight, 横をwidth, チャネル数をchannelとしてます。
Generator
- Input = 100
- MLP(128) + LeakyReLU(alpha=0.2)
- MLP(256) + LeakyReLU(alpha=0.2)
- MLP(512) + LeakyReLU(alpha=0.2)
- MLP(height x width x channel) + sigmoid
Disciminator
- Input = (height, width, channel)
- MLP(512) + LeakyReLU(alpha=0.2)
- MLP(256) + LeakyReLU(alpha=0.2)
- MLP(1) + sigomid
ちなみにGAN系は収束がくそ難しいことでも有名です。GANの学習ノウハウだけで論文が出てるほどです。なので、各種パラメータ調整はかなり厳しい戦いになると思います。がんばりましょう。僕もがんばりました(´;ω;`)
なんとなくだけど、chainerがきれいにできる気がする。。。
答え
- PyTorch answers/gan_pytorch.py
- Keras answers/gan_keras.py
- Chainer answers/gan_chainer.py
- PyTorch answers/gan_cifar10_pytorch.py
- Keras answers/gan_cifar10_keras.py
- Chainer answers/gan_cifar10_chainer.py
論文 >> https://arxiv.org/abs/1511.06434
GANの進化版、DCGAN (Deep Convolutional GAN)。GANはMulti layer perceptronだけの構成でしたが、DCGANではconvolutionやBNなどを入れてきれいな画像が生成できるようになりました。
この論文はどっちかというとGANを学習させるコツが多く書かれています。
ネットワーク構成は
Generator
- Input = 100
- Dense( (height/16) x (width/16) x 256) + ReLU + BN
- TransposedConv(kernel_size=(5,5), kernel_num=512, strides=2) + ReLU + BN
- TransposedConv(kernel_size=(5,5), kernel_num=256, strides=2) + ReLU + BN
- TransposedConv(kernel_size=(5,5), kernel_num=128, strides=2) + ReLU + BN
- TransposedConv(kernel_size=(5,5), kernel_num=channel, strides=2) + tanh
Disciminator
- Input = (height, width, channel)
- Conv(kernel_size=(5,5), kernel_num=32, stride=2) + LeakyReLU(alpha=0.2)
- Conv(kernel_size=(5,5), kernel_num=64, stride=2) + LeakyReLU(alpha=0.2)
- Conv(kernel_size=(5,5), kernel_num=128, stride=2) + LeakyReLU(alpha=0.2)
- Conv(kernel_size=(5,5), kernel_num=256, stride=2) + LeakyReLU(alpha=0.2)
- MLP(1) + sigomid
答え
- Pytorch answers/dcgan_pytorch.py
- tensorflow answers/dcgan_tensorflow_slim.py
- Keras answers/dcgan_keras.py
- Chainer answers/dcgan_chainer.py
- Pytorch answers/dcgan_cifar10_pytorch.py
- Tensorflow answers/dcgan_cifar10_tensorflow_slim.py
- Keras answers/dcgan_cifar10_keras.py
- Chainer answers/dcgan_cifar10_chainer.py
元論文 >> https://arxiv.org/abs/1411.1784
DCGANはGANよりきれいな画像を作成することができますが、あくまでランダムなノイズから作るのでどんな画像が作成されるかもランダムでした。例えば、CIFAR10では馬の画像か犬の画像ができるかこちら側では決めることができません。
なので、何の画像を作成するかこちら側が指定できるものがConditional GANです。Condtionalは条件付きということを意味しており、つまりラベル指定ができます。conditionalGANではGeneratorとDiscriminatorの両方の入力でラベルyを追加します。
具体的にはまず、Generatorへの入力となるノイズzにone-hotベクトルをconcatします。そして、Generatorの出力に対しては、同じ縦横を持ち、チャネル数がクラス数となるone-hotのデータをチャネル方向にconcatします。 これにより、Condition yをGeneratorに加えることができます。
ここでは上記事項をDCGANに追加してみましょう。
MNISTでの出力はこんな感じになります。
- Pytorch answers/cgan_mnist_pytorch.py
- Tensorflow answers/cgan_mnist_tensorflow_slim.py
- Keras answers/cgan_mnist_keras.py
- Chainer answers/cgan_mnist_chainer.py
CIFAR10での出力はこんな感じになります。
- Pytorch answers/cgan_cifar10_pytorch.py
- Tensorflow answers/cgan_cifar10_tensorflow_slim.py
- Keras answers/cgan_cifar10_keras.py
- Chainer answers/cgan_cifar10_chainer.py
論文 https://arxiv.org/abs/1701.07875
元論文 https://arxiv.org/abs/1611.07004
答え