Monthly Hacker's Blog

プログラミングや機械学習の記事を中心に書きます。

MosaicChainer -自動モザイクサービス-

できること

この記事では、次のことができるようになります。

  • MosaicChainer(自動モザイクサービス)
  • 分類問題を学習したResNetを用いて画風変換

はじめに

この記事はChainer Advent Calendar 201722日目です。Chainer Advent Calendarといえば、去年PaintsChainerの記事が話題になり、その後の発展はみなさんご存知だと思います。ちょうど同時期に、研究室で話題になったものが今回紹介するMosaicChainerです。Not Suitable For Workな画像をアップロードすると、モザイク(黒塗り)をかけて返してくれます。一応すぐに試せるようにサーバーを用意したのですが、かなり不安定なので、githubよりcloneしてローカルで試してください。
github.com

用意したサーバーはこちらです。
https://sleepy-waters-61207.herokuapp.com/
本当はブログにいくつか例を載せたいのですが、扱う画像の性質上、控えます。

利用上の注意

サーバー版をご利用の際は以下の点にご注意ください。

  • アプリの性能は保証できません。あくまで娯楽としてお楽しみください。
  • サーバーが途中で落ちていると他のユーザーの画像が表示される可能性があります。
  • アップロードされた画像は変換および表示のためにメモリ上に読み込みますが、保存はされません。ただし、前述の通り他のユーザーに見られてしまう可能性があるので、各自の責任でご利用ください。

技術的な解説

MosaicChainerはopen_nsfwからforkしたリポジトリです。open_nsfwはyahooが開発したニューラルネットワークモデルで、入力画像をNot Suitable For Workか否かで分類するResNetベースのCNNです。Residual Blocksのあと、Global Average Pooling、全結合層、softmaxと続く構造のネットワークです。MosaicChainerではGlobal Average Pooling前の特徴量マップ(1024x7x7)を利用しています。poolingをせず、全結合の重みを用いて1x1 convolution(通称projection)、softmaxという構造になっています。projectionを用いることで、Global Average Poolingをsoftmaxの直前にしても結果が同じになります。数式で見てみましょう。まずは元のモデルで全結合層のチャンネルoの出力を求める式を書いてみます。特徴量をx、全結合層の重みバイアスをそれぞれW、bとします。特徴量の添字はチャンネル高さ幅の順、重みの添字は出力チャンネル入力チャンネルの順、バイアスの添字は出力チャンネルとします。

 
\sum_{i=1}^{1024} \left[ W_{oi} \frac{\sum_{h=1}^{7} \sum_{w=1}^{7} x_{ihw}}{49} \right] + b_{o}

ちょうど分数がGlobal Average Poolingの結果を表しています。ここで少し式変形をします。上の式の総和の位置を変えると次のようになります。

 \frac{\sum_{h=1}^{7} \sum_{w=1}^{7} \sum_{i=1}^{1024} W_{oi} x_{ihw}}{49} + b_{o} = \frac{\sum_{h=1}^{7} \sum_{w=1}^{7} \left[ \sum_{i=1}^{1024} \left[ W_{oi} x_{ihw} \right]  + b_{o} \right]}{49}

このうち、 \sum_{i=1}^{1024} \left[ W_{oi} x_{ihw} \right]  + b_{o}がprojectionに当たります。つまり何が起きたかというと、特徴量マップをGlobal Average Poolingせずにlogit(softmax適用前の値)に変換できたということです。この後、特徴量マップのピクセルごとにsoftmaxをすることで、各ピクセルの出力値のようなものが計算できます。これが今回の技術のキモです。

モザイク処理はこの7x7の出力値を入力画像と同サイズにリサイズ後、入力画像とピクセルごとに掛け算しています。これにより、Not Suitable For Workであるほど黒に近づく用になります。

このような出力に影響を与えているピクセルを求める手法は他にもたくさんあります。例えばSmoothGradです。ただ、今回のモザイクのように、ある程度広い範囲でラフにやりたい場合はこのくらい単純な手法のほうがいいかもしれません。

今後について

本当はWebDNNで実装をしようと思っていました。TwitterでWebDNN開発者の @Kiikurage さんが気にかけてくださったので、助けてもらいながら年末年始の休暇で完成させようかと思います。そうすれば小さいサーバーでもある程度安定して動くようになるかと思います。これを期に、もう少しフロント側も書けるエンジニアになりたいものです。また、すでにフロント側も書けるエンジニアのみなさま、PRお待ちしております。
https://github.com/dhgrs/open_nsfw