1. 程式人生 > >MobileNet SSD 訓練自己的資料集

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格式)

  1. 圖片的標註和重新命名

   圖片的標註可以用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,下面,可以準備訓練了

三、訓練前再準備

  1. 把labelmap.prototxt複製到工程檔案下
  2. 把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下載可能會出問題