深度学习框架输出可视化中间层特征与类激活热力图

有时候为了分析深度学习框架的中间层特征,我们需要输出中间层特征进行分析,这里提供一个方法。

(1)输出中间特征层名字

导入所需的库并加载模型

import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from torch.nn import functional as F
from torchvision import transforms
import numpy as np
from PIL import Image
from collections import OrderedDict
import cv2
from models.xxx import Model  # 加载自己的模型, 这里xxx是自己模型名字
import os
device = torch.device('cuda:0')
model = Model().to(device)
print(model)

输出如下,这里我只截取了部分模型中间层输出

Model((res): ResNet50((conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3))(maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)(layer1): Sequential((0): ResNet50DownBlock((conv1): Conv2d(64, 64, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(extra): Sequential((0): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1))(1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(1): ResNet50BasicBlock((conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(2): ResNet50BasicBlock((conv1): Conv2d(256, 64, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(64, 256, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(layer2): Sequential((0): ResNet50DownBlock((conv1): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(extra): Sequential((0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2))(1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(1): ResNet50BasicBlock((conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(2): ResNet50BasicBlock((conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(3): ResNet50DownBlock((conv1): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(128, 512, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(extra): Sequential((0): Conv2d(512, 512, kernel_size=(1, 1), stride=(1, 1))(1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))))(layer3): Sequential((0): ResNet50DownBlock((conv1): Conv2d(512, 256, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(extra): Sequential((0): Conv2d(512, 1024, kernel_size=(1, 1), stride=(2, 2))(1): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(1): ResNet50BasicBlock((conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(2): ResNet50BasicBlock((conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))(3): ResNet50DownBlock((conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(extra): Sequential((0): Conv2d(1024, 1024, kernel_size=(1, 1), stride=(1, 1))(1): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(4): ResNet50DownBlock((conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(extra): Sequential((0): Conv2d(1024, 1024, kernel_size=(1, 1), stride=(1, 1))(1): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)))(5): ResNet50DownBlock((conv1): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))(bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(conv3): Conv2d(256, 1024, kernel_size=(1, 1), stride=(1, 1))(bn3): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)(extra): Sequential((0): Conv2d(1024, 1024, kernel_size=(1, 1), stride=(1, 1))(1): BatchNorm2d(1024, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True))))

(2)加载并处理图像

img_path = './dataset//val_data/images/100_0019_0165-11.jpg'
img = Image.open(img_path)
imgarray = np.array(img)/255.0
# plt.figure(figsize=(8, 8))
# plt.imshow(imgarray)
# plt.axis('off')
# plt.show()

加载后如下

将图片处理成模型可以预测的形式

# 处理图像
transform = transforms.Compose([transforms.Resize([512, 512]),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
input_img = transform(img).unsqueeze(0)  # unsqueeze(0)用于升维
# print(input_img.shape)   # torch.Size([1, 3, 512, 512])

(3)可视化中间层

1.定义钩子函数

# 定义钩子函数
activation = {}  # 保存获取的输出
def get_activation(name):def hook(model, input, output):activation[name] = output.detach()return hook

2.可视化中间层特征,这里选择了一个层,其他的自己可以类推

# 可视化中间层特征
checkpoint = torch.load('./checkpoint_best.pth')  # 加载一下权重
model.load_state_dict(checkpoint['model'])
model.eval()
model.res.layer1[2].register_forward_hook(get_activation('bn3'))  #resnet50 layer1中第三个模块的bn3注册钩子
input_img = input_img.to(device)  # cpu数据转一下gpu,这个看你会不会报错,我的不转会报错
_ = model(input_img)
bn3 = activation['bn3']   # 结果将保存在activation字典中  bn3输出<class 'torch.Tensor'>, tensor是无法用plt正常显示的
# print(bn3.shape)  # 调试到这里基本成功了
bn3 = bn3.cpu().numpy() # 转一下numpy,  shape:(1,256, 128, 128) 
plt.figure(figsize=(8,8))
plt.imshow(bn3[0][0], cmap='gray')  # bn3[0][0]  shape:(128, 128)
plt.axis('off')
# # shape:(128, 128)
plt.show()

可视化结果

(4)利用循环输出多张图像可视化中间层

整合上面的代码,利用循环输出验证集中的多张图像中的可视化中间层

# 加载依赖包
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
from torch.nn import functional as F
from torchvision import transforms
import numpy as np
from PIL import Image
from collections import OrderedDict
import cv2
from models.M_SFANet import Model
import os
import glob# 定义钩子函数
activation = {}  # 保存获取的输出
def get_activation(name):def hook(model, input, output):activation[name] = output.detach()return hook# 加载模型
device = torch.device('cuda:0')
model = Model().to(device)checkpoint = torch.load('./checkpoint_best.pth')  # 加载一下权重
model.load_state_dict(checkpoint['model'])
model.eval()
model.res.layer1[2].register_forward_hook(get_activation('bn3'))  #resnet50 layer1中第三个模块的bn3注册钩子,如果需要其他层数就用其他的# 利用循环输出多个可视化中间层#读取需要输出特征的图像
DATA_PATH = f"./val_data/"
img_list = glob.glob(os.path.join(DATA_PATH, "images", "*.jpg"))    # image 路径
img_list.sort()
for idx in range(0, len(img_list)):img_name = img_list[idx].split('/')[-1].split('.')[0]  # 获取文件名img = Image.open(img_list[idx])  # 可以读到图片imgarray = np.array(img)/255.0# 处理图像transform = transforms.Compose([transforms.Resize([512, 512]),transforms.ToTensor(),transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])input_img = transform(img).unsqueeze(0)  # unsqueeze(0)用于升维input_img = input_img.to(device)  # cpu数据转一下gpu,这个看你会不会报错,我的会报错_ = model(input_img)bn3 = activation['bn3']   # 结果将保存在activation字典中  bn3输出<class 'torch.Tensor'>, tensor是无法用plt正常显示的bn3 = bn3.cpu().numpy() plt.figure(figsize=(8,8))plt.imshow(bn3[0][0], cmap='jet')  # bn3[0][0]  shape:(128, 128)plt.axis('off')# # shape:(128, 128)plt.savefig('./feature_out/res50/layer1/{}_res50_layer1'.format(img_name), bbox_inches='tight', pad_inches=0.05, dpi=300)

保存至文件夹中如下

---------------------------------------------------更新于2023.1121.28 -----------------------------------------

(5)利用循环输出多张图像类激活热力图

使用类激活热力图,能观察模型对图像识别的关键位置。

这里接着上面的获得的特征图进一步得到类激活热力图

接着上面获取到bn3,代码如下

    bn3 = activation['bn3']   # 结果将保存在activation字典中  bn3输出<class 'torch.Tensor'>, tensor是无法用plt正常显示的'''以下代码用于输出特征图bn3 = bn3.cpu().numpy() plt.figure(figsize=(8,8))plt.imshow(bn3[0][0], cmap='jet')  # bn3[0][0]  shape:(128, 128)plt.axis('off')# # shape:(128, 128)plt.savefig('./feature_out/res50/layer4/{}_res50_layer4'.format(img_name), bbox_inches='tight', pad_inches=0.05, dpi=300)'''# 将特征图用类热力图形式叠加到原图中bn3 = bn3[0][0].cpu().numpy()bn3 = np.maximum(bn3, 0)bn3 /= np.max(bn3)# plt.matshow(bn3)# plt.show()# img1 = cv2.imread('./dataset/ShanghaiTech/part_A_final/val_data/images/100_0019_0165-11.jpg')img1 = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)  # PIL Image转一下cv2bn3 = cv2.resize(bn3, (img1.shape[1], img1.shape[0]))bn3 = np.uint8(255 * bn3)bn3 = cv2.applyColorMap(bn3, cv2.COLORMAP_JET)heat_img = cv2.addWeighted(img1, 1, bn3, 0.5, 0)cv2.imwrite('./heatmap_out/res50/layer1/{}_res50_layer1.jpg'.format(str(img_name)), heat_img)

输出如下

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/307008.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言 linux文件操作(一)

文章目录 一、linux文件权限1.1文件描述符1.2文件描述符的范围和默认值1.3打开文件和文件描述符1.4标准文件描述符1.5文件描述符的重定向和关闭1.6I/O 操作1.7使用文件描述符进行进程通信1.8资源限制 二、C语言文件读写2.1open 函数2.2 flags参数详解2.3 lseek 函数 一、linux文…

竞赛保研 基于情感分析的网络舆情热点分析系统

文章目录 0 前言1 课题背景2 数据处理3 文本情感分析3.1 情感分析-词库搭建3.2 文本情感分析实现3.3 建立情感倾向性分析模型 4 数据可视化工具4.1 django框架介绍4.2 ECharts 5 Django使用echarts进行可视化展示5.1 修改setting.py连接mysql数据库5.2 导入数据5.3 使用echarts…

爬虫学习(1)--requests模块的使用

前言 什么是爬虫 爬虫是一种自动化工具&#xff0c;用于从互联网或其他计算机网络上获取数据。它可以模拟人的行为&#xff0c;自动访问网页&#xff0c;提取感兴趣的数据&#xff0c;并将其存储到本地计算机或数据库中。爬虫通常用于搜索引擎、数据分析、信息聚合等领域&…

Lichee Nano(F1C100s) Linux 开发环境搭建

Lichee Nano是基于全志科技的F1C100s(ARM 926EJS内核)高性能soC芯片设计的迷你开发板。开发板设计小巧精致&#xff0c;将芯片的所有资源都引出&#xff0c;板载USB、Flash、TF卡、4OP LCD接口等&#xff0c;并把所有IO资源引出&#xff0c;方便开发者拓展使用&#xff0c;非常…

24年软件测试的晋升之路与能力要求,“我“该何去何从?

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、软件测试人员的…

java中如何使用elasticsearch—RestClient操作文档(CRUD)

目录 一、案例分析 二、Java代码中操作文档 2.1 初始化JavaRestClient 2.2 添加数据到索引库 2.3 根据id查询数据 2.4 根据id修改数据 2.4 删除操作 三、java代码对文档进行操作的基本步骤 一、案例分析 去数据库查询酒店数据&#xff0c;导入到hotel索引库&#xff0…

程序员必知!适配器模式的实战应用与案例分析

适配器模式是一种结构型设计模式&#xff0c;它允许不同接口的对象协同工作&#xff0c;它通过将一个类的接口转换成客户希望的另外一个接口&#xff0c;使得不兼容的类可以一起工作。适配器模式提高了类的复用性、系统的灵活性和可扩展性&#xff0c;并降低了系统间的耦合度&a…

React快速入门之组件

目录 组件JSX在标签使用{}嵌入JS表达式使用组件组件嵌套以&#x1f332;树的方式管理组件间的关系组件纯粹原则 组件 文件&#xff1a;Profile.js export default function Profile({isPacked true&#xff0c;head,stlyeTmp,src,size 80}) {if (isPacked) {head head &q…

在SpringBoot中自定义指标并使用Prometheus监控报警

公众号「架构成长指南」&#xff0c;专注于生产实践、云原生、分布式系统、大数据技术分享 在10 分钟教你使用Prometheus监控Spring Boot工程中介绍了如何使用Prometheus监控Spring Boot提供的默认指标&#xff0c;这篇介绍如何自定义业务指标&#xff0c;并使用Prometheus进行…

秋招复习篇之代码规范

目录 前言 1、变量命名 2、代码空格 1&#xff09;操作符左右一定有空格&#xff0c; 2&#xff09;分隔符&#xff08;, 和;&#xff09;前一位没有空格&#xff0c;后一位保持空格&#xff0c;例如&#xff1a; 3&#xff09;大括号和函数保持同一行&#xff0c;并有一个空格…

JavaScript Class类 | 类的继承 - 类的使用 -原型与原型链

文章目录 JavaScript class类基础概念属性与方法相关概念私有字段类的name属性 返回类的名字类的访问器方法super关键字 new的过程中发生了什么extends继承 重写-重载 语法细节类声明与类表达式补充理解:let和const的作用域提升规则 类的继承原型与隐式原型链特殊原型链 原型链…

【C++核心编程(一)】

一、内存分区模型 C程序在执行时&#xff0c;将内存大方向划分为4个区域&#xff1a; 代码区&#xff1a;存放函数体的二进制代码&#xff0c;由操作系统进行管理的。 全局区&#xff1a;存放全局变量和静态变量以及常量。 栈区&#xff1a;由编译器自动分配释放,存放函数的…