【目標檢測實戰(zhàn)】Darknet—yolov3模型訓練(VOC數(shù)據(jù)集)

19.jpg

0.前言

本文為Darknet框架下,利用官方VOC數(shù)據(jù)集的yolov3模型訓練,訓練環(huán)境為: Ubuntu18.04下的GPU訓練,cuda版本10.0;cudnn版本7.6.5。經(jīng)過一晚上的訓練,模型20個類別的mAP達到74%+。

主要模塊:

  • 概述
  • 源碼編譯
  • 功能測試
  • 模型訓練
  • 模型驗證

【概述】部分主要介紹yolo系列模型和darknet框架的關(guān)系、資源網(wǎng)站和數(shù)據(jù)集下載
【源碼編譯】主要是用官方源碼和make命令編譯出Linux下可執(zhí)行文件,包括cuda+cudnn的設(shè)置
【功能測試】主要是用官網(wǎng)給出的demo和與訓練模型來進行圖片測試
【模型訓練】主要是用darknet+yolov3模型訓練VOC圖像數(shù)據(jù)集(VOC2007+VOC2012)
【模型驗證】即用訓練好的模型,檢測模型訓練效果.

1.概述

官網(wǎng):https://pjreddie.com/

1.1 Yolo

Yolo系列模型(v1~v3)在近年些來的目標檢測領(lǐng)域,非?;馃幔olo為:You only look once的縮寫,同時也表明了其特點,只需要一次即可完成從圖像分割到檢測,故其被稱為one-stage系列模型的鼻祖。

two-stage類目標檢測模型如Fast R-CNN、Faster R-CNN

屏幕截圖_1.png

1.2 Darknet

yolo系列就是深度學習領(lǐng)域中用于目標檢測的模型(yolov1~v3),那么darknet是什么?兩者關(guān)系如何?
darknet是作者用c和cuda編寫的用于深度學習模型訓練的框架,支持CPU和GPU訓練,是個非常簡單輕量級框架,就和Tensorflow,Mxnet,Pytorch,Caffe一樣,雖然功能沒有它們多,不過小也有小的優(yōu)勢,如果你會c語言,可以對其進行充分地利用和改造,或者讀讀源碼看一下其實現(xiàn),也會收貨滿滿!
So,總結(jié)一下:Darknet是深度學習框架,yolov1~v3是yolo系列的目標檢測模型

1.3 資源下載

官網(wǎng)

https://pjreddie.com/

源碼

Darknet源碼:
https://github.com/pjreddie/darknet

Darknet是用純c和cuda編寫的,要想用darknet來訓練模型,最好用Linux/Unix系統(tǒng),官方也提供了python的接口,如果是Windows系統(tǒng),可以利用網(wǎng)友開源實現(xiàn):https://github.com/AlexeyAB/darknet

可以直接下載zip包??darknet-master.zip也可直接執(zhí)行
git clonehttps://github.com/pjreddie/darknet將源碼下載到本地

權(quán)重文件

yolov3-tiny.weights
yolov2.weights
yolov3.weights
darknet53.conv.74

VOC數(shù)據(jù)集

VOCtrainval_11-May-2012.tar
VOCtrainval_06-Nov-2007.tar
VOCtest_06-Nov-2007.tar

其他:

YOLO-V3可視化訓練過程中的參數(shù),繪制loss、IOU、avg Recall等的曲線圖:https://blog.csdn.net/qq_34806812/article/details/81459982
AlexyAB大神總結(jié)的優(yōu)化經(jīng)驗:
https://www.cnblogs.com/pprp/p/10204480.html

2.源碼編譯

2.1 編輯Makefile

指定是否使用GPU

在執(zhí)行make指令編譯之前,需要編輯一下makefile,來指定是否需要用GPU(cuda),如果用cuda,是否需要用cudnn加速;是否需要用opencv等。我這里是用GPU且需要用CUDNN加速的,不使用OpenCV。

Makefile的前5行如下,這5項內(nèi)容0表示不啟用,1表示啟用,可根據(jù)需求自己配置。

  • GPU 是否啟用GPU1
  • CUDNN 是否啟用CUDNN加速,若GPU = 1則CUDNN可選1或0;GPU=0則CUDNN=0
  • OPENCV 是否啟用OpenCV,啟用的話需先編譯安裝好,啟用可支持對視頻和圖像流文件處理
  • OPENMP 是否啟動多核CPU來加速Yolo,如果是用CPU訓練,建議開啟=1
  • DEBUG 表示編譯的Yolo版本為是否為DEBUG版

屏幕截圖_14.png

如果不使用GPU則GPU=0,CUDNN=0;還有一點需注意,如果在shell執(zhí)行nvcc找不到命令(沒有添加到環(huán)境變量),則需要將nvcc命令的全路徑寫出來

指定cuda的路徑

如果不使用GPU,則此步可忽略,如果使用GPU,則需要指定cuda路徑。官方的Makefile默認的cuda路徑為:/usr/local/cuda,如果你裝了多個cuda,但是有軟連接指向正確的cuda文件夾路徑:即/usr/local/cuda軟連接到你需要的cuda文件夾,那么無需修改,保持/usr/local/cuda即可;否則需要指定你的cuda路徑,這里需要改兩處:51行的COMMON和53行的LDFAGS。

屏幕截圖_15.png

2.2 執(zhí)行make

屏幕截圖_16.png

執(zhí)行make編譯完成后,在項目主目錄下生成可執(zhí)行的darknet文件。然后我們就可以用這個可執(zhí)行文件來進行模型訓練和測試了!

3.功能測試

將下載好的權(quán)重文件放入主目錄下,然后cd到該目錄下執(zhí)行:

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

如果你看到如下輸出,且在主目錄下找到一張predictions.jpg的圖片,則執(zhí)行成功,表明上一步驟中編譯的darknet可以正常使用。

屏幕截圖_17.png

你也可以指定一個閾值,yolo默認輸出置信度>0.25的預測框,你也可以自行指定:

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg -thresh 0.45

-thresh 0.45表示:置信度低于45%的預測框都不會被輸出。

除了使用經(jīng)典的yolov3模型外,你還可以換一個模型嘗試,譬如yolov3-tiny.weights

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

當然,也可以通過連接攝像頭實現(xiàn)實時視頻畫面預測。(需要編譯時添加opencv)

./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights <video file>

4.模型訓練

4.1 數(shù)據(jù)準備

模型訓練前首先準備數(shù)據(jù)集,我們用VOC數(shù)據(jù)集,將VOC數(shù)據(jù)集解壓,解壓后共同存放在VOCevkit文件夾中,我將VOCevkit放在了darknet主文件夾/data/VOC/下。

cd到/VOC目錄下,下載??voc_label.py ,并運行:

python voc_label.py

可以將該腳本復制到/scripts下留作備份

文件夾下會生成7個.txt文件:

屏幕截圖_17.png

如果你的voc_label.py腳本是從官網(wǎng)wget https://pjreddie.com/media/files/voc_label.py下載的,則需要在腳本57行處額外加上如下兩行內(nèi)容:

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")

目的:將2007年的訓練和驗證圖像+2012年的圖像都放入了train.txt用于集中訓練

4.2 修改配置文件voc.data

配置cfg/voc.data,來確定你需要檢測的目標類別數(shù)量和名稱;修改train和valid的圖片資源路徑。訓練資源指向train.txt測試/驗證資源指向2007_test.txt

屏幕截圖_23.png

VOC數(shù)據(jù)集默認的類別數(shù)量為20個,名稱在data/voc.names中:

屏幕截圖_19.png

我這里使用默認的20個類別,所以無需修改;如果,你只想檢測其中的幾個類別,譬如person和car,那么可以設(shè)置voc.data中classes=2,names只保留person和car這兩種,不過后面相應的需要更改yolov3-voc.cfg里的卷積層配置等。

4.3 修改yolov3-voc.cfg

yolov3-voc.cfg文件定義了yolo的卷積神經(jīng)網(wǎng)絡(luò)模型,和超參數(shù)配置等。這里需要注意,訓練時需要將#Testing區(qū)塊下的batch和subvisions注釋掉;測試和驗證時則放開注釋,同時注釋掉#Training區(qū)塊下的內(nèi)容。

訓練時,可以根據(jù)自己GPU的內(nèi)存來設(shè)置批的大小batch,可設(shè)為16、32、64、128
驗證時,batch和subvisions同時設(shè)為1即可。

屏幕截圖_22.png

4.4 開始訓練

cd回項目主目錄,將darknet53.conv.74權(quán)重放入主目錄下,運行:

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

如果報錯提示cuda內(nèi)存溢出,可以降低batch,再次運行;運行過程中可以通過nvidia-smi查看顯存占用情況:

屏幕截圖_24.png

訓練過程中會持續(xù)往backup/下生成權(quán)重文件,如:yolov3-voc_100.weights、yolov3-voc_200.weights....

5.模型驗證

檢驗生成的模型權(quán)重文件、測試準確率和map等指標。驗證前需要將yolov3-voc.cfg中的batch和subdivisions都改成1。然后找到需要測試的權(quán)重文件,默認權(quán)重文件保存在:項目目錄/bakcup/下,我選擇這個yolov3-voc_10000.weights,訓練大約一個晚上12小時左右,loss在0.6多。

屏幕截圖.png

5.1 測試

測試一

我們從VOC數(shù)據(jù)集中隨便找一找圖片來測試一下,這里我選取000275.jpg放入主目錄下

000275.jpg

運行:

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

屏幕截圖_1.png

運行結(jié)束會在控制臺打印出標注出的目標類別以及置信度、同時會在目錄下生成一張標注圖片:predictions.jpg

predictions.jpg

測試二

再隨便找一張圖片試試

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

屏幕截圖_2.png
predictions.jpg

5.2 驗證

測試只能一張張地直觀感受下模型的訓練效果,看看標注出的目標是否正確,通過驗證才能確定模型的整體訓練效果,驗證時會用模型對所有的4952張測試集圖片進行預測,同時與正確結(jié)果進行比對,得出一個模型預測準確率。

驗證測試集

可以運行以下腳本進行驗證:

./darknet detector valid cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_10000.weights
驗證完會在results文件夾下生成20個類別的驗證結(jié)果txt文件

屏幕截圖_3.png

默認的文件命名規(guī)則是:'comp4_det_test_' + '類別名稱' + .txt,如bird類生成comp4_det_test_bird.txt文件。

屏幕截圖_4.png

如圖,第一列000053表示圖像編號;第二列為置信度;后4列為檢測出的目標框坐標

計算map

計算map,我們需要兩個python文件:

  • voc_eval.py
  • compute_mAP.py

其中voc_eval.py是github上開源項目的代碼voc_eval.py;compute_mAP.py需要我們自己編寫


voc_eval.py
我們?yōu)榱诉m配darknet中voc數(shù)據(jù)集的驗證,需要對源碼做幾處修改:
a.源碼第9行:import cPickle 改為:

import _pickle as cPickle

因為源碼是python2.x版本,如果python3.x版本的運行會報錯,故需要修改。

b.源碼103行: imagenames ``=`` [x.strip() ``for`` x ``in`` lines]改為:

imagenames = [x.strip().split('/')[-1].split('.')[0] for x in lines]

這個主要是為了方便適配2007_test.txt,因為我們驗證時采用的是2007_test.txt中的測試集圖片,文件中存放的是圖片的全路徑,而imagenames需要用的是文件名、所以需要將全路徑做個轉(zhuǎn)換,截取到文件名。

c.115行:with`` ``open``(cachefile, ``'w'``) ``as`` f:和 119行with`` ``open``(cachefile, ``'r'``) ``as f:改成:

with open(cachefile, 'wb') as f:
with open(cachefile, 'rb') as f:

如果不修改成‘wb’和‘rb’存儲二進制格式,運行時會報錯

compute_mAP.py
新建compute_mAP.py文件,用于調(diào)用voc_eval.py,內(nèi)容如下:

from voc_eval import voc_eval
import os
map_ = 0
# classnames填寫訓練模型時定義的類別名稱
classnames = ['aeroplane','bicycle','bird','boat','bottle','bus','car','cat','chair','cow','diningtable','dog','horse','motorbike','person','pottedplant','sheep','sofa','train','tvmonitor']
for classname in classnames:
    ap = voc_eval('../results/{}.txt', '../data/VOC/VOCdevkit/VOC2007/Annotations/{}.xml', '../data/VOC/2007_test.txt', classname, '.')
    map_ += ap
    #print ('%-20s' % (classname + '_ap:')+'%s' % ap)
    print ('%s' % (classname + '_ap:')+'%s' % ap)
# 刪除臨時的dump文件
if(os.path.exists("annots.pkl")):
    os.remove("annots.pkl")
    print("cache file:annots.pkl has been removed!")
# 打印map
map = map_/len(classnames)
#print ('%-20s' % 'map:' + '%s' % map)
print ('map:%s' % map)

我這里在項目主目錄下新建了一個【yolo-compute-util】文件夾,將兩個.py文件放在文件夾中,cd /yolo-compute-util,然后運行:python compute_mAP.py即可根據(jù)results中的驗證結(jié)果統(tǒng)計出各個類別的ap,以及匯總的map。

屏幕截圖_5.png

可以看見,經(jīng)過1晚上的訓練,我們的模型——yolov3-voc_10000.weights的mAP是0.740,雖然沒有達到y(tǒng)olov2系列76.8+的水平,不過一晚上的訓練能達到如此程度,也是挺高了。

屏幕截圖_6.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容