Caffe9:訓練和測試自己的圖片
在caffe中,作者為我們提供了這樣一個檔案:convert_imageset.cpp,存放在根目錄下的tools資料夾下。編譯之後,生成對應的可執行檔案放在 buile/tools/ 下面,這個檔案的作用就是用於將圖片檔案轉換成caffe框架中能直接使用的db檔案。
該檔案的使用格式:
convert_imageset [FLAGS] ROOTFOLDER/ LISTFILE DB_NAME
需要帶四個引數:
FLAGS: 圖片引數組,後面詳細介紹
ROOTFOLDER/: 圖片存放的絕對路徑,從linux系統根目錄開始
LISTFILE: 圖片檔案列表清單,一般為一個txt檔案,一行一張圖片
DB_NAME: 最終生成的db檔案存放目錄
如果圖片已經下載到本地電腦上了,那麼我們首先需要建立一個圖片列表清單,儲存為txt
本文以caffe程式中自帶的圖片為例,進行講解,圖片目錄是 example/images/, 兩張圖片,一張為cat.jpg, 另一張為fish_bike.jpg,表示兩個類別。
我們建立一個sh指令碼檔案,呼叫linux命令來生成圖片清單:
# sudo vi examples/images/create_filelist.sh
編輯這個檔案,輸入下面的程式碼並儲存
- # /usr/bin/env sh
- DATA=examples/images
- echo "Create train.txt..."
- rm -rf $DATA/train.txt</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">find $DATA -name *cat.jpg | cut -d '/' -f3 | sed "s/$/ 1/"</span>>>$DATA/train.txt
- find $DATA -name *bike.jpg | cut -d <span class="hljs-string">'/'</span> -f3 | sed <span class="hljs-string">"s/$/ 2/">>$DATA/tmp.txt</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">cat $DATA/tmp.txt>>$DATA/train.txt</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">rm -rf $DATA/tmp.txt
- echo "Done.."
這個指令碼檔案中,用到了rm,find, cut, sed,cat等linux命令。
rm: 刪除檔案
find: 尋找檔案
cut: 擷取路徑
sed: 在每行的最後面加上標註。本例中將找到的*cat.jpg檔案加入標註為1,找到的*bike.jpg檔案加入標註為2
cat: 將兩個類別合併在一個檔案裡。
最終生成如下的一個train.txt檔案:
cat.jpg 1
fish-bike.jpg 2
當然,圖片很少的時候,手動編寫這個列表清單檔案就行了。但圖片很多的情況,就需要用指令碼檔案來自動生成了。在以後的實際應用中,還需要生成相應的val.txt和test.txt檔案,方法是一樣的。
生成的這個train.txt檔案,就可以作為第三個引數,直接使用了。
接下來,我們來了解一下FLAGS這個引數組,有些什麼內容:
-gray: 是否以灰度圖的方式開啟圖片。程式呼叫opencv庫中的imread()函式來開啟圖片,預設為false
-shuffle: 是否隨機打亂圖片順序。預設為false
-backend:需要轉換成的db檔案格式,可選為leveldb或lmdb,預設為lmdb
-resize_width/resize_height: 改變圖片的大小。在執行中,要求所有圖片的尺寸一致,因此需要改變圖片大小。 程式呼叫opencv庫的resize()函式來對圖片放大縮小,預設為0,不改變
-check_size: 檢查所有的資料是否有相同的尺寸。預設為false,不檢查
-encoded: 是否將原圖片編碼放入最終的資料中,預設為false
-encode_type: 與前一個引數對應,將圖片編碼為哪一個格式:‘png’,’jpg’……
好了,知道這些引數後,我們就可以呼叫命令來生成最終的lmdb格式資料了
由於引數比較多,因此我們可以編寫一個sh指令碼來執行命令:
首先,建立sh指令碼檔案:
# sudo vi examples/images/create_lmdb.sh
編輯,輸入下面的程式碼並儲存
- #!/usr/bin/en sh
- DATA=examples/images
- rm -rf $DATA/img_train_lmdb</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">build/tools/convert_imageset --shuffle \&lt;/div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">--resize_height=<span class="hljs-number">256</span> --resize_width=<span class="hljs-number">256</span> \&lt;/div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">/home/xxx/caffe/examples/images/ $DATA/train.txt $DATA/img_train_lmdb
設定引數-shuffle,打亂圖片順序。設定引數-resize_height和-resize_width將所有圖片尺寸都變為256*256.
/home/xxx/caffe/examples/images/ 為圖片儲存的絕對路徑。
最後,執行這個指令碼檔案
# sudo sh examples/images/create_lmdb.sh
就會在examples/images/ 目錄下生成一個名為 img_train_lmdb的資料夾,裡面的檔案就是我們需要的db檔案了。
上面就將影象資料轉換成db(leveldb/lmdb)檔案了。
===================================================================================================================================
再從自己的原始圖片到lmdb資料,再到訓練和測試模型的整個流程。
一、準備資料
有條件的同學,可以去imagenet的官網http://www.image-net.org/download-images,下載imagenet圖片來訓練。但是我沒有下載,一個原因是註冊賬號的時候,驗證碼始終出不來(聽說是google網站的驗證碼,而我是上不了google的)。第二個原因是資料太大了。。。
我去網上找了一些其它的圖片來代替,共有500張圖片,分為大巴車、恐龍、大象、鮮花和馬五個類,每個類100張。需要的同學,可到我的網盤下載:http://pan.baidu.com/s/1nuqlTnN
編號分別以3,4,5,6,7開頭,各為一類。我從其中每類選出20張作為測試,其餘80張作為訓練。因此最終訓練圖片400張,測試圖片100張,共5類。我將圖片放在caffe根目錄下的data資料夾下面。即訓練圖片目錄:data/re/train/ ,測試圖片目錄: data/re/test/
二、轉換為lmdb格式
首先,在examples下面建立一個myfile的資料夾,來用存放配置檔案和指令碼檔案。然後編寫一個指令碼create_filelist.sh,用來生成train.txt和test.txt清單檔案
- # sudo mkdir examples/myfile
- # sudo vi examples/myfile/create_filelist.sh
編輯此檔案,寫入如下程式碼,並儲存
- #!/usr/bin/env sh
- DATA=data/re/
- MY=examples/myfile
- echo "Create train.txt..."
- rm -rf $MY/train.txt</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">for</span> i in <span class="hljs-number">3</span> <span class="hljs-number">4</span> <span class="hljs-number">5</span> <span class="hljs-number">6</span> <span class="hljs-number">7</span> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">do</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">find $DATA/train -name $i*.jpg | cut -d <span class="hljs-string">'/'</span> -f4<span class="hljs-number">-5</span> | sed <span class="hljs-string">"s/$/ $i/"</span>>>$MY/train.txt
- done
- echo "Create test.txt..."
- rm -rf $MY/test.txt</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">for</span> i in <span class="hljs-number">3</span> <span class="hljs-number">4</span> <span class="hljs-number">5</span> <span class="hljs-number">6</span> <span class="hljs-number">7</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">do</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">find $DATA/test -name $i*.jpg | cut -d <span class="hljs-string">'/'</span> -f4<span class="hljs-number">-5</span> | sed <span class="hljs-string">"s/$/ $i/"</span>>>$MY/test.txt
- done
- echo "All done"
然後,執行此指令碼
# sudo sh examples/myfile/create_filelist.sh
成功的話,就會在examples/myfile/ 資料夾下生成train.txt和test.txt兩個文字檔案,裡面就是圖片的列表清單。
接著再編寫一個指令碼檔案,呼叫convert_imageset命令來轉換資料格式。
# sudo vi examples/myfile/create_lmdb.sh
插入:
- #!/usr/bin/env sh
- MY=examples/myfile
- echo "Create train lmdb.."
- rm -rf $MY/img_train_lmdb</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">build/tools/convert_imageset \&lt;/div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">--shuffle \&lt;/div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">--resize_height=<span class="hljs-number">256</span> \&lt;/div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">--resize_width=<span class="hljs-number">256</span> \&lt;/div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="10"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">/home/xxx/caffe/data/re/ \&lt;/div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">$MY/train.txt \
- $MY/img_train_lmdb</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="14"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">echo <span class="hljs-string">"Create test lmdb.."</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="15"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">rm -rf $MY/img_test_lmdb
- build/tools/convert_imageset \
- --shuffle \
- --resize_width=256 \
- --resize_height=256 \
- /home/xxx/caffe/data/re/ \
- $MY/test.txt \&lt;/div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="22"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">$MY/img_test_lmdb
- echo "All Done.."
因為圖片大小不一,因此我統一轉換成256*256大小。執行成功後,會在 examples/myfile下面生成兩個資料夾img_train_lmdb和img_test_lmdb,分別用於儲存圖片轉換後的lmdb檔案。
三、計算均值並儲存
圖片減去均值再訓練,會提高訓練速度和精度。因此,一般都會有這個操作。
caffe程式提供了一個計算均值的檔案compute_image_mean.cpp,我們直接使用就可以了
# sudo build/tools/compute_image_mean examples/myfile/img_train_lmdb examples/myfile/mean.binaryproto
compute_image_mean帶兩個引數,第一個引數是lmdb訓練資料位置,第二個引數設定均值檔案的名字及儲存路徑。執行成功後,會在 examples/myfile/ 下面生成一個mean.binaryproto的均值檔案。
四、建立模型並編寫配置檔案
模型就用程式自帶的caffenet模型,位置在 models/bvlc_reference_caffenet/資料夾下, 將需要的兩個配置檔案,複製到myfile資料夾內
- # sudo cp models/bvlc_reference_caffenet/solver.prototxt examples/myfile/
- # sudo cp models/bvlc_reference_caffenet/train_val.prototxt examples/myfile/
修改其中的solver.prototxt
# sudo vi examples/myfile/solver.prototxt
- net: “examples/myfile/train_val.prototxt”
- test_iter: 2
- test_interval: 50
- base_lr: 0.001
- lr_policy: “step”
- gamma: 0.1
- stepsize: 100
- display: 20
- max_iter: 500
- momentum: 0.9
- weight_decay: 0.005
- solver_mode: GPU
100個測試資料,batch_size為50,因此test_iter設定為2,就能全cover了。在訓練過程中,調整學習率,逐步變小。
修改train_val.protxt,只需要修改兩個階段的data層就可以了,其它可以不用管。
- name: "CaffeNet"
- layer {
- name: "data"
- type: "Data"
- top: "data"
- top: "label"
- include {
- phase: TRAIN
- }
- transform_param {
- mirror: true
- crop_size: 227
- mean_file: "examples/myfile/mean.binaryproto"
- }
- data_param {
- source: "examples/myfile/img_train_lmdb"
- batch_size: 256
- backend: LMDB
- }
- }
- layer {
- name: "data"
- type: "Data"
- top: "data"
- top: "label"
- include {
- phase: TEST
- }
- transform_param {
- mirror: false
- crop_size: 227
- mean_file: "examples/myfile/mean.binaryproto"
- }
- data_param {
- source: "examples/myfile/img_test_lmdb"
- batch_size: 50
- backend: LMDB
- }
- }
實際上就是修改兩個data layer的mean_file和source這兩個地方,其它都沒有變化 。
五、訓練和測試
如果前面都沒有問題,資料準備好了,配置檔案也配置好了,這一步就比較簡單了。
# sudo build/tools/caffe train -solver examples/myfile/solver.prototxt
執行時間和最後的精確度,會根據機器配置,引數設定的不同而不同。我的是gpu+cudnn執行500次,大約8分鐘,精度為95%。
以上部分轉自:http://www.cnblogs.com/denny402/p/5083300.html
=========================================================================================
下面是我自己寫的一個生成list指令碼
功能就是讀取資料夾下面的資料夾名稱作為類別並且將對應資料夾下面的圖片包括路徑輸出到txt檔案中。
- # /usr/bin/env sh
- DATA=/home/x/git/data_list/data
- TxtPath=$DATA/../txt_list</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">rm -rf $TxtPath/train.txt
- echo "Create train.txt..."
- for file_a in ${DATA}/*; do </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> temp_file=`basename $file_a`</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> path1=$DATA/${temp_file}</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="9"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> echo $path1
- #cd $path1</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="11"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> echo <span class="hljs-string">"xxxxxxxxxxxxxxx"</span></div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="12"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> find ${path1} -name q*.png | sed "s/$/ ${temp_file}/">>$TxtPath/train.txt</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="13"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> echo $temp_file
- done
- echo "Done.."