利用梯度上升可视化卷积核:基于torch实现

利用梯度上升可视化卷积核

文章目录

  • 前言
      • 基本原理
      • 版本和包
      • 结果展示
  • 简单绘图
  • 修改源码绘图
      • 方法一
    • 方法二(推荐)
  • 报错解决
  • 总结


前言

基于梯度上升的可视化是一种常用的技术,用于理解卷积神经网络(CNN)中的卷积核是如何对输入图像进行特征提取的。该方法可以通过最大化卷积层输出的激活值来生成图像,从而使得卷积核对特定特征更加敏感。

基本原理

以下是基于梯度上升可视化卷积核的基本原理步骤:

  1. 选择目标卷积层和卷积核:首先,选择你希望可视化的目标卷积层和对应的卷积核。通常选择靠近网络顶部的卷积层,因为这些层对于更高级别的特征有更强的响应。
  2. 定义损失函数:为了最大化卷积层的输出激活值,需要定义一个损失函数。通常使用该卷积层的平均激活值作为损失函数。
  3. 随机生成图像:从随机噪声图像开始,作为初始输入图像。
  4. 前向传播:将生成的图像输入到CNN网络中,并进行前向传播,记录目标卷积层的输出激活值。
  5. 反向传播:计算损失函数对于输入图像的梯度,即目标卷积层输出激活值对于输入图像的影响。
  6. 更新输入图像:根据梯度信息更新输入图像,使得激活值增大。
  7. 重复步骤4-6:重复进行前向传播、反向传播和图像更新,直到达到预定的迭代次数或满足特定的停止条件。
  8. 可视化结果:最终生成的图像即为可视化结果,它代表了卷积核对于特定特征的响应模式。

通过这个过程,可以逐步调整输入图像,使得卷积核对于特定特征更加敏感。这种方法可以帮助我们理解卷积神经网络学习到的特征,以及卷积层如何对输入图像进行处理。


版本和包

python=3.7
torch=1.7
flashtorch=0.1.3

其中flashtorch就是用来求取中间层梯度上升的包

结果展示

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

简单绘图

官方代码如下所示:
(以vgg16为例子)

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, ]## 这里调节要展示的卷积核(绘出子图的个数),最大值是对应权重的通道数

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

以上代码,用vis即可画图。
vis =【output45,output271】的列表,每个都包含很多层,源代码是用的最后一层进行绘图(下图为源码截图):
在这里插入图片描述


修改源码绘图

方法一

由于官方代码画不出来图,所以修改from flashtorch.activmax import GradientAscent 的源码,把plt返回即可:
找到GradientAscent函数(gradient_ascent.py) 第211行
在这里插入图片描述
修改为:

if return_output:
    return self.output, self.plt

方法二(推荐)

最好的方法是:在同级目录下新建文件grad_as.py
直接把以下代码复制到grad_as.py里:

import numpy as np
import matplotlib.pyplot as plt

import torch
import torch.nn as nn

from flashtorch.utils import (apply_transforms,
                              format_for_plotting,
                              load_image,
                              standardize_and_clip)


class GradientAscent:
    """Provides an interface for activation maximization via gradient descent.

    This class implements the gradient ascent algorithm in order to perform
    activation maximization with convolutional neural networks (CNN).

    `Activation maximization <https://pdfs.semanticscholar.org/65d9/94fb778a8d9e0f632659fb33a082949a50d3.pdf>`_
    is one form of feature visualization that allows us to visualize what CNN
    filters are "looking for", by applying each filter to an input image and
    updating the input image so as to maximize the activation of the filter of
    interest (i.e. treating it as a gradient ascent task with activation as the
    loss). The implementation is inspired by `this demo <https://blog.keras.io/category/demo.html>`_
    by Francois Chollet.

    Args:
        model: A neural network model from `torchvision.models
            <https://pytorch.org/docs/stable/torchvision/models.html>`_,
            typically without the fully-connected part of the network.
            e.g. torchvisions.alexnet(pretrained=True).features
        img_size (int, optional, default=224): The size of an input image to be
            optimized.
        lr (float, optional, default=1.): The step size (or learning rate) of
            the gradient ascent.
        use_gpu (bool, optional, default=False): Use GPU if set to True and
            `torch.cuda.is_available()`.

    """ # noqa

    ####################
    # Public interface #
    ####################

    def __init__(self, model, img_size=224, lr=1., use_gpu=False):
        self.model = model
        self._img_size = img_size
        self._lr = lr
        self._use_gpu = use_gpu

        self.num_layers = len(list(self.model.named_children()))
        self.activation = None
        self.gradients = None

        self.handlers = []

        self.output = None
        self.plt = None

    @property
    def lr(self):
        return self._lr

    @lr.setter
    def lr(self, lr):
        self._lr = lr

    @property
    def img_size(self):
        return self._img_size

    @img_size.setter
    def img_size(self, img_size):
        self._img_size = img_size

    @property
    def use_gpu(self):
        return self._use_gpu

    @use_gpu.setter
    def use_gpu(self, use_gpu):
        self._use_gpu = use_gpu

    def optimize(self, layer, filter_idx, input_=None, num_iter=30):
        """Generates an image that maximally activates the target filter.

        Args:
            layer (torch.nn.modules.conv.Conv2d): The target Conv2d layer from
                which the filter to be chosen, based on `filter_idx`.
            filter_idx (int): The index of the target filter.
            num_iter (int, optional, default=30): The number of iteration for
                the gradient ascent operation.

        Returns:
            output (list of torch.Tensor): With dimentions
                :math:`(num_iter, C, H, W)`. The size of the image is
                determined by `img_size` attribute which defaults to 224.

        """

        # Validate the type of the layer

        if type(layer) != nn.modules.conv.Conv2d:
            raise TypeError('The layer must be nn.modules.conv.Conv2d.')

        # Validate filter index

        num_total_filters = layer.out_channels
        self._validate_filter_idx(num_total_filters, filter_idx)

        # Inisialize input (as noise) if not provided

        if input_ is None:
            input_ = np.uint8(np.random.uniform(
                150, 180, (self._img_size, self._img_size, 3)))
            input_ = apply_transforms(input_, size=self._img_size)

        if torch.cuda.is_available() and self.use_gpu:
            self.model = self.model.to('cuda')
            input_ = input_.to('cuda')

        # Remove previous hooks if any

        while len(self.handlers) > 0:
            self.handlers.pop().remove()

        # Register hooks to record activation and gradients

        self.handlers.append(self._register_forward_hooks(layer, filter_idx))
        self.handlers.append(self._register_backward_hooks())

        # Inisialize gradients

        self.gradients = torch.zeros(input_.shape)

        # Optimize

        return self._ascent(input_, num_iter)

    def visualize(self, layer, filter_idxs=None, lr=1., num_iter=30,
                  num_subplots=4, figsize=(4, 4), title='Conv2d',
                  return_output=False):
        """Optimizes for the target layer/filter and visualizes the output.

        A method that combines optimization and visualization. There are
        mainly 3 types of operations, given a target layer:

        1. If `filter_idxs` is provided as an integer, it optimizes for the
            filter specified and plots the output.
        2. If `filter_idxs` is provided as a list of integers, it optimizes for
            all the filters specified and plots the output.
        3. if `filter_idx` is not provided, i.e. None, it randomly chooses
            `num_subplots` number of filters from the layer provided and
            plots the output.

        It also returns the output of the optimization, if specified with
        `return_output=True`.

        Args:
            layer (torch.nn.modules.conv.Conv2d): The target Conv2d layer from
                which the filter to be chosen, based on `filter_idx`.
            filter_idxs (int or list of int, optional, default=None): The index
                or indecies of the target filter(s).
            lr (float, optional, default=.1): The step size of optimization.
            num_iter (int, optional, default=30): The number of iteration for
                the gradient ascent operation.
            num_subplots (int, optional, default=4): The number of filters to
                optimize for and visualize. Relevant in case 3 above.
            figsize (tuple, optional, default=(4, 4)): The size of the plot.
                Relevant in case 1 above.
            title (str, optional default='Conv2d'): The title of the plot.
            return_output (bool, optional, default=False): Returns the
                output(s) of optimization if set to True.


        Returns:
            For a single optimization (i.e. case 1 above):
                output (list of torch.Tensor): With dimentions
                    :math:`(num_iter, C, H, W)`. The size of the image is
                    determined by `img_size` attribute which defaults to 224.
            For multiple optimization (i.e. case 2 or 3 above):
                output (list of list of torch.Tensor): With dimentions
                    :math:`(num_subplots, num_iter, C, H, W)`. The size of the
                    image is determined by `img_size` attribute which defaults
                    to 224.

        """

        self._lr = lr

        if (type(filter_idxs) == int):
            self._visualize_filter(layer,
                                   filter_idxs,
                                   num_iter=num_iter,
                                   figsize=figsize,
                                   title=title)
        else:
            num_total_filters = layer.out_channels

            if filter_idxs is None:
                num_subplots = min(num_total_filters, num_subplots)
                filter_idxs = np.random.choice(range(num_total_filters),
                                               size=num_subplots)

            self._visualize_filters(layer,
                                    filter_idxs,
                                    num_iter,
                                    len(filter_idxs),
                                    title=title)

        if return_output:
            return self.output, self.plt

    def deepdream(self, img_path, layer, filter_idx, lr=.1, num_iter=20,
                  figsize=(4, 4), title='DeepDream', return_output=False):
        """Creates DeepDream.

        It applies the optimization on the image provided. The image is loaded
        and made into a torch.Tensor that is compatible as the input to the
        network.

        Read the original blog post by Google for more information on
        `DeepDream <https://ai.googleblog.com/2015/06/inceptionism-going-deeper-into-neural.html>`_.

        Args:
            img_path (str): A path to the image you want to apply DeepDream on
            layer (torch.nn.modules.conv.Conv2d): The target Conv2d layer from
                which the filter to be chosen, based on `filter_idx`.
            filter_idx (int): The index of the target filter.
            lr (float, optional, default=.1): The step size of optimization.
            num_iter (int, optional, default=30): The number of iteration for
                the gradient ascent operation.
            figsize (tuple, optional, default=(4, 4)): The size of the plot.
                Relevant in case 1 above.
            title (str, optional default='Conv2d'): The title of the plot.
            return_output (bool, optional, default=False): Returns the
                output(s) of optimization if set to True.

        Returns:
            output (list of torch.Tensor): With dimentions
                :math:`(num_iter, C, H, W)`. The size of the image is
                determined by `img_size` attribute which defaults to 224.

        """ # noqa

        input_ = apply_transforms(load_image(img_path), self.img_size)

        self._lr = lr
        output = self.optimize(layer, filter_idx, input_, num_iter=num_iter)

        plt.figure(figsize=figsize)
        plt.axis('off')
        plt.title(title)

        plt.imshow(format_for_plotting(
            standardize_and_clip(output[-1],
                                 saturation=0.15,
                                 brightness=0.7))); # noqa

        if return_output:
            return output

    #####################
    # Private interface #
    #####################

    def _register_forward_hooks(self, layer, filter_idx):
        def _record_activation(module, input_, output):
            self.activation = torch.mean(output[:, filter_idx, :, :])

        return layer.register_forward_hook(_record_activation)

    def _register_backward_hooks(self):
        def _record_gradients(module, grad_in, grad_out):
            if self.gradients.shape == grad_in[0].shape:
                self.gradients = grad_in[0]

        for _, module in self.model.named_modules():
            if isinstance(module, nn.modules.conv.Conv2d) and \
                    module.in_channels == 3:
                return module.register_backward_hook(_record_gradients)

    def _ascent(self, x, num_iter):
        output = []

        for i in range(num_iter):
            self.model(x)

            self.activation.backward()

            self.gradients /= (torch.sqrt(torch.mean(
                torch.mul(self.gradients, self.gradients))) + 1e-5)

            x = x + self.gradients * self._lr
            output.append(x)

        return output

    def _validate_filter_idx(self, num_filters, filter_idx):
        if not np.issubdtype(type(filter_idx), np.integer):
            raise TypeError('Indecies must be integers.')
        elif (filter_idx < 0) or (filter_idx > num_filters):
            raise ValueError(f'Filter index must be between 0 and \
                             {num_filters - 1}.')

    def _visualize_filter(self, layer, filter_idx, num_iter, figsize, title):
        self.output = self.optimize(layer, filter_idx, num_iter=num_iter)

        plt.figure(figsize=figsize)
        plt.axis('off')
        plt.title(title)

        plt.imshow(format_for_plotting(
            standardize_and_clip(self.output[-1],
                                 saturation=0.15,
                                 brightness=0.7))); # noqa

    def _visualize_filters(self, layer, filter_idxs, num_iter, num_subplots,
                           title):
        # Prepare the main plot

        num_cols = 4
        num_rows = int(np.ceil(num_subplots / num_cols))

        fig = plt.figure(figsize=(16, num_rows * 5))
        plt.title(title)
        plt.axis('off')

        self.output = []

        # Plot subplots

        for i, filter_idx in enumerate(filter_idxs):
            output = self.optimize(layer, filter_idx, num_iter=num_iter)

            self.output.append(output)

            ax = fig.add_subplot(num_rows, num_cols, i+1)
            ax.set_xticks([])
            ax.set_yticks([])
            ax.set_title(f'filter {filter_idx}')

            ax.imshow(format_for_plotting(
                standardize_and_clip(output[-1],
                                     saturation=0.15,
                                     brightness=0.7)))

        plt.subplots_adjust(wspace=0, hspace=0); # noqa
        self.plt = plt```

然后使用以下代码绘图:

import torchvision.models as models
from grad_as import GradientAscent

model = models.vgg16(pretrained=True) # 这里可以改成其它模型

g_ascent = GradientAscent(model.features)


# specify layer and filter info
conv5_1 = model.features[24]  # 相应的这里也要改,可以用print(model)代码查看模型结构进行修改
conv5_1_filters = [45, 271, ]

vis,plt = g_ascent.visualize(conv5_1, conv5_1_filters, title="VGG16: conv5_1",return_output=True)

plt.show()



报错解决

报错如下

from importlib_resources import path
ImportError: cannot import name 'path' from 'importlib_resources'

找到报错处的源文件,尝试在代码中手动导入 path,而不是从 importlib_resources 直接导入:

from importlib_resources import path

替换为:

from importlib_resources import files

def path(package, resource):
    return files(package).joinpath(resource)

这样,代码将使用 files 函数来导入 path,而不是直接从 importlib_resources 中导入。


总结

以上代码均经过本人亲测可用。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Nginx(五)

负载均衡 官网文档 Using nginx as HTTP load balancer nginx中实现反向代理的方式 HTTP&#xff1a;通过nginx配置反向代理到后端服务器&#xff0c;nginx将接收到的HTTP请求转发给后端服务器。使用 proxy_pass 命令 HTTPS&#xff1a;通过nginx配置反向代理到后端服务器&…

IDEA调试总结

前言 由于 IDEA 每个人使用的版本不同以及快捷键的设置不同&#xff0c;所以忽略了快捷键的使用。如果不知道快捷键请在 IDEA 工具栏里面点开 Run 菜单即可知悉 图标介绍 下面咱们进入看图说话环节&#xff0c;下列图标小伙伴知道是啥功能么&#xff1f;日常开发进行 Debug 使…

高斯分布-最大似然估计公式白板推导

由上述推导得出结论&#xff1a; μ M L E 1 N ∑ i 1 N x i \mu_{MLE}\frac{1}{N}\sum\limits _{i1}^{N}x_{i} μMLE​N1​i1∑N​xi​ σ ^ 2 1 N − 1 ∑ i 1 N ( x i − μ ) 2 \hat{\sigma}^{2}\frac{1}{N-1}\sum\limits _{i1}^{N}(x_{i}-\mu)^{2} σ^2N−11​i1∑N…

Vue路由使用参数传递数据

一、使用query参数传递数据 &#xff08;一&#xff09;参数的传递 1. 携带参数进行传递 <router-link to"/路径?参数名1参数值1&参数名2参数值2">内容</router-link> 我们在下面的代码中传递每条消息的id和标题&#xff1a; 2. 配置对象进行传递…

UE5.3实现1秒12帧风格的动画抽帧效果

现今一些卡通风格游戏会刻意模仿早期动画1秒12帧的播放效果&#xff0c;以营造较强的风格化体验&#xff0c;博主在UE5中实现了一下&#xff08;左侧正常动画&#xff0c;右侧抽帧动画&#xff09;&#xff1a; 我们可以通过在UE中对导入设置进行一些修改&#xff0c;达到不改…

什么是安全平行切面

安全平行切面的定义 通过嵌入在端—管—云内部的各层次切点&#xff0c;使得安全管控与业务逻辑解耦&#xff0c;并通过标准化的接口为安全业务提供内视和干预能力的安全基础设施。安全平行切面是一种创新的安全体系思想&#xff0c;是实现“原生安全”的一条可行路径。 为什…

QRadioButton、QCheckBox样式表

QRadioButton、QCheckBox样式表 RGB颜色查找表阿里巴巴矢量图标库实现效果Chapter1 QRadioButton样式表详细描述示例效果源码样式表 Chapter2 QRadioButton样式表Chapter3 QCheckBox样式美化Chapter4 QCheckBox自定义样式&#xff08;$$$&#xff09;效果图1.实现QCheckBox控件…

说说你对React Router的理解?常用的Router组件有哪些?

一、是什么 react-router等前端路由的原理大致相同&#xff0c;可以实现无刷新的条件下切换显示不同的页面 路由的本质就是页面的URL发生改变时&#xff0c;页面的显示结果可以根据URL的变化而变化&#xff0c;但是页面不会刷新 因此&#xff0c;可以通过前端路由可以实现单…

3.5_文件和目录列表

要想知道系统中有哪些文件&#xff0c;可以使用列表命令&#xff08;ls&#xff09;。本节将描述ls命令和可用来格式化其输出信息的选项。 总结 ls命令最基本的形式会显示当前目录下的文件和目录&#xff1a; 命令/参数备注ls按列排序显示当前目录下的文件和目录-F区分文件和…

实体店铺必看:如何申请低手续费或免手续费的收款码

在数字支付日益普及的今天&#xff0c;为实体店铺如餐饮店引入低成本甚至免手续费的收款解决方案变得尤为重要。本文将详细介绍实体店铺如何申请低手续费或免手续费的收款码&#xff0c;助您降低运营成本&#xff0c;提升业务效率。 一、了解不同支付平台的政策 首先&#xf…

代码随想录图论部分-695. 岛屿的最大面积|1020. 飞地的数量

695. 岛屿的最大面积 题目&#xff1a;给你一个大小为 m x n 的二进制矩阵 grid 。岛屿 是由一些相邻的 1 (代表土地) 构成的组合&#xff0c;这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0&#xff08;代表水&#xff0…

6.4翻转二叉树(LC226—送分题,前序遍历)

算法&#xff1a; 第一想法是用昨天的层序遍历&#xff0c;把每一层level用切片反转。但是这样时间复杂度很高。 其实只要在遍历的过程中去翻转每一个节点的左右孩子就可以达到整体翻转的效果。 这道题目使用前序遍历和后序遍历都可以&#xff0c;唯独中序遍历不方便&#x…

双路四电磁铁控制比例多路阀放大器

比例多路换向阀属于换向阀类&#xff0c;配置外置比例放大器。它控制一个或同时操作的多个液压耗能器的运动方向和速度。 该控制装置与负载无关&#xff0c;且为无极的。全面的模块化系统&#xff0c;具有各种型号和组合选项&#xff0c;使用范围&#xff1a;装载起重机、升降工…

SpringBoot+MybatisPlus Restful示例

增删改查,分页 CREATE TABLE tbl_book ( id int NOT NULL AUTO_INCREMENT, type varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, name varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, desc_ription varchar(255) CHAR…

Python的requests库爬取商城优惠券

首先&#xff0c;我们需要了解要抓取的网页的结构和数据格式。在这个例子中&#xff0c;我们使用Python的requests库来发送HTTP请求&#xff0c;并使用BeautifulSoup库来解析HTML内容。 import requests from bs4 import BeautifulSoup然后&#xff0c;我们需要使用requests库的…

【IP-guard WebServer 远程命令执行漏洞复现(0day)】

文章目录 一、漏洞说明二、影响版本三、资产测绘四、漏洞复现五、修复建议 一、漏洞说明 IP-guard是由溢信科技股份有限公司开发的一款终端安全管理软件&#xff0c;旨在帮助企业保护终端设备安全、数据安全、管理网络使用和简化IT系统管理。 IP-guard Webserver远程命令执行漏…

家纺服装行业出口管理ERP解决方案

我国是世界上最大的纺织品生产出口国&#xff0c;有着悠久的家纺服装贸易历史。今年前8个月&#xff0c;我国家纺出口市场经历了震荡波动&#xff0c;8月单月家纺出口增速&#xff0c;结束连续3个月的下降趋势&#xff0c;由负转正。后续家纺出口市场预计将缓慢修复&#xff0c…

100+ Windows运行命令大全,装B高手必备

操作电脑关闭、重启、注销、休眠的命令细则: 用法: shutdown [/i | /l | /s | /sg | /r | /g | /a | /p | /h | /e | /o] [/hybrid] [/soft] [/fw] [/f] [/m \\computer][/t xxx][/d [p|u:]xx:yy [/c "comment"]] 没有参数 显示帮助。这与键入 /? 是一样的。…

GZ038 物联网应用开发赛题第3套

2023年全国职业院校技能大赛 高职组 物联网应用开发 任 务 书 &#xff08;第3套卷&#xff09; 工位号&#xff1a;______________ 第一部分 竞赛须知 一、竞赛要求 1、正确使用工具&#xff0c;操作安全规范&#xff1b; 2、竞赛过程中如有异议&#xff0c;可向现场考评…

canvas 曲线图 双数值轴 山峰图

下面的代码本人亲自撰写&#xff0c;原生不易啊。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>D…
最新文章