ブログ名

Smooth gradによる可視化

本記事で行うこと

前回の記事まででは、人検知を行うための環境構築を行い、実際に人検知を行いました。 これで一通り人検知は行えたことにはなります。

しかし、人検知含む画像認識において、機械はどのように画像を見て、検知しているのでしょうか? 今回はSmooth gradという技術を用いて機械がどのように人検知を行っているか可視化してみます。

機械がどのように人検知しているかということを知る意義

Smooth gradの説明や実行の仕方を説明する前に、まず、なぜ機械がどのように人検知を行っているか、すなわちモデルの中身を知ることが重要であるかを説明させていただきたいと思います。

近年、コンピューターのスペックが高まり、ディープラーニングなど機械学習を行える環境が整ったことなどから、機械学習を用いたAI技術が特に発達しています。 実際に機械学習を用いると、人検知を含む画像認識や音声認識など様々な分野で、高い精度で行えます。

その一方で、人検知などの技術を実際に自動運転などで用いるためには、非常に高い精度かつリアルタイムに行える必要があり、よりモデルを改善していく必要があります。

そのためには、ディープラーニングで作成したモデルを人間が理解し、アルゴリズムのどこが悪いか同定、改善する必要があります。

そこで、本記事ではSmooth gradという技術で、モデルからの見え方を可視化するということを目的に説明したいと思います。

Smooth gradについて

それではSmooth gradとは何なのか?何をやっているのかを軽く説明したいと思います。

Smooth gradでは、Sensitive Map(感度マップ)というものを作成することにより、入力画像のどの部分が最もクラス(「人」や「リンゴ」などその物体の名前、概念)の決定に影響を与えているか?ということを視覚的に表します。

これがすなわち、機械学習したモデルから見た見え方になるわけです。

前回にも説明したように、SSDなどのような画像認識のアルゴリズムは、最終的にCNNで物体の特徴抽出や識別を行っています。すなわち以下の図のように、入力画像に対してその画像、物体検知ではその物体だと思われる部分がどのクラスに当たるかを、すべてのクラスに対してそのクラスである確率を導出し、その中で最大のものをその領域のクラスと定義して出力します。

f:id:iTD_GRP:20190619235336p:plain
画像認識のイメージ図

そのため、感度マップを求めるためには、Sc(x)をxで微分すなわち各ピクセルごとでのSc(x)を求めることで、画像内でのSc(x)の変化が見られるため、最終的に感度マップMc(x)を作成することができます。

しかしそのままMc(x)を用いるだけでは画素値がノイズとなるため、Smooth gradでは画像の平滑化を行い、感度マップを作成しています。

f:id:iTD_GRP:20190619235423p:plain

Smooth gradによる感度マップ作成イメージ図

Smooth gradの実行

それでは実際にSmooth gradを実行してみたいと思います。Smooth gradの原著論文著者らがGitHubでコードを公開しているため、今回はそれを使って可視化してみたいと思います。

準備

まずは、GitHubから以下のようにクローンして、クローンしたリポジトリ(フォルダ)に移動します。(少し時間がかかります)

1 git clone https://github.com/pair-code/saliency
2 cd saliency

次にこのSmooth gradを実行するのに必要がsaliencyというライブラリを以下のコマンドでインストールします。

1 pip install saliency

インストールされていない場合は以下のコマンドでインストールしてください。

1 curl -kL https://bootstrap.pypa.io/get-pip.py | sudo python3

今回はクローンしてきたsaliencyのExample.ipynbというファイルを改変して実行したいと思います。

まず、Example.ipynbをjupyter notebookで開きましょう。

1 jupyter notebook Example.ipynb

するとブラウザが立ち上がって、Example.ipynbがjupyter notebookで開かれます。

f:id:iTD_GRP:20190619235746p:plain
jupyter notebookの起動画面

まずその前に本プログラムでは、tensorflowのslimを使っています。そのファイルのパスを以下のようにmodels/slimからmodels/research/slimのように変更します

1 if not os.path.exists('models/research/slim'):
2   !git clone https://github.com/tensorflow/models/
3 old_cwd = os.getcwd()
4 os.chdir('models/research/slim')
5 from nets import inception_v3
6 os.chdir(old_cwd)

変更したら変更したテキストボックスにフォーカスした上で、以下の画像のように上部にあるRunをクリックして実行します。

f:id:iTD_GRP:20190620000031p:plain
jupyter notebookの実行方法

すると、ドーベルマンの画像を用いた従来手法(Vanilla Gradiant)とSmooth gradの比較画像が出力されます。

また、より精度よく見るためには、Guided Backpropagation(後述)を行う必要がありますが、こちらも出力されます。

補足として、このSmooth gradの研究では、従来手法として使われていたVanilla gradiantにガウシアンフィルタというものを加え、画像のノイズを取ることで、より鮮明にCNNがどこを見て判断しているかを分かりやすくしているものになります。

また、このプログラムはInception V3というCNNで作成されています。

f:id:iTD_GRP:20190620000059p:plain

SSDの実際の出力結果との比較

感度マップの出力はできました。

前回の記事の最後にも説明したように、現在はYOLOv3やSSD(VGG-300)が比較的精度が良いと言われています。そこで今回はさらにSSD(VGG-300)のCNNとして用いられているVGGをSmooth gradで可視化してみようと思います。ちなみに、SSD(VGG-300)とは、VGGをCNNとして用いたSSDで、300×300の画像を用いて学習したモデルという意味で、しばしばこの表現はモデルを示すのに使われます。

それでは実際のSSDの検知結果との比較を行ってみます。

VGGの可視化

まず、VGGの可視化を行います。Smooth grad以外にもCNNがどのように見ているか可視化する手法として、Grad-CAMという手法もあります。

今回はCNNを可視化することが目的であるということと、VGGを可視化するGrad-CAMのリポジトリがあることからGrad-CAMを使って可視化します。

Grad-CAMについて

Grad-CAMとはGradient-weighted Class Activation Mappingの略で、学習済みモデルは入力画像のどこを重点的に見ているか可視化する手法です。

具体的には、前述のSmooth gradと同様に勾配を求めてそれを可視化するという手法を取っており、どのピクセルがクラス(物体名)の決定に影響を与えているかを可視化しているものになります。

これに加え、Guided Backpropagationというものもあります。これも勾配を逆伝搬してピクセルごとのクラスへの影響を可視化しているものになります。

Grad-CAMは最も出力層に近いもののみ考慮している一方、Guided BackpropagationはCNNの各層の勾配を考慮して出力されています。これらを掛け合わせて最終的にGuided Grad-CAMとして出力するものです。

Grad-CAMの実行

それでは実際にGrad-CAMを実行して可視化してみましょう。

Grad-CAMを行うために、まず以下のようにGitHubからリポジトリをクローンしてきましょう。

1 git clone https://github.com/PowerOfCreation/keras-grad-cam.git

これを以下のように実行するとGrad-CAMとGuided Grad-CAMを得ることができます。

1 python grad-cam.py input.jpg

f:id:iTD_GRP:20190620000315p:plain
左図:Grad-CAM,右図:Guided Grad-CAM

SSDを用いた検出

ここまでで、SSDでしばしば用いられるVGGは人をどのように見ているかがわかりました。 それではその結果、SSD(VGG-300)を使うとどのように出力されるか見てみましょう。

まず、SSDをクローンします。

1 git clone https://github.com/rykov8/ssd_keras.git

このままだと使用するkerasのバージョンが低いものにしか対応していないため、以下の3つのコマンドを打ち、最新バージョンに変更します。

1 git fetch origin pull/141/head:api_update_to_keras2
2 git branch -a
3 git checkout api_update_to_keras2

そしてjupyter notebookでSSD300.ipynbを開き、実行してSmooth gradで用いた画像で認識を行うと、以下のようになります。

f:id:iTD_GRP:20190620000447p:plain
SSDを用いて検知した画像

VGGの出力結果とSSDの結果を比較して

VGGを可視化した結果(図5)とSSDを用いて人検知した結果(図6)を比較してみます。

まず、最も人の可能性が高いと検知したの良い真ん中の男の子(確率:0.99)に関しては確率としては高い一方で、矩形領域に関しては上に長いように考えられます。その原因を図6から考察すると、まず、図5の右図から明確に男の子の輪郭を捉えられていないことがわかります。そして左図からは、男の子の中心部分が色が濃く、最も人であると検知していること、そして、男の子の上部も色が濃く、人と検知されている部分があることがわかります。そのため実際に図6でも人である確率は高いと検出されている一方で真ん中の男の子は実際より縦長に誤検知してしまっていると考えられます。

両サイドの男の子は、図5右図でも比較的明確に輪郭が現れているため、結果、図6でも矩形、確率ともに精度が良いことがわかります。

最後に最も後ろに映っている男の子に関して、図6の右図からもあまり明確に現れておらず、結果として図6でも他と比べてあまり精度が良くないことがわかります。

今回は比較的成功した場合でしたが、このような場合以外にも物体認識や物体分類において誤検知したときになにが原因かということを考察するためにこのような技術は使われます。

[参考サイト]


次の記事へ

前の記事へ 目次に戻る