美文网首页
Darknet && YOLO踩坑总结

Darknet && YOLO踩坑总结

作者: csuhan | 来源:发表于2019-09-25 10:36 被阅读0次

Introduction

As we all know,YOLO是一个one stage detector,其速度特别的快,且精度也较好。然而作者在实现YOLO时,硬核的使用C++编写了一个框架:Darknet,其除了包含Darknet、YOLO之外,还实现了一些基本的模型,如ResNet、DenseNet,RNN等,也包含了COCO、PASCAL VOC数据集的使用。更重要的是,Darknet依赖项少,可以通过编译后直接使用。

However!Darknet是C++编写的,与目前大多数框架都使用Python无法通用,虽然使用Darknet也很简单。。。

在此我将把在使用Darknet过程中遇到的一些问题记录下来。

自定义数据集

官方给出的数据集包含VOC和COCO,由于COCO数据集太庞大,目前仅测试过VOC数据集。
对于VOC数据集,其基本格式为:

VOC
要注意Annotaions包含每张影像的标注xml格式,JPEGImages包含了所有影像,ImageSets则记录了train、val、test的影像名称。
在使用Darknet提供的voc_label.py脚本时,其会在JPEGImages同级目录生成label文件夹,并为每一张影像生成一个txt文件,其格式为:
<object-class> <x> <y> <width> <height>
<object-class> <x> <y> <width> <height>
...
<object-class> <x> <y> <width> <height>

也就是将VOC的annotaion格式转换成Darknet的格式。

同样的在自定义数据集时,有一些问题要注意。
首先是数据目录的组织。由于Darknet支持VOC的数据格式,因此在定义数据集时,应至少包含JPEGImageslabels两个同级文件夹,在文件夹下,可以定义trainval等对应的子文件夹。如下图所示:

自定义数据集
在训练时,关于数据集其只需要一个配置文件如voc.data,格式如下:
classes= 20
train  = data/2007_train.txt
valid  = data/2007_val.txt
names = data/voc.names
backup = backup

也就是说其只需要train和val影像的位置,然后会自动的到与JPEGImages同级的labels寻找标签,如训练影像的路径为your_dataset/JPEGImages/train/demo1.jpg,那么它会到your_dataset/labels/train/demo1.txt寻找标签。

其次是标签的信息。在记录影像annotaion的txt里,其object-class是一个数字,其对应表要记录在一个文件中(如voc.nems),内容大致如下:

aeroplane
bicycle
bird
boat
bottle
bus
car
cat
chair
cow
diningtable
dog
horse
motorbike
person
pottedplant
sheep
sofa
train
tvmonitor

即每行记录一个类别,依次从0n

测试图片

当模型训练完成后,需要测试图片时,官方写的是可以用命令:./darknet detect cfg/yolov3.cfg weights/yolov3.weights data/dog.jpg来测试,然后解释到:./darknet detect中的detect是detector test 的简写。

但是请注意!这里的简写,其实是简写了detect test cfg/coco.data,而在测试时,我们需要用到coco.names,里面记录了从数字与类别的对应关系。

如果我们使用的是VOC数据集,或者是其他自定义数据集,一定要使用./darknet detector test cfg/yourdata.data cfg/your_confg.cfg yourimage.jpg这样的格式,不能将.data文件遗漏,否则将会采用默认的coco数据集标签。

自定义BDD100K数据集

BDD100K是一个新的自动驾驶数据集,是一个数据量更大,更广泛的数据集。在此我们将使用Darknet的YOLOv3模型训练BDD100k数据的过程记录下来。

  1. 文件目录格式。由于Darknet十分依赖VOC数据集的格式,因此我们在定义文件目录时可以这样:


    BDD100k原始数据组织格式
    适应Darknet的BDD100K数据组织格式
  2. 将BDD100K的annotations转换成Darknet的格式。

import os
import json

classes = ["car","person"]
classes_index = {"car":0,"person":1}

#convert absolute box to relative box
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)

#convert json annotation to darknet's format txt
def convert_json(in_file_path,out_file_path):
    with open(in_file_path) as f_in:
        info = json.load(f_in)
        objs = info['frames'][0]['objects']
        for obj in objs:
            if obj['category'] in classes:
                class_index = classes_index[obj['category']]
                bbox = convert((1280,720),[float(obj['box2d']['x1']),float(obj['box2d']['x2']),float(obj['box2d']['y1']),float(obj['box2d']['y2'])])
                with open(out_file_path,'w') as f_out:
                    f_out.write(str(class_index)+' '+str(bbox[0])+' '+str(bbox[1])+' '+str(bbox[2])+' '+str(bbox[3])+'\n')
                    return True
            else:
                return False

base_path = os.path.join(os.getcwd(),'bdd100k')
raw_label_path = os.path.join(base_path,'raw_labels')
label_path = os.path.join(base_path,'labels')

train_label_list = os.listdir(raw_label_path+'/train')
with open(base_path+'/bdd100k_train.txt','w') as f:
    for (i,label) in enumerate(train_label_list):
        has_obj = convert_json(raw_label_path+'/train/'+label,label_path+'/train/'+label.split('.')[0]+'.txt')
        if has_obj == True:
            f.write(base_path+'/JPEGImages/'+label.split('.')[0]+'.jpg\n')
    
val_label_list = os.listdir(raw_label_path+'/val')
with open(base_path+'/bdd100k_val.txt','w') as f:
    for (i,label) in enumerate(val_label_list):
        has_obj = convert_json(raw_label_path+'/val/'+label,label_path+'/val/'+label.split('.')[0]+'.txt')
        if has_obj == True:
            f.write(base_path+'/JPEGImages/'+label.split('.')[0]+'.jpg\n')
  1. bdd100k.names文件记录训练数据集的类别,每行代表一个类别
car
person
  1. bdd100k.data记录训练验证数据的信息
classes= 2
train  = data/bdd100k_train.txt
valid  = data/bdd100k_val.txt
names = data/bdd100k/bdd100k_car_person.names
backup = backup
  1. 修改yolo模型。只需要在三个yolo层上,将上一个卷积层的个数改为3 \times (classes + 5),将yolo层的num_class改为你的类别数。
  1. 训练。
./darknet detector train cfg/bdd100k.data cfg/yolov3-bdd100k.cfg weights/darknet53.conv.74 -gpus 1,2
  1. 测试。
./darknet detector test cfg/bdd100k.data cfg/yolov3-bdd100k.cfg backup/yolov3-bdd100k_final.weights data/your_test_img.jpg

相关文章

网友评论

      本文标题:Darknet && YOLO踩坑总结

      本文链接:https://www.haomeiwen.com/subject/trwyuctx.html