精华内容
下载资源
问答
  • 可视化卷及神经网络热力图

    万次阅读 多人点赞 2018-09-26 20:40:31
    我们这里介绍的一种可视化方法,它有助于了解一张图像的哪一部分让卷积神经网络做出了最终的分类决策。这有助于对卷积神经网络的决策过程进行调试,特别是分类错误的情况下。这种方法可以定位图像中的特定目标。 ...

    我们这里介绍的一种可视化方法,它有助于了解一张图像的哪一部分让卷积神经网络做出了最终的分类决策。这有助于对卷积神经网络的决策过程进行调试,特别是分类错误的情况下。这种方法可以定位图像中的特定目标。

    我们使用预训练的VGG网络来演示这种方法。

    from keras.applications.vgg16 import VGG16
    
    K.clear_session()
    model = VGG16(weights='imagenet')
    

    在这里插入图片描述
    如图所示,这是两只非洲象的图片。我们将这张图片转换为VGG16能够读取的格式:模型大小为224224的图像上进行训练,这些训练图像都根据keras.applications.vgg16.preprocess_input函数中的内置的规则进行预处理。因此,我们需要加载图像,将其大小调整为224224,然后将其转化为float32格式的Numpy张量,并应用这些预处理规则。

    from keras.preprocessing import image
    from keras.applications.vgg16 import preprocess_input, decode_predictions
    import numpy as np
    
    img_path = '/Users/fchollet/Downloads/creative_commons_elephant.jpg'
    
    img = image.load_img(img_path, target_size=(224, 224))   # 大小为224*224的Python图像库图像
    
    x = image.img_to_array(img)  # 形状为(224, 224, 3)的float32格式Numpy数组
    
    x = np.expand_dims(x, axis=0)  # 添加一个维度,将数组转化为(1, 224, 224, 3)的形状批量
    
    x = preprocess_input(x)   #按批量进行预处理(按通道颜色进行标准化)
    

    可以在图像上运行预训练的VGG16网络,并将预测向量解码为我们可以读的形式。

    preds = model.predict(x)
    print('Predicted:', decode_predictions(preds, top=3)[0])
    

    Predicted: [(‘n02504458’, ‘African_elephant’, 0.90942144), (‘n01871265’, ‘tusker’, 0.08618243), (‘n02504013’, ‘Indian_elephant’, 0.0043545929)]

    对这个图像预测的前三个类别分别是:

    • 非洲象:92.5%的概率
    • 长牙动物:7%的概率
    • 印度象:0.4%的概率

    网络认为预测向量中最大激活的元素对应是“非洲象”类别的元素,索引编号386

    np.argmax(preds[0])
    

    386

    为了展示图像中哪些部分最像非洲象,我们使用Grad-CAM算法:

    african_elephant_output = model.output[:, 386]   # 预测向量中的非洲象元素
    
    last_conv_layer = model.get_layer('block5_conv3')  # block5_conv3层的输出特征图,它是VGG16的最后一个卷积层
    
    grads = K.gradients(african_elephant_output, last_conv_layer.output)[0]   # 非洲象类别相对于block5_conv3输出特征图的梯度
    
    pooled_grads = K.mean(grads, axis=(0, 1, 2))   # 形状是(512, )的向量,每个元素是特定特征图通道的梯度平均大小
    
    iterate = K.function([model.input], [pooled_grads, last_conv_layer.output[0]])  # 这个函数允许我们获取刚刚定义量的值:对于给定样本图像,pooled_grads和block5_conv3层的输出特征图
    
    pooled_grads_value, conv_layer_output_value = iterate([x])  # 给我们两个大象样本图像,这两个量都是Numpy数组
    
    for i in range(512):
        conv_layer_output_value[:, :, i] *= pooled_grads_value[i]  # 将特征图数组的每个通道乘以这个通道对大象类别重要程度
    
    heatmap = np.mean(conv_layer_output_value, axis=-1)  # 得到的特征图的逐通道的平均值即为类激活的热力图
    
    heatmap = np.maximum(heatmap, 0)
    heatmap /= np.max(heatmap)
    plt.matshow(heatmap)
    plt.show()
    

    在这里插入图片描述

    最后,我们可以用OpenCV来生成一张图像,将原始图像叠加在刚刚得到的热力图上

    import cv2
    
    img = cv2.imread(img_path)  # 用cv2加载原始图像
    
    heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))  # 将热力图的大小调整为与原始图像相同
    
    
    heatmap = np.uint8(255 * heatmap)  # 将热力图转换为RGB格式
    
    heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)   # 将热力图应用于原始图像
    
    superimposed_img = heatmap * 0.4 + img    # 这里的0.4是热力图强度因子
    
    cv2.imwrite('/Users/fchollet/Downloads/elephant_cam.jpg', superimposed_img)   # 将图像保存到硬盘
    

    在这里插入图片描述

    更多精彩内容,欢迎关注我的微信公众号:数据瞎分析
    在这里插入图片描述

    展开全文
  • heatmap) # 将热力图转换为RGB格式 heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) # 将热力图应用于原始图像 superimposed_img = heatmap * 0.4 + img # 这里的0.4是热力图强度因子 # 将图像保存到硬盘 ...
    from PIL import Image
    import torch
    import torchvision.transforms as transforms
    import numpy as np
    import matplotlib.pyplot as plt
    import cv2
    
    def draw_CAM(model,img_path,save_path,resize=227,isSave=False,isShow=False):
        # 图像加载&预处理
        img=Image.open(img_path).convert('RGB')
        loader = transforms.Compose([transforms.Resize(size=(resize,resize)),transforms.ToTensor()]) 
        img = loader(img).unsqueeze(0) # unsqueeze(0)在第0维增加一个维度
        
        # 获取模型输出的feature/score
        model.eval() # 测试模式,不启用BatchNormalization和Dropout
        feature=model.features(img)
        output=model.classifier(feature.view(1,-1))
        
        # 预测得分最高的那一类对应的输出score
        pred = torch.argmax(output).item()
        pred_class = output[:, pred]
    
        # 记录梯度值
        def hook_grad(grad):
            global feature_grad
            feature_grad=grad
        feature.register_hook(hook_grad)
        # 计算梯度
        pred_class.backward()
        
        grads=feature_grad # 获取梯度
        
        pooled_grads = torch.nn.functional.adaptive_avg_pool2d(grads, (1, 1)) # adaptive_avg_pool2d自适应平均池化函数,输出大小都为(1,1)
    
        # 此处batch size默认为1,所以去掉了第0维(batch size维)
        pooled_grads = pooled_grads[0] # shape为[batch,通道,size,size],此处batch为1,所以直接取[0]即取第一个batch的元素,就取到了每个batch内的所有元素
        features = feature[0] # 取【0】原因同上
        
        ########################## 导数(权重)乘以相应元素
        # 512是最后一层feature的通道数
        for i in range(len(features)):
            features[i, ...] *= pooled_grads[i, ...] # features[i, ...]与features[i]效果好像是一样的,都是第i个元素
        ##########################
        
        # 绘制热力图
        heatmap = features.detach().numpy()
        heatmap = np.mean(heatmap, axis=0) # axis=0,对各列求均值,返回1*n
     
        heatmap = np.maximum(heatmap, 0)
        heatmap /= np.max(heatmap)
        
        # 可视化原始热力图
        if isShow:
            plt.matshow(heatmap)
            plt.show()
            
        img = cv2.imread(img_path)  # 用cv2加载原始图像
        heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))  # 将热力图的大小调整为与原始图像相同
        heatmap = np.uint8(255 * heatmap)  # 将热力图转换为RGB格式
        heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)  # 将热力图应用于原始图像
        superimposed_img = heatmap * 0.4 + img  # 这里的0.4是热力图强度因子
        # 将图像保存到硬盘
        if isSave:
            cv2.imwrite(save_path, superimposed_img)  
        # 展示图像
        if isShow:
            superimposed_img/=255
            plt.imshow(superimposed_img)
    
    import torchvision.models as models
    model=models.alexnet()
    # draw_CAM(model,'/Users/liuyanzhe/Study/陶瓷研究相关/陶瓷数据/ceramic_data/训练/1牡丹/mudan15.png','/Users/liuyanzhe/Downloads/热力图1.png',isSave=True,isShow=True)
    draw_CAM(model,'/Users/liuyanzhe/Downloads/2.jpg','/Users/liuyanzhe/Downloads/热力图1.png',isSave=True,isShow=True)
    

    在这里插入图片描述

    在这里插入图片描述

    import torchvision.models as models
    model=models.vgg16()
    # draw_CAM(model,'/Users/liuyanzhe/Study/陶瓷研究相关/陶瓷数据/ceramic_data/训练/1牡丹/mudan15.png','/Users/liuyanzhe/Downloads/热力图2.png',isSave=True,isShow=True)
    draw_CAM(model,'/Users/liuyanzhe/Downloads/2.jpg','/Users/liuyanzhe/Downloads/热力图2.png',isSave=True,isShow=True)
    

    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 本文将介绍在卷积神经网络(CNN)中,针对图像的某些部位可视化从而做出判断的不同技术。 类激活映射(CAM)是一种生成热力图的技术,用于突出图像的类的特定区域。 热力图效用 下面是一个典型的热力图: 图片来源:...

    全文共2280字,预计学习时长4分钟
    在这里插入图片描述
    目前在可视化方面,我们已经掌握了许多不同的技术。本文将介绍在卷积神经网络(CNN)中,针对图像的某些部位可视化从而做出判断的不同技术。

    类激活映射(CAM)是一种生成热力图的技术,用于突出图像的类的特定区域。

    热力图效用

    下面是一个典型的热力图:

    在这里插入图片描述
    图片来源:https://github.com/jacobgil/pytorch-grad-cam

    这张图片中,一只猫被红色高亮显示为“猫”类,表示网络在进行分类判断时正在查看正确位置。

    视觉化神经网络正在查看的位置大有用处,因为它帮助我们理解神经网络是否在查看图像的适当部位,或者神经网络是否在进行误导。下列是一些神经网络在做分类决判断时可能进行误导和错误查看位置的例子:

    · 卷积神经网络将一张图片分类为“火车”,而实际上它是在寻找“火车轨道”(这意味着它会错误地将一张火车轨道图片单独分类为“火车”)。

    · 卷积神经网络将x光胸片分类为“高患病几率”,依据的不是疾病的实际表现,而是放在病人左肩上的金属“L”标记。重点是,这个“L”标记只有在病人躺下的时候才会被直接放在病人的身体上,而病人也只有虚弱到无法忍受才会躺下接受x光检查。

    参考:Zech et al. 2018,Confounding variables can degradegeneralization performance of radiological deep learning models.

    传送门:https://arxiv.org/pdf/1807.00431.pdf

    · CNN可根据数据集中五分之一的马图像中出现的左下角源标记将该图像分类为“马”。但如果将这个“马的源标记”放在一幅汽车图像上,那么网络仍将该图像分类为“马”。

    参考:Lapuschkin et al. 2019, Unmasking Clever Hans Predictors and Assessing What Machines Really Learn.

    传送门:https://arxiv.org/pdf/1902.10178.pdf

    在这里插入图片描述

    相关论文集

    这张图显示了有关卷积神经网络可视化热力图的几篇论文之间的关系。文章左上角可见这篇文章的关键——类激活映射(CAM):
    在这里插入图片描述
    以下是完整类激活映射论文的链接:Zhou et al. 2016 “Learning Deep Features for DiscriminativeLocalization.”

    传送门:http://openaccess.thecvf.com/content_cvpr_2016/papers/Zhou_Learning_Deep_Features_CVPR_2016_paper.pdf

    此处特别推荐查看图1和图2。
    在这里插入图片描述
    CAM:类激活映射

    类激活映射结构

    类激活映射背后的原理是利用一种特殊的卷积神经网络结构生成可视化热力图。

    参考:this post for a review of convolutional neural networks

    传送门:https://glassboxmedicine.com/2019/05/05/how-computers-see-intro-to-convolutional-neural-networks/

    其结构如下:卷积层,全局池化层,然后是一个输出分类判断的全连接层。
    在这里插入图片描述
    在以上示意图中,可以看到一些通用的卷积层,形成了“倒数第二个卷积层”(即网络中倒数第二层,也是卷积层的最后一层)。在这个“倒数第二个卷积层”中存在K特征图。在这个示意图中,对于特征映射A1、A2和A3, K = 3。

    但实际上K可以是任何值——例如,可能会有64个或512个特征映射。

    根据文章中的标注,特征图高度为v和宽度为u:

    文章传送门:https://pdfs.semanticscholar.org/223a/d42ec73c1a41355c0ca3626fa99c7841f840.pdf
    在这里插入图片描述
    全局池化层 (GAP)

    全局池化层是通过对特征图中的数字求平均值,从而将特征图转换为单个数字。若有K=3个特征图,则在全局池化之后,我们将得到K=3个数字。这三个数字用上图中的三个小正方形表示:

    在这里插入图片描述

    以下是用于描述全局池化层的标注符号:
    在这里插入图片描述

    因此,在全局池化中,对特征图Aij的元素进行求和,从i =1到u(全宽),从j = 1到v(全高),然后除以特征图中的元素总数,Z = uv。

    全连接层和分类数

    在执行全局池化后,我们将得到K个数字。通过全连接层将这K个数字转换为分类判断:
    在这里插入图片描述
    请注意,为避免混淆绘图,图中并未显示全连接层中的每个权重。实际上,红色数字(由GAP(A1)输出)通过权重连接到每个输出类,绿色数字(由GAP(A2)输出)通过权重连接到每个输出类,蓝色数字(由GAP(A3)输出)通过权重连接到每个输出类。

    参考:this post for review offully-connected layers.

    传送门:https://glassboxmedicine.com/2019/01/17/introduction-to-neural-networks/

    仅看“猫”输出类上,有三个权重,w1、w2和w3,这三个权重将全局池化输出连接到“猫”输出节点。使用上图所示的方程为"猫"类生成一个分数y猫,对应于y猫 = (w1)(红色)+ (w2)(绿色)+(w3)(蓝色)。

    类激活映射

    现在完成了整个类激活映射结构,从输入图像到分类数。最后一步是得到类激活映射可视化热力图,步骤如下:
    在这里插入图片描述
    这看起来很像计算y^猫分数的方法,但不同之处在于,我们不是将权重w1、w2和w3乘以特征图Ak上的全局池化层生成的单个数字,而是直接将权重乘以特征图。因此,虽然分数的输出是数字,但是类激活映射实际输出的是数字网格。而这个数字网格就是热力图!

    在这里插入图片描述
    总结

    下面是一页草图,总结了整篇类激活映射论文:
    在这里插入图片描述
    在这里插入图片描述留言 点赞 关注
    我们一起分享AI学习与发展的干货
    欢迎关注全平台AI垂类自媒体 “读芯术”
    在这里插入图片描述
    (添加小编微信:dxsxbb,加入读者圈,一起讨论最新鲜的人工智能科技哦~)

    展开全文
  • 具体而言是为了做一个特定场景的车辆/车种检测,因为摄像头角度问题,大多时候只有车辆的一部分处于画面内,所以没有走检测的方式,而是尝试了一下通过各种数据增强(主要是裁剪)来指导网络对不同车种车辆的各个部位...

    最近在做一个细粒度识别的项目,具体而言是为了做一个特定场景的车辆/车种检测,因为摄像头角度问题,大多时候只有车辆的一部分处于画面内,所以没有走检测的方式,而是尝试了一下通过各种数据增强(主要是裁剪)来指导网络对不同车种车辆的各个部位进行学习,从而指导车种分类以及有无车辆检测,最终达到监控车辆(车种)的目的。

    但是因为数据集不大,尽管模型收敛很好,但心里还是没底,担心是过拟合。于是想到可以可视化一下网络的CAM,观察一下指导分类的高响应区域是否落在目标核心部位上。

    Class Activation Mapping(CAM)是一个帮助可视化CNN的工具,通过它我们可以观察为了达到正确分类的目的,网络更侧重于哪块区域。比如,下面两幅图,一个是刷牙,一个是砍树,我们根据热力图可以看到高响应区域的确集中在我们认为最有助于作出判断的部位。

    其计算方法如下图所示。对于一个CNN模型,对其最后一个featuremap做全局平均池化(GAP)计算各通道均值,然后通过FC层等映射到class score,找出argmax,计算最大的那一类的输出相对于最后一个featuremap的梯度,再把这个梯度可视化到原图上即可。直观来说,就是看一下网络抽取到的高层特征的哪部分对最终的classifier影响更大。

    找到了一篇基于Keras的CAM实现,感谢:https://blog.csdn.net/Einstellung/article/details/82858974。但是我还是习惯用Pytorch一点,所以参考着改了一版Pytorch的实现。其中,有一个地方困扰了一下,因为Pytorch的自动求导机制,一般只会保存函数值对输入的导数值,而中间变量的导数值都没有保留,而此处我们需要计算输出层相对于最后一个feature map梯度,所以参考https://blog.csdn.net/qq_27061325/article/details/84728539解决了该问题。

    基于Pytorch的CAM计算与绘制,具体代码如下:

    #coding: utf-8

    import os

    from PIL import Image

    import torch

    import numpy as np

    import cv2

    import matplotlib.pyplot as plt

    def draw_CAM(model, img_path, save_path, transform=None, visual_heatmap=False):

    '''

    绘制 Class Activation Map

    :param model: 加载好权重的Pytorch model

    :param img_path: 测试图片路径

    :param save_path: CAM结果保存路径

    :param transform: 输入图像预处理方法

    :param visual_heatmap: 是否可视化原始heatmap(调用matplotlib)

    :return:

    '''

    # 图像加载&预处理

    img = Image.open(img_path).convert('RGB')

    if transform:

    img = transform(img)

    img = img.unsqueeze(0)

    # 获取模型输出的feature/score

    model.eval()

    features = model.features(img)

    output = model.classifier(features)

    # 为了能读取到中间梯度定义的辅助函数

    def extract(g):

    global features_grad

    features_grad = g

    # 预测得分最高的那一类对应的输出score

    pred = torch.argmax(output).item()

    pred_class = output[:, pred]

    features.register_hook(extract)

    pred_class.backward() # 计算梯度

    grads = features_grad # 获取梯度

    pooled_grads = torch.nn.functional.adaptive_avg_pool2d(grads, (1, 1))

    # 此处batch size默认为1,所以去掉了第0维(batch size维)

    pooled_grads = pooled_grads[0]

    features = features[0]

    # 512是最后一层feature的通道数

    for i in range(512):

    features[i, ...] *= pooled_grads[i, ...]

    # 以下部分同Keras版实现

    heatmap = features.detach().numpy()

    heatmap = np.mean(heatmap, axis=0)

    heatmap = np.maximum(heatmap, 0)

    heatmap /= np.max(heatmap)

    # 可视化原始热力图

    if visual_heatmap:

    plt.matshow(heatmap)

    plt.show()

    img = cv2.imread(img_path) # 用cv2加载原始图像

    heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0])) # 将热力图的大小调整为与原始图像相同

    heatmap = np.uint8(255 * heatmap) # 将热力图转换为RGB格式

    heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) # 将热力图应用于原始图像

    superimposed_img = heatmap * 0.4 + img # 这里的0.4是热力图强度因子

    cv2.imwrite(save_path, superimposed_img) # 将图像保存到硬盘

    展开全文
  • Pytorch可视化神经网络热力图(CAM)

    千次阅读 多人点赞 2019-12-03 11:03:17
    具体而言是为了做一个特定场景的车辆/车种检测,因为摄像头角度问题,大多时候只有车辆的一部分处于画面内,所以没有走检测的方式,而是尝试了一下通过各种数据增强(主要是裁剪)来指导网络对不同车种车辆的各个...
  • 今天有点空,聊个IT监控系统中常见的小细节:主机热力图。所谓主机热力图,就是采用矩阵热力图的方式,来展现环境内一批主机的健康状态。类似的界面应该大家都比较熟悉。我这先贴几个业内最有名的实现:阿里云的容器...
  • 预训练网络(pretrained network)是一个保存好的网络,之前已在大型数据集(通常是大规模 像分类任务)上训练好。这个方法也叫迁移学习。预训练的模型学到的特征的空间层次结构可以有效地作为视觉世界的通用模型较低...
  • 现有的深度神经网络可解释方法主要分为基于数据的方法和基于模型的方法。基于数据的可解释性分析方法中最典型的是可视化方法。可视化方法主要通过可视化工具将数据中的重要部分进行标注,将学习过程与原始数据结合...
  • Keras中可视化卷积层的类激活热力图C小C 2018-12-26 17:05:12 5546 收藏 15展开【时间】2018.12.26【题目】Keras中可视化卷积层的类激活热力图概述本文是对《Deep Learning with python》一书中第5.4.3节Keras中可视...
  • 所幸的是,近几年来的论文,也从常规的神经网络结构转向神经网络可视化,目的是让我们能看见卷积神经网络“学习”到了什么,神经网络是怎么判别物体的类别 今天就要为大家介绍一种卷积神经网络可视化的技巧,它发表...
  • Paper nameGrad-CAM: Visual Explanations from Deep Networks via Gradient-based LocalizationPaper Reading NoteURL: ...DR提出一种对神经网络输出进行可视化的方式Grad-CAM(Gradient-weighted Cla...
  • 基于卷积神经网络和热图回归的非结构化道路消失点检测 前言:20年的一篇文章,是关于非结构化道路VP检测中第一篇基于深度学习的解决方案。之前读过,这里再读一下,顺便再跑一下程序。 原文链接: ...
  • 神经网络分别中,我们不仅想知道最终预测结果,还需要了解网络是凭借图像什么特征进行判断的。其中类激活热力图 (CAM,class activation map)就是一种很好的呈现方式。 目录标题类激活热力图 (CAM,class ...
  • 卷机神经网络的可视化(可视化类激活的热力图) 参考:https://www.cnblogs.com/zhhfan/p/9978099.html 可视化类激活的热力图 我还要介绍另一种可视化方法,它有助于了解一张图像的哪一部分让卷积神经网络做出了最终...
  • 在训练期间,空间特征图Φ(xt)和Φ(xt’ )以及关键点坐标Ψ(xt) 和Ψ(xt’) 利用卷积神经网络和斯坦福此前提出的PointNet进行帧的预测,再次过程中,关键点的坐标被转换成高斯热力图(Gaussian heatmaps) HΨ(xt) ...
  • 使用神经网络进行预测时,一个明显的缺陷就是缺少可解释性,我们不能通过一些简单的方法来知道网络做出决策或者预测的理由,这在很多方面就使得它的应用受限。虽然不能通过一些数学方法来证明模型的有效性,但我们仍...
  • 1、背景 卷积神经网络是一种黑盒技术,通过理论推导,以及梯度传播,去不断逼近局部最...比如输入到猫狗分类,如果卷积神经网络判别是猫,那它的热力图普遍分散在猫身上,而至于它是根据猫的哪一部分来判别,就利用了

空空如也

空空如也

1 2 3 4
收藏数 74
精华内容 29
关键字:

神经网络热力图