簡(jiǎn)介:Darknet項(xiàng)目是github上的一個(gè)開(kāi)源深度學(xué)習(xí)框架,用c語(yǔ)言編寫(xiě),部署C/C++環(huán)境比較方便。
- 項(xiàng)目地址:https://github.com/AlexeyAB/darknet
- 項(xiàng)目作者主頁(yè):https://pjreddie.com/darknet/
- yolo 數(shù)據(jù)集預(yù)處理工具包: http://www.reibang.com/p/574755718e51
前人栽樹(shù)后人乘涼,多謝開(kāi)源大佬
1.圖片數(shù)據(jù)標(biāo)注
labelme標(biāo)注工具標(biāo)注的文件是json格式的文件楞抡,在yolo檢測(cè)的框架下需要txt格式的標(biāo)注,但是沒(méi)有關(guān)系析藕,轉(zhuǎn)換也很簡(jiǎn)單召廷。
沒(méi)有l(wèi)abelme的話直接,pip install labelme即可账胧。
(注:labelme默認(rèn)是保存圖片數(shù)據(jù)的竞慢,一般來(lái)說(shuō)用不到,菜單-Save With Image Data取消即可)
這里我標(biāo)注了4類數(shù)據(jù)找爱,分別用0 1 2 3表示梗顺,由于圖片數(shù)據(jù)涉及到其他公司秘密不方便展示,所以隨便找了個(gè)圖片做標(biāo)注示范车摄。
2. annotation格式轉(zhuǎn)換
json格式標(biāo)簽內(nèi)容如下
{
"version": "4.5.6",
"flags": {},
"shapes": [
{
"label": "0",
"points": [
[
1966.75,
1436.375
],
[
2088.625,
1567.625
]
],
"group_id": null,
"shape_type": "rectangle",
"flags": {}
},
{
"label": "1",
"points": [
[
666.75,
895.75
],
[
935.5,
1186.375
]
],
"group_id": null,
"shape_type": "rectangle",
"flags": {}
},
],
"imagePath": "..\\FOV_0000.bmp",
"imageData": null,
"imageHeight": 2984,
"imageWidth": 4080
}
yolo的txt標(biāo)簽格式
<class> <x_center> <y_center> <width> <height>
由于圖片可能有尺度縮放所以YOLO里邊的位置用的是圖片的百分比坐標(biāo)
python轉(zhuǎn)換代碼如下
import json
import os
import cv2
img_folder_path=r'F:\imagedata\FOV\FOV'
folder_path=r"F:\imagedata\FOV\FOV\annotation"#標(biāo)注數(shù)據(jù)的文件地址
txt_folder_path = r"F:\imagedata\FOV\FOV\txt"
def create_txt(img_name,json_d,img_path):
src_img=cv2.imread(img_path)
h,w = src_img.shape[:2]
#txt文件名和圖片名保持一致
txt_name = img_name.split(".")[0]+".txt"
txt_path = os.path.join(txt_folder_path,txt_name)
print(txt_path)
with open(txt_path,'a+') as f:
for item in json_d["shapes"]:
print(item['points'])
print(item['label'])
point=item['points']
x_center = (point[0][0]+point[1][0])/2
y_center = (point[0][1]+point[1][1])/2
width = point[1][0]-point[0][0]
hight = point[1][1]-point[0][1]
print(x_center)
f.write(" {} ".format(item['label']))
f.write(" {} ".format(x_center/w))
f.write(" {} ".format(y_center/h))
f.write(" {} ".format(width/w))
f.write(" {} ".format(hight/h))
f.write(" \n")
for jsonfile in os.listdir(folder_path):
temp_path=os.path.join(folder_path,jsonfile)
#如果是一個(gè)子目錄就繼續(xù)
if os.path.isdir(temp_path):
continue
print("json_path:\t",temp_path)
jsonfile_path=temp_path
with open(jsonfile_path, "r", encoding='utf-8') as f:
json_d = json.load(f)
#讀取圖片名
img_name=json_d['imagePath'].split("\\")[1]
img_path=os.path.join(img_folder_path,img_name)
print("img_path:\t",img_path)
create_txt(img_name,json_d,img_path)
生成的txt標(biāo)簽文件
0 0.4969822303921569 0.5033512064343163 0.029871323529411766 0.043984584450402146
1 0.19635416666666666 0.3488815348525469 0.06587009803921569 0.09739443699731903
1 0.2717984068627451 0.3488815348525469 0.07123161764705882 0.09739443699731903
1 0.19673713235294119 0.24677446380697052 0.0666360294117647 0.09425268096514745
1 0.2714154411764706 0.2483453418230563 0.0628063725490196 0.09111092493297587
最后把圖片和標(biāo)簽數(shù)據(jù)放到darknet\build\darknet\x64\data\obj目錄下寺谤,標(biāo)簽和圖片在同一個(gè)目錄下,且標(biāo)簽名和圖片名一樣吮播,如圖
3. darknet cfg文件設(shè)置
在darknet\build\darknet\x64\cfg目錄下修改yolov4-tiny-obj.cfg文件(記得備份原文件)变屁,修改bath,width,height,max_batches(下面的steps= max_batches0.8,max_batches0.9),官網(wǎng)的要求width height需要能被32整除意狠,max_batches=classes*2000.
# Training
batch=4
subdivisions=4
width=2048
height=1024
............
learning_rate=0.00261
burn_in=1000
max_batches = 8000
policy=steps
steps=6400,7200
scales=.1,.1
修改classes為你訓(xùn)練數(shù)據(jù)的種類數(shù)粟关,有兩處,另外一個(gè)很重要的參數(shù)每一個(gè)[yolo]層前面的filters=(種類數(shù)+5)3,有兩處,例如如果有4類环戈,則filters=(4+5)3=27,5類:filters=(5+5)*3=30
[convolutional]
size=1
stride=1
pad=1
filters=27
activation=linear
[yolo]
mask = 3,4,5
anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319
classes=4
num=6
...........
[convolutional]
size=1
stride=1
pad=1
filters=27
activation=linear
[yolo]
mask = 0,1,2
anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319
classes=4
num=6
............
4.創(chuàng)建.data .name 文件
在darknet\build\darknet\x64\data目錄下創(chuàng)建FOV_obj.data文件(文件名隨便取),寫(xiě)入內(nèi)容
classes= 4
train = data/train.txt
valid = data/test.txt
names = data/FOV_obj.names
backup = backup/
創(chuàng)建FOV_obj.name文件寫(xiě)入以下內(nèi)容
0
1
2
3
創(chuàng)建train.txt文件寫(xiě)入你想要訓(xùn)練的圖片
data/obj/FOV_0000.jpg
data/obj/FOV_0001.jpg
data/obj/FOV_0002.jpg
data/obj/FOV_0003.jpg
data/obj/FOV_0004.jpg
..............
創(chuàng)建test.txt文件寫(xiě)入
data/obj/FOV_0065.jpg
data/obj/FOV_0066.jpg
data/obj/FOV_0067.jpg
data/obj/FOV_0068.jpg
.............
python代碼
#train.txt
txt_ = r"D:\mydoc\ML\yolo\darknet\build\darknet\x64\data\train.txt"
with open(txt_,'a+') as f:
for i in range(60):
item = "data/obj/"+"FOV_{}.jpg".format(str(i).zfill(4))
f.write(item)
f.write("\n")
#test.txt
txt_ = r"D:\mydoc\ML\yolo\darknet\build\darknet\x64\data\test.txt"
with open(txt_,'a+') as f:
for i in range(60,69):
item = "data/obj/"+"FOV_{}.jpg".format(str(i).zfill(4))
f.write(item)
f.write("\n")
最后的文件如下
5. 下載yolo預(yù)訓(xùn)練模型
https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.conv.29
放入darknet\build\darknet\x64目錄下
6.train
打開(kāi)cmd進(jìn)入darknet.exe所在目錄
輸入
darknet.exe detector train data/FOV_obj.data cfg/yolov4-tiny-obj.cfg yolov4-tiny.conv.29 29
可以看到訓(xùn)練損失開(kāi)始很大闷板,在訓(xùn)練200-300個(gè)batch時(shí)下降到3點(diǎn)幾,并在此處震蕩院塞,另外每訓(xùn)練1000個(gè)batch會(huì)保存一次模型遮晚。模型權(quán)值保存在darknet\build\darknet\x64\backup目錄下,某次訓(xùn)練中斷了拦止,想要接著上一次的訓(xùn)練過(guò)程繼續(xù)的話也很方便县遣,輸入:
darknet.exe detector train data/FOV_obj.data cfg/yolov4-tiny-obj.cfg backup\yolov4-tiny-obj_last.weights
7.demo test
使用剛剛訓(xùn)練的模型權(quán)重做測(cè)試
darknet.exe detector test data/FOV_obj.data cfg/yolov4-tiny-obj.cfg backup\yolov4-tiny-obj_1000.weights
在Enter Image path:處填入圖片路徑(eg:data/test.jpg)
OK,至此基本訓(xùn)練流程走完糜颠,剩下的就是提升網(wǎng)絡(luò)性能了。
訓(xùn)練過(guò)程的一點(diǎn)總結(jié)
- 在yolov4-tiny-obj.cfg配置中圖片的高度和寬度應(yīng)該能被32整除萧求,用其他高寬也能訓(xùn)練其兴,但是會(huì)出現(xiàn)比較大的震蕩,test測(cè)試的時(shí)候找不到目標(biāo)夸政,或者是有一層的輸入不匹配(圖像輸入0x0x0)元旬。
- 訓(xùn)練yolov4完整框架,用yolov4.conv.137預(yù)訓(xùn)練權(quán)重秒梳,圖像尺寸大一點(diǎn)常常會(huì)導(dǎo)致GPU out of memory法绵,解決方法是在.cfg文件中提高subdivisions=4(或者8箕速、16酪碘、32、64)盐茎,另外就是改輸入的尺寸width height兴垦。參考https://www.ccoderun.ca/programming/2020-09-25_Darknet_FAQ/#cuda_out_of_memory
-
網(wǎng)絡(luò)會(huì)把尺寸*1.4,例如在.cfg文件中設(shè)置width=1024,height=768,image.png
-
yolov4完整版的配置和yolov4-tiny版配置差不多字柠,就是改width,height,classes,yolo層前面卷積層的filters(classes,filters有三處需要改探越,因?yàn)樗腥齻€(gè)yolo層)。改用yolov4完整模型訓(xùn)練自己的數(shù)據(jù)集效果出乎意料窑业,非常好钦幔。130多張圖片,因?yàn)閱螐垐D片太大提高了subdivisions常柄,用quadro M4000 GPU訓(xùn)練了一個(gè)白天加一個(gè)晚上再加一個(gè)早上鲤氢。
image.png
-
使用python darknet_images.py,希望輸出prediction 時(shí),需要先編譯yolo_cpp_dll.dll和yolo_cpp_dll_nogpu.dll,我兩個(gè)都直接編譯完成沒(méi)報(bào)任何錯(cuò)誤西潘,但是用的時(shí)候出現(xiàn)這個(gè)問(wèn)題
image.png