0.前言
本文為Darknet框架下魁巩,利用官方VOC數(shù)據(jù)集的yolov3模型訓(xùn)練牺汤,訓(xùn)練環(huán)境為: Ubuntu18.04下的GPU訓(xùn)練,cuda版本10.0妓盲;cudnn版本7.6.5杂拨。經(jīng)過一晚上的訓(xùn)練,模型20個類別的mAP達(dá)到74%+悯衬。
主要模塊:
- 概述
- 源碼編譯
- 功能測試
- 模型訓(xùn)練
- 模型驗證
【概述】部分主要介紹yolo系列模型和darknet框架的關(guān)系扳躬、資源網(wǎng)站和數(shù)據(jù)集下載
【源碼編譯】主要是用官方源碼和make命令編譯出Linux下可執(zhí)行文件,包括cuda+cudnn的設(shè)置
【功能測試】主要是用官網(wǎng)給出的demo和與訓(xùn)練模型來進(jìn)行圖片測試
【模型訓(xùn)練】主要是用darknet+yolov3模型訓(xùn)練VOC圖像數(shù)據(jù)集(VOC2007+VOC2012)
【模型驗證】即用訓(xùn)練好的模型甚亭,檢測模型訓(xùn)練效果.
1.概述
官網(wǎng):https://pjreddie.com/
1.1 Yolo
Yolo系列模型(v1~v3)在近年些來的目標(biāo)檢測領(lǐng)域贷币,非常火熱亏狰!Yolo為:You only look once的縮寫役纹,同時也表明了其特點,只需要一次即可完成從圖像分割到檢測暇唾,故其被稱為one-stage系列模型的鼻祖促脉。
two-stage類目標(biāo)檢測模型如Fast R-CNN、Faster R-CNN
1.2 Darknet
yolo系列就是深度學(xué)習(xí)領(lǐng)域中用于目標(biāo)檢測的模型(yolov1~v3)策州,那么darknet是什么瘸味?兩者關(guān)系如何?
darknet是作者用c和cuda編寫的用于深度學(xué)習(xí)模型訓(xùn)練的框架够挂,支持CPU和GPU訓(xùn)練旁仿,是個非常簡單輕量級框架,就和Tensorflow,Mxnet孽糖,Pytorch,Caffe一樣枯冈,雖然功能沒有它們多毅贮,不過小也有小的優(yōu)勢,如果你會c語言尘奏,可以對其進(jìn)行充分地利用和改造滩褥,或者讀讀源碼看一下其實現(xiàn),也會收貨滿滿炫加!
So,總結(jié)一下:Darknet是深度學(xué)習(xí)框架瑰煎,yolov1~v3是yolo系列的目標(biāo)檢測模型
1.3 資源下載
官網(wǎng)
源碼
Darknet源碼:
https://github.com/pjreddie/darknet
Darknet是用純c和cuda編寫的,要想用darknet來訓(xùn)練模型俗孝,最好用Linux/Unix系統(tǒng)丢间,官方也提供了python的接口,如果是Windows系統(tǒng)驹针,可以利用網(wǎng)友開源實現(xiàn):https://github.com/AlexeyAB/darknet
可以直接下載zip包??darknet-master.zip也可直接執(zhí)行
git clone
https://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可視化訓(xùn)練過程中的參數(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訓(xùn)練挠唆,建議開啟=1
- DEBUG 表示編譯的Yolo版本為是否為DEBUG版
如果不使用GPU則GPU=0,CUDNN=0玄组;還有一點需注意,如果在shell執(zhí)行nvcc找不到命令(沒有添加到環(huán)境變量),則需要將nvcc命令的全路徑寫出來
指定cuda的路徑
如果不使用GPU,則此步可忽略巧勤,如果使用GPU,則需要指定cuda路徑弄匕。官方的Makefile默認(rèn)的cuda路徑為:/usr/local/cuda,如果你裝了多個cuda剩瓶,但是有軟連接指向正確的cuda文件夾路徑:即/usr/local/cuda軟連接到你需要的cuda文件夾延曙,那么無需修改亡哄,保持/usr/local/cuda即可;否則需要指定你的cuda路徑愿卸,這里需要改兩處:51行的COMMON和53行的LDFAGS趴荸。
2.2 執(zhí)行make
執(zhí)行make編譯完成后发钝,在項目主目錄下生成可執(zhí)行的darknet文件波闹。然后我們就可以用這個可執(zhí)行文件來進(jìn)行模型訓(xùn)練和測試了精堕!
3.功能測試
將下載好的權(quán)重文件放入主目錄下,然后cd到該目錄下執(zhí)行:
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
如果你看到如下輸出夺英,且在主目錄下找到一張predictions.jpg的圖片滋捶,則執(zhí)行成功重窟,表明上一步驟中編譯的darknet可以正常使用。
你也可以指定一個閾值扭仁,yolo默認(rèn)輸出置信度>0.25的預(yù)測框乖坠,你也可以自行指定:
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg -thresh 0.45
-thresh 0.45表示:置信度低于45%的預(yù)測框都不會被輸出熊泵。
除了使用經(jīng)典的yolov3模型外,你還可以換一個模型嘗試徐许,譬如yolov3-tiny.weights
./darknet detect cfg/yolov3-tiny.cfg yolov3-tiny.weights data/dog.jpg
當(dāng)然雌隅,也可以通過連接攝像頭實現(xiàn)實時視頻畫面預(yù)測缸沃。(需要編譯時添加opencv)
./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights <video file>
4.模型訓(xùn)練
4.1 數(shù)據(jù)準(zhǔn)備
模型訓(xùn)練前首先準(zhǔn)備數(shù)據(jù)集和泌,我們用VOC數(shù)據(jù)集,將VOC數(shù)據(jù)集解壓梯皿,解壓后共同存放在VOCevkit文件夾中东羹,我將VOCevkit放在了darknet主文件夾/data/VOC/下忠烛。
cd到/VOC目錄下美尸,下載??voc_label.py 师坎,并運行:
python voc_label.py
可以將該腳本復(fù)制到/scripts下留作備份
文件夾下會生成7個.txt文件:
如果你的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年的訓(xùn)練和驗證圖像+2012年的圖像都放入了train.txt用于集中訓(xùn)練
4.2 修改配置文件voc.data
配置cfg/voc.data,來確定你需要檢測的目標(biāo)類別數(shù)量和名稱;修改train和valid的圖片資源路徑义矛。訓(xùn)練資源指向train.txt測試/驗證資源指向2007_test.txt
VOC數(shù)據(jù)集默認(rèn)的類別數(shù)量為20個凉翻,名稱在data/voc.names中:
我這里使用默認(rèn)的20個類別噪矛,所以無需修改艇挨;如果韭赘,你只想檢測其中的幾個類別泉瞻,譬如person和car袖牙,那么可以設(shè)置voc.data中classes=2,names只保留person和car這兩種,不過后面相應(yīng)的需要更改yolov3-voc.cfg里的卷積層配置等司忱。
4.3 修改yolov3-voc.cfg
yolov3-voc.cfg文件定義了yolo的卷積神經(jīng)網(wǎng)絡(luò)模型畴蹭,和超參數(shù)配置等叨襟。這里需要注意糊闽,訓(xùn)練時需要將#Testing區(qū)塊下的batch和subvisions注釋掉;測試和驗證時則放開注釋汽纠,同時注釋掉#Training區(qū)塊下的內(nèi)容虱朵。
訓(xùn)練時,可以根據(jù)自己GPU的內(nèi)存來設(shè)置批的大小batch絮宁,可設(shè)為16绍昂、32偿荷、64跳纳、128
驗證時,batch和subvisions同時設(shè)為1即可艾蓝。
4.4 開始訓(xùn)練
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查看顯存占用情況:
訓(xùn)練過程中會持續(xù)往backup/下生成權(quán)重文件筹麸,如:yolov3-voc_100.weights、yolov3-voc_200.weights....
5.模型驗證
檢驗生成的模型權(quán)重文件白指、測試準(zhǔn)確率和map等指標(biāo)告嘲。驗證前需要將yolov3-voc.cfg中的batch和subdivisions都改成1橄唬。然后找到需要測試的權(quán)重文件,默認(rèn)權(quán)重文件保存在:項目目錄/bakcup/下隆判,我選擇這個yolov3-voc_10000.weights僧界,訓(xùn)練大約一個晚上12小時左右捂襟,loss在0.6多笆豁。
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
運行結(jié)束會在控制臺打印出標(biāo)注出的目標(biāo)類別以及置信度哄孤、同時會在目錄下生成一張標(biāo)注圖片:predictions.jpg
測試二
再隨便找一張圖片試試
>./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_10000.weights data/person.jpg
5.2 驗證
測試只能一張張地直觀感受下模型的訓(xùn)練效果,看看標(biāo)注出的目標(biāo)是否正確晨逝,通過驗證才能確定模型的整體訓(xùn)練效果捉貌,驗證時會用模型對所有的4952張測試集圖片進(jìn)行預(yù)測冬念,同時與正確結(jié)果進(jìn)行比對急前,得出一個模型預(yù)測準(zhǔn)確率。
驗證測試集
可以運行以下腳本進(jìn)行驗證:
./darknet detector valid cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_10000.weights
驗證完會在results文件夾下生成20個類別的驗證結(jié)果txt文件
默認(rèn)的文件命名規(guī)則是:'comp4_det_test_' + '類別名稱' + .txt寺晌,如bird類生成comp4_det_test_bird.txt文件折剃。
如圖怕犁,第一列000053表示圖像編號己莺;第二列為置信度凌受;后4列為檢測出的目標(biāo)框坐標(biāo)
計算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’存儲二進(jìn)制格式,運行時會報錯
compute_mAP.py
新建compute_mAP.py文件巷帝,用于調(diào)用voc_eval.py,內(nèi)容如下:
from voc_eval import voc_eval
import os
map_ = 0
# classnames填寫訓(xùn)練模型時定義的類別名稱
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浦马。
可以看見晶默,經(jīng)過1晚上的訓(xùn)練荤胁,我們的模型——yolov3-voc_10000.weights的mAP是0.740屎债,雖然沒有達(dá)到y(tǒng)olov2系列76.8+的水平盆驹,不過一晚上的訓(xùn)練能達(dá)到如此程度,也是挺高了辫封。