KerasでBEGAN(Boundary Equilibrium Generative Adversarial Networks)を実装する

テクノロジー

GAN(Generative Adversarial Networks: 敵対的生成ネットワーク)という生成モデルの中でも面白い構造の仕組みを最近よく見かけます。ただ、GANは学習が難しいというのが課題だったようなのですが、この BEGAN というのは二者の対立のバランスを取りながら学習することでこの課題を解決するとのこと。BEGANは結構内容がシンプルで理解しやすかったので、Kerasで実装してみました。

はじめに

GAN(Generative Adversarial Networks: 敵対的生成ネットワーク)という生成モデルの中でも面白い構造の仕組みを最近よく見かけます。Generator(生成者)とDiscriminator(識別者)が互いに競い合って精度を上げていく構造は、美術界での贋作者(=Generator)と鑑定士(Discriminator)の勝負のようでギャラリーフェイクのような世界を彷彿とさせます。仕組み自体に浪漫を感じます。さらにそれで精度良い生成ができるのだから本当に不思議です。

BEGANの面白いところ


色々なGANの改良を引き継ぎつつ、バランスを取る仕組みが入っているみたいなのですが、論文に書いてある特徴(それ以前に別の人が考えたものも含む)から個人的に面白いと思った部分として、

というところもありつつ、一番興味深いのは、

DiscriminatorのAutoEncoderのLoss関数を L(x)L(x) とした時に、
DiscriminatorのLoss関数をLD(x)LD(x)、GeneratorのLoss関数をLG(x)LG(x)とすると、

LD(x)=L(真の画像)−kt∗L(Generatorが生成した画像)LD(x)=L(真の画像)−kt∗L(Generatorが生成した画像)
LG(x)=L(Generatorが生成した画像)LG(x)=L(Generatorが生成した画像)
kt+1=kt+λk(γ∗L(真の画像)−L(Generatorが生成した画像))kt+1=kt+λk(γ∗L(真の画像)−L(Generatorが生成した画像))

という形で学習させるところです。
このktktというのは最初は0から始まって徐々に大きくなる感じです。

DiscriminatorはLossを減らすために「真の画像のAutoEncodeを頑張る(Lossを小さくする)」のと「偽の画像のAutoEncoderを頑張らない(Lossを大きくする)」という行為を迫られます。最初はk=0なので真の画像のAutoEncoderを最適化していきますが、徐々にkが大きくなりGeneratorの画像のLossを大きくする努力も併せて行います。最後は (γ∗L(真の画像)−L(Generatorが生成した画像))=0(γ∗L(真の画像)−L(Generatorが生成した画像))=0になる辺りでkは平衡状態に至ります(そのとき γγが効いてくるわけですね)。

Generatorは常にAutoEncoderのLossが小さくなる用に生成画像を工夫していくので、徐々に争いが高度になっていくということになります。

このジレンマのような仕組みがとても面白く、それがスッキリ表現されていて、おおー、と思いました(まあ、他のGANのことはよく知らないのですが...)。

実装

ソースコード


https://github.com/mokemokechicken/keras_BEGAN
に置いてあります。

まあまあそれっぽい画像が生成できているのでだいたい実装としてはあっているんじゃないかと思っていますが...

Kerasだとこういう一風変わったモデルや学習を行うのが難しい(あまりサンプルがない)ですが、書き方がわかってくると実はそれほど難しくはなく、作れてしまえばモジュール性の高さから読みやすく、いろいろ応用しやすい良さがあります。

学習の進行


1 batch毎の各種Lossなどの値をPlotすると以下のようになりました。
γ=0.5γ=0.5 で学習させています。

図:学習の進行をグラフ化

それぞれの値の意味は以下のとおりです。

パット見て思うのは、

実行後の生成例


サンプル画像
64x64 Pixelの正方形画像ならなんでも良いのですが、サンプル画像として、http://vis-www.cs.umass.edu/lfw/

[new] All images aligned with deep funneling

(111MB, md5sum 68331da3eb755a505a502b5aacb3c201)
を使わせてもらいました。グレイスケール画像を除くと 13194サンプルあります。

生成画像
学習の進行別に生成された画像を並べてみるとこんな感じでした。

Epoch 1

画像:生成画像例Epoch1-1。完全にぼやけていて性別も判別不可

画像:生成画像例Epoch1-2。完全にぼやけていて性別も判別不可

画像:生成画像例Epoch1-3。完全にぼやけていて性別も判別不可

画像:生成画像例Epoch1-4。完全にぼやけていて性別も判別不可

画像:生成画像例Epoch1-5。完全にぼやけていて性別も判別不可
Epoch 25

画像:生成画像例Epoch25-1。多少画像がはっきりしている。人物の判別可能

画像:生成画像例Epoch25-2

画像:生成画像例Epoch25-3

画像:生成画像例Epoch25-4

画像:生成画像例Epoch25-5
Epoch 50

画像:生成画像例Epoch50-1。

画像:生成画像例Epoch50-2

画像:生成画像例Epoch50-3

画像:生成画像例Epoch50-4

画像:生成画像例Epoch50-5
Epoch 75

画像:生成画像例Epoch75-1

画像:生成画像例Epoch75-2

画像:生成画像例Epoch75-3

画像:生成画像例Epoch75-4

画像:生成画像例Epoch75-5
Epoch 100

画像:生成画像例Epoch100-1

画像:生成画像例Epoch100-2

画像:生成画像例Epoch100-3

画像:生成画像例Epoch100-4

画像:生成画像例Epoch100-5
Epoch 125

画像:生成画像例Epoch125-1

画像:生成画像例Epoch125-2

画像:生成画像例Epoch125-3

画像:生成画像例Epoch125-4

画像:生成画像例Epoch125-5
Epoch 150

画像:生成画像例Epoch150-1

画像:生成画像例Epoch150-2

画像:生成画像例Epoch150-3

画像:生成画像例Epoch150-4

画像:生成画像例Epoch150-5
Epoch 175

画像:生成画像例Epoch175-1

画像:生成画像例Epoch175-2

画像:生成画像例Epoch175-3

画像:生成画像例Epoch175-4

画像:生成画像例Epoch175-5
Epoch 200

画像:生成画像例Epoch200-1

画像:生成画像例Epoch200-2

画像:生成画像例Epoch200-3

画像:生成画像例Epoch200-4

画像:生成画像例Epoch200-5
Epoch 215

画像:生成画像例Epoch215-1

画像:生成画像例Epoch215-2

画像:生成画像例Epoch215-3

画像:生成画像例Epoch215-4

画像:生成画像例Epoch215-5
顔写真としては、epoch125くらいまでのが結構良い感じです。
それ以降は、背景も取り込もうとしたからか、顔の部分の乱れがすごいことになっています。
顔に注目して生成したければ、背景を潰して顔だけにしたやつを使えばもう少し綺麗になるのかもしれないですね。
どれくらい綺麗な画像になるかはModelのConv Layerの数なども関係するそうですし、ちょっと不足気味だったのかもしれません。

実行時間
以下のマシンスペックで約680秒/epoch でした。

KERAS_BACKEND=theano

THEANO_FLAGS=device=gpu,floatX=float32,lib.cnmem=1.0

さいごに


やっとGANについて少しわかった気がします。

まずはお気軽にお問い合わせください

「Sprocket」の費用や導入スケジュール、また、御社の顧客体験の向上やコンバージョンの最適化、Web接客ツールの比較検討においてご不明な点がございましたら、お気軽にお問い合わせください。(無料)

03-6303-4123

受付時間:平日10時~12時/13時~17時