《21天實戰Caffe》第六章習題6.4 自己的手寫體數字圖片送入lenet測試

在看完卜居老師的《21天實戰Caffe》第六章後收穫頗豐,對之前在Caffe官網看的Tutorial,超入門的examples mnist的訓練與識別終於有了一個比較清晰的認識。

果然還是對英語寫的指導不太敏感呢(T_T)...感謝卜居大大寫的書~~

如果說“Hello World”是所有編程語言的第一個入門練習的話,那mnist就是深度學習方面的“Hello World”了。它是Mixed National Institute of Standards and Technology的縮寫,是一個大型的手寫體數字數據庫,廣泛用於機器學習領域的訓練和測試,是NYU的Yann LeCun教授整理,具體信息在這裏http://yann.lecun.com/exdb/mnist/,這裏有個教程也不錯MNIST機器學習入門 

在這一章中,卜居老師詳細介紹了caffe是如何轉換mnist數據格式並進行訓練和測試的,最後留下的習題是讓自己寫個程序,將自己的手寫體數字圖片送入自己訓練好的LeNet進行測試,評估效果。這個題剛看到還是覺得很難的,並沒有什麼思路,於是果斷打開收藏的卜老師的習題答案,【深度學習:21 天實戰 Caffe】課後習題參考答案思路:用 Windows 畫圖軟件繪製手寫體數字,縮放到 28 x 28,另存爲圖片(jpg 或 png 均可),用 MATLAB 將圖片轉換爲 MNIST 格式數據,替換掉 test 數據集,之後再創建 test_lmdb,修改 lenet_train_val.prototxt 使用該數據集。利用訓練好的模型和 lenet_train_val.prototxt 進行 caffe test,檢查正確率。

於是按這個思路,搜索了相關的實現,一開始還看到有人用C++實現,我覺得一方面實在工作量比較大,另一方面既然都用C++將數據轉換爲mnist格式,再運行create_mnist.sh腳本調用Caffe裏的convert_mnist_data.cpp將圖片轉換成普通的數組格式,不是浪費時間嗎,可能也只有練習C++的作用了,以後用C++的場合應該就直接修改Caffe源碼來進行相關練習和測試吧。那麼關於matlab的話主要參考這篇文章,圖像轉化爲手寫體mnist格式的數據,然後自己做了點微小的工作。

1.先使用PS故意畫了個很挫的6,保存爲28*28像素的png文件;


2.使用matlab打開它可以看到是28*28*3的矩陣,因爲我使用的RGB標準,所以這裏既可以在PS裏直接把它改爲灰度圖,也可以在matlab裏取三個分量的平均值或取單個通道的值也可以(因爲我畫的時候純白底純黑畫筆畫的);

3.將這個原始圖像以mnist格式寫入一個文件,類似mnist官方下載到的t10k-images.idx3-ubyte和t10k-labels.idx1-ubyte

代碼如下:

clc;
clear;

imgOrigin = imread('6.png');
imgBinaryImg = imgOrigin(:,:,1);          %只取原圖像一個分量,轉換爲灰度圖像

imgMnist = fopen('test_img_ubyte', 'wb');  %w:寫,如果沒有自動創建
magic = 2051;
numImages = 1;
numRows = 28;
numCols = 28;  

fwrite(imgMnist, magic, 'int32', 0, 'ieee-be');  %ieee-be:大端存儲
fwrite(imgMnist, numImages, 'int32', 0, 'ieee-be');%0貌似表是讀完這個都下個之前的skip,0就是連着讀,不跳
fwrite(imgMnist, numRows, 'int32', 0, 'ieee-be');  
fwrite(imgMnist, numCols, 'int32', 0, 'ieee-be');  
imgBinaryImg = permute(imgBinaryImg, [2 1]); %matlab以列爲主進行運算  
imgBinaryImg = reshape(imgBinaryImg, 1, numCols* numRows* numImages); %reshape按列轉換
fwrite(imgMnist, imgBinaryImg, 'unsigned char');  
fclose(imgMnist);  

%將label轉換爲二進制
flabel = fopen('test_lable_ubyte', 'wb');  
magic = 2049;
numLabels = 1;
labels = 6;
fwrite(flabel, magic, 'int32', 0, 'ieee-be');  
fwrite(flabel, numLabels, 'int32', 0, 'ieee-be');  
fwrite(flabel, labels, 'unsigned char');  
fclose(flabel);  
代碼裏面反正我一開始不懂的地方我都加了註釋,小夥伴們有疑問的話歡迎討論。

今晚有點晚了,只實現了一張圖片,後面有時間寫個循環多加幾張自己畫的測試圖片進去。

運行後matlab的工作空間如下:


生成的mnist格式測試數據屬性如下:



可以看到test_img_ubyte大小剛好爲4B+4B+4B+4B+28*28B = 800B;

test_lable_ubyte大小爲4B+4B+1B。


然後修改lenet_train_test.prototxt裏的

layer {
  name: "mnist"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/mnist/mnist_test_lmdb"
    batch_size: 1
    backend: LMDB
  }
}

batch_size爲 1,因爲只有一張圖片嘛

然後調用想create_mnist.sh生成caffe需要的lmdb格式數據,然而這裏我一直用的是win10系統,不能直接用linux下的腳本(找不到shell命令),於是再轉到ubuntu16.04下繼續工作,實際後面就與常規的訓練mnist步驟差不多了,Caffe官網也有tutorial.

然後修改create_mnist.sh裏面創建lmdb,輸入對應要轉換的自己的文件名,所以其實一開始直接將原測試文件替換掉也可以,可以省去這一步。

set -e

EXAMPLE=examples/mnist
DATA=data/mnist
BUILD=build/examples/mnist

BACKEND="lmdb"

echo "Creating ${BACKEND}..."

rm -rf $EXAMPLE/mnist_test_zfq_${BACKEND}

$BUILD/convert_mnist_data.bin $DATA/test_img_ubyte \
  $DATA/test_lable_ubyte $EXAMPLE/mnist_test_zfq_${BACKEND} --backend=${BACKEND}

echo "Done.

然後調用Caffe的test語句,測試模型對於我畫的6的accuracy,如下:

./build/tools/caffe test -model examples/mnist/lenet_train_test.prototxt \
-weights examples/mnist/lenet_iter_10000.caffemodel -iterations 1

輸出的最後幾行:

I1213 12:13:12.657213  4049 net.cpp:283] Network initialization done.
I1213 12:13:12.662529  4049 caffe.cpp:285] Running for 1 iterations.
I1213 12:13:12.668015  4049 caffe.cpp:308] Batch 0, accuracy = 1
I1213 12:13:12.668031  4049 caffe.cpp:308] Batch 0, loss = 3.26639e-05
I1213 12:13:12.668035  4049 caffe.cpp:313] Loss: 3.26639e-05
I1213 12:13:12.668042  4049 caffe.cpp:325] accuracy = 1
I1213 12:13:12.668048  4049 caffe.cpp:325] loss = 3.26639e-05 (* 1 = 3.26639e-05 loss)

有幾行還不能完全看懂,不過貌似是成功了,這麼醜它都能識別出來。。

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