MobileNet SSD 訓練自己的資料集
記錄下mobilnet-ssd如何跑自己的資料集。預設環境已經配置好,並且demo.py已經可以成功運行了。
mobilenet-ssd下載路徑(需要注意的點:需要以Git的方式下載,不要以zip的方式下載,否則後面訓練時可能報錯)
步驟記錄:1、製作VOC資料集
2、用create_data.sh 和create_list.sh生成lmdb庫
3、建立labelmap.prototxt檔案
4、執行gen_model.sh指令碼
5、修改資料集的路徑
6、執行train.sh
以下對上述步驟進行詳細的說明。
一、建立適用於SSD訓練的資料集(VOC格式)
- 圖片的標註和重新命名
圖片的標註可以用labelImage來做,原始碼來自GitHub, 使用前需要安裝各種環境,很複雜。直接下載打包好的也是要配置一些環境的。 也可以用一個VOC2007樣本製作工具。
圖片需要命名成這種格式:
2、 VOC格式資料集中用到的主要是下面三個資料夾:
Annotations: 存放圖片標記後生成的.xml檔案
JPEGImages:存放原始圖片(.jpg)
ImageSets:裡面建立一個Main資料夾,包含幾個.txt檔案,內容是圖片的編號(只要寫入檔名就可以,不用地址,不用字尾,四個檔案的生成方式見備註)
備註:
a)如果影象的標註資訊是寫在.txt檔案中的(如下):
五個資料的含義依次是:label,x,y,w,h
x,y,w,h 依次指圖片標註框的中心點座標,標註框的寬和高(都是歸一化後的結果)
可以用以下程式碼轉換成.xml格式
import os,sys import glob from PIL import Image #src jpg src_img_dir = "/home/xmhuang/VOCdevkit/JPEGImages/origin_sample_2018-03-08" #src_img_dir = "/home/xmhuang/VOCdevkit/JPEGImages/testxml" #src txt src_txt_dir = "/home/xmhuang/VOCdevkit/JPEGImages/origin_sample_2018-03-08" #src_txt_dir = "/home/xmhuang/VOCdevkit/JPEGImages/testxml" src_xml_dir = "/home/xmhuang/VOCdevkit/Annotations" img_Lists = glob.glob(src_img_dir + '/*.jpg') img_basenames = [] for item in img_Lists: img_basenames.append(os.path.basename(item)) img_names = [] for item in img_basenames: temp1,temp2 = os.path.splitext(item) img_names.append(temp1) for img in img_names: im = Image.open((src_img_dir + '/' + img + '.jpg')) width,height = im.size #open .txt gt = open(src_txt_dir + '/' + img +'.txt').read().splitlines() #write in xml file xml_file = open((src_xml_dir + '/' + img +'.xml'),'w') xml_file.write('<annotation>\n') xml_file.write(' <folder>VOC2007</folder>\n') xml_file.write(' <filename>' + str(img) + '.jpg' + '</filename>\n') xml_file.write(' <size>\n') xml_file.write(' <width>' + str(width) + '</width>\n') xml_file.write(' <height>' + str(height) + '</height>\n') xml_file.write(' <depth>3</depth>\n') xml_file.write(' </size>\n') #write the region of image on xml file for img_each_label in gt: spt = img_each_label.split(' ') sptt = list(map(float,spt)) if spt[0] == '0': spt[0] = "shoe" elif spt[0] =='1': spt[0] = "wire" else: spt[0] = "sock" xxmin =int( (sptt[1]-sptt[3]/2)*width) xxmax =int( (sptt[1]+sptt[3]/2)*width) yymin = int((sptt[2]-sptt[4]/2)*height) yymax =int( (sptt[2]+sptt[4]/2)*height) xml_file.write(' <object>\n') xml_file.write(' <name>' + spt[0] + '</name>\n') xml_file.write(' <pose>Unspecified</pose>\n') xml_file.write(' <truncated>0</truncated>\n') xml_file.write(' <difficult>0</difficult>\n') xml_file.write(' <bndbox>\n') xml_file.write(' <xmin>' + str(xxmin) + '</xmin>\n') xml_file.write(' <ymin>' + str(yymin) + '</ymin>\n') xml_file.write(' <xmax>' + str(xxmax) + '</xmax>\n') xml_file.write(' <ymax>' + str(yymax) + '</ymax>\n') xml_file.write(' </bndbox>\n') xml_file.write(' </object>\n') xml_file.write('</annotation>')
b)關於影象的label
由於使用的是Mobilenet-ssd網路,所以背景預設為0,也就是任何標籤不要用零。
c)四個.txt檔案生成如下,按照預先設定好的比例,隨機生成訓練集,測試集,訓練驗證集等。voc2007中test,trainval取總數的50%,train和val各取trainval的50%,可以參考這個比例。
import os
import random
trainval_percent = 0.5
train_percrent = 0.5
xmlfilepath = '/home/xmhuang/VOCdevkit/Annotations'
txtsavepath = '/home/xmhuang/VOCdevkit/ImageSets/Main'
total_xml = os.listdir(xmlfilepath)
num = len(total_xml)
list = range(num)
tv = int(num*trainval_percent)
tr = int(tv*trainval_percent)
trainval = random.sample(list,tv)
train = random.sample(trainval,tr)
ftrainval = open(txtsavepath + '/trainval.txt','w')
ftest = open(txtsavepath + '/test.txt','w')
ftrain = open(txtsavepath + '/train.txt','w')
fval = open(txtsavepath + '/val.txt','w')
for i in list:
name = total_xml[i][:-4] + '\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftrain.write(name)
else:
fval.write(name)
else:
ftest.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
完成了這幾步,VOC資料集就搞定了,VOC2007中出現的其他資料夾都可以先不管,接著就可以打包資料了。
二、生成lmdb庫
1、在caffe/data/VOC***(如VOC0712)中找到這三個檔案
在caffe/data/目錄下新建一個資料夾,如caffe/data/sweep,把上面三個檔案拷貝過來
2、修改檔案路徑
1)create_list.sh
如果嚴格按照VOC資料集的資料夾名稱來命名和放圖片的話,create_list.sh可以直接執行
補充一個關於批處理檔案的點:
\/這個代表轉移字元,就是/,如果要修改檔案路徑的話需要注意
create_list.sh檔案執行後會在該資料夾下生成
test.txt/trainval.txt內容:圖片名稱(帶路徑)
test_name_size.txt內容:檔名 大小
2)create_data.sh
修改成自己的dataset_name,就是之前建在caffe/data/下的資料夾名稱
data_root_dir填VOCdevkit的地址,這裡建在/home/xmhuang/下,所以就直接$HOME,就是代表/home/xmhuang/
最後幾行修改路徑的話可以自己指定lmdb的生成路徑
執行後生成LMDB檔案,報錯的話大概率是路徑問題
3)labelmap.prototxt
根據實際的類進行修改,需要注意的是第一類背景類和標號都不能動
注意XML中寫的name都要出現在labelmap 的name中,否則會unknown name,然後lmdb生成失敗
這樣,庫檔案生成了,labelmap.prototxt,下面,可以準備訓練了
三、訓練前再準備
- 把labelmap.prototxt複製到工程檔案下
- 把lmdb資料庫複製到工程下
也可以建立軟連結(先定義到工程所在路徑)
$ ln ‐s /home/its/data/KITTIdevkit/KITTI/lmdb/KITTI_trainval_lmdb trainval_lmdb
$ ln ‐s /home/its/data/KITTIdevkit/KITTI/lmdb/KITTI_test_lmdb test_lmdb
關於軟連結的知識點
3、執行gen_model.sh指令碼
執行命令:./gen_model.sh 4
數字為類別數,注意,實際類別+1,有個預設的背景類
之後,生成examples資料夾,裡面的3個prototxt就是從模板生成的正式網路定義,根據作者設定,其中的deploy檔案是已經合併過bn層的,需要後面配套使用。
4、修改檔案中路徑,主要就是測試集和訓練集的名稱和位置了,之前拷貝了資料集的話只要改個名稱就OK了。labelmap.prototxt沒重新命名的話就不用動
test.prototxt/train.prototxt/MobileNetSSD_test.prototxt/MobileNetSSD_train.prototxt
五、訓練過程中的錯誤
1、注意:圖中caffe是預設裝在/home/username/下面的,根據實際情況修改
2、lmdb沒生成成功
3、三中4路徑沒改好 check failed:mdb_status==0(2vs.0)No such file or directiry
資料集路徑沒改好,仔細改改
4、視訊記憶體溢位問題:cudaSuccess(2 vs 0) out of memory
1)確實GPU配置差,調小batch_size
2)GPU配置高,nvidia-smi命令檢視GPU佔用情況,可能有很多殭屍程式佔了大量記憶體
5、found background label in the dataset
這個就是background 0 標籤沒預留下來的問題啦
6、出錯時忘了截圖,大致是說什麼層沒有backend
要用git下載程式碼,直接zip下載可能會出問題