关于使用pytorch_grad_cam在可视化热力图时,自己的笔记
·
1-网上有很多的案例,基本怎么绘制,自己按照步骤先尝试,没有任何问题。(针对的是resnet50,并加载预训练模型实现)。
2-对于自己搭建的模型和自己的数据集,根据网上代码,修改如下:
#1-导入工具包
import numpy as np
import cv2
from PIL import Image
import matplotlib.pyplot as plt
import torch
from torchvision import models
from torchvision import transforms
from pytorch_grad_cam import GradCAM, HiResCAM, ScoreCAM, GradCAMPlusPlus, AblationCAM, XGradCAM, EigenCAM, EigenGradCAM, LayerCAM, FullGrad, GradCAMElementWise
from pytorch_grad_cam import GuidedBackpropReLUModel
from pytorch_grad_cam.utils.image import show_cam_on_image, deprocess_image, preprocess_image
from pytorch_grad_cam.utils.model_targets import ClassifierOutputTarget
import torchcam
from torchcam.utils import overlay_mask
# 有 GPU 就用 GPU,没有就用 CPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print('device', device)
#2-载入模型
mode_path = r'E:\GaAsEn\model.pth'
model = torch.load(mode_path)
model = model.eval().to(device)
#3-图像预处理
# 测试集图像预处理-RCTN:缩放、裁剪、转 Tensor、归一化
test_transform = transforms.Compose([transforms.Resize((448,448)),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
#4-载入图片
img_path = r'E:/00GaAs_Visual/image/1/1.jpeg'
img_pil = Image.open(img_path)
input_tensor = test_transform(img_pil).unsqueeze(0).to(device) # 预处理
print(input_tensor.shape)
#选择可解释性方法
#GradCAM
# target_layers = [model.basic_block1[-1],model.basic_block2[-1]] # 要分析的层
target_layers = [model.basic_block1[-1]]
# targets = [ClassifierOutputTarget(14)] # 要分析的类别
targets = None
cam = GradCAM(model=model, target_layers=target_layers)
#生成Grad-CAM热力图
cam_map = cam(input_tensor=input_tensor, targets=targets)[0] # 不加平滑
# cam_map = cam(input_tensor=input_tensor, targets=targets, aug_smooth=True, eigen_smooth=True)[0] # 加平滑
print(cam_map.shape)
plt.imshow(cam_map)
plt.title('Grad-CAM')
plt.show()
#叠加在原图像
result = overlay_mask(img_pil, Image.fromarray(cam_map), alpha=0.5) # alpha越小,原图越淡
plt.imshow(result)
plt.title('Grad-CAM')
plt.show()
在以上的代码中,我们实现的是对模型的中间一层,进行可视化。针对于我们原来的模型,他这里有几个特殊的地方:
(1)模型的输出有多个:output1,output2,output3
(2)output1和output2是一个由4个输出结果构成的列表。
因此,针对这个问题,直
接运行这个代码会报错。
针对于这个问题,我的解决方案是:
修改base_cam.py中的代码,具体:

在这里之所以取outputs[0][4],是因为可视化代码中的
target_layers = [model.basic_block1[-1]],这个目标层对应的所有输出是outputs[0],而测试过程中,最好的结果是outputs[0][4]。
通过以上的修改,就可以得到可视化的结果:
热力图:

热力图附着在原图上:

但是,我想要同时计算多个层,把可视化源代码中修改为:
target_layers = [model.basic_block1[-1],model.basic_block2[-1]]
以及对应相同的思想,修改base_cam.py中不能实现,但可以修改模型来实现,具体代码如下:
import torch
import torch.nn as nn
import torchvision.models as models
import torchvision.transforms as transforms
from PIL import Image
import matplotlib.pyplot as plt
from pytorch_grad_cam import GradCAM
from pytorch_grad_cam.utils.image import show_cam_on_image
import numpy as np
from model import MGS
from Resnet import *
# 修改模型以适应 GradCAM
class ModifiedModel(nn.Module):
def __init__(self, original_model):
super(ModifiedModel, self).__init__()
self.original_model = original_model
self.current_output_index = 0
def forward(self, x):
outputs = self.original_model(x)
return outputs[self.current_output_index][4]
# 创建原模型和修改后的模型
net = resnet50(pretrained=False)
original_model = MGS(net)
# 加载整个模型
model_path = r'E:\CGFF-master\GaAsEn\model.pth'
load_model = torch.load(model_path)
#获取保存模型的状态字典
loaded_statte_dict = load_model.state_dict()
#将状态字典加载到新模型中
original_model.load_state_dict(loaded_statte_dict)
modified_model = ModifiedModel(original_model)
modified_model.eval()
# 加载测试图像
img_path = r'E:/00GaAs_Visual/image/1/1.jpeg'
image = Image.open(img_path).convert('RGB')
transform = transforms.Compose([
transforms.Resize((448, 448)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
input_image = transform(image).unsqueeze(0)
# 定义目标层
target_layers2 = [modified_model.original_model.basic_block1[-1]]
target_layers3 = [modified_model.original_model.basic_block2[-1]]
# 生成第 1 个目标层的热力图
modified_model.current_output_index = 0
cam2 = GradCAM(model=modified_model, target_layers=target_layers2)
grayscale_cam2 = cam2(input_tensor=input_image, targets=None)
grayscale_cam2 = grayscale_cam2[0, :]
rgb_img2 = np.array(image.resize((448, 448))) / 255.0
visualization2 = show_cam_on_image(rgb_img2, grayscale_cam2, use_rgb=True)
# 生成第 2个目标层的热力图
modified_model.current_output_index = 1
cam3 = GradCAM(model=modified_model, target_layers=target_layers3)
grayscale_cam3 = cam3(input_tensor=input_image, targets=None)
grayscale_cam3 = grayscale_cam3[0, :]
visualization3 = show_cam_on_image(rgb_img2, grayscale_cam3, use_rgb=True)
# 可视化热力图
plt.figure(figsize=(15, 5))
plt.subplot(131)
plt.imshow(visualization2)
plt.title('Layer 2 Heatmap')
plt.axis('off')
plt.subplot(132)
plt.imshow(visualization3)
plt.title('Layer 3 Heatmap')
plt.axis('off')
plt.show()

单层的也可以采用这种方法来实现,建议使用这种方法,会使得更方便、更灵活。
更多推荐
所有评论(0)