続・GANによる二次元美少女画像生成

Lento
29 min readDec 12, 2018

--

Introduction

今回はGANを用いた二次元画像生成を中心に行いました。ただ以前にもGANを用いた二次元画像生成についての記事は書いているので、今回の記事はそれの拡張版として読んでいただけたらと思います。また、画像生成だけでなく他のタスクについても取り組んだのでまとめてこの記事に載せます。今回取り組んだタスクは以下の三つです。

  • cGANを用いた髪色条件付き二次元美少女画像生成
  • ESRGANを用いた二次元美少女超解像
  • OpticalFlowを用いた二次元美少女画像への瞬き付与

です、順に説明いたします。また、以下で参考にした論文を紹介していきますが、概要のみを述べるに止めているのでご留意ください。詳細を知りたい方は元論文を辿ってください。

GANを用いた髪色条件付き二次元美少女画像生成

まずは単に画像生成を行いました。しかし、前回の記事と同じことを行うのも冗長なので今回は髪色条件付き、即ち好きな髪色の美少女画像を生成することを目指して、条件付きGAN(cGAN)を実装しました。

① Network Architecture

cGANとして従来用いられていたものは下図の(c)に示すようにAuxiliary Classifier GAN(AC-GAN)でした。これは、Discriminatorの出力を二つに分け、一方はReal/Fakeの判別(Adversarial loss)を、もう一方はその画像がどの条件(クラス)に属するかの分類(Classification loss)を行うものでした。これにより、入力ノイズに条件(One-hot vector)をConcatして与えることで望んだ条件付画像を生成するというものです。しかし、この手法では損失関数項が増え、多クラスでの学習は困難でした。そこで、下図の(d)に示すようなProjectionを導入したDiscriminatorを用いることにしました。

出典:Takeru Miyato et al., “cGANs with Projection Discriminator”

最適なDiscriminatorの出力が対数尤度比の和で表され、対数尤度を構成する尤度がガウス分布や離散対数線形のような簡単な分布となる時、Discriminatorの出力は以下のようになると述べています。導出の過程については論文をご覧ください。

今回の場合で言うとxが入力画像、yが条件ベクトル、fがDiscriminatorの出力で、θがDiscriminatorのパラメータです。右辺が上図(d)を表しており、入力画像がφを通った後ψを通るのが第二項、φの出力と条件ベクトルyを埋め込んだものとの内積を取ったものが第一項となります。これによって損失関数はAdversarial lossのみとなり、制御もしやすくなります。また、Projectionを導入したDiscriminatorによって従来のACGANを大きく上回るスコアとなりました。因みに大きな話題を読んだBigGANのベースとなっているSelf-AttentionGANのDiscriminatorにもProjectionは導入されており、Discriminator側の構造はProjection登場以降大きく変わっていない印象です。
cGANのため、Projectionを導入するということについては述べたので、次にどのようなネットワーク構造を用いたのかについて述べます。今回は2種類のネットワーク構造を用いました。まず一つ目は、前回の記事同様下図のようなSRResNetを主体としたものです。変更点はDiscriminatorにProjectionを導入していることです。

出典:Yanghua Jin et al., “Towards the Automatic Anime Characters Creation with Generative Adversarial Networks

二つ目の構造は、Projection Discriminatorの論文やこちらの論文でも述べられているようなResidual Blockを主体とした下図のような構造です。Projectionもこちらの図では実装がイメージしやすいかと思われます。UpsamplingにはNearest Neighbor Upsampling ->Convolutionを用いています。以上二つの構造について条件付き画像生成を行いました。

出典:Ryohei Suzuki et al., “Collaging on Internal Representations: An Intuitive Approach for Semantic Transfiguration”

② Dataset

前回記事と同様、学習用画像にはGetchuでスクレイピングした画像に対して顔が入るように切り出し、全ての画像において128✕128にリサイズしました。条件となる髪色は金髪、茶髪、黒髪、青髪、ピンク髪、紫髪、緑髪、赤髪、銀髪としました。Illustration2Vecを用いて、該当する髪色のインデックスだけ値を持つ9次元ベクトルを算出しました、この時上記のどの髪色に当てはまらなかった場合には、その画像は学習データから除外しました。以上によって、22665枚の画像と、対応する条件ベクトルを用意しました。

③ Experiment

今回は2種類のネットワークを用いていますが、両方とも損失関数はDRAGANベースです。即ちAdversarial lossとGradient Penaltyを考慮しています。その他詳細は以下です。

  • バッチサイズはSRResNetの構造が64、Residual Blockを主体とした構造が100とした。しかしBigGANの例を見るに、バッチサイズは極力大きい方が良い
  • 最適化手法はAdam(α=0.0002、β1=0.5)
  • Data augumentationとしてHorizontal Flipを用いた
  • Discriminator→Generatorの順で学習。Generator一回の学習に対し先にDiscriminatorを二回学習させている
  • Adversarial lossの重みは1.0、Gradient Penaltyの重みは0.5
  • Adversarial lossの中ではHinge lossを用いた
  • GeneratorにSqueeze-And-Excitation Networkを用いてやってみたが、途中で学習が発散したので用いず

④ Result

それでは実験結果を表示していきます。まず、一つ目のSRResNetを用いたネットワークの結果です。

可愛く出来てますね、ちゃんと条件付き生成も出来ているか確認します。その結果が以下です。以下の画像は入力ノイズは固定して、青髪、金髪、緑髪を条件としたベクトルを与えた時の結果です。狙い通り、造形は変わらないまま髪色だけ変わってるのが分かるかと思います。

次に、Residual Blockを主体としたネットワーク構造においての結果を以下に示します。

こちらも可愛いですね、SRResNetと比べて褪せた色が無かったり、細かい部分の造形もきちんと生成出来ています。Generatorの総パラメータ増えているので当然のような気もしますが。同様に、条件付き生成が出来ているか確認します。今度は、今回指定した9つの髪色をちゃんと学習できているか見てみます。

ちゃんと造形は変わらず、髪色だけを変えることが出来ていますね。

⑤ Summary

今回はまずcGANを用いた髪色条件付き美少女画像生成を行いました。DiscrimiantorにProjectionを用いることで、きちんと学習出来ました。今回は条件として髪色だけを用いましたが、髪型や目の色も条件としては勿論可能なので、今後取り組んでいきたいですね。makegirlsmoeはそこまで出来ているので可能なはずですが….
今後の課題としては、条件の拡張よりも高画質化です。今回は128×128サイズの画像生成を行いましたが、これは私の保持するデータセットが全て100×100~200×200サイズのためです。従って例えばCrypkoのような512×512にするためには、それに類するサイズのデータセットが必要となります。私の保持するデータセットの特徴としては、背景が白で正面顔というところなのですが、これに合致するデータを集めようとするとかなりの労力になります。Crypko作製時にはどのようにデータを集めたのでしょうか……?気になりますね。暫定的な処理として、私は次章で超解像を試してみました。

ESRGANを用いた二次元美少女超解像

生成した画像を高画質化するために、超解像が使えないかということでこの章ではESRGANを用いた超解像について検討した結果について述べます。以前、SRGANを用いた超解像については記事を書いてるのですがSRGANは2年近く前の手法なので、それを更にEnhancedさせたESRGANを用いています。

① Enhanced Super-Resolution GAN

論文タイトル通りESRGANはSRGANをEnhancedさせたものですが、何をどうEnhancedさせているのかについて述べていきます。細かいところまで挙げるとキリがないので主な変更点である4つについて述べます。

  • Batch Normalization除去
    BatchNormalizationは入力の平均・分散を求めますがTrain時/Test時のデータの違いによって、この統計的処理が異なりアーティファクトが生じることがあります。従って、このアーティファクトを防ぐためSRGANのResidual BlockからBatch Normalizationを除去しました。
  • Residual in Residual Dense Block
    SRGANでは中間層としてResidual Blockを用いていましたがESRGANでは下図のようなResidual in Residual Dense Block(RRDB)を用いています。DenseNetでも用いられるDense Blockを弱い残差で結合しており、これによってより広いコンテキストも拾えるようになるとしています。
出典:Xintao Wang et al., “ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks”
  • Relativistic average Discriminator
    ある程度学習が進みDiscriminatorの判別力が上昇すると、Discriminatorの出力はFake画像をRealと判別した時のみ誤差が生じるようになります。これではReal画像で学習が出来ません。そこで、Real画像を入力に用いた時のDiscriminatorの出力とFake画像を入力に用いた時の出力(正確にはその平均)の差分を見て学習を進めます。これにより、Real画像Fake画像どちらを用いても学習が可能になります。
出典:Xintao Wang et al., “ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks”
  • Loss Function
    VGGの各層の出力で誤差を取るPerceptual lossにおいて、SRGANでは活性化関数であるReLUの後を出力としていました。しかし以下の画像のように、ReLUの後では画素情報が失われてしまいます。そこでESRGANではReLUの前を出力としてPerceptual lossを求めました。また、SRGANの損失関数であるAdversarial loss+Perceptual lossに加えてL1 lossも加えています。
出典:Xintao Wang et al., “ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks”

以上4つがSRGANからの変更点です。

② Dataset

データセットとしては、今回は自分が生成した二次元美少女を高解像にするというタスクなので、イラストを学習データに用いる必要があります。そこでKaggleのTagged Anime Illustrationsを用いました。こちらはDanbooruからイラストを30万枚ほどスクレイピングしたものを全て512×512サイズに整えたものです。

③ Experiment

Datasetの画像をランダムに256×256にクラップし、それをBicubic法を用いて64×64にダウンサンプリングしました。ダウンサンプリングしたものをESRGANの入力に用います。また、今回はESRGANを用いて超解像を行なっていくのですが、SRGANとの比較も気になるところなのでSRGANも上記データセットで学習しました。以下で学習の詳細について述べます。

  • ESRGANではRRDBを15層、SRGANではResidual Blockを15層とした
  • Perceptual lossではVGG16のConv1_2、Conv2_2、Conv3_3、Conv4_3、Conv5_3の出力で計算した。ESRGANではそれぞれの層のReLUの前、SRGANではそれぞれの層のReLUの後を使用。
  • バッチサイズは8
  • 最適化手法はAdam(α=0.0002,β1=0.5)
  • ESRGANではL1 lossで、SRGANはPerceptual lossでpre-trainした。その後、本来の損失関数で学習させた。
  • SRGANではAdversarial lossの重みは0.001でPerceptual lossの重みは1.0、ESRGANではAdversarial lossの重みは0.005でL1 lossの重みは0.1でPerceptual lossの重みは1.0とした。
  • ESRGANに関しては、60000iterationくらいで学習が崩壊した。従って崩壊する前の学習モデルで推論を行う。現時点で回避する方法はわかってない。

④ Result

それでは結果を示していきます。まずは、テスト用のイラストで超解像を行った結果を示します。128✕128サイズの画像を入力に用い、4倍超解像を行います。比較のため、SRGANの結果も載せていますが、SRGANでは細かいアーティファクトが生じていたり、ESRGANではどことなく線がはっきりしているように見えます。

また、どことなくSRGANの方で色合いが元画像と違うような気がしたのでカラーヒストグラムを見てみました。Ground Truthの画像をダウンサンプリングしたものを、SRGANとESRGANでそれぞれ超解像を行い、高解像度の画像のヒストグラムを見たものが下図のグラフです。MSEはESRGANのpre-trainモデルで超解像を行なったものです(本来はMAEと書くべきなのですが、ミスタイプです申し訳ありません)。ESRGANがGround Truthの追従をしようとしてるのに対し、SRGANでは特にカラー値が大きいところで異なった分布をしています。以上述べた点が、SRGANのどの部分に起因するものなのかは結局分からなかったのですが、結果だけを見るとESRGANの方が超解像としては適していると言えます。

最後に本題のGANで生成した美少女画像を超解像したらどうなるのか?について行なってみます。以下に結果を示します。

何となく予想はしていましたが、元画像サイズが小さくて見えにくくなっていた粗が目立つ結果になりました。GANで生成した画像がいかに綺麗に見えても、128×128×3の値を全て自然に近く求められるのは出来ないですよね….こうして低解像度画像から超解像を用いて高解像度画像を求める作戦は失敗に終わりました。

⑤ Summary

この章では、ESRGANを用いた超解像について述べました。SRGANと比べてノイズが少なく、ヒストグラム的にも復元が出来ていたかと思われます。
しかし、ESRGANを用いてもGANで生成した画像を超解像で高解像度にするのは粗を目立たせる結果になりました。やはり、高解像度画像生成を行いたいなら、高解像度画像を学習データに用いましょうということですね。学習データ….意地でも集めるしか….
以上により、失意に沈む結果でしたが、せめて生成した画像に対して動きだけでもつけようと思い立ちました。詳細は次章で述べます。

Optical flowを用いた二次元美少女画像への瞬き付与

最後の章では美少女を画像として生成するだけでなく、動かしたいという欲求に従って動かそうとした試みについて述べます。やるべき事としては生成した画像を1フレーム目として、動画を生成するというものです。動画生成については知見がなかったこともあり、まずはどんなNNがあるのか調査を行い、実際に自分がやったことについて記していきます。

① Video Generation

動画生成にどのようなGANが使われているのかを調べ、参考にしたものを順に述べていきます。

出典:Carl Vondrick et al., “Generating Videos with Scene Dynamics”

名が体を表していますね。画像生成で用いられるGANでは入力ノイズから2D Convolutionを用いていきますが、動画生成では時間方向も考慮しなければならないので、その時間方向をどう表現するかというところに焦点が当たります。このVideoGANではその問題に対して3D Convolutionを用いて、画像の幅と高さの次元に時間方向の次元を加えています。
Generatorでは、動画をForeground(前景)とBackground(背景)に分けてそれぞれで生成を行います。Backgroundは動体がないので、単なる画像と同じでありこれは2D Transposed Convolutionで生成可能です、動体のあるForegroundは3D Transposed Convolutionを適用しています。最後に生成したマスクで動体がある部分は背景をマスクで隠し、動画として生成します。
Discriminatorでは、フレーム画像がRealかFakeか判別するだけでなくそのフレームの連続が、時系列的に意味のあるものかを判別するために3D Convolutionを用いた構造となっています。
以上のように、VideoGANではForegroundとBackgroundに分けてそれぞれを生成しますが、当然Backgroundは固定である必要があり、適用範囲が狭そうに見えます。

出典:Masaki Saito et al., “Temporal Generative Adversarial Nets with Singular Value Clipping”

上記のVideoGANでは、3D Convolutionを用いて時間方向の次元を追加していましたが、そもそも3D Convolutionは適切なのか?という問題があります。これはAction Recognitionでも言われていることですが、そもそもデータ構造としてフレームの幅高さ方向の次元と、時間方向の次元では見ているものが異なっています。従って、時間と空間は切り離して考えるべきではないのか?という疑問が生まれます。それを解決しようとしたのがTemporalGANです。
TemporalGANでは、Generatorは2D Transposed Convolutionを用います。ただ、生成の元になる入力ノイズが各フレームで異なります。その各フレームの元になる入力ノイズは、ある潜在空間の一点から1D Transposed Convolutionを用いたTemporal Generatorによって生成されます。これによって時間方向にはTemporal Generator、幅と高さ方向には2D Transposed Convolutionを用いたImage Generatorを適用することで、時間と空間を切り離すことが出来ています。ただ、Discriminatorでは3D Convolutionを用いたものになっています。
因みに、最近TemporalGANv2が発表されました。ネットワーク構造の改変の他に、出力層付近における計算量増加を考慮したSubsampling layerを提案しています。

出典:Sergey Tulyakov et al., “MoCoGAN: Decomposing Motion and Content for Video Generation”

MoCoGANも動画生成部分のアプローチはTemporalGANと同様です。各フレームの元になる潜在空間の点を、MotionとContentに分けContentはどのフレームでも固定し、Motionは一連のランダムな変数をGRUに通して生成します。そしてそれらContentとMotionを連結させて、2D Transposed Convolutionに通すことで動画を生成します。Generatorの部分だけを見るとTemporalGANとそこまで変わらないのですが、MoCoGANではDiscriminatorにおいて工夫しています。二つのDiscriminatorを用意し、単に画像としてRealかFakeかを判別するものと、動画として整合性が取れているかの判別を行うものを用意しています。
以上の工夫によって、MoCoGANはVideoGANやTemporalGANよりも高い性能を叩き出しています。

以上が動画生成について調べた結果です。次は上記のネットワークを用いて実際に一枚の画像を与えて動かすということをやっていくのですが、まず一番簡易に組めるVideoGANで所望のことが出来ないか試してみました。入力には一枚の画像を与えるので、ネットワークとしては以下のようになります。画像をEncodeする部分以外はVideoGANと同様です。

② Dataset

画像の中の人物を動かすと言っても動かし方は無数にあります。どの動きにも対応するように学習となると学習データを集めるのが大変だと思い、動きを限定することにし、瞬きをさせるようにしました。そこで、瞬きをしているキャラクターの動画を集める必要があります。今回は、目以外はなるべく動いて欲しくないので、アイドルマスターシンデレラガールズ(モバゲー)の思い出エピソードから瞬きをしているシーンを抜き出しました。そして、18/sで静止画を切り出し瞬きをしている前後16フレームを60キャラ分集めました。

③ Experiment

上記ネットワークを元に実装しました。1枚の画像から16フレームを生成し、教師データにDatasetの項で作った16フレームを用いました。そして以下のような試行を行いました。

  • まず、素直にGenerator +Discriminatorを実装し、Adversarial lossとContent loss(生成フレームと教師データとの絶対平均誤差)で学習したところGeneratorが学習する前にDiscriminatorがすぐに学習された。これはデータが少ないため、Discriminatorが早い段階でRealとFakeを判別できるようになるためだと思われる。
  • そこで、WGANのようにGradient Clippingを行ってDiscriminatorの勾配を制限した。学習は安定するようになったが、生成された動画は入力画像を16枚並べただけのものになった。勾配が二極化されてしまうようになったため…?
  • 最後に、Discriminatorを取っ払ってContent lossのみだけで学習したが、入力画像を16枚並べただけものになった。以下はその一例(最初の8フレームを見ている)。

以上のように、うまく動きを与えることが出来ませんでした。そもそも瞬きという動作に限定して前後16フレームと言っても、どのタイミングで瞬きを初めて、どのタイミングで終わるかがそれぞれのキャラによって違うのでGeneratorはそのタイミングが分かりません。従って、何かしらの条件を入力画像と連結させて与えるべきではないかと考えました。

④ Conditioned Video Generation

何らかの参照動画を用意します。今回は瞬きを画像に与えたいので瞬きをしている動画を参照します。その参照動画から何かしらの特徴量を獲得し、それを条件付けとして入力画像に連結させます。そこで、そのようなことをやっている論文として参考にした以下の二つを紹介します。

出典:Wissam J. Baddar et al., “Dynamics Transfer GAN: Generating Video by Transferring Arbitrary Temporal Dynamics from a Source Video to a Single Target Image”

他人の表情変化の動画から、同様の表情変化を画像に与えるというものです。参照動画を各フレームずつ、CNN-LSTM(Pre-train、表情変化の過程を学習している)を通すことで特徴量を獲得し、動画の1枚目のフレームから得られた特徴量との差分を取ります。その差分をDynamics Channel Embedder(図中のF)に通して得られたものを条件として、入力画像と一緒にGeneratorに与えます。Discriminatorは二つ用意し、各フレームのReal/Fakeの判別と、生成動画から得た特徴量が時間的に整合性のあるものかの判別を行います。
表情変化を与える、Pre-trainモデルが必要(探したが見つけられなかった)の2点から今回この手法は用いていませんが、参照動画からどのように条件つけを行うかについては参考にしました。

出典:Long Zhao et al., “Learning to Forecast and Refine Residual Motion for Image-to-Video Generation”

こちらも参照動画から入力画像に動きをつけるというものです。Condition Generator、Forecasting NetworksそしてRefinement Networksの三つに分かれています。Condition Generatorでは3DMMとLSTMで次フレームの特徴量を生成します。その特徴量を条件として、Forecasting NetworksではResidualな構造でフレームとマップを生成。最後にRefinement Networksで3D Convolutionを用いてより洗練させるという流れです。きちんと読めてないので雑な説明になっています….
より洗練するためにRefinement Networksを用いた部分を参考にしました。

⑤ Experiment Again

上記二つの論文では主にLSTMを用いて参照動画から特徴量を抽出し、条件つけとしている印象でした。しかし、LSTMによって、目という画像の局所的な部分のフレーム間の違いが表せているのか怪しかったので、いっそのことフレームそのもの差を見ようということで、Optical flowを用いることにしました。(実際にConvolutionalLSTMを用いて特徴量を抽出し…ということもやってみましたが、うまくいきませんでした。)そこで、下図のようなネットワークを実装し、実験しました。
Optical flowはReference Videoのt(1 ≤ t ≤16)フレーム目と1フレーム目からOpenCVのcalcOpticalFlowFarneback関数によって求めています。Optical flow sequenceに合わせてInput Imageをtileし、Optical flow sequenceと連結させたものを入力とします。それを2D UNetに通し、そのまま3D UNetに通して動画を生成します。3D UNetがいらない気もしますが、上記論文(2つ目)のRefinement Networkを参考にしました。

データセットは最初の実験で用いたものと同じものを用いました。また、学習の際にはデータセットの動画の一フレーム目を入力として与え、動画を生成し、正解データと平均絶対値誤差を取っています(従ってDiscriminatorを用いてAdversarial lossを求めたりはしていません)。
以上により、生成した各フレームを以下に示しますが目のところに何か光があるだけで、瞬きとしては出来ていません。

これは、画像領域の大きさからして目の部分が小さすぎてCNNが見れてない所為ではと考えました。そこで、今回は瞬きということで目の部分だけを抽出し、目だけ学習させ生成した動画を元に戻しました。領域ごとに抽出して学習するというのはPairedCycleGANが行っていたので、ここから着想を得ました。
学習の詳細は以下に示します。

  • 最適化手法はAdam(α=0.0002、β1=0.5)
  • バッチサイズは2。つまり一回のiterationに2本の動画を用いた

⑥ Result

それでは生成結果を以下に示します。左が参照動画で、右が一フレーム目だけを与えた結果になります。きちんと瞬きが出来ていますね、また目の開閉タイミングも参照動画の通りになっています。

では、GANで生成した画像に対して同様の瞬きを与えます。結果を以下に示します。特に問題ないですね。生成した二次元美少女が瞬きをしています。しかし、上の結果もそうですが、抽出した目の領域の境界線がはっきりと分かります。これは不自然なので、更にこの境界線を補正するようなネットワークを後段につける必要がありそうです。

⑦ Summary

この章では、生成した画像に動きを与えるためOptical flowを条件付けとしたUNetで瞬きを与えました。
次のステップとしては、全身を使った大きな動きを与えたい、となります。しかし、これは参照している動画のOptical flowを条件付として与えるだけでは筋が悪いと考えています。というのも全身を表すOptical flowはそのキャラクターの造形に依存しており、少なくとも入力画像に沿ったOptical flowを与える必要があると考えるからです(今回は目という大体どのキャラも構造が似ているものを利用したのでうまくいった?)。やることとしては、参照動画のOptical flow→入力画像に沿ったOptical flowへと変換するか、もしくは他の特徴量を用いるか….いずれにしても一筋縄ではいかず、また長い道のりになりそうです。
動画生成や動画スタイル変換はまだ調べて日が浅いということもあるので、何か参考になる論文等知っている方いらっしゃいましたらご教授願いたいです。

Summary

まずは、ここまで読んでいただき有難うございます。文章として拙かったり間違ったことを述べていたかもしれません….
今回の記事では、画像生成と超解像、そして(局所的な)動画生成について述べました。動画生成に関してはほんの一部だけの処理とは言え、動かせることが出来て満足しています。次は、もっと大きな動きを画像に与えたいですね。そして最終的に一枚の画像だけを用意してLive2Dのような動きが出来ればと思います。

気がつけば今年も終わりですが、今年は主に画像と動画について取り組んだ一年でした。加藤恵生成計画としてはまだまだ遠い先ですが….次の一年も、勿論CV系を行っていきますが個人的には動かせたら声帯を付与したいと考えています。従って、TTSも勉強していきたいですね。

--

--