caffe從零開始學習3——mnist例程測試自定義數字圖片

測試一張自定義的手寫體數字

上面已經進行了mnist數據的訓練,也對測試數據進行的測試,準確率在99%左右。那麼如果我們想自己測一下一張字節手寫的數字,看看他學習的是否準確,改怎麼利用caffemodel權值文件呢。
下面就來測試一張自定義的手寫體數字。
利用模型lenet_iter_10000.caffemodel測試單張手寫體數字所需要的文件:
(1)待測試圖片(自己畫的也行,網絡上下的也行);需要注意的是,不管是什麼格式,都要轉換爲28*28大小的黑白灰度圖像,具體轉化方法請自行百度,不想轉化也可以從這個鏈接下載,下載鏈接: https://pan.baidu.com/s/1Ck6l7bAncK2BpcqWXG67Dg 密碼:csig,這些圖片是網上已經轉好的。
(2)deploy.prototxt(模型描述型文件);
(3)network.caffemodel(模型權值文件),在本例中就是lenet_iter_10000.caffemodel
(4)labels.txt(標籤文件),本利中是synset_words.txt文件;
(5)mean.binaryproto(二進制圖像均值文件);
(6)classification.bin(二進制程序名)。與二進制均值文件配合使用,只是均值文件不同的模型有不同的均值文件,而這個bin文件爲通用的,就是任何模型都可以做分類使用。
1.準備一張自定義的圖片
下載鏈接中的圖片,拷貝到caffe/examples/mnist/目錄下。
2.生成deploy.prototxt文件
deploy.prototxt文件的作用和lenet_train_test.prototxt文件類似,或者說對後者改動可得到前者。在熟悉生成文件的原理及方法之後我們可以之間在原訓練prototxt網絡文件中改動。在examples/mnist目錄下複製一份lenet_train_test.prototxt修改並保存後得到deploy.prototxt如下:

name: "LeNet"  
 
   
layer {  
  name:"data"  
 type: "Input"  
 top: "data"  
 input_param { shape: { dim: 1 dim: 1 dim: 28 dim: 28 } }  
}  
   
  
layer {  
  name:"conv1"  
 type: "Convolution"  
 bottom: "data"  
 top: "conv1"  
 convolution_param {  
   num_output: 20  
   kernel_size: 5  
   stride: 1  
   weight_filler {  
     type: "xavier"  
   }  
 }  
}  
layer {  
  name:"pool1"  
 type: "Pooling"  
 bottom: "conv1"  
 top: "pool1"  
 pooling_param {  
   pool: MAX  
   kernel_size: 2  
   stride: 2  
  }  
}  
layer {  
  name:"conv2"  
 type: "Convolution"  
 bottom: "pool1"  
 top: "conv2"  
 convolution_param {  
   num_output: 50  
   kernel_size: 5  
   stride: 1  
   weight_filler {  
     type: "xavier"  
   }  
 }  
}  
layer {  
  name:"pool2"  
 type: "Pooling"  
 bottom: "conv2"  
 top: "pool2"  
 pooling_param {  
   pool: MAX  
   kernel_size: 2  
   stride: 2  
  }  
}  
layer {  
  name:"ip1"  
 type: "InnerProduct"  
 bottom: "pool2"  
 top: "ip1"  
 inner_product_param {  
   num_output: 500  
   weight_filler {  
     type: "xavier"  
   }  
 }  
}  
layer {  
  name:"relu1"  
 type: "ReLU"  
 bottom: "ip1"  
 top: "ip1"  
}  
layer {  
  name:"ip2"  
 type: "InnerProduct"  
 bottom: "ip1"  
 top: "ip2"  
 inner_product_param {  
   num_output: 10  
   weight_filler {  
     type: "xavier"  
   }  
 }  
}  
   
 
layer {  
  name:"prob"  
 type: "Softmax"  
 bottom: "ip2"  
 top: "prob"  
}  

當然,也可以採用代碼的方式來自動生成該deploy.prototxt文件 。deploy文件沒有第一層數據輸入層,也沒有最後的Accuracy層,但最後多了一個Softmax概率層。
deploy.py代碼如下;

# -*- coding: utf-8 -*-

from caffe  import layers as L,params as P,to_proto
root='/root/caffe/'
deploy=root+'examples/mnist/deploy.prototxt'    #文件保存路徑

def create_deploy():
    #少了第一層,data層
    conv1=L.Convolution(name='conv1',bottom='data', kernel_size=5, stride=1,num_output=20, pad=0,weight_filler=dict(type='xavier'))
    pool1=L.Pooling(conv1,name='pool1',pool=P.Pooling.MAX, kernel_size=2, stride=2)
    conv2=L.Convolution(pool1, name='conv2',kernel_size=5, stride=1,num_output=50, pad=0,weight_filler=dict(type='xavier'))
    pool2=L.Pooling(conv2, name='pool2', pool=P.Pooling.MAX, kernel_size=2, stride=2)
    fc3=L.InnerProduct(pool2, name='ip1',num_output=500,weight_filler=dict(type='xavier'))
    relu3=L.ReLU(fc3, name='relu1',in_place=True)
    fc4 = L.InnerProduct(relu3, name='ip2',num_output=10,weight_filler=dict(type='xavier'))
    #最後沒有accuracy層,但有一個Softmax層
    prob=L.Softmax(fc4, name='prob')
    return to_proto(prob)
def write_deploy():
    with open('deploy.prototxt', 'w+') as f:
        f.write('name:"LeNet"\n')
        f.write('layer {\n')
        f.write('name:"data"\n')
        f.write('type:"Input"\n')
        f.write('top:"data"\n')
        f.write('input_param { shape : {')
        f.write('dim:1 ')
        f.write('dim:1 ')
        f.write('dim:28 ')
        f.write('dim:28 ')
        f.write('} } }\n\n')
        f.write(str(create_deploy()))
if __name__ == '__main__':
    write_deploy()


3.network.caffemodel(模型權值文件)
network.caffemodel在訓練時已經生成,在本例中就是lenet_iter_10000.caffemodel文件。
4.生成labels.txt標籤文件
在當前目錄下新建一個txt文件,命名爲synset_words.txt,裏面內容爲我們訓練mnist的圖片內容,共有0~9十個數,那麼我們就建立如下內容的標籤文件:
在這裏插入圖片描述
5.生成mean.binaryproto二進制均值文件
均值文件分爲二進制均值文件和python類均值文件。
caffe作者爲我們提供了一個計算均值的文件compute_image_mean.cpp,放在caffe根目錄下的tools文件夾裏面,運行下面命令生成mean.binaryproto二進制均值文件。

build/tools/compute_image_mean  \
examples/mnist/mnist_train_lmdb \
examples/mnist/mean.binaryproto 

在這裏插入圖片描述
6.利用classification.bin二進制程序進行測試
在example文件夾中有一個cpp_classification的文件夾,打開它,有一個名爲classification的cpp文件,這就是caffe提供給我們的調用分類網絡進行前向計算,得到分類結果的接口。就是這個文件在命令中會得到classification.bin。
使用下面的指令開始測試自定義的一個數字圖片:

./build/examples/cpp_classification/classification.bin \
examples/mnist/deploy.prototxt \
examples/mnist/lenet_iter_10000.caffemodel \
examples/mnist/mean.binaryproto \
examples/mnist/synset_words.txt \
examples/mnist/picture/0.0.jpg  

測試結果:
在這裏插入圖片描述
可以看到,測試0時輸出的0標籤對應的是1.0000,測試9時輸出的9標籤對應的是1.0000,測試2時輸出的2標籤對應的是1.0000,結果還是很準的。

繪製loss圖

在上一篇mnist訓練的過程中,不停的打印了一些訓練的速度,學習率,loss值等。那麼有沒有圖片的形式可以更直觀的反應訓練過程中loss和準確率的變化趨勢呢?
當然是有的,需要編寫一個pyton程序loss.py。參考網上的一個例程:

# -*- coding: utf-8 -*-
import numpy as np #導入numpy庫並命名爲np,numpy支持大量的維度數組與矩陣運算,此外也針對數組運算提供大量的數學函數庫。
import matplotlib.pyplot as plt #導入matplotlib.pyplot庫並命名爲plt,Matplotlib 是 Python 的繪圖庫。 matplotlib可與 NumPy 一起使用,提供了一種有效的 MatLab 開源替代方案
import sys,os  #導入sys模塊,sys模塊包含了與Python解釋器和它的環境有關的函數;導入os模塊,os模塊裏面有環境變量的映射關係,目錄等
caffe_root = '/root/caffe'
sys.path.insert(0,caffe_root+'python')  #sys.path爲一個列表,用insert直接插到首位,插入python的環境變量
import caffe

caffe.set_mode_cpu() #設置caffe  cpu運行模式 
solver = caffe.SGDSolver('/root/caffe/examples/mnist/lenet_solver.prototxt') 
# 執行完上面的語句以後,網絡的相應的權值與偏置會根據我們的定義進行賦值的

niter=1000  #迭代1000次
test_interval = 200  #200次測試一次
train_loss = np.zeros(niter) #1維,大小爲1000的數組  
#np.zeros返回一個給定形狀和類型的用0填充的數組,本例爲array([ 0,  0,  0,  0,  0 ......]),長度是1000
test_acc = np.zeros(int(np.ceil(niter / test_interval)))#1維,大小爲5的數組
#np.ceil() 計算大於等於該值的最小整數,本例niter / test_interval,np.ceil(5)是5

for it in range(niter):
	solver.step(1)
	# solver.net.forward() , solver.test_nets[0].forward() 和 solver.step(1) 區別和作用。
	#三個函數都是將批量大小(batch_size)的圖片送到網絡,
	#solver.net.forward() 和 solver.test_nets[0].forward() 是將batch_size個圖片送到網絡中去,只有前向傳播(Forward Propagation,BP),solver.net.forward()作用於訓練集,solver.test_nets[0].forward() 作用於測試集,一般用於獲得測試集的正確率。
	#solver.step(1) 也是將batch_size個圖片送到網絡中去,不過 solver.step(1) 不僅有FP,而且還有反向傳播(Back Propagation,BP)!這樣就可以更新整個網絡的權值(weights),同時得到該batch的loss。

	
	train_loss[it] = solver.net.blobs['loss'].data # 獲取每一次迭代的loss值
	solver.test_nets[0].forward(start='conv1')   #表示從conv1開始,這樣的話,data層不用傳新的數據了。
	
	if it % test_interval == 0:
		acc=solver.test_nets[0].blobs['accuracy'].data  #獲取test_interval整數倍時的準確率
		#solver.net.blobs爲一個字典的數據類型,裏面的key值爲各個layer 的名字,value爲caffe的blob塊
		print 'Iteration',it,'testing...','accuracy:',acc
		test_acc[it // test_interval] = acc  #      //是整除運算符,取整數部分

print test_acc
_,ax1= plt.subplots()  
ax2= ax1.twinx()#matplotlib:次座標軸ax2=ax1.twinx(),產生一個ax1的鏡面座標
ax1.plot(np.arange(niter),train_loss) 
ax2.plot(test_interval * np.arange(len(test_acc)),test_acc,'r')
ax1.set_xlabel('iteration')
ax1.set_ylabel('train loss')
ax2.set_ylabel('test accuracy')
plt.savefig("mnist_loss.png")
plt.show()


loss.py程序的詳細解析見上面。
運行繪製

python loss.py

執行loss.py後,就開始訓練了,這裏我訓練了1000次,200次輸出一次測試。
loss曲線圖如下:

eog mnist_loss.png

在這裏插入圖片描述
如上圖,可以看到loss隨着訓練次數的增加,呈現出逐漸震盪收斂的,loss 值呈現下降趨勢,準確率在不斷的上升。

備註:
_,ax1= plt.subplots() 這一句中爲什麼開頭有 _,這倆字符,查了一圈資料也沒明白,有知道的還請告知一下~

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