詳解FCN模型中每一層的輸出及可視化操作

對於FCN模型的搭建以及訓練自己的數據集,其實並不是特別難。可以參考FCN訓練自己的數據集。可能更多的人想知道FCN每一層輸出的結果是什麼。這篇博客主要介紹的是對FCN每一層輸出進行可視化操作。

  1. 查看FCN總體框架
    先打開工具netcope,然後打開fcn-master2\voc-fcn32s下的train.prototxt文件,將train.prototxt文件內容複製到網頁左側編輯框後,shift+enter,就可以直接顯示網絡結構。
    在這裏插入圖片描述
  2. 查看每一層輸出的結構
    打開fcn-master2\voc-fcn32s下infer.py文件,在原代碼的最後寫上如下代碼。
for layer_name, blob in net.blobs.iteritems():
    print layer_name + '\t' + str(blob.data.shape)

運行程序,可以看到輸出的結果如下

data	(1L, 3L, 375L, 500L)                                       
data_input_0_split_0	(1L, 3L, 375L, 500L)
data_input_0_split_1	(1L, 3L, 375L, 500L)
conv1_1	(1L, 64L, 573L, 698L)                              
conv1_2	(1L, 64L, 573L, 698L)
pool1	(1L, 64L, 287L, 349L)
conv2_1	(1L, 128L, 287L, 349L)
conv2_2	(1L, 128L, 287L, 349L)
pool2	(1L, 128L, 144L, 175L)
conv3_1	(1L, 256L, 144L, 175L)
conv3_2	(1L, 256L, 144L, 175L)
conv3_3	(1L, 256L, 144L, 175L)
pool3	(1L, 256L, 72L, 88L)
conv4_1	(1L, 512L, 72L, 88L)
conv4_2	(1L, 512L, 72L, 88L)
conv4_3	(1L, 512L, 72L, 88L)
pool4	(1L, 512L, 36L, 44L)
conv5_1	(1L, 512L, 36L, 44L)
conv5_2	(1L, 512L, 36L, 44L)
conv5_3	(1L, 512L, 36L, 44L)
pool5	(1L, 512L, 18L, 22L)
fc6	(1L, 4096L, 12L, 16L)
fc7	(1L, 4096L, 12L, 16L)
score_fr	(1L, 5L, 12L, 16L)
upscore	(1L, 5L, 416L, 544L)
score	(1L, 5L, 375L, 500L)

從輸出結果可以看出輸入的是500 x 375 x 3的圖片,第一層卷積後輸出的是698 x 573 x 64的特徵圖。可能有很多人疑惑爲什麼第一層卷積層分爲conv1_1和conv1_2。因爲FCN是基於VGG16的結構,VGG16總共是有16層,第一層分爲conv1_1和conv1_2因爲沒有改變圖像的大小以及卷積核數,所以兩個層合併稱爲第一層。後面的層數是同樣的道理,具體的可以參考博客詳解VGG16模型

  1. 可視化數據函數
    在fcn-master2\voc-fcn32s下新建vis_square.py文件,複製代碼
# -*- coding: utf-8 -*
####定義輔助函數來進行可視化中間層特徵
import numpy as np
from PIL import Image
import scipy.misc
import pylab
import matplotlib.pyplot as plt
def vis_square(data):
    """Take an array of shape (n, height, width) or (n, height, width, 3)
       and visualize each (height, width) thing in a grid of size approx. sqrt(n) by sqrt(n)"""

    # normalize data for display   # 數據正則化
    data = (data - data.min()) / (data.max() - data.min())

    # force the number of filters to be square
    # 此處目的是將一個個濾波器按照正方形的樣子排列
    # 先對shape[0]也就是濾波器數量取平方根,然後取大於等於該結果的正整數
    # 比如40個卷積核,則需要7*7的正方形格子(雖然填不滿)
    n = int(np.ceil(np.sqrt(data.shape[0])))
    padding = (((0, n ** 2 - data.shape[0]),
               (0, 1), (0, 1))
# add some space between filters # 在相鄰的卷積核之間加入0進行padding
               + ((0, 0),) * (data.ndim - 3))
 # don't pad the last dimension (if there is one)   如果最後最後一維是1不進行擴充
    data = np.pad(data, padding, mode='constant', constant_values=1)
 # pad函數聲明:pad(array, pad_width, mode, **kwargs),作用是把list在原維度上進行擴展;
    # pad_width是擴充參數,例如參數((3,2),(2,3));
    # 其中(3,2)爲水平方向上,上面加3行,下面加2行;
    # (2,3)爲垂直方向上,上面加2行,下面加3行;
    # constant是常數填充的意思。# pad with ones (white)

    # tile the filters into an image  # 將卷積核平鋪成圖片
    data = data.reshape((n, n) + data.shape[1:]).transpose((0, 2, 1, 3) + tuple(range(4, data.ndim + 1)))
    data = data.reshape((n * data.shape[1], n * data.shape[3]) + data.shape[4:])

    plt.imshow(data);pylab.show(); plt.axis('off')

保存退出,這代碼的功能是用來顯示每一層輸出的圖像。
然後在infer.py文件上添加模塊

import vis_square
import pylab
  1. 可視化第一層卷積核圖像

在代碼的最後寫上如下代碼

filters = net.params['conv1_1'][0].data
vis_square.vis_square(filters.transpose(0, 2, 3, 1))

輸出的是第一層卷積核模板的圖像,這卷積核圖像是通過訓練模型得出來的。FCN的第一層共有64個卷積核,所以輸出的是64個卷積核圖像。
在這裏插入圖片描述

  1. 可視化第一層圖像輸出
    先將第4步的代碼註釋,然後在寫上如下代碼
feat = net.blobs['conv1_1'].data[0, :]
vis_square.vis_square(feat)

輸出的結果爲下圖所示。因爲有64個卷積核,所以輸出的是64張特徵圖。
在這裏插入圖片描述

  1. 可視化第一層池化後的數據圖像
    同樣先註釋第5步的代碼,然後在寫上如下代碼。
feat = net.blobs['pool1'].data[0]
vis_square.vis_square(feat)
  1. 輸出第一層圖像的數據
    圖像就是一組數據組成的,如果想要得出第一層數據的話,可以下上如下代碼
print('conv1_1')
print net.blobs['conv1_1'].data[0]

輸出的結果爲如下圖所示。
在這裏插入圖片描述

  1. 總結
    以上介紹的是第一層圖像的可視化操作。如果想要其它層圖像可視化操作,只需要修改net.blobs[‘ ’]中每層網絡結構的名稱即可。如查看第5層數據。代碼爲
feat = net.blobs['conv5_1'].data[0, :]
vis_square.vis_square(feat)

到此所有的可視化操作已經介紹完了,相信通過對每一層數據的可視化操作,能夠更加深刻的理解FCN模型。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章