YOLOv3 製作並訓練自己的數據集

本文參考了:dspeia的製作教程Rani_zZ的製作教程Darknet官網中的YOLO教程。

首先對YOLO進行簡要說明。YOLO是一個one-stage網絡,其直接回歸所檢測目標的邊框參數(左上點x,y,寬高width,height),置信度值以及屬於各類的概率。YOLOv3將整張圖片切割成了7x7塊,並在每一塊中都檢測三個目標,也即每一塊中所迴歸出的結果應當是3x(5+類的數量)。

1.製作自己的數據集

目前,網上製作數據集的教程幾乎都用的是labelImg,其標註結果的格式與VOC數據集完全一致,因此可以直接使用YOLO作者製作的數據讀取文件。具體過程不再贅述。

在標註完成後,將製作好的數據集放到你的數據集文件夾內(我的是/home/xxx/dataset/VOC2007),其文件夾構成如圖:

其中,JPEGImages裏是你的所有圖片,Annotation裏是與你的圖片一一對應的XML標註文件(如果某個圖不包含物體,請在標註時隨便圈一下再刪除,隨後保存,否則不會生成XML,會報錯!)

接下來,在Main裏創建一個訓練與測試列表。在VOC2007文件夾內創建一個split.py,將下列代碼複製進去:

import os
import random

trainval_percent = 0.1
train_percent = 0.9
xmlfilepath = 'Annotations'
txtsavepath = 'ImageSets\Main'
total_xml = os.listdir(xmlfilepath)

num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)

ftrainval = open('ImageSets/Main/trainval.txt', 'w')
ftest = open('ImageSets/Main/test.txt', 'w')
ftrain = open('ImageSets/Main/train.txt', 'w')
fval = open('ImageSets/Main/val.txt', 'w')

for i in list:
    name = total_xml[i][:-4] + '\n'
    if i in trainval:
        ftrainval.write(name)
        if i in train:
            ftest.write(name)
        else:
            fval.write(name)
    else:
        ftrain.write(name)

ftrainval.close()
ftrain.close()
fval.close()
ftest.close()

接着,命令行執行該文件

$ python split.py

執行後你應該能在Main裏看到4個文件,裏面分別存儲了被作爲四類數據的文件的名稱。

2.下載並編譯Darknet和YOLO

按照官網的教程,下載並編譯測試Darknet,同時測試CUDA,cuDNN和OpenCV。CUDA和cuDNN安裝OpenCV安裝見我之前的博客。

接着測試YOLO,同樣跟隨官網教程

3.將數據集鏈接至Darknet中。

網上的一些教程將數據直接放在Darknet文件夾中,但我個人覺得這個方法很不適合後續維護。我的習慣是將數據都放在一個文件夾內方便查找,因此可以建立軟鏈接實現這一過程。

在darknet文件夾下新建一個文件夾:

mkdir VOCdevkit

創建從你的數據文件夾到該文件夾的軟鏈接:

ln -s /path/to/your/dataset/fold/VOC2007/ /path/to/your/darknet/fold/VOCdevkit/VOC2007

這樣就可以方便的訪問數據了。

4.轉換數據格式

labelImg使用的是VOC的數據格式,而YOLO則需要使用txt數據。因此,需要對數據格式進行轉換。

在darknet/scripts文件夾下有一個文件voc_label就是幹這個用的。

將該文件複製至darknet文件夾內,然後修改該文件,將上面部分修改的適配你的數據集,比如我只需要檢測car,則改爲:

sets=[('2007', 'train'), ('2007', 'val'), ('2007', 'test')]

classes = ["car"]

文件最下面兩行可以刪除:

os.system("cat 2007_train.txt 2007_val.txt 2012_train.txt 2012_val.txt > train.txt")
os.system("cat 2007_train.txt 2007_val.txt 2007_test.txt 2012_train.txt 2012_val.txt > train.all.txt")

然後執行該文件

$ python voc_label.py

你應該會看到文件夾裏生成了幾個txt,而打開數據集會看到label文件夾,裏面存放了符合YOLO格式的訓練數據。例如:

0 0.11328125 0.574305555556 0.034375 0.0263888888889
0 0.154296875 0.611111111111 0.02734375 0.025
0 0.173828125 0.645833333333 0.02734375 0.025
0 0.235546875 0.643055555556 0.02734375 0.025
0 0.300390625 0.60625 0.03046875 0.0208333333333
0 0.237109375 0.671527777778 0.03046875 0.0208333333333
0 0.283203125 0.638194444444 0.03046875 0.0208333333333
0 0.276171875 0.675694444444 0.03046875 0.0208333333333
0 0.344140625 0.610416666667 0.03046875 0.0208333333333
0 0.362109375 0.574305555556 0.03046875 0.0208333333333
0 0.344921875 0.678472222222 0.03046875 0.0208333333333
0 0.50859375 0.121527777778 0.0171875 0.0597222222222
0 0.46875 0.0291666666667 0.0171875 0.0583333333333
0 0.517578125 0.251388888889 0.01484375 0.05
0 0.53515625 0.385416666667 0.0234375 0.0569444444444
0 0.6328125 0.288194444444 0.028125 0.0597222222222
0 0.5890625 0.44375 0.028125 0.0597222222222
0 0.590625 0.527083333333 0.028125 0.0597222222222
0 0.63125 0.495138888889 0.028125 0.0597222222222
0 0.7171875 0.450694444444 0.0296875 0.0291666666667
0 0.763671875 0.459027777778 0.03359375 0.0291666666667
0 0.717578125 0.490972222222 0.03359375 0.0291666666667
0 0.669140625 0.605555555556 0.03359375 0.0416666666667
0 0.669140625 0.605555555556 0.03359375 0.0416666666667
0 0.698046875 0.56875 0.06484375 0.0819444444444
0 0.8125 0.624305555556 0.075 0.0541666666667
0 0.941015625 0.643055555556 0.07265625 0.0444444444444
0 0.76484375 0.675 0.0328125 0.0361111111111
0 0.907421875 0.678472222222 0.03359375 0.0319444444444
0 0.99140625 0.588888888889 0.015625 0.0222222222222

這裏第一個數據是類的序號,因爲我只檢測car所以只有0.第2-5項對應邊框的四個值,這裏都已經基於邊框的總寬高進行了歸一化處理。

5.準備訓練

下載ImageNet上的預訓練權重:

wget https://pjreddie.com/media/files/darknet53.conv.74 

修改data/voc.name(記得備份),裏面放你的所有類的名稱(回車分隔,最後一行無回車)。

car

修改cfg/voc.data(記得備份)

classes= 1 #classes爲訓練樣本集的類別總數,我的算法只檢測車,因此是1
train  = /darknet/2007_train.txt #train的路徑爲訓練樣本集所在的路徑,上一步中生成
valid  = /darknet/2007_val.txt #valid的路徑爲驗證樣本集所在的路徑,上一步中生成
names = data/voc.names #names的路徑爲data/voc.names文件所在的路徑
backup = backup

修改cfg / yolov3-voc.cfg(記得備份)最上面部分,註釋掉test對應部分,使用train部分。這裏subdivisions是指將數據分爲多少份輸入,例如16則是每次輸入4張圖同時訓練,最後64張圖的所有結果視爲一個batch,共同優化。這裏需要根據GPU顯存自行調整。

[net]
# Testing
# batch=1        
# subdivisions=1
# Training
 batch=64            
 subdivisions=16    
......
[convolutional]
size=1
stride=1
pad=1
filters=18        #---------------修改爲3*(5+classes)即3*(5+1)=18
activation=linear
[yolo]
mask = 6,7,8
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=1        #---------------修改爲標籤類別個數,1類
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0            #1,如果顯存很小,將random設置爲0,關閉多尺度訓練;(轉自別的blog,還不太明白)
......
[convolutional]
size=1
stride=1
pad=1
filters=18        #---------------修改同上
activation=linear
 
[yolo]
mask = 3,4,5
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=1        #---------------修改同上
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0       
......
[convolutional]
size=1
stride=1
pad=1
filters=18        #---------------修改同上
activation=linear
 
[yolo]
mask = 0,1,2
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=1        #---------------修改同上
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=0        

6.開始訓練

執行下面的代碼進行訓練,其中-gpus是多顯卡執行的命令,若只有單顯卡可不加。

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg scripts/darknet53.conv.74 -gpus 0,1

訓練過程中的執行結果應當如下:

……
Loaded: 0.000050 seconds
Region 82 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.005261, .5R: -nan, .75R: -nan,  count: 0
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.002821, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: 0.306019, Class: 0.971707, Obj: 0.377151, No Obj: 0.003877, .5R: 0.285714, .75R: 0.000000,  count: 14
299: 18.237528, 28.675016 avg, 0.000008 rate, 0.065416 seconds, 299 images
……

這裏只要有一個Region的IOU有顯示就是正確的。隨着訓練過程進行,IOU應當會越來越高,例如對於我的任務最終都在75%左右。訓練好的模型會被存儲在darknet/backup中,名字如yolov3-voc_900.weights,這裏的數字是執行epoch的數目。YOLO默認最多隻會存儲到900,後面雖然程序沒停,但這個backup不會再增加。所以不要以程序停止作爲訓練結束的標誌。

訓練過程中可以查看GPU顯存佔用情況。nvidia-smi可以,但是隻能查看一次。如果需要一直監控可執行

watch -n 0.1 nvidia-smi

其中-n後面的數字是多少秒刷新一次。

中間部分2727MiB/11777MiB就是你當前使用的gpu顯存和總顯存數。如果發現gpu不太滿,可以減小上面subdivision數字的大小,從而提高訓練速度。

 

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