caffe:利用python分類,並可視化模型參數、數據

caffe官方文檔:http://nbviewer.jupyter.org/github/BVLC/caffe/blob/master/examples/00-classification.ipynb

1準備工作

1.1 安裝python,numpy,matplotlib

 #安裝python、numpy、matplotlib
 import numpy as np
 import matplotlib.pyplot as plt
 %matplotlib inline

 #設置默認顯示參數
 plt.rcParams['figure.figsize'] = (10, 10)        # 圖像顯示大小
 plt.rcParams['image.interpolation'] = 'nearest'  # 最近鄰差值: 像素爲正方形
 plt.rcParams['image.cmap'] = 'gray'              # 使用灰度輸出而不是彩色輸出


1.2 加載 caffe

import sys
caffe_root = '/home/shine/caffe/' 
sys.path.insert(0, caffe_root + 'python')
import caffe
# 如果你看到"No module named _caffe",那麼要麼就是你沒有正確編譯pycaffe;要麼就是你的路徑有錯誤。


1.3 下載CaffeNet模型,該模型是AlexNet的變形

import os
if os.path.isfile(caffe_root + 'models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel'):
     print 'CaffeNet found.'
else:
     print 'Downloading pre-trained CaffeNet model...'
     !../scripts/download_model_binary.py ../models/bvlc_reference_caffenet


2 加載網絡並設置輸入預處理

2.1 將Caffe設置爲CPU模式,並從硬盤加載網絡

caffe.set_mode_cpu()
model_def = caffe_root + 'models/bvlc_reference_caffenet/deploy.prototxt'    #注意這裏使用deploy.prototxt
model_weights = caffe_root + 'models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel'
net = caffe.Net(model_def,      # 定義模型結構
                model_weights,  # 包含了模型的訓練權值
                caffe.TEST)     # 使用測試模式(不執行dropout)


2.2 設置輸入預處理

       利用caffe.io.Transformer來進行預處理。CaffeNet模型默認的輸入圖像格式是BGR,像素值的取值範圍爲[0,255],同時每個像素值都減去了ImageNet圖像的平均值。matplotlib加載的圖像的像素值位於[0,1]之間,並且格式是RGB格式,所以我們需要做一些變換。

# 加載ilsvrc12數據集的圖像均值 (隨着Caffe一起發佈的)
mu = np.load(caffe_root + 'python/caffe/imagenet/ilsvrc_2012_mean.npy')
mu = mu.mean(1).mean(1)                      #對所有像素值取平均以此獲取BGR的均值像素值
print 'mean-subtracted values:', zip('BGR', mu)

# 對輸入數據進行變換
transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})
transformer.set_transpose('data', (2,0,1))    #還沒弄清楚?
transformer.set_mean('data', mu)              #對於每個通道,都減去BGR的均值像素值
transformer.set_raw_scale('data', 255)        #將像素值從[0,255]變換到[0,1]之間
transformer.set_channel_swap('data', (2,1,0)) #交換通道,從RGB變換到BGR

3 用CPU分類

3.1 開始分類,儘管我們只對一張圖像進行分類,不過我們將batch的大小設置爲50,以此來演示batching

# 設置輸入圖像大小
net.blobs['data'].reshape(50,        # batch 大小
                          3,         # 3-channel (BGR) images
                          227, 227)  # 圖像大小爲:227x227


3.2 加載圖像,並進行預處理

image = caffe.io.load_image(caffe_root + 'examples/images/cat.jpg')
transformed_image = transformer.preprocess('data', image)
plt.imshow(image)

3.3 進行識別分類


3.3.1 分類
# 將圖像數據拷貝到爲net分配的內存中
net.blobs['data'].data[...] = transformed_image

# 執行分類
output = net.forward()  
output_prob = output['prob'][0]  #batch中第一張圖像的概率值   
print 'predicted class is:', output_prob.argmax()
輸出:predictd class is: 281

3.3.1 輸出類別標籤
# 加載標籤
labels_file = caffe_root + 'data/ilsvrc12/det_synset_words.txt'
if not os.path.exists(labels_file):
     !../data/ilsvrc12/get_ilsvrc_aux.sh
labels = np.loadtxt(labels_file, str, delimiter='\t')
# 輸出對應的類別標籤
print 'output label:', labels[output_prob.argmax()]
輸出:output label: n02123043 tabby, tabby cat

3.3.2 輸出置信度較高的前幾個類別
# 查看置性度較高的幾個結果
# sort top five predictions from softmax output
top_inds = output_prob.argsort()[::-1][:5]  # reverse sort and take five largest items
print 'probabilities and labels:'
zip(output_prob[top_inds], labels[top_inds])

4 測試網絡的中間層輸出

4.1 讀取網絡的結構 

對於每一層參數爲(batch_size, channel_dim, height, width)
# 對於每一層,顯示輸出類型。
for layer_name, blob in net.blobs.iteritems():
      print layer_name + '\t' + str(blob.data.shape)
輸出:
data	        (50, 3, 227, 227)
conv1	(50, 96, 55, 55)
pool1	(50, 96, 27, 27)
norm1	(50, 96, 27, 27)
conv2	(50, 256, 27, 27)
pool2	(50, 256, 13, 13)
norm2	(50, 256, 13, 13)
conv3	(50, 384, 13, 13)
conv4	(50, 384, 13, 13)
conv5	(50, 256, 13, 13)
pool5	(50, 256, 6, 6)
fc6	        (50, 4096)
fc7	        (50, 4096)
fc8	        (50, 1000)
prob	(50, 1000)

4.2 讀取網絡的參數

net.params[0]表示weights, net.params[0]表示biases, weights:(output_channels, input_channels, filter_height, filter_width),biases:
(output_channels)
for layer_name, param in net.params.iteritems():
       print layer_name + '\t' + str(param[0].data.shape), str(param[1].data.shape)
輸出:
conv1	(96, 3, 11, 11) (96,)
conv2	(256, 48, 5, 5) (256,)
conv3	(384, 256, 3, 3) (384,)
conv4	(384, 192, 3, 3) (384,)
conv5	(256, 192, 3, 3) (256,)
fc6	        (4096, 9216) (4096,)
fc7	        (4096, 4096) (4096,)
fc8	        (1000, 4096) (1000,)

4.3 可視化特徵

def vis_square(data):
        # 輸入一個形如:(n, height, width) or (n, height, width, 3)的數組,並對每一個形如(height,width)的特徵進行可視化

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

        # 將濾波器的核轉變爲正方形
        n = int(np.ceil(np.sqrt(data.shape[0])))
        padding = (((0, n ** 2 - data.shape[0]),
                   (0, 1), (0, 1))                 # 在相鄰的濾波器之間加入空白 
                   + ((0, 0),) * (data.ndim - 3))  # 不擴展最後一維
        data = np.pad(data, padding, mode='constant', constant_values=1)  # 擴展一個像素(白色)

        # 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)
        plt.axis('off')
        plt.show()

4.3.1 可視化第一個卷積層(
conv1)的參數
# 參數爲一個[weights, biases]的列表
filters = net.params['conv1'][0].data
vis_square(filters.transpose(0, 2, 3, 1))

4.3.2 可視化第一個卷積層(conv1)的輸出特徵
feat = net.blobs['conv1'].data[0, :36]
vis_square(feat)

4.3.3 可視化第五個池化層(pooling5)的輸出特徵
feat = net.blobs['pool5'].data[0]
vis_square(feat)

4.3.4 可視化第一個全連接層(f6)的輸出特徵
feat = net.blobs['fc6'].data[0]
plt.subplot(2, 1, 1)
plt.plot(feat.flat)
plt.subplot(2, 1, 2)
_ = plt.hist(feat.flat[feat.flat > 0], bins=100)
plt.show()
輸出:


發佈了81 篇原創文章 · 獲贊 51 · 訪問量 27萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章