1. haru1977

    Posted

    haru1977
Changes in title
+kerasでGrad-CAM 自分で作ったモデルで
Changes in tags
Changes in body
Source | HTML | Preview
@@ -0,0 +1,143 @@
+### kerasでGrad-CAM 自分で作ったモデルで
+
+```
+ここでは、Python3.6.4 で行なっています。また、主に以下のパッケージを利用しています。
+Keras (2.1.5)
+```
+### はじめに
+***
+
+kerasでGrad-CAMを行ってみました。自分で作成したモデルで試しています。
+モデルは、kaggleの dog vs cat のデータについてResnet50で転移学習をおこない
+作成しました。
+
+犬か猫かを判別するモデルについて、どこの影響が大きいのかをみてみます。
+なお、画像サイズは200x200でモデルを作成したので、そのサイズにしています。
+
+まずは関数の部分。
+
+```py
+
+# coding:utf-8
+
+import pandas as pd
+import numpy as np
+import cv2
+from keras import backend as K
+from keras.preprocessing.image import array_to_img, img_to_array, load_img
+from keras.models import load_model
+
+K.set_learning_phase(1) #set learning phase
+
+
+
+def Grad_Cam(input_model, x, layer_name):
+ '''
+ Args:
+ input_model: モデルオブジェクト
+ x: 画像(array)
+ layer_name: 畳み込み層の名前
+
+ Returns:
+ jetcam: 影響の大きい箇所を色付けした画像(array)
+
+ '''
+
+ # 前処理
+ X = np.expand_dims(x, axis=0)
+
+ X = X.astype('float32')
+ preprocessed_input = X / 255.0
+
+
+ # 予測クラスの算出
+
+ predictions = model.predict(preprocessed_input)
+ class_idx = np.argmax(predictions[0])
+ class_output = model.output[:, class_idx]
+
+
+ # 勾配を取得
+
+ conv_output = model.get_layer(layer_name).output # layer_nameのレイヤーのアウトプット
+ grads = K.gradients(class_output, conv_output)[0] # gradients(loss, variables) で、variablesのlossに関しての勾配を返す
+ gradient_function = K.function([model.input], [conv_output, grads]) # model.inputを入力すると、conv_outputとgradsを出力する関数
+
+ output, grads_val = gradient_function([preprocessed_input])
+ output, grads_val = output[0], grads_val[0]
+
+ # 重みを平均化して、レイヤーのアウトプットに乗じる
+ weights = np.mean(grads_val, axis=(0, 1))
+ cam = np.dot(output, weights)
+
+
+ # 画像化してヒートマップにして合成
+
+ cam = cv2.resize(cam, (200, 200), cv2.INTER_LINEAR) # 画像サイズは200で処理したので
+ cam = np.maximum(cam, 0)
+ cam = cam / cam.max()
+
+ jetcam = cv2.applyColorMap(np.uint8(255 * cam), cv2.COLORMAP_JET) # モノクロ画像に疑似的に色をつける
+ jetcam = cv2.cvtColor(jetcam, cv2.COLOR_BGR2RGB) # 色をRGBに変換
+ jetcam = (np.float32(jetcam) + x / 2) # もとの画像に合成
+
+ return jetcam
+
+```
+
+### やってること
+***
+理論の詳細な説明は他に譲りますが、ここでは画像の予測クラスを取得したのち、
+予測への影響が大きい画像箇所を特定し、色付けをしています。
+予測への影響については、その箇所に変化を加えたときに、予測確率にどの程度の変化が生じるか、
+ということで特定しています。
+
+コードでは、「勾配を取得」のあたりで計算をしています。ここでは、レイヤーの出力が必要になりますので、
+K.functionなどを利用しています。
+
+そのあと、レイヤーに重みを乗じて画像化してヒートマップにしています。
+ヒートマップにする部分はopencvを利用していますが、pythonで画像を読んだ時とRGBの順番が
+違うので、同じにして元の画像と合成できるようにしています。
+(画像部分では型変換をしきりに行っていますが、arrayを画像にしたり連結させる上で必要な処理とのこと)
+
+
+### 実行
+***
+
+実際に実行してみますが、レイヤーの名称を特定する必要があります。
+model.summary()でレイヤーの構造と名称は把握できると思います。
+Grad-CAMではConvolution最終層の勾配を取るらしいので、その名称を入力しています。
+だいたい、(各種処理・・・ → pooling → flatten ) と進むと思うので、各種処理の最後の層名称を
+入れてます。activationになっちゃってるのはresnetだからかな・・・
+
+私自身の理解が怪しい部分もあるので、間違っている部分などあれば
+ご指摘いただけるとありがたいです。
+
+
+```py
+
+model = load_model("./resnet_cat_dog.h5")
+x = img_to_array(load_img('./input/cat10007.jpg', target_size=(200,200)))
+array_to_img(x)
+```
+![Unknown.jpg](https://qiita-image-store.s3.amazonaws.com/0/50110/2a7556fb-4bce-7cad-8465-be74bf0586c4.jpeg)
+
+```py
+image = Grad_Cam(model, x, 'activation_49')
+array_to_img(image)
+```
+
+
+![Unknown.jpg](https://qiita-image-store.s3.amazonaws.com/0/50110/da97b315-2ed7-a724-cd1b-258fa0e560a2.jpeg)
+
+
+
+
+
+
+
+
+
+
+
+