darknet框架下yolov3實戰(一)

目錄

運行demo

使用VOC數據訓練自己的模型

標註數據

生成訓練用的txt文件

修改配置文件

運行訓練後的模型

遇到的坑


參考文章:https://www.cnblogs.com/xieqi/p/9818056.html

運行demo

1. 安裝darknet很簡單,https://pjreddie.com/darknet/yolo/,直接按照該網站的步驟配置就行。

其中,需要安裝cuda與opencv直接在makefile文件裏修改對應的值就行,1是安裝,0是不安裝,默認都是不安裝的。

2. 下載預訓練模型,運行命令:

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

如果出現如下圖的結果,則說明已正確運行了;

如果你在安裝是OPENCV設置爲1了,那麼會直接顯示運行的結果圖像並保存;如果沒有安裝opencv,則圖像保存在同級目錄下的predictions.jpg。

因爲我的opencv之前已經安裝好的,如果之前沒有安裝好,我不知道在編譯darknet時候是也編譯了opencv還是說編譯的時候只配置了opencv,但我感覺應該是隻負責配置opencv,因爲darknet的編譯過程我沒有看到編譯opencv,而且編譯opencv耗時很長,而編譯darknet的時候一會兒就編譯完了,所以我感覺應該只是配置opencv。

使用VOC數據訓練自己的模型

darknet是在VOC格式的數據集上訓練yolov3

標註數據

darknet框架下的訓練數據是兩個txt文本,一個記錄路徑,以及記錄標註目標的位置。生成這兩個txt文件首先需要有標註好的voc數據,voc2007或voc2012均可,我用的是voc2007數據格式,生成標註數據和生成voc2007數據格式可見我的博文《將標註的數據集轉化爲VOC2007格式

生成訓練用的txt文件

由於我的數據結構是voc2007的,自己修改了官網的scripts\voc_label.py文件,添加了一些註釋。自己修改文件裏面還是有很多坑的,要特別注意,在文章後面我也列出了一些。修改後程序如下:

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join

classes = ["myobject"]


def convert(size, box):
    dw = 1./(size[0])
    dh = 1./(size[1])
    x = (box[0] + box[1])/2.0 - 1
    y = (box[2] + box[3])/2.0 - 1
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x*dw
    w = w*dw
    y = y*dh
    h = h*dh
    return (x,y,w,h)

def convert_annotation(image_id):
    in_file = open('E:\dataset\myobject\VOC2007\Annotations/%s.xml'%(image_id))#讀取標註數據
    out_file = open('E:\dataset\myobject\VOC2007/labels/%s.txt'%(image_id), 'w')#輸出的標註訓練數據文本文件
    tree=ET.parse(in_file)
    root = tree.getroot()
    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()#獲取當前執行文件夾的路徑
 
if not os.path.exists('E:\dataset\myobject\VOC2007/labels'):#判斷是否存在輸出文件夾
        os.makedirs('E:\dataset\myobject\VOC2007/labels')#不存在則創建輸出文件夾
image_ids = open('E:\dataset\myobject\VOC2007\ImageSets\Main/train.txt').read().strip().split()#分離文本中的imageID
list_file = open('2007_train.txt','w')
for image_id in image_ids:
    list_file.write('E:\dataset\myobject\VOC2007\JPEGImages/%s.jpg\n'%(image_id))#將路徑寫入到文本文件中
    convert_annotation(image_id)      
list_file.close()

運行以下命令生成訓練縮需的txt文件。

python voc_label.py

修改配置文件

(1) 修改cfg/yolov3-voc.cfg,建議在Windows下修改,用文本工具打開文件後查找"yolo"字段,文件中共有3處yolo節點,在yolo節點下面的類別數改成你的類別數,yolo節點上面的卷積層的濾波數改成類別數對應的濾波數,具體計算如下:

[convolutional]
size=1
stride=1
pad=1
filters=18    #filters = 3 * ( classes + 5 )   here,filters=3*(1+5)
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=1

此處我只例舉了一個,配置文件中共有3處要修改。

(2)修改data\voc.names文件,改成你自己的類別名,記住一行一個,千萬別多出空行,空行程序也會識別爲類別數

(3)修改數據格式:

data load_data_detection(int n, char **paths, int m, int w, int h, int boxes, int classes, float jitter, float hue, float saturation, float exposure)
{
    char **random_paths = get_random_paths(paths, n, m);
    int i;
    data d = {0};
    d.shallow = 0;

    d.X.rows = n;
    d.X.vals = calloc(d.X.rows, sizeof(float*));
    d.X.cols = h*w;                   //灰階圖
    //d.X.cols = h*w*3;               //RGB圖
    
  ...

(4)修改cfg\voc.data文件,該文件內容如下圖,classes修改成你的類別數,train.txt修改成標註數據時候的2007_train.txt文件的路徑(train.txt文件中記錄的是訓練圖片的路徑列表),valid是測試數據路徑,可以改成和train一樣的路徑,names路徑就是voc.names的路徑,backup爲輸出的權重信息文件夾路徑

(5)下載預訓練權重:https://pjreddie.com/media/files/darknet53.conv.74,也可以下載官方的預訓練權重,https://pjreddie.com/darknet/yolo/,但下載後需進行格式轉換,轉化爲conv.74的格式,轉換命令參考該鏈接:

https://github.com/AlexeyAB/darknet/blob/57e878b4f9512cf9995ff6b5cd6e0d7dc1da9eaf/build/darknet/x64/partial.cmd#L24

對於yolov3-tiny.weights權重,轉換命令爲:

./darknet partial cfg/yolov3-tiny yolov3-tiny.weights yolov-tiny.conv.15 15

yolov3.weights權重,轉換命令爲:

sudo ./darknet partial cfg/yolov3.cfg yolov3.weights yolov3.conv.81 81

後面的數字代表了卷積層的層數。

(6)訓練自己的模型:

./darknet -i <gpu_id> detector train <data_cfg> <train_cfg> <weights>

其中:"-i" 是GPU標籤號,如果你只有一個GPU,那麼就是"-i 0",<data_cfg>是數據配置文件,即voc.data的路徑,<train_cfg> 爲網絡結構的配置文件路徑,即yolov3-voc.cfg的路徑,<weights>爲預訓練權重的路徑。

我的命令是:

./darknet -i 0 detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74

對於yolov3-tiny.weights

./darknet -i 0 detector train cfg/voc.data cfg/yolov3-tiny.cfg yolov3-tiny.conv.15

訓練過程如下:

Loaded: 4.533954 seconds
Region Avg IOU: 0.262313, Class: 1.000000, Obj: 0.542580, No Obj: 0.514735, Avg Recall: 0.162162,  count: 37
Region Avg IOU: 0.175988, Class: 1.000000, Obj: 0.499655, No Obj: 0.517558, Avg Recall: 0.070423,  count: 71
Region Avg IOU: 0.200012, Class: 1.000000, Obj: 0.483404, No Obj: 0.514622, Avg Recall: 0.075758,  count: 66
Region Avg IOU: 0.279284, Class: 1.000000, Obj: 0.447059, No Obj: 0.515849, Avg Recall: 0.134615,  count: 52
1: 629.763611, 629.763611 avg, 0.001000 rate, 6.098687 seconds, 64 images
Loaded: 2.957771 seconds
Region Avg IOU: 0.145857, Class: 1.000000, Obj: 0.051285, No Obj: 0.031538, Avg Recall: 0.069767,  count: 43
Region Avg IOU: 0.257284, Class: 1.000000, Obj: 0.048616, No Obj: 0.027511, Avg Recall: 0.078947,  count: 38
Region Avg IOU: 0.174994, Class: 1.000000, Obj: 0.030197, No Obj: 0.029943, Avg Recall: 0.088889,  count: 45
Region Avg IOU: 0.196278, Class: 1.000000, Obj: 0.076030, No Obj: 0.030472, Avg Recall: 0.087719,  count: 57
2: 84.804230, 575.267700 avg, 0.001000 rate, 5.959159 seconds, 128 imagesiter  
迭代次數 總損失  平均損失       學習率         花費時間           參與訓練的圖片總數
Region cfg文件中yolo-layer的索引
Avg IOU 當前迭代中,預測的box與標註的box的平均交併比,越大越好,期望數值爲1
Class 標註物體的分類準確率,越大越好,期望數值爲1
obj 越大越好,期望數值爲1
No obj 越小越好,但不爲零
.5R 以IOU=0.5爲閾值時候的recall; recall = 檢出的正樣本/實際的正樣本
.75R 以IOU=0.75爲閾值時候的recall
count 正樣本數

運行訓練後的模型

模型訓練完後,按照voc.data的配置,保存在backup文件夾下,在該文件夾下,有許多訓練的中間文件,中間文件名中的數值代表了迭代次數。但都加了鎖,需要先解鎖才能進行預測,使用以下命令對文件進行解鎖:

sudo chown $USER 文件路徑

測試單張圖片命令:

./darknet detector test <data_cfg> <test_cfg> <weights> <image_file> 

實例:

./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_10000.weights test.jpg

附上darknet程序使用方式:

./darknet detector test <data_cfg> <models_cfg> <weights> <test_file> [-thresh] [-out]
./darknet detector train <data_cfg> <models_cfg> <weights> [-thresh] [-gpu] [-gpus] [-clear]
./darknet detector valid <data_cfg> <models_cfg> <weights> [-out] [-thresh]
./darknet detector recall <data_cfg> <models_cfg> <weights> [-thresh]

'<>'必選項,’[ ]‘可選項

輸出:保存./darknet目錄下的predict.png

參數說明
data_cfg 數據配置文件,eg:cfg/voc.data
models_cfg 模型配置文件,eg:cfg/yolov3-voc.cfg
weights 權重配置文件,eg:weights/yolov3.weights
test_file 測試文件,eg:*/*/*/test.txt
-thresh 顯示被檢測物體中confidence大於等於 [-thresh] 的bounding-box,默認0.005
-out 輸出文件名稱,默認路徑爲results文件夾下,eg:-out "" //輸出class_num個文件,文件名爲class_name.txt;若不選擇此選項,則默認輸出文件名爲comp4_det_test_"class_name".txt
-i/-gpu 指定單個gpu,默認爲0,eg:-gpu 2
-gpus 指定多個gpu,默認爲0,eg:-gpus 0,1,2

 

 

遇到的坑

1.我一開始運行程序是在ubuntu虛擬機下運行的,運行demo直接報錯,程序killed。如下圖:

網上查了很多資料,沒有找到,後來在純ubuntu環境下運行,居然可以了,靈感突現,可能是內存太小的原因,因爲錯誤發生是loading預訓練模型的時候,而預訓練模型文件較大,進而修改了分配的內存,問題順利解決。

2. 訓練之前路徑設置,python中路徑設置時路徑字符串中不是正斜槓"\",都是反斜槓"/",如果使用了正斜槓,則會報如下圖錯誤:

3. 在linux下生成訓練的txt文件時,一般系統裏有兩個python版本,需要注意使用python2還是python3版本,在運行py腳本文件時,由於系統默認是python2的,要改成python3的,所以運行命令如下:

python3 xxx.py

4. 從checkpoint繼續訓練,測試訓練後的模型,報錯如下:

segmentation fault

但從預訓練模型開始訓練卻沒有報錯,不知道是什麼原因。因此儘量不要從模型保存文件夾backup下的yolov3-backup.weights開始訓練。


如果錯誤之處,希望各位同行可以指正。

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