Skip to content

Top

Guided Grad-CAM

Deep Learningをしていると、CNNのモデルがどこを見ているのかが気になる。

それをヒートマップで可視化する技術がGrad-CAM。
Grad-CAMのGradは勾配、CAMはClass Activation Mapping。

それとは別にGuided Backpropなる手法があり、それらのいいとこ取りをしたのがGuided Grad-CAM。

以下に例示。

Guided Backprop

ピクセル単位の可視化

Grad-CAM

クラス単位の可視化

Guided Grad-CAM

クラス単位かつピクセル単位の可視化

1. デモンストレーションリンク

とりあえずGrad-CAMがどんなもんかは、以下のデモページで確認できる。

Grad-CAM: Demonstration Links

2. 医師と看護師の分類モデルにおける活用例

論文: https://arxiv.org/abs/1610.02391に載っていた例を示す。

医師と看護師を分類するモデルを作成し、Grad-CAMを用いてモデルがどこに着目しているのかを確認する。

うまく判定できなかった時のGradCAM画像。

医師 看護師

顔や髪型で判断しようとしている。
そのため、精度が低い。

学習データの男女比などの隔たりをなくし、再度学習を行う。

医師 看護師

判断する場所が先ほどと代わり、正しく判定できるようになった。

3. 実際に動かしてみる

Torchによるソースコードが公式にある。
https://github.com/ramprs/grad-cam/

が、PyTorchならまだしもTorchじゃさっぱりなので、Chainerに移植してくださった以下のソースを利用させてもらって解説する。
ChainerによるGrad-CAMの実装: https://github.com/tsurumeso/chainer-grad-cam/

1
$ git clone https://github.com/tsurumeso/chainer-grad-cam/

3.1. サンプル実行

前提条件としてChainerはすでにインストール済みであること。

chainer-grad-camディレクトリに移動し、サンプルスクリプト(run.py)を実行する。

1
2
$ cd chainer-grad-cam
$ python run.py --input images/dog_cat.png --label 242 --layer conv5_3
オプション 説明
--label ImageNet1000のラベル値
(242はBoxer)
--layer Convolution層の指定

実行すると画像が出力される。

次にラベルに282(Tiger Cat)を指定して実行してみる。

1
$ python run.py --input images/dog_cat.png --label 282 --layer conv5_3

すると以下の画像になる。

さっきは犬だったが、今度は猫に注目している。

4. AlexNetでGrad-CAM画像生成

デフォルトでVGG16になっている。が、AlexNetでも動かしてみる。

4.1. AlexNet用にサンプルコードを改造

1
2
$ vi run.py
39     x = src.astype(np.float32) - np.float32([103.939, 116.779, 123.68])

1
2
3
4
39    if args.arch == 'vgg':
40        x = src.astype(np.float32) - np.float32([103.939, 116.779, 123.68])
41    else:
42        x = src.astype(np.float32)

4.2. 実行

1
$ python run.py --input images/dog_cat.png --label 242 --layer conv5

???
ゼロ除算が発生する!

以下を参考に修正。

chainer での Grad-CAM についてメモ: http://www.geocities.jp/kandou_quester/Knowledge/Programming/Python/_chainer_grad_cam.html

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ vi models/alex.py

     42             ('prob', [_softmax]),
〜
     63 def _softmax(x):
     64     max_abs = np.max([np.abs(np.max(x.data)), np.abs(np.min(x.data))])
     65     _x = x
     66     _x.data /= max_abs
     67     h = F.softmax(_x)
     68     return h