前言:本文是講的是如何配置pytorch版本的yolov3、數(shù)據(jù)集處理樱蛤、常用的命令等內(nèi)容壮莹。該庫(kù)的數(shù)據(jù)集格式既不是VOC2007格式也不是MS COCO的格式,而是一種新的格式荣德,跟著文章一步一步來闷煤,很簡(jiǎn)單。另外我們公眾號(hào)針對(duì)VOC2007格式數(shù)據(jù)集轉(zhuǎn)化為本庫(kù)所需要格式特意開發(fā)了一個(gè)簡(jiǎn)單的數(shù)據(jù)處理庫(kù)涮瞻。
1. 環(huán)境搭建
- 將github庫(kù)download下來鲤拿。
git clone https://github.com/ultralytics/yolov3.git
- 建議在linux環(huán)境下使用anaconda進(jìn)行搭建
conda create -n yolov3 python=3.7
- 安裝需要的軟件
pip install -r requirements.txt
環(huán)境要求:
- python >= 3.7
- pytorch >= 1.1
- numpy
- tqdm
- opencv-python
其中只需要注意pytorch的安裝:
到https://pytorch.org/
中根據(jù)操作系統(tǒng),python版本署咽,cuda版本等選擇命令即可近顷。
2. 數(shù)據(jù)集構(gòu)建
1. xml文件生成需要Labelimg軟件
在Windows下使用LabelImg軟件進(jìn)行標(biāo)注:
- 使用快捷鍵:
Ctrl + u 加載目錄中的所有圖像,鼠標(biāo)點(diǎn)擊Open dir同功能
Ctrl + r 更改默認(rèn)注釋目標(biāo)目錄(xml文件保存的地址)
Ctrl + s 保存
Ctrl + d 復(fù)制當(dāng)前標(biāo)簽和矩形框
space 將當(dāng)前圖像標(biāo)記為已驗(yàn)證
w 創(chuàng)建一個(gè)矩形框
d 下一張圖片
a 上一張圖片
del 刪除選定的矩形框
Ctrl++ 放大
Ctrl-- 縮小
↑→↓← 鍵盤箭頭移動(dòng)選定的矩形框
2. VOC2007 數(shù)據(jù)集格式
-data
- VOCdevkit2007
- VOC2007
- Annotations (標(biāo)簽XML文件,用對(duì)應(yīng)的圖片處理工具人工生成的)
- ImageSets (生成的方法是用sh或者M(jìn)ATLAB語言生成)
- Main
- test.txt
- train.txt
- trainval.txt
- val.txt
- JPEGImages(原始文件)
- labels (xml文件對(duì)應(yīng)的txt文件)
通過以上軟件主要構(gòu)造好JPEGImages和Annotations文件夾中內(nèi)容,Main文件夾中的txt文件可以通過以下python腳本生成:
import os
import random
trainval_percent = 0.9
train_percent = 1
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()
接下來生成labels文件夾中的txt文件幕庐,voc_label.py文件具體內(nèi)容如下:
# -*- coding: utf-8 -*-
"""
Created on Tue Oct 2 11:42:13 2018
將本文件放到VOC2007目錄下久锥,然后就可以直接運(yùn)行
需要修改的地方:
1. sets中替換為自己的數(shù)據(jù)集
2. classes中替換為自己的類別
3. 將本文件放到VOC2007目錄下
4. 直接開始運(yùn)行
"""
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
sets=[('2007', 'train'), ('2007', 'val'), ('2007', 'test')] #替換為自己的數(shù)據(jù)集
classes = ["person"] #修改為自己的類別
#進(jìn)行歸一化
def convert(size, box):
dw = 1./(size[0])
dh = 1./(size[1])
x = (box[0] + box[1])/2.0 - 1
y = (box[2] + box[3])/2.0 - 1
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(year, image_id):
in_file = open('VOC%s/Annotations/%s.xml'%(year, image_id)) #將數(shù)據(jù)集放于當(dāng)前目錄下
out_file = open('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').text
cls = obj.find('name').text
if cls not in classes or int(difficult)==1:
continue
cls_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('VOC%s/labels/'%(year)):
os.makedirs('VOC%s/labels/'%(year))
image_ids = open('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('VOC%s/JPEGImages/%s.jpg\n'%(year, image_id))
convert_annotation(year, image_id)
list_file.close()
到底為止,VOC格式數(shù)據(jù)集構(gòu)造完畢异剥,但是還需要繼續(xù)構(gòu)造符合darknet格式的數(shù)據(jù)集(coco)瑟由。
需要說明的是:如果打算使用coco評(píng)價(jià)標(biāo)準(zhǔn),需要構(gòu)造coco中json格式冤寿,如果要求不高歹苦,只需要VOC格式即可,使用作者寫的mAP計(jì)算程序即可督怜。
3. 創(chuàng)建*.names file,
其中保存的是你的所有的類別殴瘦,每行一個(gè)類別,如data/coco.names:
person
4. 更新data/coco.data,其中保存的是很多配置信息
classes = 1 # 改成你的數(shù)據(jù)集的類別個(gè)數(shù)
train = ./data/2007_train.txt # 通過voc_label.py文件生成的txt文件
valid = ./data/2007_test.txt # 通過voc_label.py文件生成的txt文件
names = data/coco.names # 記錄類別
backup = backup/ # 在本庫(kù)中沒有用到
eval = coco # 選擇map計(jì)算方式
5. 更新cfg文件号杠,修改類別相關(guān)信息
打開cfg文件夾下的yolov3.cfg文件蚪腋,大體而言,cfg文件記錄的是整個(gè)網(wǎng)絡(luò)的結(jié)構(gòu)姨蟋,是核心部分屉凯,具體內(nèi)容講解請(qǐng)參考之前的文章:【從零開始學(xué)習(xí)YOLOv3】1. YOLOv3的cfg文件解析與總結(jié)
只需要更改每個(gè)[yolo]層前邊卷積層的filter個(gè)數(shù)即可:
每一個(gè)[region/yolo]層前的最后一個(gè)卷積層中的 filters=預(yù)測(cè)框的個(gè)數(shù)(mask對(duì)應(yīng)的個(gè)數(shù),比如mask=0,1,2, 代表使用了anchors中的前三對(duì)眼溶,這里預(yù)測(cè)框個(gè)數(shù)就應(yīng)該是3*(classes+5) ,5的意義是5個(gè)坐標(biāo)(論文中的tx,ty,tw,th,po)悠砚,3的意義就是用了3個(gè)anchor。
舉個(gè)例子:假如我有三個(gè)類堂飞,n = 3, 那么filter = 3 × (n+5) = 24
[convolutional]
size=1
stride=1
pad=1
filters=255 # 改為 24
activation=linear
[yolo]
mask = 6,7,8
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
classes=80 # 改為 3
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1
6. 數(shù)據(jù)集格式說明
- yolov3
- data
- 2007_train.txt
- 2007_test.txt
- coco.names
- coco.data
- annotations(json files)
- images(將2007_train.txt中的圖片放到train2014文件夾中灌旧,test同理)
- train2014
- 0001.jpg
- 0002.jpg
- val2014
- 0003.jpg
- 0004.jpg
- labels(voc_labels.py生成的內(nèi)容需要重新組織一下)
- train2014
- 0001.txt
- 0002.txt
- val2014
- 0003.txt
- 0004.txt
- samples(存放待測(cè)試圖片)
2007_train.txt內(nèi)容示例:
/home/dpj/yolov3-master/data/images/val2014/Cow_1192.jpg
/home/dpj/yolov3-master/data/images/val2014/Cow_1196.jpg
.....
注意images和labels文件架構(gòu)一致性,因?yàn)閠xt是通過簡(jiǎn)單的替換得到的:
images -> labels
.jpg -> .txt
具體內(nèi)容可以在datasets.py文件中找到詳細(xì)的替換绰筛。
3. 訓(xùn)練模型
預(yù)訓(xùn)練模型:
- Darknet
*.weights
format:https://pjreddie.com/media/files/yolov3.weights
- PyTorch
*.pt
format:https://drive.google.com/drive/folders/1uxgUBemJVw9wZsdpboYbzUN4bcRhsuAI
開始訓(xùn)練:
python train.py --data data/coco.data --cfg cfg/yolov3.cfg
如果日志正常輸出那證明可以運(yùn)行了
如果中斷了枢泰,可以恢復(fù)訓(xùn)練
python train.py --data data/coco.data --cfg cfg/yolov3.cfg --resume
4. 測(cè)試模型
將待測(cè)試圖片放到data/samples中,然后運(yùn)行
python detect.py --cfg cfg/yolov3.cfg --weights weights/best.pt
目前該文件中也可以放入視頻進(jìn)行視頻目標(biāo)檢測(cè)铝噩。
- Image:
--source file.jpg
- Video:
--source file.mp4
- Directory:
--source dir/
- Webcam:
--source 0
- RTSP stream:
--source rtsp://170.93.143.139/rtplive/470011e600ef003a004ee33696235daa
- HTTP stream:
--source http://wmccpinetop.axiscam.net/mjpg/video.mjpg
5. 評(píng)估模型
python test.py --weights weights/best.pt
如果使用cocoAPI使用以下命令:
$ python3 test.py --img-size 608 --iou-thr 0.6 --weights ultralytics68.pt --cfg yolov3-spp.cfg
Namespace(batch_size=32, cfg='yolov3-spp.cfg', conf_thres=0.001, data='data/coco2014.data', device='', img_size=608, iou_thres=0.6, save_json=True, task='test', weights='ultralytics68.pt')
Using CUDA device0 _CudaDeviceProperties(name='Tesla V100-SXM2-16GB', total_memory=16130MB)
Class Images Targets P R mAP@0.5 F1: 100% 157/157 [03:30<00:00, 1.16it/s]
all 5e+03 3.51e+04 0.0353 0.891 0.606 0.0673
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.409
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.615
Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.437
Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.242
Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.448
Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.519
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.337
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.557
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.612
Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.438
Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.658
Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.746
mAP計(jì)算
- mAP@0.5 run at
--iou-thr 0.5
, mAP@0.5...0.95 run at--iou-thr 0.7
6. 可視化
可以使用python -c from utils import utils;utils.plot_results()
創(chuàng)建drawLog.py
def plot_results():
# Plot YOLO training results file 'results.txt'
import glob
import numpy as np
import matplotlib.pyplot as plt
#import os; os.system('rm -rf results.txt && wget https://storage.googleapis.com/ultralytics/results_v1_0.txt')
plt.figure(figsize=(16, 8))
s = ['X', 'Y', 'Width', 'Height', 'Objectness', 'Classification', 'Total Loss', 'Precision', 'Recall', 'mAP']
files = sorted(glob.glob('results.txt'))
for f in files:
results = np.loadtxt(f, usecols=[2, 3, 4, 5, 6, 7, 8, 17, 18, 16]).T # column 16 is mAP
n = results.shape[1]
for i in range(10):
plt.subplot(2, 5, i + 1)
plt.plot(range(1, n), results[i, 1:], marker='.', label=f)
plt.title(s[i])
if i == 0:
plt.legend()
plt.savefig('./plot.png')
if __name__ == "__main__":
plot_results()
7. 數(shù)據(jù)集配套代碼
如果你看到這里了宗苍,恭喜你,你可以避開以上略顯復(fù)雜的數(shù)據(jù)處理薄榛。我們提供了一套代碼讳窟,集成了以上腳本,只需要你有jpg圖片和對(duì)應(yīng)的xml文件敞恋,就可以直接生成符合要求的數(shù)據(jù)集丽啡,然后按照要求修改一些代碼即可。
代碼地址:https://github.com/pprp/voc2007_for_yolo_torch
請(qǐng)按照readme中進(jìn)行處理就可以得到數(shù)據(jù)集硬猫。
后記:這套代碼一直由一個(gè)外國(guó)的團(tuán)隊(duì)進(jìn)行維護(hù)补箍,也添加了很多新的trick改执。目前已獲得了3.3k個(gè)star,1k fork坑雅。不僅如此辈挂,其團(tuán)隊(duì)會(huì)經(jīng)常回復(fù)issue裹粤,目前也有接近1k的issue终蒂。只要處理過一遍數(shù)據(jù),就會(huì)了解到這個(gè)庫(kù)的亮點(diǎn)遥诉,非常容易配置拇泣,不需要進(jìn)行編譯等操作,易用性極強(qiáng)矮锈。再加上提供的配套數(shù)據(jù)處理代碼霉翔,在短短10多分鐘就可以配置好。(?ω?)
這是這個(gè)系列第二篇內(nèi)容苞笨,之后我們將對(duì)yolov3進(jìn)行代碼級(jí)別的學(xué)習(xí)债朵,也會(huì)學(xué)習(xí)一下這個(gè)庫(kù)提供的新的特性,比如說超參數(shù)金華瀑凝,權(quán)重采樣機(jī)制序芦、loss計(jì)算、Giou處理等猜丹。希望各位多多關(guān)注。
參考內(nèi)容:
官方代碼:https://github.com/ultralytics/yolov3
官方講解:https://github.com/ultralytics/yolov3/wiki/Train-Custom-Data
數(shù)據(jù)集配置庫(kù):https://github.com/pprp/voc2007_for_yolo_torch