keras如何可视化 模型预测时的 中间 特征图,网络模型如何可视化中间层特征图以及如何打印网络结构

需求:

注意:可视化中间层特征图操作一般是在测试阶段,因为该文中提到的可视化的操作类似于在某一层网络中断,然后输出该层之后的结果,也可以理解为提前结束,当然也可以在训练的时候打印,但是这样的意义并不大,这样终止训练过程,训练过程本身就是在找最优参数,所以可视化基本都是可视化训练好的模型之后的测试结果

使用模型文件预测一张图片(下图cat.jpeg为测试图片,超萌的小猫咪。。。有木有啊。。。。),将模型的某一层结果进行可视化。基于keras实现。

分享两个示例,示例一为自己建立的卷积池化结构,示例2为VGG16(具体哪一个版本的VGG16不重要)示例。

使用的方法是:

#index = 8表示可视化第八层卷积的结果,其它层结果类似
model = Model(inputs=model.input, outputs=model.get_layer(index=8).output) 

具体示例及注释见如下代码部分:

示例1:手动自己建立的简易CNN网络

代码中关键的几点为:(标记的位置 我都注释在代码里了,不懂的可以留言)

标记0:index = ? 我们想可视化第几层的结果就让index等于几,index = 0 表示你直接没卷积(这里是几就是几,并不是 从0开始的哈,这样说的很通俗易懂了吧。。)示例1中为index = 8,可视化第八层[层数是相对于model.summary()结果而言的]

标记1:model.summary() 该方法的意思是打印整个的网络结构,直接看示例1的model.summary() 结果

model.summary()的输出结果:
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 336, 276, 9)       684       
_________________________________________________________________
activation_1 (Activation)    (None, 336, 276, 9)       0         
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 84, 69, 9)         0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 80, 65, 9)         2034      
_________________________________________________________________
activation_2 (Activation)    (None, 80, 65, 9)         0         
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 26, 21, 9)         0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 22, 17, 9)         2034      
_________________________________________________________________
activation_3 (Activation)    (None, 22, 17, 9)         0         
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 11, 8, 9)          0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 9, 6, 9)           738       
_________________________________________________________________
activation_4 (Activation)    (None, 9, 6, 9)           0         
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 4, 3, 9)           0         
=================================================================
Total params: 5,490
Trainable params: 5,490
Non-trainable params: 0
_________________________________________________________________
None

标记2:num_pic = feature_map.shape[2]。该方法中的 数字2 与具体的情况有关【解释一下这里为什么是2,我们看summary显结果,第一层的输出shape为(336, 276, 9),很明显我们需要打印出九张图像,9 对应的下标正好是2,这个需要看具体情况定,具体情况在哪看,就是打印出网络结构图,看看每一层的输出层数所对应的下标在shape的哪一维 】,表示我要显示几张图。

标记3:该处要注意和标记2是对应的,也就是i 的位置要与标记2中的数字相匹配,可以看示例1 示例2 的代码理解一下,


# coding: utf-8

from keras.models import Model
import cv2
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers.convolutional import Convolution2D, MaxPooling2D
from keras.layers import Activation
from pylab import *
from keras import backend as K


def get_row_col(num_pic):
    squr = num_pic ** 0.5
    row = round(squr)
    col = row + 1 if squr - row > 0 else row
    return row, col


def visualize_feature_map(img_batch):
    feature_map = np.squeeze(img_batch, axis=0)
    print(feature_map.shape)

    feature_map_combination = []
    plt.figure()

    num_pic = feature_map.shape[2] #标记2
    print('num_pic',num_pic)
    row, col = get_row_col(num_pic)

    for i in range(0, num_pic):
        feature_map_split = feature_map[:, :, i] #标记3
        feature_map_combination.append(feature_map_split)
        plt.subplot(row, col, i + 1)
        plt.imshow(feature_map_split)
        axis('off')
        title('feature_map_{}'.format(i))

    # plt.savefig('feature_map.png')
    plt.show()

    # 各个特征图按1:1 叠加
    feature_map_sum = sum(ele for ele in feature_map_combination)
    plt.imshow(feature_map_sum)
    # plt.savefig("feature_map_sum.png")


def create_model():
    model = Sequential()

    # 第一层CNN
    # 第一个参数是卷积核的数量,第二三个参数是卷积核的大小
    model.add(Convolution2D(9, (5,5),  input_shape=img.shape))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(4, 4)))
    #
    # 第二层CNN
    model.add(Convolution2D(9, (5,5),  input_shape=img.shape))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(3, 3)))

    # 第三层CNN
    model.add(Convolution2D(9, (5,5),  input_shape=img.shape))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))

    # 第四层CNN
    model.add(Convolution2D(9, (3,3), input_shape=img.shape))
    model.add(Activation('relu'))
    model.add(MaxPooling2D(pool_size=(2, 2)))
    #model.summary()打印网络的结构,看结果输出
    print(model.summary()) #标记1
    return model


if __name__ == "__main__":
    img = cv2.imread('cat.jpeg')

    model = create_model()

    model = Model(inputs=model.input, outputs=model.get_layer(index=8).output) #标记0

    print('img ', img.shape)
    img_batch = np.expand_dims(img, axis=0)
    print('img_batch',img_batch.shape)
    conv_img = model.predict(img_batch)  # conv_img 卷积结果
    print('conv_img.shape', conv_img.shape)


    visualize_feature_map(conv_img)

-----------------------------------------------------------以下为示例1的结果图------------------------------

=====================分割线================================

示例2:VGG16

标记说明和上边一样。标记我在代码中注释了,这个例子需要models.py文件和示例.py两个文件。

model.py (里边有很多代码是我需要的东西,并没有删,使用的话直接复制即可,这个文件不需要动里边的东西【标记1在这这个文件里】)

import numpy as np
import sys
import math
import operator
import csv
import glob, os
import xlrd
import cv2
import pandas as pd

from sklearn.svm import SVC
from collections import Counter
from sklearn.metrics import confusion_matrix
import scipy.io as sio
import keras
from keras.models import Sequential, Model
from keras.layers.core import Flatten, Dense, Dropout
from keras.layers.convolutional import Conv2D, MaxPooling2D, ZeroPadding2D
from keras.layers import LSTM, GlobalAveragePooling2D, GRU, Bidirectional, UpSampling2D, Input, BatchNormalization, add, \
    concatenate, Lambda, Activation, multiply
from keras.optimizers import SGD
import keras.backend as K
from keras.callbacks import Callback
from keras.engine.topology import Layer

from labelling import collectinglabel
from reordering import readinput
from evaluationmatrix import fpr
import numpy as np


def VGG_16(spatial_size, classes, channels, channel_first=True, weights_path=None):
    model = Sequential()
    if channel_first:
        model.add(ZeroPadding2D((1, 1), input_shape=(channels, spatial_size, spatial_size)))
    else:
        model.add(ZeroPadding2D((1, 1), input_shape=(spatial_size, spatial_size, channels)))

    # print("model0:" + str(model.get_layer(index=0).output_shape) + "\n")
    model.add(Conv2D(64, (3, 3), activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(64, (3, 3), activation='relu'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))
    # print("model1:" +str(model.get_layer(index=1)) + str(model.get_layer(index=1).output_shape) + "\n")
    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(128, (3, 3), activation='relu', name="conv3"))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(128, (3, 3), activation='relu'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))
    # print("model2:" + str(model.get_layer('conv3')) + str(model.get_layer('conv3').output_shape) + "\n")
    # print("model3:" + str(model.get_layer(index=3)) + str(model.get_layer(index=3).output_shape) + "\n")
    # print("model:" + str(model.get_layer))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(256, (3, 3), activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(256, (3, 3), activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(256, (3, 3), activation='relu'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))

    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(512, (3, 3), activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(512, (3, 3), activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(512, (3, 3), activation='relu'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))

    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(512, (3, 3), activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(512, (3, 3), activation='relu'))
    model.add(ZeroPadding2D((1, 1)))
    model.add(Conv2D(512, (3, 3), activation='relu'))
    model.add(MaxPooling2D((2, 2), strides=(2, 2)))  # 33

    # print("length:"+str(len(model.get_layer)))
    model.add(Flatten())
    model.add(Dense(4096, activation='relu'))  # 34
    model.add(Dropout(0.5))
    model.add(Dense(4096, activation='relu'))  # 35
    model.add(Dropout(0.5))
    model.add(Dense(2622, activation='softmax'))  # Dropped
    # print("length:"+str(len(model.layers))+"\n")
    # # for i in range(len(model.layers)):
    # # 	print(model.get_layer(index=i).output)
    # for layer in model.layers:
    # 	print(layer.output)
    # model.add(Dense(classes, activation='softmax')) # 36

    if weights_path:
        model.load_weights(weights_path)
    print(model.summary()) #标记1
    # model.pop()
    # model.add(Dense(classes, activation='softmax')) # 36

    return model

示例2代码:

# coding: utf-8
from keras.applications.vgg19 import VGG19
from keras.preprocessing import image
# from keras.applications.vgg19 import preprocess_input
from keras.models import Model
from models import VGG_16
import numpy as np
import matplotlib.pyplot as plt
from pylab import *
import cv2
from keras import backend as K
K.set_image_dim_ordering('th')
import os

def get_row_col(num_pic):
    squr = num_pic ** 0.5
    row = round(squr)
    col = row + 1 if squr - row > 0 else row
    return row, col


def visualize_feature_map(img_batch):
    feature_map = img_batch
    # feature_map = np.squeeze(img_batch, axis=0)
    print('this is ',feature_map.shape)

    feature_map_combination = []
    plt.figure()

    num_pic = feature_map.shape[0] #标记2
    row, col = get_row_col(num_pic)

    for i in range(0, num_pic):
        feature_map_split = feature_map[i, :, :] #标记3
        feature_map_combination.append(feature_map_split)
        plt.subplot(row, col, i + 1)
        plt.imshow(feature_map_split)
        axis('off')

    # plt.savefig('feature_map.png')
    plt.show()

    # 各个特征图按1:1 叠加
    feature_map_sum = sum(ele for ele in feature_map_combination)
    plt.imshow(feature_map_sum)
    # plt.savefig("feature_map_sum.png")


if __name__ == "__main__":
    base_model = VGG_16(spatial_size=224, classes=5, channels=3, weights_path="VGG_Face_Deep_16.h5")

    model = Model(inputs=base_model.input, outputs=base_model.get_layer(index=2).output) #标记0
   

    img = cv2.imread("cat.jpeg")

    img = cv2.resize(img,(224,224)) #VGG输入要求

    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    img_batch = np.expand_dims(img, axis=0)
    block_pool_features = model.predict(x)
    feature = block_pool_features.reshape(block_pool_features.shape[1:])
    visualize_feature_map(feature)

-----------------------------------------------------------以下为示例2的结果图------------------------------

发布了36 篇原创文章 · 获赞 25 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/Kansas_Jason/article/details/102500844
今日推荐