精华内容
下载资源
问答
  • 本文将介绍在卷积神经网络(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,加入读者圈,一起讨论最新鲜的人工智能科技哦~)

    展开全文
  • 基于卷积神经网络和热图回归的非结构化道路消失点检测 前言:20年的一篇文章,是关于非结构化道路VP检测中第一篇基于深度学习的解决方案。之前读过,这里再读一下,顺便再跑一下程序。 原文链接: ...

    Unstructured Road Vanishing Point Detection Using the Convolutional Neural Network and Heatmap Regression(URVP)

    基于卷积神经网络和热图回归的非结构化道路消失点检测

    前言:20年的一篇文章,是关于非结构化道路VP检测中第一篇基于深度学习的解决方案。之前读过,这里再读一下,顺便再跑一下程序。

    原文链接:

    https://arxiv.org/abs/2006.04691

    源代码

    https://github.com/qd213618/URVP

    引用信息

    @article{liu2020unstructured,
      title={Unstructured Road Vanishing Point Detection Using the Convolutional Neural Network and Heatmap Regression},
      author={Liu, Yin-Bo and Zeng, Ming and Meng, Qing-Hao},
      journal={arXiv preprint arXiv:2006.04691},
      year={2020}
    }
    

    摘要

    • 轻量化骨架:depthwise convolution modified HRNet。用于提取非结构化道路的层次特征
    • VP检测:multi-scale supervised learning + heatmap super-resolution + coordinate regression
    • Kong数据集上达到了33fps

    引言

    消失点定义:在三维场景中,一组平行线的透视投影在图像平面上的交点。
    自动驾驶车辆可根据消失点辨别可行驶区域。

    heatmap regression:可用于估计图像中像素级关键点的位置,然而传统的heatmap regression只在输入图像的1/4或1/2单一的粗尺度上估计关键点,无法满足高精度的要求。而HRNet无法满足高实时性要求,因此本文对HRNet进行了修正,同时采用三个tricks:(multi-scale supervised learning + heatmap super-resolution + coordinate regression)

    同时,本文也贡献了含有5355张带有标注的数据集(unstructured road vanishing point ,URVP

    关于道路消失点检测的传统方法中,基于边缘和基于区域用于结构化道路,基于纹理的方法可用于非结构化道路,但存在两个问题:

    1. 性能容易受到光照不均匀和图像分辨率等因素的影响,检测结果往往不稳定
    2. 处理非常耗时,不能满足实时性要求
      在这里插入图片描述

    本文方法

    1. depthwise convolution modified HRNet:提取图像特征
    2. multiscale heatmap supervised learning:获得准确的VP点估计(结合1/4和1/2尺度的热力图)
    3. coordinate regression:获得准确的VP坐标
      图1显示了网络架构。

    在这里插入图片描述

    多尺度监督学习

    多尺度监督学习:在关键点检测中混合两个或以上热力图。
    1/4尺度热力图:在原图中会造成4倍的误差放大。所以采用基于反投影的超分辨率技术(the back-projection-based super-resolution technique)从1/4尺度得到1/2尺度的超分辨率热力图。
    图2显示了上采样方法。

    从1/4→1/2尺度有下图所示三种方法。本文采用第二种:up-projection unit (UPU)方法。

    upsample模块的输入是feature map和预测的1/4比例尺热图的拼接(concatenation)

    1. Deconv:5x5 deconvolution + BatchNorm + ReLU
    2. Conv:3x3 convolution + BatchNorm + ReLU
      在这里插入图片描述

    坐标回归

    从热力图中获取关键点坐标的两个传统方法:提取热图中最大点的坐标或通过高斯分布估计关键点的位置;缺点如下:

    1. 误差同样会放大相应的倍数。(1/4尺度的热力图会放大4倍,1/2尺度热力图会放大2倍)
    2. 计算量大,达不到实时性要求。
      因此本文采用坐标回归模块直接输出准确的VP点坐标。思路来源于YOLOv2,YOLOv2中证明,在二维坐标回归中,对单元偏移量的预测是一种稳定、准确的方法。因此,预测点(Vx,Vy)定义如下:
      在这里插入图片描述
      f(·):VP的sigmoid函数
      (cx,cy):相关网格单元的左上角的坐标

    损失函数

    在这里插入图片描述
    本文的一些设置如下
    lcoord:VP点的坐标损失。logistic regression
    lh1:1/4尺度热力图损失。MSE
    lh2:1/2尺度热力图损失。MSE
    lconf:置信度(confidence)损失。logistic regression
    λconf=0.5:不含VP的cells
    λconf=1:含VP的cells
    λcoord=2和λh=1:用于平衡热力图和和坐标回归的平衡。

    实验

    实验细节

    Pytorch 1.3
    dual RTX 2080 Ti
    CUDA 10
    i7-8700K@3.7GHz

    URVP作为训练集;Kong作为测试集
    输入图像尺寸:320x320
    给所有ground truth热力图添加上std=3的Gaussian kernel
    SGD
    backbone:开始时lr=0.001
    网络其他部分:开始时lr=0.01
    每20个epoch将lr除10,momentum=0.9
    数据增强:随机翻转和图像旋转

    数据集

    目前用于非结构化道路VP检测的数据集只有两个:Kong-1003张;Moghadam-500张
    URVP:利用Flickr谷歌Image工具构建的一个新的训练数据集

    评价指标

    标准化欧氏距离来测量预测的VP点和ground truth VP点之间的距离。
    在这里插入图片描述
    Pg:ground truth
    Pv:预测的
    Diag(I):输入图片的对角线长度
    NormDist>=0.1的置为0.1,认为预测失败。
    图3显示了关于热力图尺度对比效果。
    在这里插入图片描述
    (从左到右依次是:输入,1/4尺度VP估计,1/2尺度VP估计,本文方法估计)
    (白点是ground truth,红点是本文方法预测点。)

    图4显示了不同方法对比效果。
    在这里插入图片描述
    图5显示了用NormDist度量的效果对比。
    在这里插入图片描述
    在这里插入图片描述

    消融研究

    骨架网络

    在这里插入图片描述
    Hourglass (Stack = 4) (Hg4)
    HRNet (W = 48)(HRNet-48)

    多尺度监督学习

    在这里插入图片描述

    上采样模块

    在这里插入图片描述

    坐标回归

    在这里插入图片描述

    结论

    下一步:多任务学习

    展开全文
  • 在大部分人看来,卷积神经网络是一种黑盒技术,通过理论推导,以及梯度传播,去不断逼近局部最优解。这也导致人们对于神经网络研究进展的缓慢,因为这种黑盒模型无法给出研究人员进行改进的思路。所幸的是,近几年来...

    前言

    在大部分人看来,卷积神经网络是一种黑盒技术,通过理论推导,以及梯度传播,去不断逼近局部最优解。这也导致人们对于神经网络研究进展的缓慢,因为这种黑盒模型无法给出研究人员进行改进的思路。所幸的是,近几年来的论文,也从常规的神经网络结构转向神经网络可视化,目的是让我们能看见卷积神经网络“学习”到了什么,神经网络是怎么判别物体的类别

    今天就要为大家介绍一种卷积神经网络可视化的技巧,它发表于一篇论文,名叫Grad CAM,通过热力图来对神经网络进行可视化。

    简介

    热力图通常是用来对类别进行划分的图像,它有点像红外成像图,温度高的地方就很红,温度低的部分就呈现蓝色。同理,我们使用热力图可以以权重的形式来展现,神经网络对图片的哪一部分激活值最大。比如输入到猫狗分类,如果卷积神经网络判别是猫,那它的热力图普遍分散在猫身上,而至于它是根据猫的哪一部分来判别,就利用了热力图的原理

    原理

    我们卷积神经网络进行分类,最后一层通常是softmax层,其最大值对应的就是分类类别

    我们从这个最大概率分类类别的节点出发,进行反向传播,对最后一层卷积层求得梯度,然后对每一张特征图求出均值,最后我们取出 最后一层卷积层的激活值,与前面我们对梯度特征图的均值进行相乘,这个过程可以理解为,每个通道的重要程度与我们卷积激活值进行相乘,就相当于是一个加权操作。最后根据这个乘积值生成一个热力图,与原图进行叠加。

    代码实现

    这里笔者参考的是deep learning with python。环境为最新的keras框架
    模型是自己简单训练出来的一个vgg16模型,只不过将对应的卷积层改为depthwise Separable卷积,全连接层也调小了很多,最后做的是一个多分类(五个类别)

    先看一下我自己实现的vgg16代码

    from keras import layers
    from keras import models
    from keras import optimizers
    from keras.preprocessing.image import ImageDataGenerator
    
    base_dir = './train_data/'
    
    train_data_gen = ImageDataGenerator(rescale=1./255,
                                        rotation_range=30,
                                        horizontal_flip=True)
    train_generator = train_data_gen.flow_from_directory(
        base_dir,
        target_size=(224, 224),
        batch_size=20,
        class_mode='categorical'
    )
    
    model = models.Sequential()
    model.add(layers.SeparableConv2D(64, 3, padding='SAME', activation='relu'))
    model.add(layers.MaxPooling2D(pool_size=(2, 2)))
    model.add(layers.SeparableConv2D(128, 3, padding='SAME', activation='relu'))
    model.add(layers.MaxPooling2D(pool_size=(2, 2)))
    model.add(layers.BatchNormalization())
    model.add(layers.SeparableConv2D(256, 3, padding='SAME', activation='relu'))
    model.add(layers.MaxPooling2D(pool_size=(2, 2)))
    model.add(layers.BatchNormalization())
    model.add(layers.SeparableConv2D(512, 3, padding='SAME', activation='relu'))
    model.add(layers.MaxPooling2D(pool_size=(2, 2)))
    model.add(layers.SeparableConv2D(512, 3, padding='SAME', activation='relu'))
    model.add(layers.MaxPooling2D(pool_size=(2, 2)))
    model.add(layers.SeparableConv2D(512, 3, padding='SAME', activation='relu'))
    model.add(layers.BatchNormalization())
    model.add(layers.Flatten())
    model.add(layers.Dropout(0.5))
    model.add(layers.Dense(32, activation='relu'))
    model.add(layers.Dense(5, activation='softmax'))
    
    model.build(input_shape=(None, 224, 224, 3))
    model.summary()
    
    model.compile(loss='mean_squared_error',
                  optimizer=optimizers.Adam(),
                  metrics=['acc'])
    
    history = model.fit_generator(
        train_generator,
        steps_per_epoch=20,
        epochs=15
    )
    model.save('five_flowers_categorical_vgg16.h5')
    

    我这里通过keras的图像生成器加载目录下的训练图片
    然后指定目标图像的大小,为224 224

    最后将模型保存

    现在我们正式开始进行热力图的实现
    首先我把源代码都贴上来,这是我自己封装的一个代码

    from keras import backend as K
    from keras.models import load_model
    from keras.preprocessing import image
    from keras.utils import plot_model
    from keras import Model
    import numpy as np
    import matplotlib.pyplot as plt
    from keras.applications.vgg16 import preprocess_input
    import cv2
    
    
    def load_model_h5(model_file):
        """
        载入原始keras模型文件
        :param model_file: 模型文件,h5类型
        :return: 模型
        """
        return load_model(model_file)
    
    def load_img_preprocess(img_path, target_size):
        """
        加载图片并进行预处理
        :param img_path: 图片文件名
               target_size: 要加载图片的缩放大小
                            这是一个tuple元组类型
        :return: 预处理过的图像文件
        """
        img = image.load_img(img_path, target_size=target_size)
        img = image.img_to_array(img) # 转换成数组形式
        img = np.expand_dims(img, axis=0) # 为图片增加一维batchsize,直接设置为1
    
        img = preprocess_input(img) # 对图像进行标准化
    
        return img
    
    def gradient_compute(model, layername, img):
        """
        计算模型最后输出与你的layer的梯度
        并将每个特征图的梯度进行平均
        再将其与卷积层输出相乘
        :param model: 模型
        :param layername: 你想可视化热力的层名
        :param img: 预处理后的图像
        :return:
        卷积层与平均梯度相乘的输出值
        """
        preds = model.predict(img)
        idx = np.argmax(preds[0]) # 返回预测图片最大可能性的index索引
    
        output = model.output[:, idx] # 获取到我们对应索引的输出张量
        last_layer = model.get_layer(layername)
    
        grads = K.gradients(output, last_layer.output)[0]
    
        pooled_grads = K.mean(grads, axis=(0, 1, 2)) # 对每张梯度特征图进行平均,
                                                     # 返回的是一个大小是通道维数的张量
        iterate = K.function([model.input], [pooled_grads, last_layer.output[0]])
    
        pooled_grads_value, conv_layer_output_value = iterate([img])
    
        for i in range(pooled_grads.shape[0]):
            conv_layer_output_value[:, :, i] *= pooled_grads_value[i]
    
        return conv_layer_output_value
    
    def plot_heatmap(conv_layer_output_value, img_in_path, img_out_path):
        """
        绘制热力图
        :param conv_layer_output_value: 卷积层输出值
        :param img_in_path: 输入图像的路径
        :param img_out_path: 输出热力图的路径
        :return:
        """
        heatmap = np.mean(conv_layer_output_value, axis=-1)
        heatmap = np.maximum(heatmap, 0)
        heatmap /= np.max(heatmap)
    
        img = cv2.imread(img_in_path)
        heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))
        heatmap = np.uint8(255 * heatmap)
    
        heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)
        superimopsed_img = heatmap * 0.4 + img
    
        cv2.imwrite(img_out_path, superimopsed_img)
    
    img_path = r'./train_data/daisy/4534460263_8e9611db3c_n.jpg'
    model_path = r'./five_flowers_categorical_vgg16.h5'
    layername = r'separable_conv2d_6'
    
    img = load_img_preprocess(img_path, (224, 224))
    model = load_model_h5(model_path)
    
    conv_value = gradient_compute(model, layername, img)
    plot_heatmap(conv_value, img_path, './packagetest.jpg')
    

    下面我来解释各个函数的意思

    load_model_h5

    这个函数很简单,读取模型h5文件

    load_img_preprocess

    这个函数调用了keras的图像包
    先对进来的图像进行缩放
    转换成数组形式
    而通常张量里面还有一个batch_size维数

    所以我这里调用了numpy的expand_dims函数来给图像数组增加一个维度,注意这里要设置axis=0,因为keras图像数据格式第一维就是batch_size维

    keras另外还自带了一个preprocess函数,对图像进行一个标准化操作

    gradient_compute

    这里就是我们的重点了

    preds先利用模型predict函数对图片进行预测,获取他的输出张量
    然后我们利用argmax找出张量中,输出值最大的index索引

    这里就是找模型预测可能性最大的那个索引

    然后output就根据索引,取得对应的张量

    last_layer这里我们调用了get_layer函数,传入你要的对应层的层名,这里我们通常要的是最后一层卷积层的结果,所以理所当然在后续调用里面,传入的是最后一层卷积层的名字

    然后我们调用keras的后端来求梯度
    在这里插入图片描述
    因为last_layer 是一个层,我们需要调用其output属性才能获得它输出的张量,然后我们根据这个张量对输出output求得梯度

    pooled_gradient这里是在0, 1, 2维度上求一个平均,即最后返回的是一个大小为通道数的梯度张量(因为是对整张特征图进行池化)

    iterate这里也是调用keras的backend后端,对一个函数进行实例化,即执行我们前面定义的操作

    最后我们获得的是梯度,也就是对应的权重
    我们利用一个for循环进行加权

    plot_heatmap

    这个函数就是绘制热力图

    首先对热力图矩阵做一些预处理,除去负值,进行归一化

    然后缩放到原图的大小
    然后用opencv自带的applycolormap函数对其做一个色图的转换

    最后我们乘以0.4,这是一个热力图强度因子,你调的越大,它叠加的就更多
    然后与原图进行累加,保存到你指定的路径

    最终结果展示

    在这里插入图片描述
    这是我原始输入的图像

    经过热力图叠加之后
    在这里插入图片描述
    这个特征很抽象,它似乎是根据这朵花的花瓣底下以及根茎来进行判别

    总结

    我认为这个热力图的可视化还是很不错的,能比较清晰的展现出来神经网络对某一区域的响应程度

    但目前我发现的一个bug是
    当你训练的模型准确度非常高,接近过拟合的情况
    你softmax的结果就是一堆0和一个1

    这时候再调用后端函数进行求梯度会失败
    具体原因目前还不明确

    展开全文
  • 预训练网络(pretrained network)是一个保存好的网络,之前已在大型数据集(通常是大规模 像分类任务)上训练好。这个方法也叫迁移学习。预训练的模型学到的特征的空间层次结构可以有效地作为视觉世界的通用模型较低...

    选择预训练模型

    将深度学习应用于小型图像数据集,一种常用且非常高效的方法是使用预训练网络。

    预训练网络(pretrained network)是一个保存好的网络,之前已在大型数据集(通常是大规模图 像分类任务)上训练好。这个方法也叫迁移学习。预训练的模型学到的特征的空间层次结构可以有效地作为视觉世界的通用模型

    较低层学到的结构都是一些点线等低层次的特征,

    这里使用的预训练的模型的数据是 ImageNet 数据集(140 万张标记图像,1000 个不同的类别),为了降低理解的难度使用VGG16架构来获取预训练的模型。它是一种简单而又广泛使用的卷积神经网络架构。其实还有很多架构例如: - VGG - ResNet - Inception - Inception-ResNet - Xception

    预训练模型的特征提取

    特征提取是使用之前网络学到的表示来从新样本中提取出有用的特征。然后将这些特征输入一个新的分类器,从头开始训练。

    卷积基

    对于分类的卷积神经网络基本包含两个主要组成: - 一系列池化层和卷积层 卷积基 - 一个密集连接分类器

    特征提取就是取出之前训练好的网络的卷积基,在上面运行新数据,然后在输出上面训练一个新的分类器 具体如下图:

    卷积基复用性卷积基学到的表示可能更加通用,因此更适合重复使用

    特征图表示通用概念在图像中是否存在

    特征图表示输入图像中的位置信息

    使用预训练模型的时候需要注意: - 低层学到的结构都是一些点线等低层次的特征(比如视觉边缘、颜色和纹理) - 靠近顶部的层提取的是更加抽象的概念(猫的眼睛,狗的鼻子)

    如果新的数据集与预训练的数据集差异很大,那么最好只使用前几层来做特征提取

    keras内置的模型

    keras.applications 中的一部分图像分类模型,都是在 ImageNet 数据集上预训练得到:VGG16

    VGG19

    ResNet50

    Inception V3

    MobileNet

    具体的使用如下函数,参数如下weights: 指定模型初始化的权重检查点

    include_top:指定模型最后是否包含密集连接分类器,

    input_shape: 是输入到网络中的图像张量的形状

    from keras.applications import VGG16

    conv_base = VGG16(weights = 'imagenet',

    include_top = False,

    input_shape=(150,150,3))

    Using TensorFlow backend.

    Colocations handled automatically by placer.

    conv_base.summary()

    _________________________________________________________________

    Layer (type) Output Shape Param #

    =================================================================

    input_1 (InputLayer) (None, 150, 150, 3) 0

    _________________________________________________________________

    block1_conv1 (Conv2D) (None, 150, 150, 64) 1792

    _________________________________________________________________

    block1_conv2 (Conv2D) (None, 150, 150, 64) 36928

    _________________________________________________________________

    block1_pool (MaxPooling2D) (None, 75, 75, 64) 0

    _________________________________________________________________

    block2_conv1 (Conv2D) (None, 75, 75, 128) 73856

    _________________________________________________________________

    block2_conv2 (Conv2D) (None, 75, 75, 128) 147584

    _________________________________________________________________

    block2_pool (MaxPooling2D) (None, 37, 37, 128) 0

    _________________________________________________________________

    block3_conv1 (Conv2D) (None, 37, 37, 256) 295168

    _________________________________________________________________

    block3_conv2 (Conv2D) (None, 37, 37, 256) 590080

    _________________________________________________________________

    block3_conv3 (Conv2D) (None, 37, 37, 256) 590080

    _________________________________________________________________

    block3_pool (MaxPooling2D) (None, 18, 18, 256) 0

    _________________________________________________________________

    block4_conv1 (Conv2D) (None, 18, 18, 512) 1180160

    _________________________________________________________________

    block4_conv2 (Conv2D) (None, 18, 18, 512) 2359808

    _________________________________________________________________

    block4_conv3 (Conv2D) (None, 18, 18, 512) 2359808

    _________________________________________________________________

    block4_pool (MaxPooling2D) (None, 9, 9, 512) 0

    _________________________________________________________________

    block5_conv1 (Conv2D) (None, 9, 9, 512) 2359808

    _________________________________________________________________

    block5_conv2 (Conv2D) (None, 9, 9, 512) 2359808

    _________________________________________________________________

    block5_conv3 (Conv2D) (None, 9, 9, 512) 2359808

    _________________________________________________________________

    block5_pool (MaxPooling2D) (None, 4, 4, 512) 0

    =================================================================

    Total params: 14,714,688

    Trainable params: 14,714,688

    Non-trainable params: 0

    _________________________________________________________________

    VGG16的模型架构非常的常见,如上面所示。最后的特征图的反馈的是(4,4,512).目前有两种方式来使用VGG16的卷积基。 - 独立使用卷积基:就是先将输入数据再卷积基上运行一次,然后将结果作为输入,再放到独立的Dense网络中计算训练一个dense 网络。 - 速度快,计算代价低,因为每个输入图像只需运行一次卷积基 - 但是无法做数据扩增,容易过拟合 - 对于电脑配置不高的可以使用该方法将卷积基放到整个模型中,直接使用数据输入端到端的运行整个模型计算量大,需要电脑的配置较高,一定要有GPU的加持

    可以使用数据增强来训练模型,

    独立使用卷积基的快速特征提取利用conv_base predict 方法从模型中的使用预训练的卷积基提取特征

    提取的特征形状为,并将将其展平成密集连接分类器的数据

    定义自己的密集连接分类器

    从图中可以看到验证精度达到了约 90%,比上一节从头开始训练的小型模型效果要好得多。但从图中也可以看出,虽然 dropout 比率相当大,但模型几乎从一开始就过拟合。

    import os

    import numpy as np

    from keras.preprocessing.image import ImageDataGenerator

    base_dir = "G:/Data/Kaggle/dogcat/smallData"

    train_dir = os.path.join(base_dir,'train')

    validation_dir = os.path.join(base_dir,'validation')

    test_dir = os.path.join(base_dir,'test')

    datagen = ImageDataGenerator(rescale=1./255)

    batch_size = 20

    def extract_features(directory,sample_count):

    features = np.zeros(shape=(sample_count,4,4,512))

    labels = np.zeros(shape=(sample_count))

    generator = datagen.flow_from_directory(

    directory,

    target_size=(150,150),

    batch_size=batch_size,

    class_mode='binary')

    i = 0

    for inputs_batch,labels_batch in generator:

    features_batch = conv_base.predict(inputs_batch)

    features[i * batch_size: (i+1) * batch_size] = features_batch

    labels[i * batch_size : (i+1) * batch_size] = labels_batch

    i += 1

    if i * batch_size >= sample_count:

    break

    return features,labels

    train_features,train_labels = extract_features(train_dir,2000)

    validation_features,validation_labels = extract_features(validation_dir,1000)

    test_features,test_labels = extract_features(test_dir,1000)

    Found 2000 images belonging to 2 classes.

    Found 1000 images belonging to 2 classes.

    Found 1000 images belonging to 2 classes.

    #其形状展平为

    print(train_features.shape)

    print(validation_features.shape)

    print(test_features.shape)

    train_features = np.reshape(train_features,(2000,4*4*512))

    validation_features = np.reshape(validation_features,(1000,4*4*512))

    test_features = np.reshape(test_features,(1000,4*4*512))

    print(test_features.shape)

    (1000, 8192)

    # 定义并训练密集连接分类器

    from keras import models

    from keras import layers

    from keras import optimizers

    model = models.Sequential()

    model.add(layers.Dense(256,activation='relu',input_dim=4*4*512))

    model.add(layers.Dropout(0.5))

    model.add(layers.Dense(1,activation='sigmoid'))

    model.compile(optimizer=optimizers.RMSprop(lr = 2e-5),

    loss='binary_crossentropy',

    metrics=['acc'])

    history = model.fit(train_features, train_labels,

    epochs=30,

    batch_size=20,

    validation_data=(validation_features, validation_labels))

    Use tf.cast instead.

    Train on 2000 samples, validate on 1000 samples

    Epoch 1/30

    2000/2000 [==============================] - 2s 764us/step - loss: 0.6043 - acc: 0.6650 - val_loss: 0.4369 - val_acc: 0.8600

    Epoch 2/30

    2000/2000 [==============================] - 1s 348us/step - loss: 0.4321 - acc: 0.8055 - val_loss: 0.3604 - val_acc: 0.8730

    Epoch 3/30

    2000/2000 [==============================] - 1s 349us/step - loss: 0.3655 - acc: 0.8365 -

    Epoch 30/30

    2000/2000 [==============================] - 1s 374us/step - loss: 0.0938 - acc: 0.9700 - val_loss: 0.2330 - val_acc: 0.9050

    #  绘制训练过程中的损失曲线和精度曲线

    import matplotlib.pyplot as plt

    acc = history.history['acc']

    val_acc = history.history['val_acc']

    loss = history.history['loss']

    val_loss = history.history['val_loss']

    epochs = range(1,len(acc) +1)

    plt.plot(epochs,acc,'bo',label='Training acc')

    plt.plot(epochs,val_acc,'b',label='validation acc')

    plt.title('train and validation acc')

    plt.legend()

    plt.figure()

    plt.plot(epochs,loss,'bo',label='Training loss')

    plt.plot(epochs,val_loss,'b',label='val_loss acc')

    plt.title('train and validation loss')

    plt.legend()

    plt.show()

    联合卷积基进行特征提取

    模型的行为和层类似,所以你可以向 Sequential 模型中添加一个模型,具体模型如下:

    VGG16 的卷积基有 14 714 688 个参数,非常多。在其上添加的分类器有 200 万个参数.如此多的参数都是预先定义好的 所以这里再训练的时候不需要重新再训练一遍:在编译和训练模型之前,一定要“冻结”卷积基。 冻结(freeze) 一个或多个层是指在训练过程中保持其权重不变。

    #在卷积基上添加一个密集连接分类器

    from keras import models

    from keras import layers

    model2 = models.Sequential()

    model2.add(conv_base)

    model2.add(layers.Flatten())

    model2.add(layers.Dense(256,activation='relu'))

    model2.add(layers.Dense(1,activation = 'sigmoid'))

    model2.summary()

    _________________________________________________________________

    Layer (type) Output Shape Param #

    =================================================================

    vgg16 (Model) (None, 4, 4, 512) 14714688

    _________________________________________________________________

    flatten_1 (Flatten) (None, 8192) 0

    _________________________________________________________________

    dense_1 (Dense) (None, 256) 2097408

    _________________________________________________________________

    dense_2 (Dense) (None, 1) 257

    =================================================================

    Total params: 16,812,353

    Trainable params: 16,812,353

    Non-trainable params: 0

    _________________________________________________________________

    keras冻结网络层的方法

    冻结网络的方法是将其 trainable 属性设为 False,如此设置之后,只有添加的两个 Dense 层的权重才会被训练。总共有 4 个权重张量,每层 2 个(主权重矩阵和偏置向量)。 *注意,为了让这些修改生效,你必须先编译模型。如果在编译之后修改了权重的 trainable 属性,那么应该重新编译模型,否则这些修改将被忽略。

    #conv_base.trainable = True

    print('This is the number of trainable weights '

    'before freezing the conv base:', len(model2.trainable_weights))

    conv_base.trainable = False

    print('This is the number of trainable weights '

    'after freezing the conv base:', len(model2.trainable_weights))

    This is the number of trainable weights before freezing the conv base: 30

    This is the number of trainable weights after freezing the conv base: 4

    from keras.preprocessing.image import ImageDataGenerator

    from keras import optimizers

    train_datagen = ImageDataGenerator(

    rescale=1./255,

    rotation_range=40,

    width_shift_range=0.2,

    height_shift_range=0.2,

    shear_range=0.2,

    zoom_range=0.2,

    horizontal_flip=True,

    fill_mode='nearest'

    )

    test_datagen = ImageDataGenerator(rescale=1./255)

    train_generator = train_datagen.flow_from_directory(

    train_dir,

    target_size=(150,150),

    batch_size = 20,

    class_mode = 'binary'

    )

    validation_generator = test_datagen.flow_from_directory(

    validation_dir,

    target_size=(150,150),

    batch_size = 20,

    class_mode='binary'

    )

    model2.compile(loss='binary_crossentropy',

    optimizer=optimizers.RMSprop(lr = 2e-5),

    metrics=['acc'])

    history = model2.fit_generator(

    train_generator,

    steps_per_epoch=100,

    epochs=30,

    validation_data=validation_generator,

    validation_steps=50

    )

    Found 2000 images belonging to 2 classes.

    Found 1000 images belonging to 2 classes.

    Use tf.cast instead.

    Epoch 1/30

    100/100 [==============================] - 21s 210ms/step - loss: 0.5961 - acc: 0.6910 - val_loss: 0.4507 - val_acc: 0.8360

    Epoch 2/30

    100/100 [==============================] - 17s 174ms/step - loss: 0.4815 - acc: 0.7915 - val_loss: 0.3790 - val_acc: 0.8640

    Epoch 30/30

    100/100 [==============================] - 17s 166ms/step - loss: 0.2839 - acc: 0.8835 - val_loss: 0.2366 - val_acc: 0.9050

    #  绘制训练过程中的损失曲线和精度曲线

    import matplotlib.pyplot as plt

    acc = history.history['acc']

    val_acc = history.history['val_acc']

    loss = history.history['loss']

    val_loss = history.history['val_loss']

    epochs = range(1,len(acc) +1)

    plt.plot(epochs,acc,'bo',label='Training acc')

    plt.plot(epochs,val_acc,'b',label='validation acc')

    plt.title('train and validation acc')

    plt.legend()

    plt.figure()

    plt.plot(epochs,loss,'bo',label='Training loss')

    plt.plot(epochs,val_loss,'b',label='val_loss acc')

    plt.title('train and validation loss')

    plt.legend()

    plt.show()

    请大家关注公众号:瓦力人工智能

    分享关于人工智能,机器学习,深度学习以及计算机视觉的好文章,同时自己对于这个领域学习心得笔记。想要一起深入学习人工智能的小伙伴一起结伴学习吧!

    展开全文
  • 神经网络分别中,我们不仅想知道最终预测结果,还需要了解网络是凭借图像什么特征进行判断的。其中类激活热力图 (CAM,class activation map)就是一种很好的呈现方式。 目录标题类激活热力图 (CAM,class ...
  • 可视化卷及神经网络热力图

    万次阅读 多人点赞 2018-09-26 20:40:31
    我们这里介绍的一种可视化方法,它有助于了解一张图像的哪一部分让卷积神经网络做出了最终的分类决策。这有助于对卷积神经网络的决策过程进行调试,特别是分类错误的情况下。这种方法可以定位图像中的特定目标。 ...
  • 一、可视化卷积神经网络的中间输出(中间激活):有助于理解卷积神经网络连续的层如何对输入进行变换,也有助于初步了解卷积神经网络每个过滤器的含义。 二、可视化卷积神经网络的过滤器:有助于精确理解卷积神经...
  • 卷积神经网络的可视化 - 类激活

    千次阅读 2019-08-14 18:26:19
    有助于了解一张图片的那个部分使得卷积神经网络做出最终的决策. 还可以定位图像中特定的目标 使用keras的完整实现方法(从<<python深度学习>>书中相关部分整理而来) 使用keras的预训练VGG16模型对图片...
  • 摘要:本文介绍一种卷积网络的可视化方法,类激活图可视化。使用预训练的VGG16模型,对一张网上随便找的动物图片进行分析,并将生成的热力图与原图像结合观察网络模型的分类依据。使用Keras框架。
  • 其二,是卷积神经网络的过滤器,帮助我们精确理解卷积神经网络中每个过滤器最容易接受的视觉模式。(即使得过滤器所有元素值最大的输入) 此外,还有类激活的热力图,帮助我们理解哪个部分被识别属于某个类别,从而...
  • 卷积神经网络的可视化:可视化卷积神经网络中间输出(中间激活),可视化卷积神经网络的过滤器,可视化图像中类激活的热力图。 可视化中间激活:对于指定输入,展示网络中各个卷积层和池化层输出的特征图(层的输出...
  • 卷积神经网络可视化与可解释性

    千次阅读 2018-05-05 14:59:24
    卷积网络可视化与可解释性相关资料的...学会如何生成热力图,如下图: 博客 Distill 非常推荐的一个网站 Global Average Pooling Layers for Object Localization Yes, Deep Networks are great, bu...
  • 我还要介绍另一种可视化方法,它有助于了解一张图像的哪一部分让卷积神经网络做出了最终的分类决策。这有助于对卷积神经网络的决策过程进行调试,特别是出现分类错误的情况下。 这种方法还可以定位图像中的特定目标...
  • 1、背景 卷积神经网络是一种黑盒技术,通过理论推导,以及梯度传播,去不断逼近局部最...比如输入到猫狗分类,如果卷积神经网络判别是猫,那它的热力图普遍分散在猫身上,而至于它是根据猫的哪一部分来判别,就利用了
  • 我还要介绍另一种可视化方法,它有助于了解一张图像的哪一部分让卷积神经网络做出了 最终的分类决策。这有助于对卷积神经网络的决策过程进行调试,特别是出现分类错误的情况下。这种方法还可以定位图像中的特定目标...
  • 卷积神经网络的各层卷积单元在模型网络中实际上有充当了目标检测器的作用,尽管没有提供对目标位置的监督。虽然其拥有在卷积层中定位对象的非凡能力,但当使用全连接层进行分类时,这种能力就会丧失。基于此,提出了...
  • 类激活(CAM,class activation map)技术有助于帮助我们了解一张图像的那一部分让卷积神经网络作出最终的分类决策,它对于输入图像的每个位置都进行计算,表示每个位置对该类别的重要程度。 一、加载VGG16网络权重...

空空如也

空空如也

1 2 3
收藏数 45
精华内容 18
关键字:

卷积神经网络热力图