Pytorch与深度学习自查手册6-网络结构、卷积层、attention层可视化
Pytorch与深度学习自查手册6-网络结构、卷积层、attention层可视化
网络结构可视化
torchinfo工具包可以用于打印模型参数,输入大小,输出大小,模型的整体参数等,类似keras中的model.summary()。
使用torchinfo可视化网络结构
安装torchinfo
# 安装方法一 |
使用torchinfo
只需要使用torchinfo.summary()
,必需的参数分别是model,input_size[batch_size,channel,h,w]
,更多参数可以参考documentation。
import torchvision.models as models |
输出:
========================================================================================= |
可以看到torchinfo提供包括模块信息(每一层的类型、输出shape和参数量)、模型整体的参数量、模型大小、一次前向或者反向传播需要的内存大小等信息。
注意:
但使用的是colab或者jupyter notebook时,想要实现该方法,summary()
一定是该单元(即notebook中的cell)的返回值,否则我们就需要使用print(summary(...))
来可视化。
Attention层可视化
这里主要是对NLP中bert开发的一个可视化工具BertViz进行介绍:BertViz: Visualize Attention in Transformer Models (BERT, GPT2, BART, etc.)
安装BertViz
pip install bertviz |
其他依赖安装:
pip install jupyterlab |
BertViz使用
推荐用Jupyter Notebook进行尝试。
注意力头可视化
注意力头视图可视化来自单个 Transformer 层的一个或多个头部的注意力。 每行显示从一个标记(左)到另一个标记(右)的注意力。 线颜色深浅反映注意力值(范围从 0 到 1),而线条颜色标识注意力头。 选择多个头时(由顶部的彩色片状表示),相应的可视化彼此叠加。
- 将鼠标悬停在可视化左侧/右侧的任何标记上,以过滤来自/到该标记的注意力。
- 双击顶部的任何彩色图块以过滤到相应的注意力头。
- 单击任何彩色图块以切换选择相应的注意力头。
- 单击图层下拉菜单以更改模型图层(零索引)。
from bertviz import head_view |
模型视图
整个模型中注意力的预览图。
每个单元格显示特定头部的注意力权重,按层(行)和头部(列)索引。 每个单元格中的线表示从一个标记(左)到另一个标记(右)的注意力,线重与注意力值成正比(范围从 0 到 1)。
- 单击任何单元格以查看相关注意力头的注意力详细视图(或取消选择该单元格)。
- 然后将鼠标悬停在详细视图左侧的任何标记上以过滤来自该标记的注意力。
from transformers import AutoTokenizer, AutoModel, utils |
神经元视图
用于计算注意力的中间表示(例如查询和关键向量)。在折叠视图(初始状态)中,线条显示了从每个标记(左)到每个其他标记(右)的注意力。在展开的视图中,该工具跟踪产生这些注意力权重的计算链。
目前只支持可视化自定义的BERT, GPT-2, 和 RoBERTa模型。
- 将鼠标悬停在可视化左侧的任何标记上,以过滤来自该标记的注意力。
- 然后单击悬停时显示的加号图标。这暴露了用于计算注意力权重的查询向量、关键向量和其他中间表示。每个色带代表一个神经元值,其中颜色强度表示幅度,色调表示符号(蓝色=正,橙色=负)。
- 进入展开视图后,将鼠标悬停在左侧的任何其他标记上以查看相关的注意力计算。
- 单击图层或头部下拉菜单以更改模型图层或头部(零索引)。
# Import specialized versions of models (that return query/key vectors) |
卷积层可视化
CNN卷积核可视化
卷积核在CNN中负责提取特征,可视化卷积核可以帮助理解CNN各个层在提取什么样的特征,进而理解模型的工作原理。例如在Zeiler和Fergus 2013年的paper中就研究了CNN各个层的卷积核的不同,他们发现靠近输入的层提取的特征是相对简单的结构,而靠近输出的层提取的特征就和图中的实体形状相近了,如下图所示:
可视化卷积核就等价于可视化对应的权重矩阵。
下面给出在PyTorch中可视化卷积核的实现方案,以torchvision自带的VGG11模型为例。
首先加载模型,并确定模型的层信息:
import torch |
卷积核对应的应为卷积层(Conv2d),这里以第“3”层为例,可视化对应的参数:
conv1 = dict(model.features.named_children())['3'] |
由于第“3”层的特征图由64维变为128维,因此共有128*64个卷积核,其中部分卷积核可视化效果如下图所示:
CNN特征图可视化方法
与卷积核相对应,输入的原始图像经过每次卷积层得到的数据称为特征图.
可视化卷积核是为了看模型提取哪些特征,可视化特征图则是为了看模型提取到的特征是什么样子的。
获取特征图的方法有很多种,可以从输入开始,逐层做前向传播,直到想要的特征图处将其返回。尽管这种方法可行,但是有些麻烦了。在PyTorch中,提供了一个专用的接口使得网络在前向传播过程中能够获取到特征图,这个接口的名称非常形象,叫做hook(钩子)。
数据通过网络向前传播,在网络某一层预先设置了一个钩子,数据传播过后钩子上会留下数据在这一层的输入输出,读取钩子的信息就是这一层的特征图。具体实现如下:
- 首先实现了一个hook类;
- 之后在plot_feature函数中,将该hook类的对象注册到要进行可视化的网络的某层中。
- model在进行前向传播的时候会调用hook的__call__函数,也就是在那里存储了当前层的输入和输出。
- features_out_hook 是一个list,每次前向传播一次,都是调用一次,也就是features_out_hook 长度会增加1。
class Hook(object): |
CNN class activation map可视化方法
class activation map (CAM)的作用是判断哪些变量对模型来说是重要的,在CNN可视化的场景下,即判断图像中哪些像素点对预测结果是重要的。
除了确定重要的像素点,重要区域的梯度也可以反映一些特点,因此在CAM的基础上也进一步改进得到了Grad-CAM(以及诸多变种)。
相比可视化卷积核与可视化特征图,CAM系列可视化更为直观,能够一目了然地确定重要区域,进而进行可解释性分析或模型优化改进。
CAM和Grad-CAM的示例如下图所示:
CAM系列操作的实现可以通过开源工具包pytorch-grad-cam来实现。
grad-cam安装
pip install grad-cam |
grad-cam使用
import torch |
from pytorch_grad_cam import GradCAM,ScoreCAM,GradCAMPlusPlus,AblationCAM,XGradCAM,EigenCAM,FullGrad |
使用FlashTorch快速实现CNN可视化
随着PyTorch社区的努力,目前已经有不少开源工具能够帮助我们快速实现CNN可视化。这里介绍其中的一个——FlashTorch。
flashtorch安装
pip install flashtorch |
flashtorch可视化梯度
# Download example images |
flashtorch可视化卷积核
import torchvision.models as models |
使用TensorBoard可视化训练过程
结合训练集的损失函数和验证集的损失函数,绘制两条损失函数的曲线来确定训练的终点,找到对应的模型用于测试。那么除了记录训练中每个epoch的loss值,能否实时观察损失函数曲线的变化,及时捕捉模型的变化呢?
此外,我们也希望可视化其他内容,如输入数据(尤其是图片)、模型结构、参数分布等,这些对于我们在debug中查找问题来源非常重要(比如输入数据和我们想象的是否一致)。
对于TensorBoard来说,主要的实现方案是构建一个SummaryWriter,然后通过add_XXX()
函数来实现。
TensorBoard安装
在已安装PyTorch的环境下使用pip安装即可:
pip install tensorboardX |
也可以使用PyTorch自带的tensorboard工具,此时不需要额外安装tensorboard。
TensorBoard可视化的基本逻辑
TensorBoard在模型训练过程中会不断记录模型每一层的feature map,权重,以及训练loss等指定的信息,并存到一个特定的文件夹里,最终记录下的内容可以通过网页的形式加以可视化。
TensorBoard的配置与启动
代码中配置SummaryWriter
在使用TensorBoard前,需要先指定一个文件夹供TensorBoard保存记录下来的数据。然后在训练过程中不断调用tensorboard中的SummaryWriter记录训练过程信息。
from tensorboardX import SummaryWriter |
上面的操作实例化SummaryWritter为变量writer,并指定writer的输出目录为当前目录下的"runs"目录,之后tensorboard记录下来的内容都会保存在runs。
如果使用PyTorch自带的tensorboard,则采用如下方式import:
from torch.utils.tensorboard import SummaryWriter |
命令行启动tensorboard显示信息
在命令行中输入
tensorboard --logdir=/path/to/logs/ --port=xxxx |
其中“path/to/logs/"是指定的保存tensorboard记录结果的文件路径(等价于上面的“./runs",port是外部访问TensorBoard的端口号,可以通过访问ip:port访问tensorboard,这一操作和jupyter notebook的使用类似。如果不是在服务器远程使用的话则不需要配置port。
有时,为了tensorboard能够不断地在后台运行,也可以使用nohup命令或者tmux工具来运行tensorboard。大家可以自行搜索,这里不展开讨论了。
TensorBoard模型结构可视化
首先定义模型:
import torch.nn as nn |
输出如下:
Net( |
通过TensorBoard对模型的graph进行可视化,使用add_graph:
writer.add_graph(model, input_to_model = torch.rand(1, 3, 224, 224)) |
展示结果如下(其中框内部分初始会显示为“Net",需要双击后才会展开):
TensorBoard图像可视化
当做图像相关的任务时,可以方便地将所处理的图片在tensorboard中进行可视化展示。
- 对于单张图片的显示使用add_image
- 对于多张图片的显示使用add_images
- 使用torchvision.utils.make_grid将多张图片拼成一张图片后,用writer.add_image显示
使用torchvision的CIFAR10数据集为例:
import torchvision |
依次运行上面三组可视化(注意不要同时在notebook的一个单元格内运行),得到的可视化结果如下(最后运行的结果在最上面):
另外注意上方menu部分,刚刚只有“GRAPHS"栏对应模型的可视化,现在则多出了”IMAGES“栏对应图像的可视化。左侧的滑动按钮可以调整图像的亮度和对比度。
此外,除了可视化原始图像,TensorBoard提供的可视化方案也适用于在Python中用matplotlib等工具绘制的其他图像,用于展示分析结果等内容。
TensorBoard连续变量可视化
TensorBoard可以用来可视化连续变量(或时序变量)的变化过程,通过add_scalar实现:
writer = SummaryWriter('./pytorch_tb') |
可视化结果如下:
如果想在同一张图中显示多个曲线,则需要分别建立存放子路径(使用SummaryWriter指定路径即可自动创建,但需要在tensorboard运行目录下),同时在add_scalar中修改曲线的标签使其一致即可:
writer1 = SummaryWriter('./pytorch_tb/x') |
这里也可以用一个writer,但for循环中不断创建SummaryWriter不是一个好选项。此时左下角的Runs部分出现了勾选项,我们可以选择我们想要可视化的曲线。曲线名称对应存放子路径的名称(这里是x和y)。
这部分功能非常适合损失函数的可视化,可以更加直观地了解模型的训练情况,从而确定最佳的checkpoint。左侧的Smoothing滑动按钮可以调整曲线的平滑度,当损失函数震荡较大时,将Smoothing调大有助于观察loss的整体变化趋势。
TensorBoard参数分布可视化
当需要对参数(或向量)的变化,或者对其分布进行研究时,可以方便地用TensorBoard来进行可视化,通过add_histogram实现。下面给出一个例子:
import torch |
结果如下: