from Load_process.file_processing import Process_File from keras.models import Model from matplotlib import pyplot as plt import cv2 import numpy as np from keras import backend as K from keras.preprocessing import image import tensorflow as tf import datetime class Grad_CAM: def __init__(self, Label, One_Hot, Experiment_Name, Layer_Name) -> None: self.experiment_name = Experiment_Name self.Layer_Name = Layer_Name self.Label = Label self.One_Hot_Label = One_Hot self.Save_File_Name = self.Convert_One_Hot_To_int() pass def process_main(self, model, index, images): for i in range(len(images)): array = np.expand_dims(images[i], axis=0) # 替圖片增加一個維度,代表他的數量 heatmap = self.gradcam(array, model) self.plot_heatmap(heatmap, images[i], self.Save_File_Name[i], index, i) pass def Convert_One_Hot_To_int(self): return [np.argmax(Label)for Label in self.One_Hot_Label] def gradcam(self, Image, model, pred_index = None): # 首先,我們創建了一個模型,將輸入圖像映射為最後一個卷積層的激活值以及輸出的預測結果。 grad_model = Model( [model.inputs], [model.get_layer(self.Layer_Name).output, model.output] ) # 然後,我們計算了對於輸入圖像而言預測類別的最高梯度,並相對於最後一個卷積層的激活值進行了計算。 with tf.GradientTape() as tape: # 創建一個梯度紀錄器,並做前向傳播 last_conv_layer_output, preds = grad_model(Image) if pred_index is None: pred_index = tf.argmax(preds[0]) class_channel = preds[:, pred_index] # 這是輸出神經元(預測的頂部或所選的)對於最後一個卷積層的輸出特徵圖的梯度。 grads = tape.gradient(class_channel, last_conv_layer_output) # 這是一個向量,其中每個項目是在特定特徵圖通道上梯度的平均強度。 pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2)) # 我們將特徵圖陣列中的每個通道乘以「這個通道相對於頂部預測類別的重要性」,然後將所有通道加總起來,以獲得熱圖類別激活。n last_conv_layer_output = last_conv_layer_output[0] heatmap = last_conv_layer_output @ pooled_grads[..., tf.newaxis] heatmap = tf.squeeze(heatmap) # For visualization purpose, we will also normalize the heatmap between 0 & 1 heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap) return heatmap.numpy() def plot_heatmap(self, heatmap, img, Label, index, Title): File = Process_File() # ReLU heatmap = np.maximum(heatmap, 0) # 正規化 heatmap /= np.max(heatmap) # 讀取影像 # img = cv2.imread(img) fig, ax = plt.subplots() # im = cv2.resize(cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB), (img.shape[1], img.shape[0])) # 拉伸 heatmap img_path = cv2.resize(img, (512, 512)) heatmap = cv2.resize(heatmap, (512, 512)) heatmap = np.uint8(255 * heatmap) img_path = cv2.cvtColor(img_path, cv2.COLOR_BGR2RGB) # 以 0.6 透明度繪製原始影像 ax.imshow(img_path, alpha=1) # 以 0.4 透明度繪製熱力圖 ax.imshow(heatmap, cmap='jet', alpha=0.3) save_root = '../Result/CNN_result_of_reading('+ str(datetime.date.today()) + " )/" + str(Label) File.JudgeRoot_MakeDir(save_root) save_root = File.Make_Save_Root(self.experiment_name + "-" + str(index) + "-" + str(Title) + ".png", save_root) # 存plt檔 plt.savefig(save_root) plt.close("all") # 關閉圖表 pass