Grad 您所在的位置:网站首页 unet的pytorch代码 Grad

Grad

2023-07-03 03:03| 来源: 网络整理| 查看: 265

最近感觉类激活图可视化是一件很有趣的事情。 CAM(传送门:CAM实现的流程(pytorch))由于对网络结构有定性要求,所以在可视化一些有多个全连接层的网络时,表现不太友好,于是出现了Grad-CAM。

文章目录 算法思路实现过程1.导入各种包2.定义一些函数3.运行函数

算法思路

引用的博主 G5Lorenzo 一句话

Grad-CAM根据输出向量,进行backward,求取特征图的梯度,得到每个特征图上每个像素点对应的梯度,也就是特征图对应的梯度图,然后再对每个梯度图求平均,这个平均值就对应于每个特征图的权重,然后再将权重与特征图进行加权求和,最后经过relu激活函数就可以得到最终的类激活图

实现过程

先准备图片、标签以及模型 类别标签下载方法: 先安装axel: sudo apt-get install axel 执行下载命令 axel -n 5 https://s3.amazonaws.com/outcome-blog/imagenet/labels.json labels.json如果下不了就从网盘下: 链接:https://pan.baidu.com/s/1JAfwLtVEp1-ourEdd4VLhg 提取码:1234 图片下载: axel -n 5 http://media.mlive.com/news_impact/photo/9933031-large.jpg 模型下载: senet1_1:axel -n 5 https://download.pytorch.org/models/squeezenet1_1-f364aa15.pth resnet18:axel -n 5 https://download.pytorch.org/models/resnet18-5c106cde.pth

1.导入各种包 import cv2 import os import numpy as np import torch import torchvision.transforms as transforms from torchvision import models import json 2.定义一些函数

图片预处理函数

# 图片预处理 def img_preprocess(img_in): img = img_in.copy() img = img[:, :, ::-1] # 1 img = np.ascontiguousarray(img) # 2 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize([0.4948052, 0.48568845, 0.44682974], [0.24580306, 0.24236229, 0.2603115]) ]) img = transform(img) img = img.unsqueeze(0) # 3 return img

1.之后读取图片会使用opencv读取,读取的颜色通道为BGR,为了适应模型,需要将颜色通道转回为RGB。 2.由于更改通道后,数组变为不连续,所以需要使用np.ascontiguousarray将img转为连续数组,否则无法转为tensor。 3.增加第一维的batch通道,使得图片能够输入网络

定义获取梯度和特征图的函数

# 定义获取梯度的函数 def backward_hook(module, grad_in, grad_out): grad_block.append(grad_out[0].detach()) # 定义获取特征图的函数 def farward_hook(module, input, output): fmap_block.append(output)

定义计算grad-cam并显示的函数

# 计算grad-cam并可视化 def cam_show_img(img, feature_map, grads, out_dir): H, W, _ = img.shape cam = np.zeros(feature_map.shape[1:], dtype=np.float32) # 4 grads = grads.reshape([grads.shape[0],-1]) # 5 weights = np.mean(grads, axis=1) # 6 for i, w in enumerate(weights): cam += w * feature_map[i, :, :] # 7 cam = np.maximum(cam, 0) cam = cam / cam.max() cam = cv2.resize(cam, (W, H)) heatmap = cv2.applyColorMap(np.uint8(255 * cam), cv2.COLORMAP_JET) cam_img = 0.3 * heatmap + 0.7 * img path_cam_img = os.path.join(out_dir, "cam.jpg") cv2.imwrite(path_cam_img, cam_img)

4.feature_map.shape[1:] 表示取第一维度及之后的其余维度的尺寸,如 [512, 14, 14] --> (14, 14) 5-6.计算每个通道的权重均值 7.将梯度权重与特征图相乘再累加

3.运行函数 if __name__ == '__main__': path_img = './cam/bicycle.jpg' json_path = './cam/labels.json' output_dir = './cam' with open(json_path, 'r') as load_f: load_json = json.load(load_f) classes = {int(key): value for (key, value) in load_json.items()} # 只取标签名 classes = list(classes.get(key) for key in range(1000)) # 存放梯度和特征图 fmap_block = list() grad_block = list() # 图片读取;网络加载 img = cv2.imread(path_img, 1) img_input = img_preprocess(img) # 加载 squeezenet1_1 预训练模型 net = models.squeezenet1_1(pretrained=False) pthfile = './pretrained/squeezenet1_1-f364aa15.pth' net.load_state_dict(torch.load(pthfile)) net.eval() # 8 print(net) # 注册hook net.features[-1].expand3x3.register_forward_hook(farward_hook) # 9 net.features[-1].expand3x3.register_backward_hook(backward_hook) # forward output = net(img_input) idx = np.argmax(output.cpu().data.numpy()) print("predict: {}".format(classes[idx])) # backward net.zero_grad() class_loss = output[0,idx] class_loss.backward() # 生成cam grads_val = grad_block[0].cpu().data.numpy().squeeze() fmap = fmap_block[0].cpu().data.numpy().squeeze() # 保存cam图片 cam_show_img(img, fmap, grads_val, output_dir)

8.一定要加上net.eval(),不然深一点的网络(如resnet)就会识别出错,而且每次执行后的类激活图都不一样。 9.-1索引为features中最后一个卷积层,看打印的模型就知道了。

squeezenet1_1的Grad-Cam可视化效果 在这里插入图片描述 vgg16的Grad-Cam可视化效果 在这里插入图片描述 resnet50的Grad-Cam可视化效果 在这里插入图片描述

resnet101的Grad-Cam可视化效果 在这里插入图片描述 参考代码链接: https://github.com/TingsongYu/PyTorch_Tutorial/blob/master/Code/4_viewer/6_hook_for_grad_cam.py



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有