可視化的概念
深度學習模型是“黑盒”,即模型學到的表示很難用人類可以了解的方式來提取和呈現。但是我們現在的學習的卷積伸進網絡卻可以通過可視化很形象的說明深度學習在卷積神經網絡方面可以很表示的,并不是黑盒。目前比較容易了解的三種可視化的方法如下:
- 可視化卷積神經網絡的中間輸出(中間激活)
- 就是可以展示網絡中各個卷積層和池化層輸出的特征圖
- 了解卷積神經網絡連續的層如何對輸入進行變換
- 于初步了解卷積神經網絡每個過濾器的含義
- 可視化卷積神經網絡的過濾器
- 精确了解卷積神經網絡中每個過濾器容易接受的視覺模式或視覺概念
- 可視化圖像中類激活的熱力圖
- 有助于了解圖像的哪個部分被識别為屬于某個類别
- 可以定位圖像中的物體
中間激活激活的概念了解
可視化中間激活,是指對于給定輸入,展示網絡中各個卷積層和池化層輸出的特征圖。
這樣我們就可以通過檢視不同層的不同的過濾器最終輸出圖像的結果,來分析模型是怎麼來識别圖檔的過程,會去識别那些資訊,對于哪些資訊會保留和過濾都有很好的記錄。
這裡我們需要做的就是:将這些特征圖可視化的正确方法是将每個通道的内容分别繪制成二維圖像。這裡以貓狗分類的案例-從頭訓練一個模型為例子來分析。
- 加載模型
- 預處理單張圖像
# 加載模型貓狗分類的案例-從頭訓練一個模型
from keras.models import load_model
model = load_model('cats_and_dogs_small_data_2.h5')
model.summary()
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_1 (Conv2D) (None, 148, 148, 32) 896
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 74, 74, 32) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 72, 72, 64) 18496
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 36, 36, 64) 0
_________________________________________________________________
conv2d_3 (Conv2D) (None, 34, 34, 128) 73856
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 17, 17, 128) 0
_________________________________________________________________
conv2d_4 (Conv2D) (None, 15, 15, 128) 147584
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 (None, 7, 7, 128) 0
_________________________________________________________________
flatten_1 (Flatten) (None, 6272) 0
_________________________________________________________________
dropout_1 (Dropout) (None, 6272) 0
_________________________________________________________________
dense_1 (Dense) (None, 512) 3211776
_________________________________________________________________
dense_2 (Dense) (None, 1) 513
=================================================================
Total params: 3,453,121
Trainable params: 3,453,121
Non-trainable params: 0
_________________________________________________________________
#預處理單張圖像
img_path = 'G:/Data/Kaggle/dogcat/smallData/test/cats/cat.1700.jpg'
from keras.preprocessing import image
import numpy as np
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.
print(img_tensor.shape)
(1, 150, 150, 3)
# 顯示測試圖像
import matplotlib.pyplot as plt
plt.imshow(img_tensor[0])
plt.show()
Keras 模型多輸出
建立一個 Keras 模型,以圖像批量作為輸入,并輸出所有卷積層和池化層的激活。 Keras 的 Model 類,模型執行個體化需要兩個參數:一個輸入張量(或輸入張量的清單)和一個輸出張量(或輸出張量的清單),得到的類是一個Keras 模型.
輸入一張圖像,這個模型将傳回原始模型前 8 層的激活值.一般情況下,模型可以有任意個輸入和輸出。這個模型有一個輸入和 8 個輸出,即每層激活對應一個輸出。
from keras import models
#from keras import layers
# 輸入一張圖像,這個模型将傳回原始模型前 8 層的激活值
# 每層激活對應一個輸出。
layers_outputs = [layer.output for layer in model.layers[:8]]
# 建立一個模型,給定模型輸入,可以傳回這些輸出
activation_model = models.Model(inputs = model.input,outputs=layers_outputs)
#以預測模式運作模型
activations = activation_model.predict(img_tensor)
first_layer_activation = activations[0]
print(first_layer_activation.shape)
(1, 148, 148, 32)
# 将第 6 和10個通道可視化
import matplotlib.pyplot as plt
plt.matshow(first_layer_activation[0,:,:,6],cmap='viridis')
plt.matshow(first_layer_activation[0,:,:,10],cmap='viridis')
layer_names = []
for layer in model.layers[:8]:
layer_names.append(layer)
image_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 // image_per_row
display_grid = np.zeros((size * n_cols,image_per_row * size))
for col in range(n_cols):
for row in range(image_per_row):
channel_image = layer_activation[0,:,:,col * image_per_row+row]
channel_image -= channel_image.mean()
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')
中間激活的結論
- 第一層是各種邊緣探測器的集合。在這一階段,激活幾乎保留了原始圖像中的所有資訊。
- 随着層數的加深,激活變得越來越抽象,并且越來越難以直覺地了解。它們開始表示更高層次的概念,比如“貓耳朵”和“貓眼睛”。層數越深,其表示中關于圖像視覺内容的資訊就越少,而關于類别的資訊就越多。
- 激活的稀疏度(sparsity)随着層數的加深而增大。在第一層裡,所有過濾器都被輸入圖像激活,但在後面的層裡,越來越多的過濾器是空白的。也就是說,輸入圖像中找不到這些過濾器所編碼的模式。
随着層數的加深,層所提取的特征變得越來越抽象。更高的層激活包含關于特定輸入的資訊越來越少,而關于目标的資訊越來越多(本例中即圖像的類别:貓或狗)。這個跟人類的認知場景很相似,我們認識一個東西也是這樣開始的。
分享關于人工智能,機器學習,深度學習以及計算機視覺的好文章,同時自己對于這個領域學習心得筆記。想要一起深入學習人工智能的小夥伴一起結伴學習吧!掃碼上車!