栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

毕业设计记录-Pytorch学习-隐藏层特征查看与类激活热力图

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

毕业设计记录-Pytorch学习-隐藏层特征查看与类激活热力图

文章目录
    • 2021.12.8的记录
    • 2021.12.9的记录

代码文件路径:E:sotsugyosextsukeiVGG16featuresvision.py
书本 P167-176

2021.12.8的记录

先看一下效果,我的可莉。


![在这里插入图片描述](https://img-blog.csdnimg.cn/1d73a10840814ba0a21f2457ef8a3ed7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6IqD6IqD44Gn44GZ,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center
python的钩子技术,不懂,记下了。
需要再理解神经网络的特征提取原理和工作机制,记下了。

2021.12.9的记录

可视化代码:

activation = {}
def get_activation(name):
    def hook(model, input, output):
        activation[name] = output.detach()
    return hook
vgg16.eval()
vgg16.features[4].register_forward_hook(get_activation("maxpool1"))
_ = vgg16(input_im)
maxpool1 = activation["maxpool1"]
print("获得特征的尺寸为:", maxpool1.shape)
plt.figure(figsize=(11, 6))
for ii in range(maxpool1.shape[1]):
    plt.subplot(6, 11, ii+1)
    plt.imshow(maxpool1.data.numpy()[0, ii, :, :], cmap="gray")
    plt.axis("off")
plt.subplots_adjust(wspace=0.1, hspace=0.1)
plt.show()

首先定义了一个字典。关于字典:字典是一种可变容器模型,且可存储任意类型对象。
然后get_activation(name)函数中的hook函数了。
首先了解一下什么是回调函数:添加链接描述
钩子技术代码:修改自添加链接描述

import time


class LazyPerson(object):
    def __init__(self, name):
        self.name = name
        self.watch_tv_func = None
        self.have_dinner_func = None

    def get_up(self):
        print("%s get up at:%s" % (self.name, time.time()))

    def go_to_sleep(self):
        print("%s go to sleep at:%s" % (self.name, time.time()))

    def register_tv_hook(self, watch_tv_func):
        self.watch_tv_func = watch_tv_func

    def register_dinner_hook(self, have_dinner_func):
        self.have_dinner_func = have_dinner_func

    def enjoy_a_lazy_day(self):

        # get up
        self.get_up()
        time.sleep(3)
        # watch tv
        # check the watch_tv_func(hooked or unhooked)
        # hooked
        if self.watch_tv_func is not None:
            self.watch_tv_func(self.name)
        # unhooked
        else:
            print("no tv to watch")
        time.sleep(3)
        # have dinner
        # check the have_dinner_func(hooked or unhooked)
        # hooked
        if self.have_dinner_func is not None:
            self.have_dinner_func(self.name)
        # unhooked
        else:
            print("nothing to eat at dinner")
        time.sleep(3)
        self.go_to_sleep()


def watch_daydayup(name):
    print("%s : The program ---day day up--- is funny!!!" % name)


def watch_happyfamily(name):
    print("%s : The program ---happy family--- is boring!!!" % name)


def eat_meat(name):
    print("%s : The meat is nice!!!" % name)


def eat_hamburger(name):
    print("%s : The hamburger is not so bad!!!" % name)


if __name__ == "__main__":
    lazy_tom = LazyPerson("Tom")
    lazy_tom.register_tv_hook(watch_daydayup)
    lazy_tom.register_dinner_hook(eat_meat)
    lazy_tom.enjoy_a_lazy_day()

个人理解:钩子技术貌似就是函数调用函数。为什么叫钩子呢。我的理解是他的父级的输入并没有什么限制,可以挂载任何函数,你想用啥函数的时候就钩上去。但我总感觉还是不能用这个来说服自己,什么是钩子技术。希望有高人指点。
好了再看一下这个函数,参考链接:添加链接描述

.register_forward_hook(hook)

这里要输入的参数是一个固定格式的hook函数

hook(module, input, output) -> None or modified output

hook可以修改input和output,但是不会影响forward的结果。最常用的场景是需要提取模型的某一层(不是最后一层)的输出特征,但又不希望修改其原有的模型定义文件,这时就可以利用forward_hook函数。
其中hook的内容是可以自己写的,像上文程序中利用字典获取也行,像链接文章中用列表也行。

activation[name] = output.detach()

先看一下百度百科的解释吧:
神经网络的训练有时候可能希望保持一部分的网络参数不变,只对其中一部分的参数进行调整;或者值训练部分分支网络,并不让其梯度对主网络的梯度造成影响,torch.tensor.detach()和torch.tensor.detach_()函数来切断一些分支的反向传播。本文会具体介绍这两种方法的用法和区别。
也就是说这个.detach()去掉也是没有任何问题的,并不会对output有什么改变。但是在反向传播到这一层的时候会停止更新权重。由于这里也没有进行反向传播,去掉也是没有问题的。测试一下也的确如此。

下午去办身份证遇到一个老奶奶,说卡没了没吃午饭,问我要几块钱。我没理就走了。后来想想,估计是地铁卡丢了,要几块钱坐地铁回家吧。不像是骗子,唉,想想老奶奶当时的表情心里挺不是滋味。

解释一下.register_hook()函数,是对梯度进行各种操作,需要注意的是传入的参数必须是一个函数,然后传入的函数测试下来,只能有一个参数,不然会报错。如下代码

import torch
v = torch.randn((1, 3), dtype=torch.float32, requires_grad=True)
z = v.sum()
zi = {}
def a(m):
    zi["grad"] = m
def b(m):
    zi["g"] = m * 2
v.register_hook(a)
v.register_hook(b)
z.backward()
print(v.grad)
print(zi["grad"])
print(zi)

输出为

tensor([[1., 1., 1.]])
tensor([[1., 1., 1.]])
{'grad': tensor([[1., 1., 1.]]), 'g': tensor([[2., 2., 2.]])}

函数a就是将梯度直接传给字典中的“grad”,而b是将梯度乘2传给“g”。至于register_hook()是怎么传的,猜测也是和上文的name一样,把梯度作为类中的一个变量传给了a或b函数中的m。
最后的类激活热力图输出

真好看。但好不明显,换个大象的图吧。

网络更关注大象的牙齿和脸呢。
代码部分缺少理论知识的辅助,暂时无法知道所有在干嘛,只能理解部分。明天再看看吧。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/649711.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号