全22行のコードでGradCAM。tf_explainは、使い易いかも、お薦め！

#目的
**tf_explain**というのがあるらしい。
そこには、**GradCAM**がモジュールとして入っているようです。
それを使っているgithubをみると、
わずか、全22行（空行あり）で、**GradCAM**が実行できていた。
すばらしいと思うので、
動かしてみた。

#全22行のコード
以下のgithubにこのコードがある。
https://github.com/sicara/tf-explain/blob/master/examples/core/grad_cam.py

以下のコードがすべてなので、

```
python grad_cam_py.py
```

だけで、動作します。


```grad_cam.py
import tensorflow as tf

from tf_explain.core.grad_cam import GradCAM

IMAGE_PATH = "./cat.jpg"

if __name__ == "__main__":
    model = tf.keras.applications.vgg16.VGG16(weights="imagenet", include_top=True)

    img = tf.keras.preprocessing.image.load_img(IMAGE_PATH, target_size=(224, 224))
    img = tf.keras.preprocessing.image.img_to_array(img)

    model.summary()
    data = ([img], None)

    tabby_cat_class_index = 281
    explainer = GradCAM()
    # Compute GradCAM on VGG16
    grid = explainer.explain(
        data, model, class_index=tabby_cat_class_index, layer_name="block5_conv3"
    )
    explainer.save(grid, ".", "grad_cam.png")
```

#実行結果

ネコ（の中の「tabby cat」）の画像は、wikipediaより引用。
https://en.wikipedia.org/wiki/Tabby_cat
この種類の猫は、~~顔の真ん中に目を囲むように、Mの文字がある~~ **「額」にMの文字がある**のが特徴らしい。
(※「顔の真ん中に目を囲むように、Mの文字がある」（誤り）も、Mに見えなくもないが。。。）

sample1

<img width="164" alt="cat_sample1.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/2e49e7c0-9f6a-05cf-1f1b-a1f3ccfce4aa.jpeg">![grad_cam_sample1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/fe4bdab9-cfee-52f3-2c4f-a0d2e1b4bdde.png)

sample2




<img width="112" alt="cat_sample2.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/e9ba4a01-765c-dbcc-10c6-c3e75806733d.jpeg">![grad_cam_sample2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/a6ab209d-059e-53d6-06c3-d5a73192b5f6.png)

#結果に対するコメント

GradCAMの結果は、的を射ている気がする。
（ただし、
この記事の目的は、tf_explainが使い易いというところにポイントがあるので、
GradCAM自体の良し悪しに関しては、特に、コメントなし。
念のため、
**GradCAMの表示に気持ちを乗せすぎると、占い師の占いがあたりまくるという心理に近くなる気がするので、できるだけ、冷たい気持ちで見るべきだとは思います、完全な余談ですが。**）

#環境
Window10です。GPUなしです。
**tensorflow               2.0.0**
tf-explain               0.2.1

上記のtf-explainは、たぶん、入っていないと思うので、pip他の通常の方法でinstallして下さい。
**tensorflowは、いま(2020/3/11)だと、2.1.xが最新だと思いますが、ひどくエラーがでました。**
**治し方わからずで、完全な勘！で、2.0.0にすると動きました。**

#この項は、tf_explainのことより、実際にCNNの性質を少し見るための項（この記事からすると余談？）

![cat2_2nd_224.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/fd09c334-c4eb-4469-c101-a4adf2ce73f4.jpeg)![grad_cam_cat2_2nd_224.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/9551322e-6d07-d460-2053-75f33f264a5c.png)



![cat2_3rd_224.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/c779e648-00de-afc6-6032-97e280fd0b76.jpeg)![grad_cam_cat2_3rd_224.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/cb5f0d09-c7cb-c3d5-a49d-2596934b6b2b.png)



![cat2_4th_224.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/49410fc0-2a41-f862-6a3e-1d24ba4fe500.jpeg)![grad_cam_cat2_4th_224.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/f4de6b6e-7664-fda1-e7fe-f82745aa5f3c.png)


![cat2_5th_224.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/d085adbd-7ffd-0db8-0063-f46eb892e8c9.jpeg)![grad_cam_cat2_5th_224.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/9504cc38-d102-b9ca-b32d-b5a58ef67467.png)



![cat2_6th_224.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/61b63a6c-391c-5c62-d4e2-eb8482e9327e.jpeg)![grad_cam_cat2_6th_224.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/fd69b21e-0fb3-76a6-c16e-c094b4392551.png)

この例の場合、
一括で特徴を捕まえられているのは、60x60ピクセル前後ぐらいの範囲か？
⇒最後のほうの画像では、個別の領域に、個別に反応している感じ。
また、画像と注目点の表示は、重畳しないモード（あるのか？）でも表示されたほうが正確にわかるかも。
（元画像の輝度の影響をうけると、わかりにくいので。）
⇒⇒CNNは、「より画像（アップの画像）」に弱いでしょうね。
⇒⇒⇒　全体の構成を追及、把握している感じの表示がGradCAMで示されるようなモデルが出ると感動しますけど。。。（それが、GradCAMで表現できるかは、また、別の話にもなりますが。。。GradCAMで表現できるできないは別として、そのようなモデルが出ると、凄いことかと思います。Capsule系とかで弾けたモデルとかがでれば。。。
）

# 上記の項の関連（よって、余談）。CNNは「寄りに弱い（ズームアップに弱い）」の件。

GradCAMの注目点がよりわかるように、図も追加しました。
確率も追加しました。

![cat2_2nd_224.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/46589ee6-005a-a610-e4b4-cac8c73efd6e.jpeg)![grad_cam_cat2_2nd_224.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/9103da4b-8ccc-9536-450c-d127f09391c1.png)![grad_cam_cat2_2nd_224ex.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/17715dc7-4055-14bc-504a-fd2237b2ed9b.png)

```
[[('n02123045', 'tabby', 0.40362296),
  ('n02124075', 'Egyptian_cat', 0.34350035),
  ('n02123159', 'tiger_cat', 0.1646882),
  ('n02747177', 'ashcan', 0.022324266),
  ('n02127052', 'lynx', 0.009675921),
  ('n03223299', 'doormat', 0.008641529),
  ('n02123394', 'Persian_cat', 0.00528028),
  ('n02909870', 'bucket', 0.0034843169),
  ('n04040759', 'radiator', 0.0028082374),
  ('n03958227', 'plastic_bag', 0.002630277),
  ('n04265275', 'space_heater', 0.002209679),
  ('n04493381', 'tub', 0.0015652123),
  ('n04049303', 'rain_barrel', 0.001464855),
  ('n04553703', 'washbasin', 0.0014180988),
  ('n04589890', 'window_screen', 0.0012623073),
  ('n03887697', 'paper_towel', 0.0012330494),
  ('n04522168', 'vase', 0.0012083148),
  ('n02123597', 'Siamese_cat', 0.0010707852),
  ('n03950228', 'pitcher', 0.0010204213),
  ('n03255030', 'dumbbell', 0.00096622825)]]
```

![cat2_6th_224.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/3904fa2c-a052-f90b-a6ff-d19ad66b211a.jpeg)![grad_cam_cat2_6th_224.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/1f2417eb-dd7b-0379-3d1d-f5ce89c1b82d.png)![grad_cam_cat2_6th_224ex.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/342207/c465fa4d-ca40-4359-d8a0-d181a80a8f8d.png)

```
[[('n03958227', 'plastic_bag', 0.23590706),
  ('n04209133', 'shower_cap', 0.117050014),
  ('n02124075', 'Egyptian_cat', 0.068308175),
  ('n01968897', 'chambered_nautilus', 0.052455623),
  ('n03825788', 'nipple', 0.042889122),
  ('n02123597', 'Siamese_cat', 0.040462725),
  ('n02120079', 'Arctic_fox', 0.02897999),
  ('n03868863', 'oxygen_mask', 0.018255476),
  ('n04370456', 'sweatshirt', 0.018049669),
  ('n02123045', 'tabby', 0.017420992),
  ('n04525038', 'velvet', 0.01728542),
  ('n02123394', 'Persian_cat', 0.0140852835),
  ('n03534580', 'hoopskirt', 0.012244948),
  ('n03724870', 'mask', 0.0106809465),
  ('n03045698', 'cloak', 0.007704126),
  ('n02120505', 'grey_fox', 0.0072637224),
  ('n02326432', 'hare', 0.006367313),
  ('n04127249', 'safety_pin', 0.006034479),
  ('n03887697', 'paper_towel', 0.0056772656),
  ('n04033995', 'quilt', 0.0056173983)]]
```
**tabby は、10位ぐらいですね。。。**
⇒いろいろなサイズでやればいいという言い方あるかもしれませんが、もう少し、構成を強く意識する側になったほうがいい気がします、CNNは。
**tabbyの特徴のMの文字の場所の理解を間違えてサンプルを作って**いるので、肝心のMの文字が画像の領域外になっている。（本当は、やり直したほうがいいのだが。。。。やり直しても、たぶん、ダメなままだと思うので、ちょっと、後回し。）


率を出すのは、以下を参考にしました。
https://medium.com/@gkadusumilli/image-recognition-using-pre-trained-xception-model-in-5-steps-96ac858f4206

変更したソース示します。

```python
import tensorflow as tf

import numpy as np ##
import pprint ##

from tf_explain.core.grad_cam import GradCAM

from tensorflow.keras.applications.vgg16 import decode_predictions ##

IMAGE_PATH = "./cat2_2nd_224.jpg"

if __name__ == "__main__":
    model = tf.keras.applications.vgg16.VGG16(weights="imagenet", include_top=True)

    img = tf.keras.preprocessing.image.load_img(IMAGE_PATH, target_size=(224, 224))
    img = tf.keras.preprocessing.image.img_to_array(img)
    
    predictions=model.predict(np.array([img])) ##
    pprint.pprint(decode_predictions(predictions,top=20))##

    model.summary()
    data = ([img], None)

    tabby_cat_class_index = 281
    explainer = GradCAM()
    # Compute GradCAM on VGG16
    grid = explainer.explain(
        data, model, class_index=tabby_cat_class_index, layer_name="block5_conv3"
    )
    explainer.save(grid, ".", "grad_cam_cat2_2nd_224.png")
    
    grid = explainer.explain( ##
        data, model, class_index=tabby_cat_class_index, layer_name="block5_conv3", image_weight=0.01 ##
    ) ##
    explainer.save(grid, ".", "grad_cam_cat2_2nd_224ex.png") ##
```



#まとめ
日々、環境が進んでますね（**tf_explainのこと**）。
コメントなどあれば、お願いします。
ちなみに、自分の別記事になりますが、以下は、参考になるかも。

[tf-explainのGrad CAMとOcclusion Sensitivityを見比べる](https://qiita.com/enoughspacefor/items/5bc8d9c2660fc177c118)