从零开始带你一步一步使用YOLOv3训练自己的数据
紅色石頭的個(gè)人網(wǎng)站:redstonewill.com
 知乎:https://www.zhihu.com/people/red_stone_wl
 公眾號(hào):AI有道(redstonewill)
YOLOv3是比較常見和常用的深度學(xué)習(xí)目標(biāo)檢測(cè)(Object Dection)算法。今天給大家介紹一下如何一步一步使用YOLOv3訓(xùn)練自己的數(shù)據(jù)集。
一、標(biāo)注數(shù)據(jù)集
首先我們需要使用 labelimg 工具來標(biāo)注圖片數(shù)據(jù)集,例如圖片是 .jpg 格式的,用矩形框標(biāo)注圖片中的目標(biāo)位置,得到 .xml 文件。這里 labelimg 的使用方法就不作介紹了,讀者自行查閱。
例如 100 張圖片對(duì)應(yīng)得到 100 個(gè) .xml 文件:
得到 .jpg 和 .xml 文件之后,我們還需要把數(shù)據(jù)集整理成 VOC2007 規(guī)定的格式,方便我們使用 YOLOv3 進(jìn)行訓(xùn)練。
方法很簡(jiǎn)單,建立如下目錄層級(jí):
然后將 100 張 .jpg 圖片放入到 VOCdevkit/VOC2007/JPEGImages 目錄下,將 100 個(gè) .xml 文件放入到 VOCdevkit/VOC2007/Annotations 目錄下。
至此,數(shù)據(jù)集準(zhǔn)備完畢!
二、下載 YOLOv3 源碼
在我們的 Ubuntu 系統(tǒng)或者服務(wù)器上,使用 git 命令直接下載 YOLOv3 的源碼工程:
$ git clone https://github.com/pjreddie/darknet下載完成之后,進(jìn)入 darknet 目錄,會(huì)發(fā)現(xiàn)如下:
YOLOv3 使用的是開源的神經(jīng)網(wǎng)絡(luò)框架 Darknet53,有 CPU 和 GPU 兩種模式。默認(rèn)使用的是 CPU 模式,如果我們使用 GPU 的話,需要修改 darknet 目錄下的 Makefile 文件:
$ vim Makefile修改的幾點(diǎn)如下:
 修改的地方有 4 處。其中,第 1 處 GPU=1,CUDNN=1,表示使用 GPU 和 CUDNN,若使用 CPU 的話,置為 0 即可;第 2 處將 NVCC 設(shè)為本地安裝 nvcc 的實(shí)際目錄;第 3 處將 COMMON+ 設(shè)為本地 cuda 的頭文件目錄;第 4 處將 LDFLAGS+ 設(shè)為 cuda 的庫(kù)目錄。
Makeflie 文件修改完成之后,保存退出。
三、準(zhǔn)備數(shù)據(jù)
將我們之前準(zhǔn)備好的包含 100 張 .jpg 圖片和 100 個(gè) .xml 文件的 VOCdevkit 文件夾拷貝到 darknet 目錄下,替換原來的 VOCdevkit 文件夾。
進(jìn)入到 darknet/VOCdevkit/VOC2007/ 目錄下,新建 test.py 腳本,腳本內(nèi)容如下:
import os import randomtrainval_percent = 0.8 train_percent = 0.8 xmlfilepath = 'Annotations' txtsavepath = 'ImageSets\Main' total_xml = os.listdir(xmlfilepath)num = len(total_xml) list = range(num) tv = int(num * trainval_percent) tr = int(tv * train_percent) trainval = random.sample(list, tv) train = random.sample(trainval, tr)ftrainval = open('ImageSets/Main/trainval.txt', 'w') ftest = open('ImageSets/Main/test.txt', 'w') ftrain = open('ImageSets/Main/train.txt', 'w') fval = open('ImageSets/Main/val.txt', 'w')for i in list:name = total_xml[i][:-4] + '\n'if i in trainval:ftrainval.write(name)if i in train:ftrain.write(name)else:fval.write(name)else:ftest.write(name)ftrainval.close() ftrain.close() fval.close() ftest.close()該 test.py 腳本的作用就是對(duì) 100 個(gè)樣本進(jìn)行訓(xùn)練集和測(cè)試集的劃分,trainval_percent = 0.8 表示劃分 80% 的樣本作為訓(xùn)練集,20% 的樣本作為測(cè)試集。
在當(dāng)前目錄,運(yùn)行該腳本:
$python test.py運(yùn)行完之后,在 /ImageSets/Main/ 目錄下會(huì)生成 4 個(gè)文件:test.txt、train.txt、trainval.txt、val.txt。其中,trainval.txt 存放的是 80 個(gè)訓(xùn)練集的樣本名,test.txt 存放的是 20 個(gè)測(cè)試集的樣本名。
返回到 drknet 目錄下,新建 voc_label.py 腳本,也可以使用下面命令下載:
wget https://pjreddie.com/media/files/voc_label.pyvoc_label.py 腳本內(nèi)容如下:
import xml.etree.ElementTree as ET import pickle import os from os import listdir, getcwd from os.path import joinsets=[('2007', 'train'), ('2007', 'val'), ('2007', 'test')]classes = ["person", "car", "bicycle", "train"]def convert(size, box):dw = 1./size[0]dh = 1./size[1]x = (box[0] + box[1])/2.0y = (box[2] + box[3])/2.0w = box[1] - box[0]h = box[3] - box[2]x = x*dww = w*dwy = y*dhh = h*dhreturn (x,y,w,h)def convert_annotation(year, image_id):in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, 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').textcls = obj.find('name').textif cls not in classes or int(difficult) == 1:continuecls_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()for year, image_set in sets:if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)):os.makedirs('VOCdevkit/VOC%s/labels/'%(year))image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()list_file = open('%s_%s.txt'%(year, image_set), 'w')for image_id in image_ids:list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id))convert_annotation(year, image_id)list_file.close()該文件需要修改兩個(gè)地方,分別是 sets 和 classes,classes 根據(jù)實(shí)際的類別進(jìn)行修改。
修改完成之后,保存退出。在 darknet 目錄下,運(yùn)行該腳本:
$ python voc_label.py運(yùn)行之后,在當(dāng)前目錄下生成 3 個(gè)文件:2007_train.txt, 2007_val.txt, 2007_test.txt,存放的是訓(xùn)練集、測(cè)試集圖片的路徑。
運(yùn)行下面的命令:
$ cat 2007_train.txt 2007_val.txt > train.txt這樣,train.txt 即為真正的訓(xùn)練集圖片路徑,2007_test.txt 即為真正的測(cè)試集圖片路徑。
同時(shí),在 VOCdevkit/VOC2007 目錄下也會(huì)多生成一個(gè) labels 文件夾,labels 文件夾里存放的就是訓(xùn)練集每個(gè)圖片包含的類別、矩形框四個(gè)坐標(biāo)信息。這時(shí)候數(shù)據(jù)集正式完成。
四、修改配置文件
1. 修改 voc.data 文件
在 drknet 目錄下,打開 cfg/voc.data 文件,根據(jù)實(shí)際情況作如下修改:
其中,class 是類別,train 和 valid 是之前運(yùn)行 voc_label.py 得到的 train.txt 和 2007_test.txt。names 改為自己的實(shí)際路徑,backup 為模型存放的路徑。
2. 修改 voc.names 和 coco.names
在 darknet 目錄下,打開 data/voc.names 和 data/coco.names 文件,修改成自己的類別:
保存退出!
3. 修改 yolov3-voc.cfg
下面需要修改配置文件,打開 cfg/yolov3-voc.cfg,搜索 yolo, 總共會(huì)搜出 3 個(gè)含有 yolo 的地方。
 每個(gè)地方都必須要改 2 處:
參數(shù) filters 由下式計(jì)算:3*(5+classes),例如本例中 classs=4,則filters=27;
參數(shù) class 改為實(shí)際的類別個(gè)數(shù);
 yolov3-voc.cfg 文件中修改 filters 和 classes 的地方一共有 3 處,注意別遺漏了。
在 yolov3-voc.cfg 文件的開頭處,修改訓(xùn)練的一些參數(shù)
 一般根據(jù)具體情況作適當(dāng)修改即可,注意,訓(xùn)練的時(shí)候,Testing 的 batch 和 subdivisions 需要注釋掉,learning_rate 是學(xué)習(xí)率,max_batches 是最大迭代訓(xùn)練次數(shù),可根據(jù)訓(xùn)練集大小自行修改。
關(guān)于 yolov3-voc.cfg 中更詳細(xì)的參數(shù)解釋,可自行查閱。
五、編譯
剛才我們修改了 Makefile文件,并修改了各個(gè)配置文件,下面就對(duì)該工程進(jìn)行編譯,在 darknet 目錄下輸入下面的命令:
$ make編譯完成之后,生成 darknet 可執(zhí)行程序。
六、訓(xùn)練
在 darknet 目錄下,
首先下載 YOLOv3 的預(yù)訓(xùn)練模型:
$ wget https://pjreddie.com/media/files/darknet53.conv.74然后直接輸入下面的命令進(jìn)行訓(xùn)練:
$ ./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74 -gpus 0,1其中,-gpus 0,1 表示使用 2 塊 gpu 進(jìn)行訓(xùn)練,編號(hào)是 0 和 1。根據(jù)你可使用的 gpu 個(gè)數(shù)進(jìn)行調(diào)整。
當(dāng)看到上面的打印內(nèi)容,基本就表示訓(xùn)練開始了,慢慢等待吧~
關(guān)于 YOLOv3 詳細(xì)的訓(xùn)練步驟就介紹到這里,下一篇我將帶大家來學(xué)習(xí)一下使用 YOLOv3 訓(xùn)練好的模型進(jìn)行實(shí)際的圖片測(cè)試還有如何進(jìn)行批量測(cè)試~
總結(jié)
以上是生活随笔為你收集整理的从零开始带你一步一步使用YOLOv3训练自己的数据的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        