前言
最近打算重新跟著官方教程學習一下caffe,順便也自己翻譯了一下官方的文檔。自己也做了一些標注,都用斜體標記出來了。中間可能額外還加了自己遇到的問題或是運行結果之類的。歡迎交流指正,拒絕噴子! 官方教程的原文鏈接:http://nbviewer.jupyter.org/github/BVLC/caffe/blob/master/examples/00-classification.ipynb
Classification: Instant Recognition with Caffe
在這個例子中我們將會使用由官方提供的CaffeNet (該網絡結構由Krizhevsky提出)模型來進行圖片分類。后面我們會比對其在CPU和GPU模式下的性能,然后再深入剖析一下網絡的一些特征和輸出結果。
1.準備工作
首先要裝好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'
import sys
caffe_root =
'/home/xhb/caffe/caffe/'
sys.path.insert(
0 , caffe_root +
'python' )
import caffe
如果有必要,請到網上下載我們要用到的模型(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
CaffeNet found.
2.導入網絡并設置預處理的輸入
caffe.set_mode_cpu()model_def = caffe_root +
'models/bvlc_reference_caffenet/deploy.prototxt'
model_weights = caffe_root +
'models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel' net = caffe.Net(model_def, model_weights, caffe.TEST)
設置輸入預處理。(我們要用到Caffe的caffe.io.Transformer,但是這一步與Caffe的其他部分是相互獨立的,所以任何浴池里代碼都可以適用)。 我們的CaffeNet默認獲取的圖像格式是BGR格式的。各像素的灰度值范圍是[ 0 , 255 ] [0,255] ,并且每個像素都減去了IMageNet圖像的均值。另外,通道維數等于第一維(outermost)的大小。 由于matplotlib加載圖像的灰度值范圍是[ 0 , 1 ] [0,1] ,而且是以RGB格式讀取圖像,通道維數等于innermost的維數,所以我們需要在這里對圖像格式做一下轉換。
補充:可能有人不太清楚innermost和outermost那段是什么意思。舉個例子會好理解一點:outermost:【3,255,255】;innermost:【255,255,3】,通道數是3,長和寬都是255。
mu = np.load(caffe_root +
'python/caffe/imagenet/ilsvrc_2012_mean.npy' )
mu = mu.mean(
1 ).mean(
1 )
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)
transformer.set_raw_scale(
'data' ,
255 )
transformer.set_channel_swap(
'data' , (
2 ,
1 ,
0 ))
mean-subtracted values: [('B', 104.0069879317889), ('G', 116.66876761696767), ('R', 122.6789143406786)]
3.使用CP模式行分類
現在我們已經準備好進行分類了。盡管我們一次只能分類一張圖片,我們會將batch_size設置為50,來進行演示。
net.blobs[
'data' ].reshape(
50 ,
3 ,
227 ,
227 )
加載一幅圖像(使用CaffeNet自帶的接口),并按照前面設置的方式進行圖像預處理。
image = caffe.io.load_image(caffe_root +
'examples/images/cat.jpg' )
transformed_image = transformer.preprocess(
'data' , image)
plt.imshow(image)
<matplotlib.image.AxesImage at 0x7fa1301c4350>
補充:這里我們不妨停下來想想,讀入的圖像image和轉換的圖像transformed_image分別是BGR格式還是RGB格式?很簡單,讀入圖像image是RGB格式,轉換的圖像transformed_image是BGR格式。
net.blobs[
'data' ].data[...] = transformed_image
output = net.forward()output_prob = output[
'prob' ][
0 ]
print 'predicted class is:' , output_prob.argmax()
predicted class is: 281
這個網絡的結果輸出的是一堆概率值組成的向量;這里去的是其中概率最大的那個,也就是預測最有可能是第281類。但是這個真的是正確的嘛?讓我們看看ImageNet中的標簽…
labels_file = caffe_root +
'data/ilsvrc12/synset_words.txt'
if not os.path.exists(labels_file):!../data/ilsvrc12/get_ilsvrc_aux.shlabels = np.loadtxt(labels_file, str, delimiter=
'\t' )
print 'output label:' , labels[output_prob.argmax()]
output label: n02123045 tabby, tabby cat
“Tabby cat”是正確的!但是讓我再看看其他的比較高概率的可能結果(盡管概率不是最高的)
top_inds = output_prob.argsort()[::-
1 ][:
5 ]
print 'probabilities and labels:'
zip(output_prob[top_inds], labels[top_inds])
probabilities and labels:
[(0.31243622, 'n02123045 tabby, tabby cat'),(0.23797178, 'n02123159 tiger cat'),(0.12387244, 'n02124075 Egyptian cat'),(0.10075705, 'n02119022 red fox, Vulpes vulpes'),(0.070957385, 'n02127052 lynx, catamount')]
好的,我們可以看出來,哪怕取那幾個概率較低的結果,也還是有一定的合理性的。
切換到GPU模式
讓我們看看分類花了多少時間,并將其與GPU模式下的用時對比。
%timeit net.forward()
1 loop, best of 3: 5.24 s per loop
嘛,還是要花一段時間的,即使batch只有50張圖片。讓我們切換到GPU模式。
caffe.set_device(
0 )
caffe.set_mode_gpu()
net.forward()
%timeit net.forward()
10 loops, best of 3: 30.4 ms per loop
測試中間層的輸出
這個網絡不只是一個黑盒子;讓我們看看這個網絡中的一些參數和中間輸出。 首先我們要看看如何根據每層的激活函數和參數的維數得到網絡的結構。 對于每一層來說,我們可以看看激活層的結構:[batch_size, channel_dim, height, width)。 激活層都由OrderedDict,net.blobs類型定義。
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)
現在再來看看參數的shape。這些參數都是OrderedDict,net.params類型。我們需要根據索引來獲得參數:[0]對應權重,1對應偏置。 這些參數參數的shape為:(output_channels, input_channels, filter_height, filter_width)(權重參數),和只有1維的(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,)
既然我們這里要處理的是四維的數據,那么我們可以定義一個幫助函數來可視化矩形熱圖。
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)""" 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 ) 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' )
filters = net.params[
'conv1' ][
0 ].data
vis_square(filters.transpose(
0 ,
2 ,
3 ,
1 ))
第一層的輸出,conv1(使用上面的濾波器提取特征后的結果,只取前36個)。
feat = net.blobs[
'conv1' ].data[
0 , :
36 ]
vis_square(feat)
feat = net.blobs[
'pool5' ].data[
0 ]
vis_square(feat)
第一個全連接層,fc6. 我們使用輸出值和正值的直方圖來顯示結果。
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 )
feat = net.blobs[
'prob' ].data[
0 ]
plt.figure(figsize=(
15 ,
3 ))
plt.plot(feat.flat)
[<matplotlib.lines.Line2D at 0x7fa12c7b5450>]
注意到,預測的概率值比較高的幾個類都聚集在一起;標簽是根據語義進行劃分的。正如上圖所示,峰值對應這預測的最可能的結果。
使用自己的圖片進行測試
現在我們從網上下載一張圖片,并參照上面的步驟預測。 - 試著設置my_image_url為任何JPEG圖像的URL。
image = caffe.io.load_image(
'cat.jpg' )
net.blobs[
'data' ].data[...] = transformer.preprocess(
'data' , image)net.forward()output_prob = net.blobs[
'prob' ].data[
0 ]top_inds = output_prob.argsort()[::-
1 ][:
5 ]plt.imshow(image)
print 'probabilities and labels:'
zip(output_prob[top_inds], labels[top_inds])
probabilities and labels:
[(0.52841139, 'n02124075 Egyptian cat'),(0.20741074, 'n02123045 tabby, tabby cat'),(0.20226726, 'n02123159 tiger cat'),(0.055884782, 'n02127052 lynx, catamount'),(0.0017415404,'n02125311 cougar, puma, catamount, mountain lion, painter, panther, Felis concolor')]
《新程序員》:云原生和全面數字化實踐 50位技術專家共同創作,文字、視頻、音頻交互閱讀
總結
以上是生活随笔 為你收集整理的Caffe官方教程翻译(5):Classification: Instant Recognition with Caffe 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。