天天看點

Darknet概述優點代碼結構安裝分類訓練

轉載自:https://blog.csdn.net/u010122972/article/details/83541978

優點

Darknet是一個比較小衆的深度學習架構,沒有社群,主要靠作者團隊維護,是以推廣較弱,用的人不多。而且由于維護人員有限,功能也不如tensorflow等架構那麼強大,但是該架構還是有一些獨有的優點:

1.易于安裝:在makefile裡面選擇自己需要的附加項(cuda,cudnn,opencv等)直接make即可,幾分鐘完成安裝;

2.沒有任何依賴項:整個架構都用C語言進行編寫,可以不依賴任何庫,連opencv作者都編寫了可以對其進行替代的函數;

3.結構明晰,源代碼檢視、修改友善:其架構的基礎檔案都在src檔案夾,而定義的一些檢測、分類函數則在example檔案夾,可根據需要直接對源代碼進行檢視和修改;

4.友好python接口:雖然darknet使用c語言進行編寫,但是也提供了python的接口,通過python函數,能夠使用python直接對訓練好的.weight格式的模型進行調用;

5.易于移植:該架構部署到機器本地十分簡單,且可以根據機器情況,使用cpu和gpu,特别是檢測識别任務的本地端部署,darknet會顯得異常友善。

代碼結構

下圖是darknet源代碼下載下傳解壓後檔案夾的分布情況:

Darknet概述優點代碼結構安裝分類訓練

1.cfg檔案夾内是一些模型的架構,每個cfg檔案類似與caffe的prototxt檔案,通過該檔案定義的整個模型的架構

2.data檔案夾内放置了一些label檔案,如coco9k的類别名等,和一些樣例圖(該檔案夾主要為示範用,或者是直接訓練coco等對應資料集時有用,如果要用自己的資料自行訓練,該檔案夾内的東西都不是我們需要的)

3.src檔案夾内全是最底層的架構定義檔案,所有層的定義等最基本的函數全部在該檔案夾内,可以了解為該檔案夾就是架構的源碼;

4.examples檔案夾是更為高層的一些函數,如檢測函數,識别函數等,這些函數直接調用了底層的函數,我們經常使用的就是example中的函數;

5.include檔案夾,顧名思義,存放頭檔案的地方;

6.python檔案夾裡是使用python對模型的調用方法,基本都在darknet.py中。當然,要實作python的調用,還需要用到darknet的動态庫libdarknet.so,這個動态庫稍後再介紹;

7.scripts檔案夾中是一些腳本,如下載下傳coco資料集,将voc格式的資料集轉換為訓練所需格式的腳本等

8.除了license檔案,剩下的就是Makefile檔案,如下圖,在問價開頭有一些選項,把你需要使用的選項設為1即可

Darknet概述優點代碼結構安裝分類訓練

安裝

1.點開Makefile,将需要的選項設定為1,如圖,使用GPU和CUDNN

Darknet概述優點代碼結構安裝分類訓練

2.打開終端,進入到darknet檔案夾根目錄,輸入make,開始編譯

3.幾分鐘後編譯完成,檔案夾中會多出一些檔案夾和檔案,obj檔案中存放了編譯過程中的.o檔案,其他的幾個空檔案夾也不需要太大關注,這裡最重要的就是三個:名為darknet的exe檔案,名為libdarknet.a的靜态連結庫和名為libdarknet.so的動态連結庫。如果直接在本地進行模型調用嘗試,可以直接運作darknet這個exe檔案,如果需要移植調用,則需要用到libdarknet.so這個動态連結庫,這個動态連結庫中隻包含了src檔案夾中定義的架構基礎函數,沒有包含examples中的高層函數,是以調用過程中需要自己去定義檢測函數

運作如下代碼

./darknet detector test data/detect.data data/yolov3.cfg data/yolov3.weight
           

其中./darknet表示運作編譯生成的darknet.exe檔案,darknet.exe首先調用example檔案夾下的darknet.c,該檔案中的main函數需要預定義參數,detector即為預定義參數,如下代碼

else if (0 == strcmp(argv[1], "detector")){
        run_detector(argc, argv);
           

由‘detector’轉而調用run_detector,run_detector存在于example檔案夾下的detector.c中,再根據預定義參數,确定是調用檢測函數,訓練函數還是驗證函數:

if(0==strcmp(argv[2], "test")) test_detector(datacfg, cfg, weights, filename, thresh, hier_thresh, outfile, fullscreen);
else if(0==strcmp(argv[2], "train")) train_detector(datacfg, cfg, weights, gpus, ngpus, clear);
else if(0==strcmp(argv[2], "valid")) validate_detector(datacfg, cfg, weights, outfile);
else if(0==strcmp(argv[2], "valid2")) validate_detector_flip(datacfg, cfg, weights, outfile);
else if(0==strcmp(argv[2], "recall")) validate_detector_recall(cfg, weights);
else if(0==strcmp(argv[2], "demo")) 
           

其中test表示檢測,train表示訓練,valid表示驗證,recall表示測試其召回率,demo為調用攝像頭的實時檢測

指令最後的三個參數表示運作需要的檔案,.data檔案記錄了模型檢測的類别,類名檔案等,如下:

classes= 1
train  = /media/seven/yolov3/data/plate2/train.list
#valid = data/coco_val_5k.list
names = data/plate/plate.names
backup = /media/seven/yolov3/data/plate2/models
#eval=coco
           

class表示檢測類别,train為訓練中需要用到的訓練資料的清單,valid為驗證集清單,names為檢測類别的名稱,backup為訓練中用到的存放訓練模型的路徑

.cfg檔案定義了模型結構,而.weight檔案為調用的模型權重檔案

運作以上指令,會在終端得到如下提示:

Enter Image Path: 
           

直接在終端輸入圖像的路徑,就可以對該圖像進行檢測,并在darknet的根目錄生成名為predictions.png的檢測結果,如圖:

Darknet概述優點代碼結構安裝分類訓練

分類

分類和檢測類似,調用指令如下:

./darknet classifier predict classify.data classify.cfg classify.weights
           

與檢測同理,./darknet運作darknet.exe,并調用example中的darknet.c檔案,通過classfier調用classifier.c中的run_classifier函數:

else if (0 == strcmp(argv[1], "classifier")){
        run_classifier(argc, argv);
           

并通過predict進而調用predict_classifier函數:

if(0==strcmp(argv[2], "predict")) predict_classifier(data, cfg, weights, filename, top);
 else if(0==strcmp(argv[2], "fout")) file_output_classifier(data, cfg, weights, filename);
 else if(0==strcmp(argv[2], "try")) try_classifier(data, cfg, weights, filename, atoi(layer_s));
 else if(0==strcmp(argv[2], "train")) train_classifier(data, cfg, weights, gpus, ngpus, clear);
 else if(0==strcmp(argv[2], "demo")) demo_classifier(data, cfg, weights, cam_index, filename);
 ...
           

而classify.data,classify.cfg,classify.weights分别表示分類對應的.data檔案,模型定義cfg檔案和模型權重.weights檔案。

訓練

檢測模型的訓練:

資料準備:

首先,你需要将資料的groundtruth轉化為darknet需要的格式,如果你的gt為voc格式的xml,可以通過如下腳本進行轉換

import pickle
import os
from os import listdir, getcwd
from os.path import join
classes = ["plate"]#類别改為自己需要檢測的所有類别
def convert(size, box):
    dw = 1./size[0]
    dh = 1./size[1]
    x = (box[0] + box[1])/2.0
    y = (box[2] + box[3])/2.0
    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(xml_path)#與圖檔對應的xml檔案所在的位址
    out_file = open(txt_save_path,'w') #與此xml對應的轉換後的txt,這個txt的儲存完整路徑
    tree=ET.parse(in_file)
    root = tree.getroot()
    size = root.find('size')  #通路size标簽的資料
    w = int(size.find('width').text)#讀取size标簽中寬度的資料
    h = int(size.find('height').text)#讀取size标簽中高度的資料

    for obj in root.iter('object'):
        cls = obj.find('name').text
        if cls not in classes :#or int(difficult) == 1:
            continue
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')   #通路boundbox标簽的資料并進行處理,都按yolo自帶的代碼來,沒有改動
        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')
           

上面的代碼需要自行設定xml_path和txt_save_path

從上面的代碼可以看到,對于object的位置x_min,x_max,y_min,y_max,先求得其中心點坐标center_x,center_y以及位置框的長寬width_rect,height_rect,再将這四個值分别除以長寬以将資料歸一化,如果不是voc格式的資料可以按照這樣的思路進行類似處理

如果是voc格式的資料可以參照我之前的部落格進行一步一步的處理darknet用自己的資料進行訓練

按照上面的流程,每張圖像都生成了對應的txt檔案來儲存其歸一化後的位置資訊,如下圖對應生成的txt如下:

Darknet概述優點代碼結構安裝分類訓練
0 0.250925925926 0.576388888889 0.1 0.0263888888889
0 0.485185185185 0.578125 0.0685185185185 0.0201388888889
           

圖中共有車牌兩個,每行儲存一個車牌的資訊,第一個0表示檢測object的label,因為我隻有一類,是以都是0

後面的四位即為歸一化後的中心點坐标和位置框的長和寬

最後将圖像和對應txt的檔案名統一,并拷貝到同一個檔案夾(a.jpg對應的txt為a.txt),如圖:

Darknet概述優點代碼結構安裝分類訓練

注意,txt和對應jpg檔案的名稱除了最後.jpg,.txt的字尾不一樣,其他的必須完全一樣,且需要儲存在同一檔案夾,訓練過程中會直接将a.jpg的名稱替換為a.txt來尋找該圖像對應的gt。對應的gt檔案也不一定必須是txt格式,如果不是txt格式可以去源碼中将這部分代碼進行修改,将.jpg替換為你需要的格式字尾

.data檔案準備

前面已經貼過.data的圖,訓練的時候必須的項目有“class”,“train”,“backup”。“names”最好也設定上,友善以後調用。

“class”表示你要檢測的類别個數,如檢測類别為20則

class=20

“backup”表示訓練過程中的緩存和儲存的模型。訓練過程中,會在該路徑下生成一個字尾為.backup的檔案,該檔案每100個step将模型更新一遍,以防止訓練忽然終端而沒有儲存模型。并且,訓練儲存的模型也會存在該路徑下。預設情況下,每10000step還是多少(記不太清了,我自己修改過)會儲存一個模型,命名為yolov3_疊代次數.weights,最終訓練完成還會儲存一個yolov3_final.weights。這些模型都會儲存在backup路徑下

“names”為儲存檢測object名稱的路徑,names=plate.names

“train”為你訓練集的list路徑,如train=data/trainlist.txt,trainlist.txt中儲存了所有訓練集圖像的路徑,如下圖

Darknet概述優點代碼結構安裝分類訓練

可以通過如下指令直接生成該檔案:

find image_path -name \*.jpg > trainlist.txt
           

image_path為你資料集的路徑

.cfg檔案準備

如果要調用yolo v3,可以直接使用cfg檔案夾下的yolov3.cfg,但是需要做如下幾個修改:

首先,将最上方的

# Testing
batch=1
subdivisions=1
# Training
# batch=64
# subdivisions=16
           

修改為

# Testing
#batch=1
#subdivisions=1
# Training
batch=64
subdivisions=16
           

其中batch表示batchsize,而subdivisions是為了解決想要大batchsize而顯存又不夠的情況,每次代碼隻讀取batchsize/subdivisions 個圖像,如圖中設定為64/16=4,但是會将16次的結果也就是64張圖的結果,作為一個batch來統一處理

(調用的時候再将testing部分解除注釋,并将train部分注釋)

然後,根據自己檢測的類别,将每個

[yolo]

(共有三個

[yolo]

) 下方的classes修改為自己需要檢測的類别,如果隻檢測一類則classes=1

然後将每個

[yolo]

上方的第一個filters的值進行修改,計算方式為

(5+classes)*3

,如果classes為1,則為18,修改前後的對比:

[convolutional]
size=1
stride=1
pad=1
filters=255
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=80
num=9
jitter=.3
ignore_thresh = .5
truth_thresh = 1
random=1
           
[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=1
           

圖中的random表示論文中提及的resize network來增強網絡的适應性,如果顯存足夠,最好設定為1,如果顯存不夠,也可以将其設定為0,即不進行network resizing

weights檔案準備

如果你使用的是作者提供的cfg模型結構,如yolov3,那麼可以到其官網去下載下傳預訓練模型來初始化模型參數,這樣可以加快收斂。當然,你也可以不使用預訓練模型進行訓練

開始訓練

如果使用預訓練模型則使用如下指令

./darknet detector train data/detect.data data/yolov3.cfg data/yolov3.weight
           

否則,使用

./darknet detectortrain data/detect.data data/yolov3.cfg
           

分類模型的訓練

資料準備

和檢測不一樣,分類的gt隻需要一個label即可,不再需要位置框的資訊,是以不再需要單獨的txt檔案來儲存gt,而是直接将label在圖像名稱上進行展現。是以需要對圖像名稱進行重命名,命名規則為:

(圖檔序号)_(标簽).(圖檔格式),如1_numzero.jpg

需要注意的是:

1.label不區分大小寫,即 numzero和NumZero是一樣的效果

2.label之間不能有包含關系,如ji和jin,不能出現這樣的形式,可改為ji1和jin

.data檔案準備

和檢測類似:

classes=65
train  = data/char/train.list
labels = data/char/labels.txt
backup = backup/
top=2
           

其中top不是在訓練中使用,而是在分類調用時使用,表示輸出Top個最高的可能值

.cfg檔案準備

可以從cfg檔案夾中選擇,也可以自行定義

.weights檔案

同上面的檢測

開始訓練

使用指令:

./darknet classifier train cfg/cifar.data cfg/cifar_small.cfg (xxx.weights)
           

繼續閱讀