Guided Grad-CAM
Deep Learningをしていると、CNNのモデルがどこを見ているのかが気になる。
それをヒートマップで可視化する技術がGrad-CAM。
(Gradは勾配、CAMはClass Activation Mapping)
それとは別にGuided Backpropなる似たような目的の手法がある。
それらのいいとこ取りをしてがっちゃんこしたのがGuided Grad-CAM。
以下に例示。
Grad-CAM
クラス単位の可視化
Guided Backprop
ピクセル単位の可視化
Guided Grad-CAM
クラス単位かつピクセル単位の可視化
1. デモンストレーションリンク
とりあえずGrad-CAMがどんなもんかは、以下のデモページで確認できる。
2. 医師と看護師の分類モデルにおける活用例
論文: https://arxiv.org/abs/1610.02391に載っていた例を示す。
医師と看護師を分類するモデルを作成し、Grad-CAMを用いてモデルがどこに着目しているのかを確認する。
以下は医師を看護師と間違えて判断したときのGrad-CAM画像。
医師を看護師と間違えてる | 看護師 |
---|---|
顔や髪型で判断しようとしている。一般的に看護師に女性の比率が高いので、女医を看護師と間違えたのだろう。
学習データの男女比などの隔たりをなくし、再度学習を行う。
医師 | 看護師 |
---|---|
判断する場所が先ほどと代わり、正しく判定できるようになった。
3. 実際に動かしてみる
Torchによるソースコードが公式にある。
https://github.com/ramprs/grad-cam/
が、PyTorchならまだしもTorchじゃさっぱりなので、Chainerに移植してくださった以下のソースを利用させてもらって解説する。
ChainerによるGrad-CAMの実装: https://github.com/tsurumeso/chainer-grad-cam/
$ git clone https://github.com/tsurumeso/chainer-grad-cam/
3.1. サンプル実行
前提条件としてChainerはすでにインストール済みであること。
chainer-grad-camディレクトリに移動し、サンプルスクリプト(run.py)を実行する。
$ 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)を指定して実行してみる。
$ python run.py --input images/dog_cat.png --label 282 --layer conv5_3
すると以下の画像になる。
さっきは犬だったが、今度は猫に注目している。
4. AlexNetでGrad-CAM画像生成
デフォルトでVGG16になっている。が、AlexNetでも動かしてみる。
4.1. AlexNet用にサンプルコードを改造
$ vi run.py
39 x = src.astype(np.float32) - np.float32([103.939, 116.779, 123.68])
↓
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. 実行
$ 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
$ 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
以上!