Deep Learning を使って背景イラストを生成した話

お疲れ様です。まっくす @minux302 と申します。 話が長いのでまずは完成した背景イラストを見せます。キャラクターに馴染むような背景イラストを Deep Learning の技術を使って生成していきます。ちょっと長いですがお付き合いいただければ幸いです。

f:id:minux302:20171110123021j:plain

秘められた力で背景写真を自分に馴染むように変換したと勘違いしている女の子のイラスト

背景と提案

背景

絵、描けるようになりたいですよね。背景画,憧れますよね。 よく絵描きの方々が描く、アンニュイな表情した女の子が廃墟や浜辺に佇んでるような絵を描けるようになりたいですよね。 ……. 描けないですよね…. 趣味でちょこちょこキャラ絵とか描いたりするんですが背景画は全然描きません (描けません)。

背景画を描く際には、キャラとはまた違った知識や技法とかがおそらく必要になってきます 。あと描く量が多いので大変です。そしてある程度はパースなりなんなりを意識して描かないと変な感じになってしまいます。

そんな僕でもやっぱりキャラに背景画を付け加えたい時があります。そういう時は写真を使います。絵を描く必要もなく、パースも完璧です。案外写真でも、加工してうまいこと使えばかなりキャライラストに映えます。フォトショやクリスタでガシガシうまいことやれば、かなりいい感じになる(らしい)。

問題点

でもやっぱり加工した写真の中にキャラクターを立たせても浮いてしまうんですよね。技術不足などもあるでしょうが以下の点あたりが自分は気になります。

  • 色合い
  • 質感

そのままバンとキャラをのせても、彩度とか色相とか全然違ったりして浮いちゃいますよね。 もう一つは質感(や描き込み量)。写真は本当に細かいところまで描いてあるし、色の塗り方(?)も全然違う。絵描きの方はキャラを描いてるのと似たような筆で、似たような塗り方で背景画を描いたりしているので、いい感じにキャラが浮かず馴染んでいるように思います。

提案

そこで、加工した背景写真からキャラが浮いちゃう問題を Deep Learning ってやつでなんとかしたいと思います。今回は 画風変換 の技術を使いました。一時期話題になったので皆さんも多分ご存知だと思います。ゴッホの絵のスタイルを写真に反映させました!って画像をよく見ましたよね。

f:id:minux302:20171110094342p:plain
本家の人たちのHPから引用した図
1の背景写真に2のゴッホのスタイル反映させ3を生成している

今回のブログは、この画風変換の技術を使って、自分が描いたキャラクターの塗りのスタイルを写真に反映させて、キャラクターに馴染んだ背景写真を生成しよう!と言うお話です。 上図のゴッホの場合のように、キャラの質感を風景写真に反映させたらキャラが浮かないような背景画像が生成されるのでは?という目論見です。 画風変換についてはこちらの記事がとてもわかりやすくまとめられています。

 画風変換について

画風変換の流れ

画風変換の技術では、画像を”コンテンツ“と”スタイル“に分けて考えます。コンテンツとは、物体を物体として認識するための情報、つまり輪郭などのことです。スタイルはテクスチャなど、質感のことです。

以下、画風を変換させたい画像をコンテンツ画像、反映させたいスタイルを持っている画像をスタイル画像とします。画風変換は何をしているかというと、コンテンツ画像において、コンテンツを保ちながらスタイルを弱めて、スタイル画像のスタイルと入れ替えてしまおう、ということをしています.。そうなってくると

  1. どのようにしてコンテンツを保ちながらスタイルを弱めるか
  2. スタイルをどうやって獲得するか

ということが必要になってきます。

 画風変換の大雑把な中身

どのようにしてコンテンツを保ちながらスタイルを弱めるか

下図は画像認識に用いられる Deep Learning の中身です(VGGモデル)。Deep っていうくらいなので深いです。深いってのは図のように層が何層にも重なってるという意味です。左から画像が入力され、だんだんと層を経て右側から値が出力されます。

このVGGモデルはもともと画像認識のタスクに使われていたモデルです。画像認識とは、猫の画像を入力した時に、それが猫の画像であると判定できるようなタスクです。 このモデルに画像を入力すると、物体を認識するのに必要な情報だけ抽出されるように画像が変換されていきます。

物体を認識するのにどんな情報が必要かと言われれば、物体の輪郭などが考えられます。反対に質感などはあまり必要ありません。

f:id:minux302:20171110101213p:plain
出典:VGG in TensorFlowより VGG モデル
このVGGモデルに画像を入力することにより、コンテンツを保ったままスタイルを弱めることができます。 実際に画風変換の論文 A Neural Algorithm of Artistic Styleh から引用した図を下図に載せます。

下方の家の写真では、実際にVGGモデルに画像を入力して、各層から得られる情報から画像を再構成しています。なんとなく深い層の部分では画像の質感等が失われて、輪郭だけが残るようになってるように見えませんか?.

f:id:minux302:20171110100236p:plain
VGGモデルの途中の層から得られる情報から画像を再構成

スタイルをどのように獲得するか

次にどのようにして画像のスタイル(質感)を獲得するのか、ということについて述べます。まず何かを獲得するには相手を見定めなければなりません。つまりどのようにスタイルを定義するか、ということです。 VGG の途中の層からは何枚かの画像データが取得できます。

この論文では、それらの画像間での関係性(相関)によってスタイルを定義しています。詳しいことは数式を用いないの説明できないのですが、これを用いることによって画像の色、線の太さやテクスチャなどの情報が獲得できます。 この定義によって定められたスタイル情報を元に画像を再構成した結果が上図の上方の図です。各層からゴッホの絵のスタイルが再構成できているように見えますね。

どのように学習するか

次にどのように学習していくかという話をします。 Deep Learning では”損失関数”というものを定義して、それを最小化するような学習を行います。損失関数はどれだけ欲しいものが得られているかの指標となります。この値が小さいほど、欲しいものが獲得できていることになります。 今回は、生成された画像が

  • どれだけコンテンツ画像のコンテンツを持っているか (\mathcal{L_{contents}} とします)
  • どれだけスタイル画像のスタイルが反映されているか (\mathcal{L_{style}} とします)

ということが指標となります。生成された画像がコンテンツ画像と同じコンテンツであれば \mathcal{L_{contents}} = 0であり、コンテンツ画像からコンテンツが離れるほど \mathcal{L_{contents}} の値は大きくなります。\mathcal{L_{style}} についても同様のことが言えます。 指標が二つあるので和をとり以下のように損失関数 \mathcal{L_{total}} が定義されます。\mathcal{L_{total}} = \alpha \mathcal{L_{contents}} +\beta \mathcal{L_{style}}

\alpha, \beta はどれだけコンテンツ、スタイルの差を損失関数に反映させるかを決める重みです。これらのパラメータは人間が決める必要があり、そのようなものをハイパーパラメータと言います。後々出てくるので覚えておいてください。
今回はこの \mathcal{L_{total}} が小さくなるような画像を生成するように学習が進んで行きます。VGGの重みは固定で、入力となる生成画像がどんどん更新されていきます。 以上が画風変換の大雑把な流れとなります。

実験

環境

OS: Ubuntu 16.04, CP: Intel Icore 7, Memory: 16G, GPU: GForce 750Ti 今回はこちらのリポジトリのものを使用しました。画風変換(Neural Style Transfer)をTensorflowで実装したものです。嬉しいことに –preserve-colors のオプションをつけることで元画像の色を保持できます。

とりあえず動かす

今回はコンテンツ画像として次の写真を使いました。香川に1人旅に行った時の夕焼けがとても綺麗だったので撮りました。

f:id:minux302:20171110110713j:plain
コンテンツ画像

まずは試しにゴッホの絵をスタイルとして画像を生成します。いい感じになってますね。

f:id:minux302:20171110111011j:plain
ゴッホのスタイル画像を使った時の生成画像

次にいらすとやさんの背景画像をスタイルとして使ってみます。

f:id:minux302:20171110113632j:plain
スタイル画像(風景画)

以下が生成結果です。なるほど、ちょっと角ばった感じの質感になってますね。

f:id:minux302:20171110113748p:plain
いらすとやの風景画をスタイルとして使った場合の生成画像

次に、キャラ画像をそのままスタイルとして使います。

f:id:minux302:20171110111135p:plain
スタイル画像(キャライラスト)

変になってしまった。やっぱりキャラ画像をそのまま使うのは野蛮だったか?

f:id:minux302:20171110114000p:plain
いらすとやのキャラ画像をスタイル画像として使った場合の生成画像

適切なハイパーパラメータを探す

Neural Style Transfer: Prismaの背景技術を解説する にも述べられていたんですが、用いる画像によって適した \alpha, \beta の値が異なるらしいです。諦める前にこの写真とキャライラストの組み合わせにあったハイパーパラメータを探索して行きます。 探索にはグリッドサーチという手法を用いました。あらかじめ \alpha, \beta ( この実装の場合は content_weight と style_weight)の値をいくつか決めておき、それらの組み合わせを全部試していくという手法です。

今回辛いのが定量評価ができないということ。損失関数の値が小さいからといって実際の画像がいい感じにスタイルが反映されたものにはなってないんですね。\mathcal{L_{contents}}\mathcal{L_{style}} の散布図などを書いたりしましたが、良い生成画像の傾向などはあまり見られませんでした。(強いて言うなれば\mathcal{L_{contents}}\mathcal{L_{style}} の比率が、値が小さい時に1:3くらい、値が大きい問いに3:1になってるくらいだったが、ここら辺はあまり詳しくは見ていません。)

色々試した結果、以下の場合が一番いい感じになってると思いました。 content_weight = 0.001, style_weight = 0.1 で500イテレーションで生成しています。実行コードに追加で –content-weight 0.001 –style-weight 0.1 –iteration 500 –preserve-colors のオプションを付け加えています。 キャラ画像のそのままの使用でも、塗りの感じとか割といらすとやっぽいものが反映されているように見えませんか??

f:id:minux302:20171110092636p:plain
content-weight = 0.001, style-weight = 0.1 500イテレーションで色を保持した場合に生成された画像

先ほどのキャラ画像と合わせて少しいじるとこんな感じ。まぁまぁなんでないでしょうか。

f:id:minux302:20171110123021j:plain
合わせた画像

反省と今後の展望

今回は思いつきでとりあえず試してみるかという感じでやりましたが、やっぱり余白が結構あるキャラ画像を無理やり使うのは自分でもかなり野蛮だと思っています。キャラのスタイルをキャラに反映するならまだいいですが、キャラのスタイルを風景写真に反映させるのはちょっと無理があったように思います。

スタイル画像もこの場合はたまたまいいものが生成できましたが、割とうまくいかない場合が多かったです。(下図のようにだいたい画像が壊れた感じになる)このスタイル画像としてのキャラ画像の扱いの仕方を工夫していきたいです。あと以下のように新しい画風変換の技術もあるのでそこらへんも試していきたいです。

f:id:minux302:20171110105643p:plain
うまくいかなかった例

まとめ

画風変換を使って、キャラのスタイル反映したような背景画像の生成を試みた。ハイパーパラメータおじさんになればなんとなくうまくいってるように見える場合もある。正直キャラ画像をそのままスタイル画像として風景写真のスタイル変更に使うのはあんまりよくなさそうです。

良い所 GPUを持っていてパラメータチューニングを頑張れば、キャライラストに馴染みそうな背景画像が生成できる(かもしれない)(ちなみに500iteration 18枚生成とかで1.5hくらいかかった)
悪い所 背景画を描く練習をしないので、一生描けるようにならない。

おまけ

いらすとやの風景画を –content-weight 0.001 –style-weight 0.1 –iteration 500 –preserve-colors で動かした時のもの。色が暗くなっていて見にくいですが、ビルの塗りの筆の感じなど、かなりいらすとやっぽいと個人的に思う。f:id:minux302:20171110114541p:plain 自分が過去に描いたイラストで試した。
–content-weight 0.001 –style-weight 0.1 –iteration 500 –preserve-colors で動かしたもの。 f:id:minux302:20171110114932p:plain​​​​​​​

参考文献

最後までご覧くださりありがとうございました。

プログラミング未経験からでもAIスキルが身につくAidemy Premium Plan

PythonやAIプログラミングを学ぶなら、オンライン制スクールのAidemy Premium Planがおすすめです。
「機械学習・ディープラーニングに興味がある」
「AIをどのように活用するのだろう?」
「文系の私でもプログラミング学習を続けられるだろうか?」
少しでも気になることがございましたら、ぜひお気軽にAidemy Premium Planの【オンライン無料相談会】にご参加いただき、お悩みをお聞かせください!