darknet yolov2 训练自己的数据集


ubuntu14.04+opencv2.4.10+cuda7.5+cudnn5.0

训练集:20张图片 00001.jpg-00020.jpg           测试集:5张图片 00021.jpg-00025.jpg

其中,训练集中18张用于Train,2张用于Validation。

分类个数6个


一、生成xml,使用工具https://github.com/tzutalin/labelImg

二、生成txt文件

1. 在darknet文件夹中

新建文件夹mytrain

在mytrain文件夹中

将scripts/voc_label.py复制到该文件夹中

新建文件夹JPEGImages,将训练集中20张图片放入该文件夹中

新建文件夹Annotations,将训练集中20张图片对应的xml文件放入该文件夹中

新建文件夹ImageSets,将create_list.py生成的train.txt和val.txt存放在该文件夹中

新建文件夹labels,用于存放每张图片生成的txt

新建文件create_list.py

2.生成train.txt和val.txt

脚本create_list.py如下:

import os
from os import listdir, getcwd
from os.path import join
if __name__ == '__main__':
    source_folder='JPEGImages/'
    dest='ImageSets/Main/train.txt'
    dest2='ImageSets/Main/val.txt'
    file_list=os.listdir(source_folder)
    train_file=open(dest,'a')
    val_file=open(dest2,'a')
    for file_obj in file_list:
        file_path=os.path.join(source_folder,file_obj) 
        file_name,file_extend=os.path.splitext(file_obj)
        file_num=int(file_name)
        if(file_num<19):
            train_file.write(file_name+'\n')
        else :
            val_file.write(file_name+'\n')
    train_file.close()
    val_file.close()

3.生成每张图片的txt文件以及Trian和Validation的路径分别存放在mytrain/train.txt和mytrain/val.txt

脚本voc_label.py修改如下:

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join

classes = ["chariot","bike","box","bag","car","person"]


def convert(size, box):
    dw = 1./size[0]
    dh = 1./size[1]
    x = (box[0] + box[1])/2.0
    y = (box[2] + box[3])/2.0
    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(image_id):
    in_file = open('Annotations/%s.xml'%(image_id))
    out_file = open('labels/%s.txt'%(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()

if not os.path.exists('labels/'):
    os.makedirs('labels/')
image_ids = open('ImageSets/Main/train.txt').read().strip().split()
list_file = open('train.txt', 'w')
#image_ids = open('ImageSets/Main/val.txt').read().strip().split()
#list_file = open('val.txt', 'w')
for image_id in image_ids:
    list_file.write('%s/JPEGImages/%s.jpg\n'%(wd,image_id))
    convert_annotation(image_id)
list_file.close()

更改注释,分别运行两次,生成mytrain/train.txt和mytrain/val.txt

三、修改文件

1.cfg/voc.data中

classes改为分类的个数6
train  改为 /home/ndd/darknet/mytrain/train.txt
valid 改为 /home/ndd/darknet/mytrain/val.txt
names 改为 data/chariot.names
backup 改为  /home/ndd/darknet/backup

2.cfg/yolo-voc.cfg(tiny-yolo-voc.cfg)中

【region】层classes改为分类的个数6

【region】层上一个【convolution】层中filters改为(classes+ coords+ 1)* (NUM)=(6+4+1)×5=55

3.src/yolo.c中

char *voc_names[] = {"chariot","car","bike","bag","box","person"};//分类的名称
draw_detections(im, l.side*l.side*l.n, thresh, boxes, probs, voc_names, alphabet, 6);//20改为6

else if(0==strcmp(argv[2], "demo")) demo(cfg, weights, thresh, cam_index, filename, voc_names, 6, frame_skip, prefix, .5);//20改为6

train_yolo函数中:
char *train_images = "/home/ndd/darknet/mytrain/train.txt";
char *backup_directory = "/home/ndd/darknet/backup/";

validate_yolo函数中:

char *base = "/home/ndd/darknet/results/comp4_det_test_";
list *plist = get_paths("/home/ndd/darknet/mytrain/val.txt");

validate_yolo_recall函数中:

char *base = "/home/ndd/darknet/results/comp4_det_test_";
list *plist = get_paths("/home/ndd/darknet/mytrain/val.txt");

src/detector.c 文件中validate_detector_recall函数中:

list *plist = get_paths("/home/ndd/darknet/mytrain/val.txt");

四、编译

1.Makefile修改

GPU=1
CUDNN=1
OPENCV=1
DEBUG=0


NVCC=/usr/local/cuda-7.5/bin/nvcc


2. 在darknet/下运行

    make clean

    make

生成darknet.exe

五、训练

1.下载预训练模型darknet19_448.conv.23放在darknet目录下

2.运行./darknet detector train cfg/voc.data cfg/yolo-voc.cfg darknet19_448.conv.23

3.最大迭代次数在yolo-voc.cfg中max_matches修改

六、评估性能

1.detector.c中validate_detector_recall函数中修改阈值thresh

默认的值是.001,这个默认值设的很小,会让系统识别出更多的框来,导致proposals值激增,还会让recall值变高,达到98.5%。(最终我改成了 .25。)


上面的函数只会显示出recall值,没有precision值,precision的值计算方法是:识别为正确的个数/画了多少个框,所以我修改了代码。我把第447行显示结果的代码修改为 :

我运行后显示的结果是:
…..
ID: 101 Correct: 106 Total: 111 RPs/Img: 1.07 IOU: 82.00% Recall:95.50% proposals: 109 Precision:97.25%
ID: 102 Correct: 107 Total: 112 RPs/Img: 1.07 IOU: 82.11% Recall:95.54% proposals: 110 Precision:97.27%

结果中的参数,我的理解是:

Correct :可以理解为正确地画了多少个框,遍历每张图片的Ground Truth,网络会预测出很多的框,对每一Groud Truth框与所有预测出的框计算IoU,在所有IoU中找一个最大值,如果最大值超过一个预设的阈值,则correct加一。

Total:一共有多少个Groud Truth框。

Rps/img:p 代表proposals, r 代表region。 意思就是平均下来每个图片会有预测出多少个框。预测框的决定条件是,预测某一类的概率大于阈值。在validation_yolo_recall函数中,默认的这一个阈值是0.001,这一阈值设置的比较低,这就会导致会预测出很多个框,但是这样做是可以提升recall的值,一般yolo用于画框的默认值是.25,使用这个阈值会让画出来的框比较准确。而validation_yolo_recall使用的阈值改成。25的时候,Rps/img 值会降低,recall的值会降低,所以validation_yolo_recall默认使用一个较低的阈值,有可能作者的目的就是为了提高recall值,想在某种程度上体现网络的识别精度比较高。

IoU、Recall、Precision:解释起来比较麻烦,请看博客有详细说明:
http://blog.csdn.net/hysteric314/article/details/54093734


2.运行

./darknet detector recall cfg/voc.data cfg/yolo-voc.cfg backup/yolo_voc_final.weights

(.weights为自己训练好的weights)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值