
類激活圖可視化:有助于了解一張圖像的哪一部分讓卷積神經網絡做出了最終的分類決策
- 對輸入圖像生成類激活熱力圖
- 類激活熱力圖是與特定輸出類別相關的二維分數網格:對任何輸入圖像的每個位置都要進行計算,它表示每個位置對該類別的重要程度
我們將使用的具體實現方式是“Grad-CAM: visual explanations from deep networks via gradient based localization”
- 給定一張輸入圖像,對于一個卷積層的輸出特征圖,用類別相對于通道的梯度對這個特征圖中的每個通道進行加權
代碼示例如下
-
加載 VGG16 執行圖片分類
from keras.preprocessing import image from keras.applications.vgg16 import VGG16 from keras.applications.vgg16 import preprocess_input, decode_predictions import numpy as np from keras import backend as K import tensorflow as tf tf.compat.v1.disable_eager_execution()##---------------------------------- 加載 VGG16 網絡 model = VGG16(weights='imagenet') ##---------------------------------- 預測給定圖片 img_path = 'elephant.png' img = image.load_img(img_path, target_size=(224, 224)) x = image.img_to_array(img) x = np.expand_dims(x, axis=0) x = preprocess_input(x) preds = model.predict(x) ##---------------------------------- 解讀預測結果 print('Predicted:', decode_predictions(preds, top=3)[0]) # 打印出:對這張圖像預測的前三個類別 # Predicted:', [(u'n02504458', u'African_elephant', 0.92546833), ## 非洲象(African elephant,92.5% 的概率) # (u'n01871265', u'tusker', 0.070257246), ## 長牙動物(tusker,7%的概率) # (u'n02504013', u'Indian_elephant', 0.0042589349)] ## 印度象(Indian elephant,0.4% 的概率)print(np.argmax(preds[0])) # 獲得 非洲象對應輸出索引:386
-
應用Grad-CAM算法,計算類激活熱力圖 heatmap
african_elephant_output = model.output[:, 386] # 預測向量中的 “非洲象” 元素 (None,) last_conv_layer_output = model.get_layer('block5_conv3').output # VGG16 最后一個卷積層 (None, 14, 14, 512)# 類別相對于通道的梯度: “非洲象”類別相對于 block5_conv3 輸出特征圖的梯度 grads = K.gradients(african_elephant_output, last_conv_layer_output)[0] # grads.shape: (None, 14, 14, 512) pooled_grads = K.mean(grads, axis=(0, 1, 2)) # pooled_grads.shape: (512,)# 獲得當前圖 conv_layer_output_value 和 pooled_grads_value 實際值 iterate = K.function([model.input], [pooled_grads, last_conv_layer_output[0]]) pooled_grads_value, conv_layer_output_value = iterate([x]) # 計算加權值 for i in range(512): conv_layer_output_value[:, :, i] *= pooled_grads_value[i]heatmap = np.mean(conv_layer_output_value, axis=-1)
-
可視化
import matplotlib.pyplot as plt heatmap = np.maximum(heatmap, 0) heatmap /= np.max(heatmap) plt.matshow(heatmap) plt.show() ## ---------------------------------------------------- 下方左圖# 縮放 heatmap 后,在原圖上疊加顯示 import cv2 img = cv2.imread(img_path) heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0])) heatmap = np.uint8(255 * heatmap) heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) superimposed_img = heatmap * 0.4 + img cv2.imwrite('elephant_cam.jpg', superimposed_img) ## -------------- 下方右圖
完整代碼參考
from keras.preprocessing import image
from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input, decode_predictions
import numpy as np
from keras import backend as K
import tensorflow as tf
tf.compat.v1.disable_eager_execution()##---------------------------------- 加載 VGG16 網絡
model = VGG16(weights='imagenet') ##---------------------------------- 預測給定圖片
img_path = 'elephant.png'
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
preds = model.predict(x) ##---------------------------------- 解讀預測結果
print('Predicted:', decode_predictions(preds, top=3)[0])
# 打印出:對這張圖像預測的前三個類別
# Predicted:', [(u'n02504458', u'African_elephant', 0.92546833), ## 非洲象(African elephant,92.5% 的概率)
# (u'n01871265', u'tusker', 0.070257246), ## 長牙動物(tusker,7%的概率)
# (u'n02504013', u'Indian_elephant', 0.0042589349)] ## 印度象(Indian elephant,0.4% 的概率)print(np.argmax(preds[0]))
# 獲得 非洲象對應輸出索引:386african_elephant_output = model.output[:, 386] # 預測向量中的 “非洲象” 元素 (None,)
last_conv_layer_output = model.get_layer('block5_conv3').output # VGG16 最后一個卷積層 (None, 14, 14, 512)# 類別相對于通道的梯度: “非洲象”類別相對于 block5_conv3 輸出特征圖的梯度
grads = K.gradients(african_elephant_output, last_conv_layer_output)[0] # grads.shape: (None, 14, 14, 512)
pooled_grads = K.mean(grads, axis=(0, 1, 2)) # pooled_grads.shape: (512,)# 獲得當前圖 conv_layer_output_value 和 pooled_grads_value 實際值
iterate = K.function([model.input], [pooled_grads, last_conv_layer_output[0]])
pooled_grads_value, conv_layer_output_value = iterate([x])
# 計算加權值
for i in range(512): conv_layer_output_value[:, :, i] *= pooled_grads_value[i]heatmap = np.mean(conv_layer_output_value, axis=-1) import matplotlib.pyplot as plt
heatmap = np.maximum(heatmap, 0)
heatmap /= np.max(heatmap)
plt.matshow(heatmap)
# plt.show()# 縮放 heatmap 后,在原圖上疊加顯示
import cv2
img = cv2.imread(img_path)
heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
heatmap = np.uint8(255 * heatmap)
heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
superimposed_img = heatmap * 0.4 + img
cv2.imwrite('elephant_cam.jpg', superimposed_img)
參考書籍:Python 深度學習