1. 程式人生 > >卷積神經網路特徵圖視覺化(自定義網路和VGG網路)

卷積神經網路特徵圖視覺化(自定義網路和VGG網路)

藉助Keras和Opencv實現的神經網路中間層特徵圖的視覺化功能,方便我們研究CNN這個黑盒子裡到發生了什麼。

自定義網路特徵視覺化

程式碼:

# 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 *
import keras


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]
    row,col = get_row_col(num_pic)

    for i in range(0,num_pic):
        feature_map_split=feature_map[:,:,i]
        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.jpg')
    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.jpg")

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)))

    return model


if __name__ == "__main__":

    img = cv2.imread('001.jpg')

    model = create_model()

    img_batch = np.expand_dims(img, axis=0)
    conv_img = model.predict(img_batch)  # conv_img 卷積結果

    visualize_feature_map(conv_img)

這裡定義了一個4層的卷積,每個卷積層分別包含9個卷積、Relu啟用函式和尺度不等的池化操作,係數全部是隨機初始化。
輸入的原圖如下:

第一層卷積後視覺化的特徵圖:

所有第一層特徵圖1:1融合後整體的特徵圖:

第二層卷積後視覺化的特徵圖:

所有第二層特徵圖1:1融合後整體的特徵圖:

第三層卷積後視覺化的特徵圖:

所有第三層特徵圖1:1融合後整體的特徵圖:

第四層卷積後視覺化的特徵圖:

所有第四層特徵圖1:1融合後整體的特徵圖:

從不同層可視化出來的特徵圖大概可以總結出一點規律:

  • 1. 淺層網路提取的是紋理、細節特徵
  • 2. 深層網路提取的是輪廓、形狀、最強特徵(如貓的眼睛區域)
  • 3. 淺層網路包含更多的特徵,也具備提取關鍵特徵(如第一組特徵圖裡的第4張特徵圖,提取出的是貓眼睛特徵)的能力
  • 4. 相對而言,層數越深,提取的特徵越具有代表性
  • 5. 影象的解析度是越來越小的

VGG19網路特徵視覺化

程式碼:

# 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
import numpy as np
import matplotlib.pyplot as plt
from pylab import *


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
    print feature_map.shape

    feature_map_combination=[]
    plt.figure()

    num_pic = feature_map.shape[2]
    row,col = get_row_col(num_pic)

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

    plt.savefig('feature_map.jpg')
    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.jpg")


if __name__ == "__main__":
    base_model = VGG19(weights='imagenet', include_top=False)
    # model = Model(inputs=base_model.input, outputs=base_model.get_layer('block1_pool').output)
    # model = Model(inputs=base_model.input, outputs=base_model.get_layer('block2_pool').output)
    # model = Model(inputs=base_model.input, outputs=base_model.get_layer('block3_pool').output)
    # model = Model(inputs=base_model.input, outputs=base_model.get_layer('block4_pool').output)
    model = Model(inputs=base_model.input, outputs=base_model.get_layer('block5_pool').output)

    img_path = '001.jpg'
    img = image.load_img(img_path)
    x = image.img_to_array(img)
    x = np.expand_dims(x, axis=0)
    x = preprocess_input(x)
    block_pool_features = model.predict(x)
    print(block_pool_features.shape)

    feature = block_pool_features.reshape(block_pool_features.shape[1:])

    visualize_feature_map(feature)

從第一到第五層的特徵圖分別如下:

從第一層到第五層各特徵圖按1:1比例融合後特徵依次為: