首頁 > 軟體

darknet框架中YOLOv3對資料集進行訓練和預測詳解

2022-11-27 14:00:59

1. 下載darknet原始碼

在命令視窗(terminal)中進入你想存放darknet原始碼的路徑,然後在該路徑下輸入依次輸入以下命令:

git clone https://github.com/pjreddie/darknet
cd darknet

上述命令首先從darknet的原始碼地址複製一份原始碼到本地,下載下來的是一個名為darknet的檔案。然後進入這個名為darknet的資料夾。

2. 修改darknet的Makefile檔案

Note:如果不需要darknet在GPU上執行,則略過此步驟,只需執行make命令。 在命令視窗輸入以下命令開啟Makefile檔案:

    vi Makefile

將Makefile檔案開頭的GPU=0改為GPU=1,如下所示:

GPU=1
CUDNN=0
OPENCV=0
OPENMP=0
DEBUG=0

修改完之後,需要執行make命令才可以生效。

make

3. 準備資料集

在./darknet/scripts資料夾下建立資料夾,命名為VOCdevkit,然後再在VOCdevkit資料夾下建立一系列資料夾,整個目錄結構如下所示:

VOCdevkit
-VOC2019 # 這個資料夾的年份可以自己取
--Annotations # 在這個資料夾下存放所有的xml檔案
--ImageSets
---Main # 在這個資料夾下新建兩個TXT檔案
----train.txt
----val.txt
--JPEGImages # 在這個資料夾下存放所有的圖片檔案

上述檔案及資料夾建立好之後,下面來對我們的資料集生成train.txt和val.txt,這兩個檔案中存放訓練影象和測試影象的檔名(不含.jpg字尾)。 新建一個creat_train_val_txt.py檔案(名字可以自己隨便取),然後將以下程式碼複製進去(注意相應路徑的修改)

#coding:utf-8
import os
from os import listdir, getcwd
from os.path import join
if __name__ == '__main__':           # 只有在檔案作為指令碼檔案直接執行時才執行下面程式碼  
    source_folder='/home/tukrin/zhl/darknet/scripts/VOCdevkit/VOC2019/JPEGImages/'           #圖片儲存的路徑
    dest='/home/tukrin/zhl/darknet/scripts/VOCdevkit/VOC2019/ImageSets/Main/train.txt'          #寫有圖片的名字的路徑
    dest2='/home/tukrin/zhl/darknet/scripts/VOCdevkit/VOC2019/ImageSets/Main/val.txt'           #寫有圖片的名字的路徑
    file_list=os.listdir(source_folder)  #獲取各圖片的名稱       
    train_file=open(dest,'a')     #追加寫開啟              
    val_file=open(dest2,'a')       #追加寫開啟    
    count = 0              
    for file_obj in file_list:  
        count += 1                
        file_path=os.path.join(source_folder,file_obj) #路徑拼接  指向 圖片檔案的路徑
        file_name,file_extend=os.path.splitext(file_obj) #分離檔名與擴充套件名 file_name為去掉擴充套件名的圖片名稱 
        # file_num=int(file_name) 
        if(count<800):                     
            train_file.write(file_name+'n')  #寫入去掉擴充套件名的檔名名稱  前800個作為 訓練集資料
        else :
            val_file.write(file_name+'n')    #寫入去掉擴充套件名的檔名名稱   後面的作為  驗證集資料
    train_file.close() #關閉檔案
val_file.close()   #關閉檔案

製作好creat_train_val_txt.py檔案後,在命令列執行該檔案:

python creat_train_val_txt.py

執行完畢之後可以看到剛剛我們新建的train.txt和val.txt檔案中被寫進了我們的資料集圖片的檔名。

4. 修改voc_label.py

開啟scripts資料夾下的 voc_label.py 檔案,修改資訊:#要修改的地方 共三處

import xml.etree.ElementTree as ET 
import pickle
import os
from os import listdir, getcwd
from os.path import join
#要修改的地方
sets=[('2019', 'train'), ('2019', 'val')]  # 此處的2019對應前面新建資料夾時的2019,train和val對應兩個TXT檔案的檔名
#要修改的地方
classes =["car", "people"] # 此處為資料集的類別名稱,一定要與xml檔案中的類別名稱一致,有幾類就寫幾類
def convert(size, box):#size是圖片的尺寸 box是矩形的四個點
    dw = 1./size[0] # 歸一化的時候就是使用寬度除以整個image_size的寬度
    dh = 1./size[1] # 歸一化的時候就是使用高度除以整個image_size的高度
    x = (box[0] + box[1])/2.0 # 使用(xmin+xmax)/2得到x的中心點
    y = (box[2] + box[3])/2.0 # 使用(ymin+ymax)/2得到y的中心點
    w = box[1] - box[0] # 然後寬度就是使用xmax-xmin計算得到
    h = box[3] - box[2] # 然後高度就是使用ymax-ymin計算得到
    x = x*dw# 歸一化
    w = w*dw# 歸一化
    y = y*dh# 歸一化
    h = h*dh# 歸一化
    return (x,y,w,h)
def convert_annotation(year, image_id):
    in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))
    out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, image_id), 'w')#此時檔案是如何形成的?    open的時候自動建立
    root = tree.getroot()#獲得root節點  
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)
    for obj in root.iter('object'):
        difficult = obj.find('difficult').text
        cls = obj.find('name').text
        if cls not in classes or int(difficult) == 1:
            continue
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
        bb = convert((w,h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + 'n')
wd = getcwd()
for year, image_set in sets:
    if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)):#如果沒有存在這個檔案
        os.makedirs('VOCdevkit/VOC%s/labels/'%(year))#建立這個路徑 來存放txt標籤
    image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()#此時檔案是如何形成的? 通過另一個指令碼檔案與圖片名稱生成的
    list_file = open('%s_%s.txt'%(year, image_set), 'w')#這個檔案可能是自己建的? open的時候自動建立
    for image_id in image_ids:
        list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpgn'%(wd, year, image_id))
        convert_annotation(year, image_id)
    list_file.close()
#要修改的地方
os.system("cat 2019_train.txt 2019_val.txt > train.txt") # 此處是將兩個txt連線成一個txt,如果你訓練時不用val.txt中的資料,可以註釋掉這句話。
 # os.system("cat 2007_train.txt 2007_val.txt 2007_test.txt 2012_train.txt 2012_val.txt > train.all.txt")# 另外,刪除另外一條os.system(...)語句。

儲存修改後,執行該檔案:

python voc_label.py

執行完畢之後,會生成2018_train.txt、2018_val.txt、train.txt 三個檔案,如下圖:

在labels資料夾下會生成圖片對應的txt形式的圖片標註資訊

5. 下載預訓練模型

為了加速訓練過程,可以在darknet官網上下載預訓練模型,在該預訓練模型上再進行訓練。 在命令視窗輸入以下命令:

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

檔案儲存在script資料夾下即可

6. 修改./darknet/cfg/voc.data檔案

classes= 2  # 你的資料集的類別數
train  =  /home/tukrin/zhl/darknet/scripts/2019_train.txt  # 第4步中生成的txt檔案路徑
valid  =  /home/tukrin/zhl/darknet/scripts/2019_val.txt  # 第4步中生成的txt檔案路徑
names  =  /home/tukrin/zhl/darknet/data/voc.names # voc.names 的檔案路徑
backup =  /home/tukrin/zhl/darknet/backup/  #backup資料夾的路徑 訓練的權重將儲存在這

7. 修改./darknet/data/voc.name檔案

將voc.name檔案做如下修改:

car
people

內容為你的資料集的類別名稱,注意和xml檔案中的類別名稱一致。

8. 修改./darknet/cfg/yolov3-voc.cfg檔案

該檔案為網路結構檔案。 首先修改開頭處如下:

[net]
# Testing
# batch=1
# subdivisions=1
# Training
batch=64
subdivisions=16

即,將訓練模式開啟,將測試模式的語句註釋掉。

其中subdivisions為將一個batch(此處為64)分成多大的小batch。如果訓練時提示超出記憶體,則可以相應的改小這兩個引數的值。

接著視情況修改開頭處的超引數(學習率,迭代次數等):

width=416
height=416
channels=3
momentum=0.9
decay=0.0005
angle=0
saturation = 1.5
exposure = 1.5
hue=.1
learning_rate=0.001
burn_in=1000
max_batches = 50200 # 迭代次數
policy=steps
steps=40000,45000 # 在指定迭代次數時進行學習率衰減
scales=.1,.1  # 學習率衰減率 此處是0.1

然後再該檔案的底部部分,找到如下語句進行如下修改:

......
[convolutional]
size=1
stride=1
pad=1
filters=21 ....................# 修改為 3 * (類別數 + 5),此處類別數為2,所以設定為 3*(2+5)=21
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=2 .....................# 修改類別數
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=1
......
[convolutional]
size=1
stride=1
pad=1
filters=21 .....................# 同上
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=2 .....................# 同上
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=1
......
[convolutional]
size=1
stride=1
pad=1
filters=21 .....................# 同上
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=2 .....................# 同上
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=1

有三處[yolo]的上面的[convolutional]的filters要改 和[yolo]的classes要改開始訓練

9. 開始訓練

在 ./darknet 目錄下,在命令視窗中執行以下命令,其中 -gpus 0, 1 用來指定參與訓練的GPU編號,可以省略。填0 或1

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

10.訓練終止後繼續訓練方法

假如訓練由於意外情況,如視訊記憶體不夠終止了,可以通過載入中間權重檔案,進而繼續訓練 中間權重檔案在backup資料夾中

把9步權重檔案的路徑換為backup中檔案即可

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_900.weights -gpus 0,1

backup裡檔案儲存規則: 訓練1000次之前每100次儲存一次。所以上面圖片出現了100~900的權重中間檔案。 訓練1000次之後每10000次儲存一次。 yolov3-voc.backup 會保持100整數倍的訓練結果。 所以在1000次之後想繼續訓練的話應該載入 yolov3-voc.backup檔案。注意此檔案不能作為檢查模型使用。

以上就是darknet框架中YOLOv3對資料集進行訓練和預測詳解的詳細內容,更多關於darknet YOLOv3資料集訓練預測的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com