CNNs: ZFNet之CNN的可视化网络介绍
CNNs: ZFNet之CNN的可视化网络介绍
- 导言
- Deconvnet
- 1. Unpooling
- 2. ReLU
- 3. Transpose conv
- AlexNet网络修改
- AlexNet Deconv网络介绍
- 特征可视化
导言
上一个内容,我们主要学习了AlexNet网络的实现、超参数对网络结果的影响以及网络中涉及到一些其他的知识点,如激活函数、dropout等。
经过前面三节关于AlexNet的学习,我们大概了解一个简单的卷积神经网络模型的工作过程和如何针对一个数据集去调参以实现我们期望的模型结果。当然,这里我们忽略了一个重要的点就是数据集,我们训练出来的模型的好坏第一步是要确认我们手头的数据集是比较好的,如我在第二篇中提供的flower数据集,如dandelion下的数据(还有其他)很差,导致我们在训练过程中很难达到我们需要的效果。所以,我们在工程中或者研究中一定要保证第一个前提:采集较好的数据集。当然,当数据集不够时,我们需要对数据集进行增强(这里先挖一个坑,关于数据集增强系列)。
从本篇开始,我们将参考文章Visualizing and Understanding Convolutional Networks基于AlexNet模型对模型训练过程中convnet模块进行探索,窥视网络不同层学习到了什么特征。
Deconvnet
首先,让我们对deconvnet进行介绍:
AlexNet中一个基础的convnet模块基本上要进行卷积、ReLU和池化操作。所以,对应的deconvnet模块需要进行反池化、ReLU和卷积的转置操作。

1. Unpooling
在convnet模块中,最大池化的基本原理是:
- 将输入数据分割成若干个不重叠的矩形。
- 对于每个矩形块,取其中最大的数作为输出。
- 将所有输出组合成一个新的矩阵作为最终的输出。
最大池化的作用是减少特征图的大小,从而减少计算量和参数数量,同时可以提取出输入数据中的最显著的特征。
在convnet中,最大池化操作是不可逆的,但是我们可以通过记录一组switch变量(每个池化区域内的最大值的位置)来获得近似逆。在deconvnet中,unpooling操作使用这些switch变量将来自上层的重建放置到适当的位置。具体操作如上图所示。
2. ReLU
convnet使用ReLU非线性,为了在每一层获得有效的特征重建我们将重建的信号通过ReLU。
3. Transpose conv
convnet模块使用学习后的卷积核来卷积来自前一层的特征图。为了近似地反转这一点,deconvnet使用相同滤波器的转置,应用在使用ReLU后的特征图上,而不是下面的层的输出。
AlexNet网络修改
为了能够将AlexNet可视化,我们需要对在AlexNet网络介绍中的网络进行修改:
import torch
import torch.nn as nn
from collections import OrderedDictclass AlexNet(nn.Module):def __init__(self, class_num = 5):super(AlexNet, self).__init__()self.features = nn.Sequential(# input[3, 227, 227] output[96, 55, 55]nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=0),nn.ReLU(inplace=True),# output[96, 27, 27]nn.MaxPool2d(kernel_size=3, stride=2, return_indices=True),# output[256, 27, 27]nn.Conv2d(96, 256, kernel_size=5, padding=2),nn.ReLU(inplace=True),# output[256, 13, 13]nn.MaxPool2d(kernel_size=3, stride=2, return_indices=True),# output[384, 13, 13]nn.Conv2d(256, 384, kernel_size=3, padding=1),nn.ReLU(inplace=True),# output[384, 13, 13]nn.Conv2d(384, 384, kernel_size=3, padding=1),nn.ReLU(inplace=True),# output[256, 13, 13]nn.Conv2d(384, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),# output[256, 6, 6]nn.MaxPool2d(kernel_size=3, stride=2, return_indices=True),)self.classifier = nn.Sequential(nn.Linear(256 * 6 * 6, 4096),nn.ReLU(inplace=True),nn.Dropout(p=0.5),nn.Linear(4096, 4096),nn.ReLU(inplace=True),nn.Linear(4096, class_num),)# index of convself.conv_layer_indices = [0, 3, 6, 8, 10]# feature mapsself.feature_maps = OrderedDict()# switchself.pool_locs = OrderedDict()def forward(self, x):for idx, layer in enumerate(self.features):if isinstance(layer, nn.MaxPool2d):x, location = layer(x)self.pool_locs[idx] = locationself.feature_maps[idx] = xelse:x = layer(x)self.feature_maps[idx] = xx = torch.flatten(x, start_dim=1)x = self.classifier(x)return x
首先,我们在执行最大池化时,将最大池化的位置需要返回,以便我们可以记录下来,所以nn.MaxPool2d中参数return_indices置为true。
nn.MaxPool2d(kernel_size=3, stride=2, return_indices=True),
然后,我们在执行forward方法时,需要将最大池化层的位置和每一层的feature map都记录下来。
AlexNet Deconv网络介绍
import sys
sys.path.append('.')import torch
import torch.nn as nn
from utils_module import param_settingsclass AlexNetDeconv(nn.Module):def __init__(self):super(AlexNetDeconv, self).__init__()self.features = nn.Sequential(# deconv1nn.MaxUnpool2d(kernel_size=3, stride=2),nn.ReLU(inplace=True),nn.ConvTranspose2d(256, 384, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.ConvTranspose2d(384, 384, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.ConvTranspose2d(384, 256, kernel_size=3, padding=1),# deconv2nn.MaxUnpool2d(kernel_size=3, stride=2),nn.ReLU(inplace=True),nn.ConvTranspose2d(256, 96, kernel_size=5, padding=2),# deconv3nn.MaxUnpool2d(kernel_size=3, stride=2),nn.ReLU(inplace=True),nn.ConvTranspose2d(96, 3, kernel_size=11, stride=4, padding=0))self.conv2deconv_indices = { 0:12, 3:9, 6:6, 8:4, 10:2 }self.unpool2pool_indices = { 10:2, 7:5, 0:12 }self.init_weight()def init_weight(self):model_path = param_settings.SAVE_PATHalexnet_model = torch.load(model_path)for idx, layer in enumerate(alexnet_model.features):if isinstance(layer, nn.Conv2d):self.features[self.conv2deconv_indices[idx]].weight.data = layer.weight.datadef forward(self, x, layer, activation_idx, pool_locs):if layer in self.conv2deconv_indices:start_idx = self.conv2deconv_indices[layer]else:raise ValueError('layer is not a conv feature map')for idx in range(start_idx, len(self.features)):if isinstance(self.features[idx], nn.MaxUnpool2d):x = self.features[idx]\(x, pool_locs[self.unpool2pool_indices[idx]].cpu())else:x = self.features[idx](x)return x
首先,我们做Deconv模块时,需要从convnet模块的最底层反向进行操作。
其次,我们需要记录conv和deconv的相对关系以及unpooling和pooling之间的相对关系。
接着,我们需要将conv模型的feature参数记录下来,并对其进行初始化。
forward方法定义了模型的前向传播过程。给定输入x、层索引layer、激活索引activation_idx和池化位置pool_locs,它根据指定的层开始进行反卷积操作,直到模型的最后一层。
特征可视化
首先,获取指定层的特征图,并选择其中最大激活的特征。
然后,将其他层的特征图置为0,并将激活值设置为0,以便反卷积模型能够还原出原始图像。
接着,使用反卷积模型对处理后的特征图进行反卷积操作,得到原始图像。
def layer_viewer(layer, model, model_deconv):feat_num = model.feature_maps[layer].shape[1]new_feat_map = model.feature_maps[layer].clone().cpu()# 选择最大激活特征act_lst = []for i in range(0, feat_num):choose_map = new_feat_map[0, i, :, :]activation = torch.max(choose_map)act_lst.append(activation.item())act_lst = np.array(act_lst)mark = np.argmax(act_lst)choose_map = new_feat_map[0, mark, :, :]max_activation = torch.max(choose_map)# 将其他层的特征图置为0if mark == 0:new_feat_map[:, 1:, :, :] = 0else:new_feat_map[:, :mark, :, :] = 0choose_map = torch.where(choose_map == max_activation,choose_map, torch.zeros(choose_map.shape))# 将激活值设置为0new_feat_map[0, mark, :, :] = choose_mapprint(max_activation)deconv_output = model_deconv(new_feat_map, layer, mark, model.pool_locs)# (H, W, C)new_img = deconv_output.data.numpy()[0].transpose(1, 2, 0) # normalizenew_img = (new_img - new_img.min()) / (new_img.max() - new_img.min()) * 255new_img = new_img.astype(np.uint8)# cv2.imshow('reconstruction img ' + str(layer), new_img)# cv2.waitKey()return new_img, int(max_activation)
项目地址:
https://gitee.com/jiangli01/dl-practice/tree/master/AlexNet-Visualizing
相关文章:
CNNs: ZFNet之CNN的可视化网络介绍
CNNs: ZFNet之CNN的可视化网络介绍 导言Deconvnet1. Unpooling2. ReLU3. Transpose conv AlexNet网络修改AlexNet Deconv网络介绍特征可视化 导言 上一个内容,我们主要学习了AlexNet网络的实现、超参数对网络结果的影响以及网络中涉及到一些其他的知识点࿰…...
云原生之深入解析Airbnb的动态Kubernetes集群扩缩容
一、前言 Airbnb 基础设施的一个重要作用是保证我们的云能够根据需求上升或下降进行自动扩缩容,我们每天的流量波动都非常大,需要依靠动态扩缩容来保证服务的正常运行。为了支持扩缩容,Airbnb 使用了 Kubernetes 编排系统,并且使…...
Django框架之模板其他补充
本篇文章是对django框架模板内容的一些补充。包含注释、html转义和csrf内容。 目录 注释 单行注释 多行注释 HTML转义 Escape Safe Autoescape CSRF 防止csrf方式 表单中使用 ajax请求添加 注释 单行注释 语法:{# 注释内容 #} 示例: {# 注…...
安装Maven 3.6.1:图文详细教程(适用于Windows系统)
一、官网下载对应版本 推荐使用maven3.6.1版本,对应下载链接: Maven3.6.1下载地址 或者,这里提供csdn下载地址,点击下载即可: Maven3.6.1直链下载 其他版本下载地址: 进入网址:http://mave…...
计算机图形学 | 实验八:Phong模型
计算机图形学 | 实验八:Phong模型 计算机图形学 | 实验八:Phong模型Phong模型光源设置 光照计算定向光点光源聚光 华中科技大学《计算机图形学》课程 MOOC地址:计算机图形学(HUST) 计算机图形学 | 实验八:…...
第三十一回:GestureDetector Widget
文章目录 概念介绍使用方法示例代码 我们在上一章回中介绍了ListView响应事件的内容t,本章回中将介绍 GestureDetector Widget.闲话休提,让我们一起Talk Flutter吧。 概念介绍 我们在这里介绍的GestureDetector是一个事件响应Widget,它可以响应双击事件࿰…...
Java面试知识点(全)-Java并发-多线程JUC三- JUC集合/线程池
Java面试知识点(全) 导航: https://nanxiang.blog.csdn.net/article/details/130640392 注:随时更新 JUC集合类 为什么HashTable慢? 它的并发度是什么? 那么ConcurrentHashMap并发度是什么? Hashtable之所以效率低下主要是因为其实现使用了synchro…...
Android 如何获取有效的DeviceId
目录 前言官方唯一标识符建议使用广告 ID使用实例 ID 和 GUID不要使用 MAC 地址标识符特性常见用例和适用的标识符 解决方案DeviceIdANDROID_IDMac地址UUID补充 总结 前言 从 Android 10 开始,应用必须具有 READ_PRIVILEGED_PHONE_STATE 特许权限才能访问设备的不可…...
<SQL>《SQL命令(含例句)精心整理版(2)》
《SQL命令(含例句)精心整理版(2)》 跳转《SQL命令(含例句)精心整理版(1)8 函数8.1 文本处理函数8.2 数值处理函数8.3 时间处理函数8.3.1 时间戳转化为自定义格式from_unixtime8.3.2 …...
完全自主研发,聚芯微发布3D dToF图像传感器芯片!
日前,由中国半导体行业协会IC设计分会(ICCAD)、芯原股份、松山湖管委会主办的主题为“AR/VR/XR元宇宙”的“2023松山湖中国IC创新高峰论坛”正式在广东东莞松山湖召开。武汉市聚芯微电子有限责任公司发布了完全自主知识产权的3D dToF图像传感…...
MySQL 事物(w字)
目录 事物 首先我们来看一个简单的问题 什么是事务 为什么会出现事务 事务的版本支持 事务提交方式 事务常见操作方式 设置隔离级别 事物操作 事物结论 事务隔离级别 理解隔离性 隔离级别 查看与设置隔离性 注意可重复读【Repeatable Read】的可能问题ÿ…...
字节跳动测试岗四面总结....
字节一面 1、 简单做一下自我介绍 2、 简要介绍一下项目/你负责的模块/选一个模块说一下你设计的用例 3 、get请求和post请求的区别 4、 如何判断前后端bug/3xx是什么意思 5、 说一下XXX项目中你做的接口测试/做了多少次 6、 http和https的区别 7、 考了几个ADB命令/查看…...
基于.NetCore开源的Windows的GIF录屏工具
推荐一个Github上Start超过20K的超火、好用的屏幕截图转换为 GIF 动图开源项目。 项目简介 这是基于.Net Core WPF 开发的、开源项目,可将屏幕截图转为 GIF 动画。它的核心功能是能够简单、快速地截取整个屏幕或者选定区域,并将其转为 GIF动画&#x…...
PCB 基础~典型的PCB设计流程,典型的PCB制造流程
典型的PCB设计流程 典型的PCB制造流程 • 从客户手中拿到Gerber, Drill以及其它PCB相关文件 • 准备PCB基片和薄片 – 铜箔的底片会被粘合在基材上 • 内层图像蚀刻 – 抗腐蚀的化学药水会涂在需要保留的铜箔上(例如走线和过孔) – 其他药水…...
Python logging使用
目录 logging模块 logging核心组件 logger handler StreamHandler:把日志内容在控制台中输出 FileHandler:把日志内容写入到文件中 filter formatter 注意日志级别的继承问题 logger.exception 上述样例的整体代码 日志的配置文件及其模板 lo…...
红黑树的实现原理和应用场景
红黑树的实现原理和应用场景; 有如图所示的表,现在希望查询的结果将列成行 建表语句如下: CREATE TABLE TEST_TB_GRADE2 ( ID int(10) NOT NULL AUTO_INCREMENT, USER_NAME varchar(20) DEFAULT NULL, CN_SCORE float DEFAULT NU…...
idea插件完成junit代码生成,和springboot代码示例
在idea环境下,可以用过插件的方式自动生成juint模板代码。不过具体要需要自己手动编写。 1、安装插件 打开idea,file–settings–plugins,搜索和安装插件(JunitGenerator V2.0和JUnit),安装后,后…...
【Redis面试点总结】
1、缓存 1.1、穿透 查询一个空数据,mysql也查不到也不会写入缓存可能导致多次请求数据库 方案一:缓存设空即可(可能发生数据不一致就是这条数据有了但此时缓存是空,消耗内存) 方案二:布隆过滤器&#x…...
打卡智能中国(五):博士都去哪儿了?
《打卡智能中国》系列更新了几期,有读者表示,很爱看这类接地气的真实故事,也有读者反映,不是电工,就是文员、农民、治沙人,人工智能不是高精尖学科吗?那些学历很高的博士都去哪儿了?…...
[Nacos] Nacos Client获取调用服务的提供者列表 (四)
文章目录 1.Nacos Client获取调用服务的提供者列表1.1 从Ribbon的负载均衡入手到Nacos Client获取调用服务的提高者列表1.2 getServers方法返回分析1.3 通过selectInstances方法查找Instances实例1.4 获取到要调用服务的serviceInfo Nacos Client 从Ribbon负载均衡调用服务。 …...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...
如何通过git命令查看项目连接的仓库地址?
要通过 Git 命令查看项目连接的仓库地址,您可以使用以下几种方法: 1. 查看所有远程仓库地址 使用 git remote -v 命令,它会显示项目中配置的所有远程仓库及其对应的 URL: git remote -v输出示例: origin https://…...
【题解-洛谷】P10480 可达性统计
题目:P10480 可达性统计 题目描述 给定一张 N N N 个点 M M M 条边的有向无环图,分别统计从每个点出发能够到达的点的数量。 输入格式 第一行两个整数 N , M N,M N,M,接下来 M M M 行每行两个整数 x , y x,y x,y,表示从 …...
黑马Javaweb Request和Response
一.介绍 在 Web 开发中,HttpServletRequest 和 HttpServletResponse 是两个非常重要的类,它们分别用于处理客户端的请求和服务器的响应。以下是它们的详细说明和使用方法: 1. HttpServletRequest HttpServletRequest 是一个接口࿰…...
虚拟机时间同步
一、常见同步方式 常见的虚拟机同步方式有给虚拟机配置ntp、或者用平台提供的agent对时与虚拟机所在的宿主机。第一种依赖网络、第二种依赖平台的agent这个三方工具。 二、利用ptp_kvm.ko来直接和宿主机同步时间 关键组件 ptp_kvm驱动、chrony。 PTP_KVM同步原理 |--------…...
