【datawhale202203】深入浅出PyTorch:PyTorch可视化

25 篇文章 1 订阅

前情回顾

  1. PyTorch的模型定义及模型搭建
  2. PyTorch进阶训练

小结

本节内容非常实用,涉及网络结构的可视化,卷积神经网络的可视化,以及使用tensorboard实现训练过程可视化。

卷积神经网络的可视化包含卷积核,特征图,以及CAM的可视化,三者都可以用基础的代码实现,也可以调用现有的库(FlashTorch和pytorch-grad-cam实现)。

tensorboard是训练过程可视化的好帮手~

1 可视化网络结构

随着深度神经网络做的的发展,网络的结构越来越复杂,我们也很难确定每一层的输入结构,输出结构以及参数等信息,这样导致我们很难在短时间内完成debug。因此掌握一个可以用来可视化网络结构的工具是十分有必要的。类似的功能在另一个深度学习库Keras中可以调用一个叫做model.summary()的API来很方便地实现,调用后就会显示我们的模型参数,输入大小,输出大小,模型的整体参数等,但是在PyTorch中没有这样一种便利的工具帮助我们可视化我们的模型结构。

为了解决这个问题,人们开发了torchinfo工具包.

torchinfo是由torchsummarytorchsummaryX重构出的库, torchsummarytorchsummaryX已经许久没更新了) 。

后续内容都使用ResNet18的结构进行展示。

import torchvision.models as models
model = models.resnet18()

1.1 使用print打印

最基础的展示方式是直接print,不需要借助torchinfo。
在这里插入图片描述
单纯的print(model),只能得出基础构件的信息,既不能显示出每一层的shape,也不能显示对应参数量的大小,而且并不易读。

1.2 使用torchinfo可视化

1.2.1 torchinfo的安装

其实没有什么特别的,就是直接pip安装就可以,或者conda也行。

可以阅读对应的PyPI

# 安装方法一
pip install torchinfo 
# 安装方法二
conda install -c conda-forge torchinfo

1.2.2 torchinfo的使用

只需要使用torchinfo.summary()就行了,必需的参数分别是model,input_size[batch_size,channel,h,w]

更多参数可以参考documentation

import torchvision.models as models
from torchinfo import summary
resnet18 = models.resnet18() # 实例化模型
summary(model, (1, 3, 224, 224)) # 1:batch_size 3:图片的通道数 224: 图片的高宽

运行上述代码输出结果如下:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
torchinfo提供了更加详细的信息,包括

  • 模块信息(每一层的类型、输出shape和参数量)
    在这里插入图片描述

  • 模型整体的参数量
    在这里插入图片描述

  • 模型大小
    在这里插入图片描述

  • 一次前向或者反向传播需要的内存大小等
    在这里插入图片描述

注意
当使用的是colab或者jupyter notebook时,想要实现该方法,summary()一定是该单元(即notebook中的cell)的返回值,否则我们就需要使用print(summary(...))来可视化。

2 CNN可视化

CNN中间层的可视化是其可解释性的重要组成部分。

如果能理解CNN工作的方式,人们不仅能够解释所获得的结果,提升模型的鲁棒性,而且还能有针对性地改进CNN的结构以获得进一步的效果提升。
理解CNN的重要一步是可视化,包括可视化特征是如何提取的、提取到的特征的形式以及模型在输入数据上的关注点等。

CNN模型的可视化可以分为三类,卷积核的可视化,特征图的可视化,以及显著图(class activation map)的可视化。

2.1 CNN卷积核可视化

卷积核在CNN中负责提取特征,可视化卷积核能够帮助人们理解CNN各个层在提取什么样的特征,进而理解模型的工作原理。例如在Zeiler和Fergus 2013年的paper中就研究了CNN各个层的卷积核的不同,他们发现靠近输入的层提取的特征是相对简单的结构,而靠近输出的层提取的特征就和图中的实体形状相近了,如下图所示:
请添加图片描述
请添加图片描述
请添加图片描述

卷积核的可视化可以帮助我们了解CNN提取到的特征。

在PyTorch中可视化卷积核非常方便,核心在于特定层的卷积核即特定层的模型权重,可视化卷积核就等价于可视化对应的权重矩阵。

torchvision自带的VGG11模型为例可视化卷积核。

import torch
from torchvision.models import vgg11

model = vgg11(pretrained=True)
print(dict(model.features.named_children()))

首先查看这个模型
在这里插入图片描述
可以看到有21层。

卷积核对应的应为卷积层(Conv2d),以第“3”层为例,可视化对应的参数

conv1 = dict(model.features.named_children())['3']
kernel_set = conv1.weight.detach()
num = len(conv1.weight.detach())
print(kernel_set.shape)
for i in range(0,num):
    i_kernel = kernel_set[i]
    plt.figure(figsize=(20, 17))
    if (len(i_kernel)) > 1:
        for idx, filer in enumerate(i_kernel):
            plt.subplot(9, 9, idx+1) 
            plt.axis('off')
            plt.imshow(filer[ :, :].detach(),cmap='bwr')

卷积核的大小为torch.Size([128, 64, 3, 3])

由于第“3”层的特征图由64维变为128维,因此共有128*64个卷积核,其中部分卷积核可视化效果如下图所示:
请添加图片描述
挺抽象的…

2.2 特征图可视化

与卷积核相对应,输入的原始图像经过每次卷积层得到的数据称为特征图,可视化卷积核是为了看模型提取哪些特征,可视化特征图则是为了看模型提取到的特征是什么样子的

获取特征图的方法有很多种,可以从输入开始,逐层做前向传播,直到想要的特征图处将其返回。尽管这种方法可行,但是有些麻烦了。

在PyTorch中,提供了一个专用的接口使得网络在前向传播过程中能够获取到特征图,这个接口的名称非常形象,叫做hook

可以想象这样的场景,数据通过网络向前传播,网络某一层我们预先设置了一个钩子,数据传播过后钩子上会留下数据在这一层的样子,读取钩子的信息就是这一层的特征图。

class Hook(object):
    def __init__(self):
        self.module_name = []
        self.features_in_hook = []
        self.features_out_hook = []

    def __call__(self,module, fea_in, fea_out):
        print("hooker working", self)
        self.module_name.append(module.__class__)
        self.features_in_hook.append(fea_in)
        self.features_out_hook.append(fea_out)
        return None

Hook主要实现了每一个module前后都记录一下进出特征。

def plot_feature(model, idx):
    hh = Hook()
    model.features[idx].register_forward_hook(hh)
    
    forward_model(model,False)
    print(hh.module_name)
    print((hh.features_in_hook[0][0].shape))
    print((hh.features_out_hook[0].shape))
    
    out1 = hh.features_out_hook[0]

    total_ft  = out1.shape[1]
    first_item = out1[0].cpu().clone()    

    plt.figure(figsize=(20, 17))
    

    for ftidx in range(total_ft):
        if ftidx > 99:
            break
        ft = first_item[ftidx]
        plt.subplot(10, 10, ftidx+1) 
        
        plt.axis('off')
        
        plt.imshow(ft[ :, :].detach())

这里我们首先实现了一个hook类,之后在plot_feature函数中,将该hook类的对象注册到要进行可视化的网络的某层中。

model在进行前向传播的时候会调用hook__call__函数,我们也就是在那里存储了当前层的输入和输出

这里的features_out_hook 是一个list,每次前向传播一次,都是调用一次,也就是features_out_hook 长度会增加1。(这样的话每步训练都可以保存下来,就可以看到训练过程的变化

想到之前的自己用keras做的一个CNN可视化的任务里,可视化出来的同层所有特征图的都一样…(mark一下需要找找原因

还mark一下代码实现

2.3 CNN class activation map可视化

class activation map (CAM)的作用是判断哪些变量对模型来说是重要的,在CNN可视化的场景下,即判断图像中哪些像素点对预测结果是重要的。

除了确定重要的像素点,人们也会对重要区域的梯度感兴趣,因此在CAM的基础上也进一步改进得到了Grad-CAM(以及诸多变种)。

CAM和Grad-CAM的示例如下图所示:请添加图片描述
相比可视化卷积核与可视化特征图,CAM系列可视化更为直观,能够一目了然地确定重要区域,进而进行可解释性分析或模型优化改进。

CAM系列操作的实现可以通过开源工具包pytorch-grad-cam来实现。

2.3.1 pytorch-grad-cam安装

直接pip就好

pip install grad-cam

2.3.2 简单的例子

先读取下面这个照片,然后用预训练好的VGG11做预测。
请添加图片描述
实现代码如下

import torch
from torchvision.models import vgg11,resnet18,resnet101,resnext101_32x8d
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np

model = vgg11(pretrained=True)
img_path = './dog.jpg'
# resize操作是为了和传入神经网络训练图片大小一致
img = Image.open(img_path).resize((224,224))
# 需要将原始图片转为np.float32格式并且在0-1之间 
rgb_img = np.float32(img)/255
plt.imshow(img)

CAM的获取过程如下(这段代码再好好看下


from pytorch_grad_cam import GradCAM,ScoreCAM,GradCAMPlusPlus,AblationCAM,XGradCAM,EigenCAM,FullGrad
from pytorch_grad_cam.utils.model_targets import ClassifierOutputTarget
from pytorch_grad_cam.utils.image import show_cam_on_image

target_layers = [model.features[-1]]
# 选取合适的类激活图,但是ScoreCAM和AblationCAM需要batch_size
cam = GradCAM(model=model,target_layers=target_layers)
targets = [ClassifierOutputTarget(preds)]
grayscale_cam = cam(input_tensor=img_tensor, targets=targets)
grayscale_cam = grayscale_cam[0, :]
cam_img = show_cam_on_image(rgb_img, grayscale_cam, use_rgb=True)
print(type(cam_img))
Image.fromarray(cam_img)

CAM有很多种,可以选择合适的,上面选择的是GradCAM。可以获得
请添加图片描述
也就是说狗鼻子最受关心~

有大佬用hook的方法实现了,PyTorch 实现 GradCAM

2.4 使用FlashTorch快速实现CNN可视化

除去上面2.1,2.2的手动方法(其实也没有很手动),也有一些快速实现CNN可视化的方法。

FlashTorch是其中一个

2.4.1 FlashTorch的安装

也是直接pip就可以。

pip install flashtorch

2.4.2 可视化梯度(特征图)

# Download example images
# !mkdir -p images
# !wget -nv \
#    https://github.com/MisaOgura/flashtorch/raw/master/examples/images/great_grey_owl.jpg \
#    https://github.com/MisaOgura/flashtorch/raw/master/examples/images/peacock.jpg   \
#    https://github.com/MisaOgura/flashtorch/raw/master/examples/images/toucan.jpg    \
#    -P /content/images

import matplotlib.pyplot as plt
import torchvision.models as models
from flashtorch.utils import apply_transforms, load_image
from flashtorch.saliency import Backprop

model = models.alexnet(pretrained=True)
backprop = Backprop(model)

image = load_image('/content/images/great_grey_owl.jpg')
owl = apply_transforms(image)

target_class = 24
backprop.visualize(owl, target_class, guided=True, use_gpu=True)

请添加图片描述

只需要一个实例化(Backprop),然后导入图片,应用一下就可以~

2.4.3 可视化卷积核

import torchvision.models as models
from flashtorch.activmax import GradientAscent

model = models.vgg16(pretrained=True)
g_ascent = GradientAscent(model.features)

# specify layer and filter info
conv5_1 = model.features[24]
conv5_1_filters = [45, 271, 363, 489]

g_ascent.visualize(conv5_1, conv5_1_filters, title="VGG16: conv5_1")

请添加图片描述
卷积核的可视化就更简单啦,只需要一个实例化,然后指定想看的层。

3 使用TensorBoard可视化训练过程

  • 安装TensorBoard工具
  • 了解TensorBoard可视化的基本逻辑
  • 掌握利用TensorBoard实现训练过程可视化
  • 掌握利用TensorBoard完成其他内容的可视化

待补充

参考阅读

  1. PyTorch 实现 GradCAM
  • 1
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SheltonXiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值