本文介紹目标檢測中資料集的準備、轉換以及使用ssd進行訓練的整個過程。内容包括: 1,資料集的準備 1)圖檔的标注 2)制作VOC資料集 3)将VOC資料集轉換成lmdb格式 2,如何使用ssd進行訓練 3,使用ssd做測試 需要的環境: win7,編譯好的caffe ,python27, python PIL(Pillow)子產品。 注意:在caffe編譯中,工程convert_annoset、convert_imageset和ssd_detect都要進行編譯,在後面的腳本中要用到. 1.1,圖檔的标注: 圖檔的标注使用BBox-Label-Tool工具,該工具使用python實作,支援多标簽的标注。 下載下傳位址:http://download.csdn.net/download/u010725283/10216939 使用方法: (1) 在BBox-Label-Tool/Images目錄下建立儲存圖檔的目錄, 目錄以數字命名(BBox-Label-Tool/Images/1) , 然後将待标注的圖檔copy到1這個目錄下; (2) 在BBox-Label-Tool目錄下執行指令 python main.py (3) 在工具界面上, Image Dir 框中輸入需要标記的目錄名(比如 1), 然後點選load按鈕, 工具自動将Images/1目錄下的圖檔加載進來; 需要說明一下, 如果目錄中的圖檔已經标注過,點選load時不會被重新加載進來. (4) 該工具支援多類别标注, 畫bounding boxs框标定之前,需要先標明類别,然後再畫框. (5) 一張圖檔标注完後, 點選Next>>按鈕, 标注下一張圖檔, 圖檔label成功後,會在BBox-Label-Tool/Labels對應的目錄下生成與圖檔檔案名對應的label檔案. 1.2,制作VOC資料集 caffe訓練使用LMDB格式的資料,ssd架構中提供了voc資料格式轉換成LMDB格式的腳本。是以實踐中先将BBox-Label-Tool标注的資料轉換成voc資料格式,然後再轉換成LMDB格式。 VOC資料格式:
(1)Annotations中儲存的是xml格式的label資訊 如下:
(2)ImageSet目錄下的Main目錄裡存放的是用于表示 訓練的圖檔集和測試的圖檔集,如下:
(3)JPEGImages目錄下存放所有圖檔集。 (4)label目錄下儲存的是BBox-Label-Tool工具标注好的bounding box坐标檔案,該目錄下的檔案就是待轉換的label标簽檔案。 (5)将Label轉換成VOC資料格式 BBox-Label-Tool工具标注好的bounding box坐标檔案轉換成VOC資料格式的形式. 具體的轉換過程包括了兩個步驟: 1:将BBox-Label-Tool下的txt格式儲存的bounding box資訊轉換成VOC資料格式下以xml方式表示; 2:生成用于訓練的資料集和用于測試的資料集。 用python實作了上述兩個步驟的換轉。 createXml.py 完成txt到xml的轉換; 執行腳本./createXml.py 1.3,VOC資料轉換成LMDB資料 SSD提供了VOC資料到LMDB資料的轉換腳本 data/VOC0712/create_list.sh 和 /data/VOC0712/create_data.sh,這兩個腳本是完全針對VOC0712目錄下的資料進行的轉換。在windows下使用create_data.bat和get_image_size.bat檔案用于資料格式的轉換。 具體的步驟如下: (1) 在%CAFFE_ROOT%/data/VOCdevkit目錄下建立VAP目錄,該目錄中存放自己轉換完成的VOC資料集; (2) %CAFFE_ROOT%/examples目錄下建立VOC目錄; (3) %CAFFE_ROOT%/data目錄下建立VAP目錄,同時将data/VOC0712下的create_data.bat create_list.sh, labelmap_voc.prototxt這三個檔案copy到%CAFFE_ROOT%/data/VAP目錄下 (4)對上面兩個.bat和create_list.sh檔案進行修改,修改的主要内容主要是一些路徑資訊: create_list.sh檔案修改如下:
#!/bin/bash root_dir=F:/caffe/caffe-ssd-microsoft/data/VOCdevkit sub_dir=ImageSets/Main bash_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" echo $HOME for dataset in trainval test do dst_file=$bash_dir/$dataset.txt if [ -f $dst_file ] then rm -f $dst_file fi for name in VAP do if [[ $dataset == "test" && $name == "VOC2012" ]] then continue fi echo "Create list for $name $dataset..." dataset_file=$root_dir/$name/$sub_dir/$dataset.txt img_file=$bash_dir/$dataset"_img.txt" cp $dataset_file $img_file sed -i "s/^/$name\/JPEGImages\//g" $img_file sed -i "s/$/.bmp/g" $img_file label_file=$bash_dir/$dataset"_label.txt" cp $dataset_file $label_file sed -i "s/^/$name\/Annotations\//g" $label_file sed -i "s/$/.xml/g" $label_file paste -d' ' $img_file $label_file >> $dst_file rm -f $label_file rm -f $img_file done # Generate image name and size infomation. if [ $dataset == "test" ] then F:/caffe/caffe-ssd-microsoft/Build/x64/Release/get_image_size $root_dir $dst_file $bash_dir/$dataset"_name_size.txt" fi # Shuffle trainval file. if [ $dataset == "trainval" ] then rand_file=$dst_file.random cat $dst_file | perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' > $rand_file mv $rand_file $dst_file fi done
create_data.bat檔案修改如下:
@Echo off Echo caffe create_annoset Batch set root_dir= F:\caffe\caffe-ssd-microsoft cd %root_dir% set redo=1 set test_train_dir= data\VAP set data_root_dir =data\VOCdevkit set mapfile= F:\caffe\caffe-ssd-microsoft\data\VAP\labelmap_voc.prototxt set anno_type=detection set db=lmdb set min_dim=0 set max_dim=0 set width=0 set height=0 set "extra_cmd=--encode-type=jpg --encoded" if %redo%==1 ( set "extra_cmd=%extra_cmd% --redo" ) for %%s in (trainval test) do ( echo Creating %%s lmdb... python2 %root_dir%\scripts\create_annoset.py ^ --anno-type=%anno_type% ^ --label-map-file=%mapfile% ^ --min-dim=%min_dim% ^ --max-dim=%max_dim% ^ --resize-width=%width% ^ --resize-height=%height% ^ --check-label %extra_cmd% ^ %data_root_dir% ^ %test_train_dir%\%%s.txt ^ %test_train_dir%\%%s_%db% ) pause
注意:以上檔案的修改,都是對路徑的修改,相對簡單。 完成上面步驟的修改後,可以開始LMDB資料資料的制作,在%CAFFE_ROOT%目錄下分别運作: 1) ./data/indoor/create_list.sh 注意: 在windows下運作.sh檔案可以選擇cygwin工具. 這一步生成了兩個檔案,test.txt 和trainval.txt 2)create_data.bat 指令執行完畢後,可以在%CAFFE_ROOT%/data/VAP目錄下檢視轉換完成的LMDB資料資料。如下:
2使用caffe-ssd進行訓練 網絡的訓練需要相關的prototxt和預訓練好的caffemodel 1)複制%cafferoot%\examples\ssd目錄下的ssd_pascal.py為ssd_pascal_VAP.py,修改如下幾點:
修改好後,運作腳本可得到solver.prototxt,test.prototxt,trainval.prototxt和deploy.prototxt四個檔案。
- 準備好VGG_VOC0712_SSD_300x300_iter_20000.caffemodel(在文檔所在目錄可以找到)
- 将solver.prototxt,test.prototxt,trainval.prototxt,deploy.prototxt和VGG_VOC0712_SSD_300x300_iter_20000.caffemodel放到目錄:%cafferoot%\models\VGGNet\VOC0712\SSD_300x300
4)在caffe根目錄建立train_ssd_my.bat 内容如下:
.\Build\x64\Release\caffe.exe train --solver=models/VGGNet/VOC0712/SSD_300x300/solver.prototxt --weights=models/VGGNet/VOC0712/SSD_300x300/VGG_VOC0712_SSD_300x300_iter_20000.caffemodel Pause
輕按兩下運作即開始ssd的訓練過程。 3.使用ssd進行測試。 測試需要的檔案包括deploy.prototxt,VGG_scenetext_SSD_300x300_iter_60000.caffemodel 測試需要的圖檔路徑; 在caffe根目錄下建立ssd_detect.bat,内容如下:
F:\caffe\caffe-ssd-microsoft\Build\x64\Release\ssd_detect.exe -confidence_threshold=0.5 F:\caffe\caffe-ssd-microsoft\examples\ssd\models\VGGNet\VOC0712\SSD_300x300\deploy.prototxt F:\caffe\caffe-ssd-microsoft\models\VGGNet\VOC0712\SSD_300\VGG_scenetext_SSD_300x300_iter_60000.caffemodel F:\caffe\caffe-ssd-microsoft\data\demo\test.txt pause
注意:具體路徑需要設定成自己的。
問題總結:(所有問題都是沒有使用正确的test.ptototxt和train.prototxt檔案,以及caffemodel模型)
1,報錯Check failed: num_priors_ * num_classes_ == bottom[1]->channels() (36540 vs. 105852 ) . 問題了解,出現這種問題的原因一般通過修改test.prototxt中的num_classes即可,計算出對應的num_classes。num_classes一般是要分類的數量+1,+1是背景類。注意:将train.prototxt和test.prototxt中的num_classes全部都修改。也可以修改ssd_pascal.py中的num_classes來生成對應的trian和test檔案。 1 ,報錯Check failed: label < num_classes (5 vs. 5) 打開train_tv_logo.prototxt搜尋num_classes改為9(8classes+1) 2 ,報錯Check failed: num_priors_ * num_classes_ == bottom[1]->channels() (62136 vs. 34520) . 了解:在multibox_loss_layer裡,有Number of priors must match number of confidence predictions這一句話,查到 http://blog.csdn.net/u012235274/article/details/52212077 裡面: 預測loction bottom[0] dimension is [N*C*1*1],confidence bottom[1] dimension is [N*C*1*1] //priors bottom[2] dimension is [N*1*2*W], gound truth bottom[3] dimension is [N*1*H*8] 修改:train_tv_logo.prototxt1148行num_output=36和另外三個,36=4*9,4是一個cell裡面的priorbox數目,9是8class+背景class 3 ,報錯:Cannot copy param 0 weights from layer ‘ fire8_norm_mbox_conf ’ ; shape mismatch. Source param shape is 20 512 3 3 (92160); target param shape is 36 512 3 3 (165888). To learn this layer ’ s parameters from scratch rather than copying from a saved net, rename the layer. 在train.sh裡最後一行去掉-weights $WEIGHT 4, 正常訓練,loss一直保持在6.9左右不下降 初始化有問題 5 ,test-train時候警告:Missing true_pos for label: 6, 改變flip=true後:Check failed: num_priors_ * loc_classes_ * 4 == bottom[0]->channels() (41424 vs. 27616) Number of priors must match number of location predictions 需要把4個mbox_loc層的numoutput從16改成24(4*4->6*4)(test和train都要改) 7 ,Check failed: num_priors_ * num_classes_ == bottom[1]->channels() (51780 vs. 34520) Number of priors must match number of confidence predictions. 需要把4個mbox_conf層的numoutput從20改成30(4*5->6*5)(test和train都要改) 8 ,Check failed: 0 == bottom[0]->count() % explicit_count (0 vs. 2) bottom count (80430) must be divisible by the product of the specified dimensions (4) test 裡面reshape裡面的4改成5(test要改,train沒有) 9, checked failed : num_test_image_ <= names_.size() (4952 vs. 117) 原因及解決方法:ssd_pascal.py檔案中num_test_image參數沒有修改,将其修改為實際的117,同時還要修改的參數為num_classes