本节讲卷积神经网络的可视化
三种方法html
可视化卷积神经网络的中间输出(中间激活)算法
有助于理解卷积神经网络连续的层如何对输入进行变换,也有助于初步了解卷积神经网络每一个过滤器的含义数组
可视化卷积神经网络的过滤器网络
有助于精确理解卷积神经网络中每一个过滤器容易接受的视觉模式或视觉概念app
可视化图像中类激活的热力图dom
有助于理解图像的哪一个部分被识别为属于某个类别,从而能够定位图像中的物体函数
可视化中间激活
是指对于给定输入,展现网络中各个卷积层和池化层输出的特征图,这让咱们能够看到输入如何被分解为网络学到的不一样过滤器。咱们但愿在三个维度对特征图进行可视化:宽度、高度和深度(通道)。每一个通道都对应相对独立的特征,因此将这些特征图可视化的正确方法是将每一个通道的内容分别绘制成二维图像学习
Keras加载模型方法ui
from keras.models import load_model model = load_model('cats_and_dogs_small_2.h5')
可视化方法3d
from keras.models import load_model from keras.preprocessing import image import numpy as np import matplotlib.pyplot as plt from keras import models model = load_model('dogVScat.h5') # 查看模型 model.summary() img_path = "C:\\Users\\fan\\Desktop\\testDogVSCat\\test\\cats\\cat.1700.jpg" img = image.load_img(img_path, target_size=(150, 150)) img_tensor = image.img_to_array(img) img_tensor = np.expand_dims(img_tensor, axis=0) img_tensor /= 255 # shape(1, 150, 150, 3) print(img_tensor.shape) plt.title("original cat") plt.imshow(img_tensor[0]) plt.show() # 提取前 8 层的输出 layer_outputs = [layer.output for layer in model.layers[:8]] # 建立一个模型,给定模型输入,能够返回这些输出 activation_model = models.Model(inputs=model.input, outputs=layer_outputs) # 返回8个Numpy数组组成的列表,每一个层激活对应一个 Numpy 数组 activations = activation_model.predict(img_tensor) first_layer_activation = activations[0] # 将第 4 个通道可视化 plt.matshow(first_layer_activation[0, :, :, 4]) plt.show() # 将每一个中间激活的全部通道可视化 layer_names = [] for layer in model.layers[:8]: layer_names.append(layer.name) images_per_row = 16 for layer_name, layer_activation in zip(layer_names, activations): # 特征图中的特征个数 n_features = layer_activation.shape[-1] size = layer_activation.shape[1] # 在这个矩阵中将激活通道平铺 n_cols = n_features // images_per_row display_grid = np.zeros((size * n_cols, images_per_row * size)) for col in range(n_cols): for row in range(images_per_row): channel_image = layer_activation[0, :, :, col * images_per_row + row] # 对特征进行后处理,使其看起来更美观 channel_image -= channel_image.mean() if channel_image.std() != 0: channel_image /= channel_image.std() channel_image *= 64 channel_image += 128 channel_image = np.clip(channel_image, 0, 255).astype('uint8') display_grid[col * size: (col + 1) * size, row * size: (row + 1) * size] = channel_image scale = 1. / size plt.figure(figsize=(scale * display_grid.shape[1], scale * display_grid.shape[0])) plt.title(layer_name) plt.grid(False) plt.imshow(display_grid, aspect='auto', cmap='viridis') plt.show()
结果
原始猫
模型,使用之上第一个介绍的猫狗二分类的模型
第一层
第四层
第七层
第八层
随着层数的加深,激活变得愈来愈抽象,而且愈来愈难以直观地理解。它们开始表示更高层次的概念
即,随着层数的加深,层所提取的特征变得愈来愈抽象。更高的层激活包含关于特定输入的信息愈来愈少,而关于目标的信息愈来愈多
可视化卷积神经网络的过滤器
想要观察卷积神经网络学到的过滤器,另外一种简单的方法是显示每一个过滤器所响应的视觉模式。这能够经过在输入空间中进行梯度上升来实现:从空白输入图像开始,将梯度降低应用于卷积神经网络输入图像的值,其目的是让某个过滤器的响应最大化。获得的输入图像是选定过滤器具备最大响应的图像
过程
首先,须要构建一个损失函数,其目的是让某个卷积层的某个过滤器的值最大化;而后,咱们要使用随机梯度降低来调节输入图像的值,以便让这个激活值最大化
from keras import backend as K import numpy as np from keras.applications import VGG16 import matplotlib.pyplot as plt from keras.preprocessing import image # 将张量转换为有效图像 def deprocess_image(x): x -= x.mean() x /= (x.std() + 1e-5) x *= 0.1 x += 0.5 # 将 x 裁切(clip)到 [0, 1] 区间 x = np.clip(x, 0, 1) x *= 255 # 将 x 转换为 RGB 数组 x = np.clip(x, 0, 255).astype('uint8') return x # 生成过滤器可视化 def generate_pattern(layer_name, filter_index, size=150): layer_output = model.get_layer(layer_name).output loss = K.mean(layer_output[:, :, :, filter_index]) grads = K.gradients(loss, model.input)[0] grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5) iterate = K.function([model.input], [loss, grads]) input_img_data = np.random.random((1, size, size, 3)) * 20 + 128. step = 1. for i in range(40): loss_value, grads_value = iterate([input_img_data]) input_img_data += grads_value * step img = input_img_data[0] return deprocess_image(img) # 为过滤器的可视化定义损失张量 model = VGG16(weights='imagenet', include_top=False) layer_name = 'block3_conv1' filter_index = 0 layer_output = model.get_layer(layer_name).output loss = K.mean(layer_output[:, :, :, filter_index]) # 获取损失相对于输入的梯度 grads = K.gradients(loss, model.input)[0] # 将梯度张量除以其 L2 范数来标准化 grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5) # 给定 Numpy 输入值,获得 Numpy 输出值 iterate = K.function([model.input], [loss, grads]) loss_value, grads_value = iterate([np.zeros((1, 150, 150, 3))]) # 经过随机梯度降低让损失最大化 # 从一个带噪声的随机图像开始 input_img_data = np.random.random((1, 150, 150, 3)) * 20 + 128. plt.imshow(image.array_to_img(input_img_data[0])) plt.show() step = 1. for i in range(40): loss_value, grads_value = iterate([input_img_data]) input_img_data += grads_value * step def draw_layer_filter(layer_name): size = 64 margin = 5 results = np.zeros((8 * size + 7 * margin, 8 * size + 7 * margin, 3)) for i in range(8): for j in range(8): filter_img = generate_pattern(layer_name, i + (j * 8), size=size) horizontal_start = i * size + i * margin horizontal_end = horizontal_start + size vertical_start = j * size + j * margin vertical_end = vertical_start + size results[horizontal_start: horizontal_end, vertical_start: vertical_end, :] = filter_img plt.figure(figsize=(20, 20)) results = image.array_to_img(results) plt.imshow(results) plt.show() draw_layer_filter(layer_name='block1_conv1') draw_layer_filter(layer_name='block4_conv1')
结果
输入图像
过滤器: block1_conv1
过滤器:block4_conv1
经过对比发现
模型第一层(block1_conv1)的过滤器对应简单的方向边缘和颜色(还有一些是彩色边缘)
高层的过滤器相似于天然图像中的纹理
可视化类激活的热力图
这种可视化方法有助于了解一张图像的哪一部分让卷积神经网络作出了最终的分类决策。这有助于对卷积神经网络的决策过程进行调试,特别是出现分类错误的状况下。这种方法还能够定位图像中的特定目标
这种通用的技术叫做类激活图(CAM,class activation map)可视化,它是指对输入图像生成类激活的热力图。类激活热力图是与特定输出类别相关的二维分数网格,对任何输入图像的每一个位置都要进行计算,它表示每一个位置对该类别的重要程度
一种方法
给定一张输入图像,对于一个卷积层的输出特征图,用类别相对于通道的梯度对这个特征图中的每一个通道进行加权
from keras.applications.vgg16 import VGG16 from keras.preprocessing import image from keras.applications.vgg16 import preprocess_input, decode_predictions import numpy as np from keras import backend as K import matplotlib.pyplot as plt from PIL import Image import cv2 model = VGG16(weights='imagenet') img_path = 'E:\\study\\研究生\\笔记\\studyNote\\bookStudy\\bookNote\\imgs\\testImg.png' img = image.load_img(img_path, target_size=(224, 224)) x = image.img_to_array(img) # 添加一个维度,将数组转换为(1, 224, 224, 3) 形状的批量 x = np.expand_dims(x, axis=0) x = preprocess_input(x) preds = model.predict(x) print('Predicted:', decode_predictions(preds, top=3)[0]) # 索引编号 np.argmax(preds[0]) # 来使用 Grad-CAM 算法展现图像中哪些部分最像非洲象 african_elephant_output = model.output[:, 386] last_conv_layer = model.get_layer('block5_conv3') grads = K.gradients(african_elephant_output, last_conv_layer.output)[0] pooled_grads = K.mean(grads, axis=(0, 1, 2)) iterate = K.function([model.input], [pooled_grads, last_conv_layer.output[0]]) pooled_grads_value, conv_layer_output_value = iterate([x]) 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() # 将热力图与原始图像叠加 img = Image.open(img_path).convert('RGB') img = np.array(img) heatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0])) heatmap = np.uint8(255 * heatmap) heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET) superimposed_img = heatmap * 0.4 + img cv2.imwrite('elephant_cam.jpg', superimposed_img) superimposed_img = image.array_to_img(superimposed_img) plt.imshow(superimposed_img) plt.show()
原始图像
热力图
混合图像
保存的图像
此处保存的图像和显示的图像不一致
Deep learning with Python 学习笔记(5)
Deep learning with Python 学习笔记(3)