神經網絡自己包含了一系列特徵提取器,理想的feature map應該是稀疏的以及包含典型的局部信息。經過模型可視化能有一些直觀的認識並幫助咱們調試模型,好比:feature map與原圖很接近,說明它沒有學到什麼特徵;或者它幾乎是一個純色的圖,說明它太過稀疏,多是咱們feature map數太多了(feature_map數太多也反映了卷積核過小)。可視化有不少種,好比:feature map可視化、權重可視化等等,我以feature map可視化爲例。linux
模型可視化web
用了keras作實驗,如下圖做爲輸入:瀏覽器
取網絡的前15層,每層取前3個feature map。網絡
從左往右看,能夠看到整個特徵提取的過程,有的分離背景、有的提取輪廓,有的提取色差,但也能發現十、11層中間兩個feature map是純色的,可能這一層feature map數有點多了,另外汽車的光暈對feature map中光暈的影響也能比較明顯看到。app
一般咱們把神經網絡最後一個fc全鏈接層做爲整個圖片的特徵表示,可是這一表示可能過於粗糙(從上面的feature map可視化也能看出來),無法精確描述局部空間上的特徵,而網絡的第一層空間特徵又太過精確,缺少語義信息(好比後面的色差、輪廓等),因而論文《Hypercolumns for Object Segmentation and Fine-grained Localization》提出一種新的特徵表示方法:Hypercolumns——將一個像素的 hypercolumn 定義爲全部 cnn 單元對應該像素位置的激活輸出值組成的向量),比較好的tradeoff了前面兩個問題,直觀地看如圖:ide
把汽車第一、四、7層的feature map以及第1, 4, 7, 10, 11, 14, 17層的feature map分別作平均,可視化以下:網站
代碼實踐google
1 # -*- coding: utf-8 -*- 2 from keras.applications import InceptionV3 3 from keras.applications.inception_v3 import preprocess_input 4 from keras.preprocessing import image 5 from keras.models import Model 6 from keras.applications.imagenet_utils import decode_predictions 7 import numpy as np 8 import cv2 9 from cv2 import * 10 import matplotlib.pyplot as plt 11 import scipy as sp 12 from scipy.misc import toimage 13 14 def test_opencv(): 15 # 加載攝像頭 16 cam = VideoCapture(0) # 0 -> 攝像頭序號,若是有兩個三個四個攝像頭,要調用哪個數字往上加嘛 17 # 抓拍 5 張小圖片 18 for x in range(0, 5): 19 s, img = cam.read() 20 if s: 21 imwrite("o-" + str(x) + ".jpg", img) 22 23 def load_original(img_path): 24 # 把原始圖片壓縮爲 299*299大小 25 im_original = cv2.resize(cv2.imread(img_path), (299, 299)) 26 im_converted = cv2.cvtColor(im_original, cv2.COLOR_BGR2RGB) 27 plt.figure(0) 28 plt.subplot(211) 29 plt.imshow(im_converted) 30 return im_original 31 32 def load_fine_tune_googlenet_v3(img): 33 # 加載fine-tuning googlenet v3模型,並作預測 34 model = InceptionV3(include_top=True, weights='imagenet') 35 model.summary() 36 x = image.img_to_array(img) 37 x = np.expand_dims(x, axis=0) 38 x = preprocess_input(x) 39 preds = model.predict(x) 40 print('Predicted:', decode_predictions(preds)) 41 plt.subplot(212) 42 plt.plot(preds.ravel()) 43 plt.show() 44 return model, x 45 46 def extract_features(ins, layer_id, filters, layer_num): 47 ''' 48 提取指定模型指定層指定數目的feature map並輸出到一幅圖上. 49 :param ins: 模型實例 50 :param layer_id: 提取指定層特徵 51 :param filters: 每層提取的feature map數 52 :param layer_num: 一共提取多少層feature map 53 :return: None 54 ''' 55 if len(ins) != 2: 56 print('parameter error:(model, instance)') 57 return None 58 model = ins[0] 59 x = ins[1] 60 if type(layer_id) == type(1): 61 model_extractfeatures = Model(input=model.input, output=model.get_layer(index=layer_id).output) 62 else: 63 model_extractfeatures = Model(input=model.input, output=model.get_layer(name=layer_id).output) 64 fc2_features = model_extractfeatures.predict(x) 65 if filters > len(fc2_features[0][0][0]): 66 print('layer number error.', len(fc2_features[0][0][0]),',',filters) 67 return None 68 for i in range(filters): 69 plt.subplots_adjust(left=0, right=1, bottom=0, top=1) 70 plt.subplot(filters, layer_num, layer_id + 1 + i * layer_num) 71 plt.axis("off") 72 if i < len(fc2_features[0][0][0]): 73 plt.imshow(fc2_features[0, :, :, i]) 74 75 # 層數、模型、卷積核數 76 def extract_features_batch(layer_num, model, filters): 77 ''' 78 批量提取特徵 79 :param layer_num: 層數 80 :param model: 模型 81 :param filters: feature map數 82 :return: None 83 ''' 84 plt.figure(figsize=(filters, layer_num)) 85 plt.subplot(filters, layer_num, 1) 86 for i in range(layer_num): 87 extract_features(model, i, filters, layer_num) 88 plt.savefig('sample.jpg') 89 plt.show() 90 91 def extract_features_with_layers(layers_extract): 92 ''' 93 提取hypercolumn並可視化. 94 :param layers_extract: 指定層列表 95 :return: None 96 ''' 97 hc = extract_hypercolumn(x[0], layers_extract, x[1]) 98 ave = np.average(hc.transpose(1, 2, 0), axis=2) 99 plt.imshow(ave) 100 plt.show() 101 102 def extract_hypercolumn(model, layer_indexes, instance): 103 ''' 104 提取指定模型指定層的hypercolumn向量 105 :param model: 模型 106 :param layer_indexes: 層id 107 :param instance: 模型 108 :return: 109 ''' 110 feature_maps = [] 111 for i in layer_indexes: 112 feature_maps.append(Model(input=model.input, output=model.get_layer(index=i).output).predict(instance)) 113 hypercolumns = [] 114 for convmap in feature_maps: 115 for i in convmap[0][0][0]: 116 upscaled = sp.misc.imresize(convmap[0, :, :, i], size=(299, 299), mode="F", interp='bilinear') 117 hypercolumns.append(upscaled) 118 return np.asarray(hypercolumns) 119 120 if __name__ == '__main__': 121 img_path = '~/auto1.jpg' 122 img = load_original(img_path) 123 x = load_fine_tune_googlenet_v3(img) 124 extract_features_batch(15, x, 3) 125 extract_features_with_layers([1, 4, 7]) 126 extract_features_with_layers([1, 4, 7, 10, 11, 14, 17])
還有一些網站作的關於CNN的可視化作的很是不錯,譬如這個網站:http://shixialiu.com/publications/cnnvis/demo/,能夠在訓練的時候採起不一樣的卷積核尺寸和個數對照來看訓練的中間過程。spa
Tensorflow的可視化命令行
Tensorboard是Tensorflow自帶的可視化模塊,能夠經過Tensorboard直觀的查看神經網絡的結構,訓練的收斂狀況等。要想掌握Tensorboard,咱們須要知道一下幾點:
數據形式
(1)標量Scalars
(2)圖片Images
(3)音頻Audio
(4)計算圖Graph
(5)數據分佈Distribution
(6)直方圖Histograms
(7)嵌入向量Embeddings
可視化過程
(1)創建一個graph。(2)肯定在graph中的不一樣節點設置summary operations。(3)將(2)中的全部summary operations合併成一個節點,運行合併後的節點。(4)使用tf.summary.FileWriter將運行後輸出的數據都保存到本地磁盤中。(5)運行整個程序,並在命令行輸入運行tensorboard的指令,打開web端可查看可視化的結果
使用Tensorborad的實例
這裏我就不講的特別詳細啦,若是用過Tensorflow的同窗其實很好理解,只須要在平時寫的程序後面設置summary,tf.summary.scalar記錄標量,tf.summary.histogram記錄數據的直方圖等等,而後正常訓練,最後把全部的summary合併成一個節點,存放到一個地址下面,在linux界面輸入一下代碼:
tensorboard --logdir=‘存放的總summary節點的地址’
而後會出現如下信息:
1 Starting TensorBoard 41 on port 6006 2 (You can navigate to http://127.0.1.1:6006)
將http://127.0.1.1:6006在瀏覽器中打開,就能夠看到web端的可視化了