darknet训练自己的数据集

参考博客https://blog.csdn.net/lilai619/article/details/79695109

 

系统环境 Ubuntu 16.04

-1.在制作数据时最好先将所有图片重新命名,这样会方便后面数据集的制作,比如这次我演示的是只训练一个杯子(也就是训练一个类),那么我把所有的图片的名字都改为bottle_*.jpg。这可以自己写一个脚本去重命名。制作好后如下图darknet训练自己的数据集_第1张图片

 

0.先使用labelimg标注图片数据,把生成的xml文件放在同一个文件夹,比如名为xml

 

1.在自己喜欢的目录下新建一个文件夹,比如命名为voc_mybottle(因为自己要训练的数据是我的一个杯子)。在这个文件夹下新建一个名为images的文件(一定要是images,原因等下会说)。在新建一个叫labels的文件夹(一定要是labels)。把训练的所有图片放在images的文件夹中。(如第一张图)

2.为了方便我把images labels xml三个文件夹下,然后把下面这个python脚本放在同一个目录下然后执行,labels就会添加所有照片的labels.txt文件,和一个叫img_list.txt的文件,内容是所用图片的路径

darknet训练自己的数据集_第2张图片

#!/usr/bin/env python
# coding: utf-8

# In[3]:


import os

pre_path = os.getcwd()
print(pre_path)


# In[16]:


img_pre_path = pre_path + "/images"
print(img_pre_path)

IMG_txt = "img_list.txt"  
img_list = os.listdir(img_pre_path)

with open(IMG_txt, "w") as f:
    for index in img_list:
        img_path = img_pre_path + '/' + index
        print(img_path)
        f.write(img_path + '\n')
        
    


# In[39]:


import xml.etree.ElementTree as ET
xml_path = pre_path + '/xml'
label_pre_path = pre_path + '/labels'
xml_list = os.listdir(xml_path)
print(xml_path)
print(label_pre_path)
print(xml_list[3])
for index in xml_list:
    print(xml_path + '/' + index)


# In[41]:


classes = ["mybottle"]

def convert(size, box):
    print(size[0], size[1])
    dw = 1.0 / size[0]
    dh = 1.0 / 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_xml(in_path, out_path):
    in_file = open(in_path)
    out_file = open(out_path, '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)
    print("w,h", w, h)
    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')


for index in xml_list:
    xml_file_path = xml_path + '/' +  index
    # print(index.split('.')[0])
    lable_txt_path = pre_path + '/labels/' + index.split('.')[0] + '.txt'
    print("xml:" + xml_file_path)
    print("label" + lable_txt_path)
    convert_xml(xml_file_path, lable_txt_path)

里面的内容是这样的

0 0.571875 0.500925925925926 0.3979166666666667 0.5851851851851853

代表物体的分类编号和两个坐标的xy在图片中的归一化的值

3.执行下面两句指令,使图片分成两份数据,分别为train和test两个数据的图片路径,18是把头18张图片归为train,19以后的图片归为test,这里自行修改

cat img_list.txt | head -n 18 > train_list.txt
cat img_list.txt | tail -n +19 > test_list.txt
~                                                     

4.根据官网提示我们要制作一个xxx.data的文件,用来给程序传递参数的。

darknet训练自己的数据集_第3张图片

根据自己的需求建立

比如我的是voc_mybottle.data 内容为


classes = 1 # 训练一个类
train =/voc_mybottle/train_list.txt #path 自己电脑的路径
valid = /voc_mybottle/test_list.txt
names = /voc_mybottle/mybottle.names
backup = mybottle_backup      #自己在darknet下建立的mybottle_backup文件夹,用来放训练的模型


.names文件是用来存放分类的名字,在这里我只有一个mybottle的类,所以只有mybottle这行内容

5.修改关于训练的cfg文件,里面是关于网络的参数

因为这里我们用的是yolov3去训练voc格式数据,所以要修改darknet/cfg/yolov3-voc.cfg文件,为了方便我自己新创了一个mybottle_yolov3-voc.cfg文件。把yolov3-voc.cfg复制过来,改参数。主要改的参数是这些

darknet训练自己的数据集_第4张图片

按照需求改,这里可以去参考其他文章,这里不过多描述。

还有就是改网络结构,因为voc是有20个类,而我现在是只有一个类,所以要把网络调整。每个yolo层都有一个filter=75的参数(3*(num_class + 5)), 这里改成18(3×(1+5))。一共要改3处。

darknet训练自己的数据集_第5张图片

到这里数据就准备好了。

最后一部是下载预权重文件放在darknet文件夹下

wget https://pjreddie.com/media/files/darknet53.conv.74

安装官网训练的例子进行修改运行的参数

darknet训练自己的数据集_第6张图片

cfg/voc.data修改成自己创建的.data文件路径,cfg/yolov3-voc.cfg修改成自己创建的.cfg文件路径。执行就能训练了

运行界面

darknet训练自己的数据集_第7张图片

 

 

每默认100步保存一次模型,只保存十次模型,最后一次会被每次更新覆盖。

训练到此结束。


说一下我遇到的坑

在读取照片的时候遇到读取的labels中的文件不在images文件夹的问题。这很奇怪,于是我去找源码,发现一定要把图片的文件夹命名为images才能读取同一个目录下的labels文件夹中的文件

//data.c
void fill_truth_detection(char *path, int num_boxes, float *truth, int classes, int flip, float dx, float dy, float sx, float sy)
{
    char labelpath[4096];
    find_replace(path, "images", "labels", labelpath);
    find_replace(labelpath, "JPEGImages", "labels", labelpath);

    find_replace(labelpath, "raw", "labels", labelpath);
    find_replace(labelpath, ".jpg", ".txt", labelpath);
    find_replace(labelpath, ".png", ".txt", labelpath);
    find_replace(labelpath, ".JPG", ".txt", labelpath);
    find_replace(labelpath, ".JPEG", ".txt", labelpath);
    int count = 0;
    box_label *boxes = read_boxes(labelpath, &count);

第二个坑是训练好后,模型能识别物体,可是标签是错的

Loading weights from mybottle_backup/mybottle_yolov3-voc_200.weights...Done!
path/images/bottle_1.jpg: Predicted in 0.028537 seconds.
person: 89%
 

查了一下源码,发现原来是我用用了官网的测试图片的指令 detect 

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

 

// darknet.c
if (0 == strcmp(argv[1], "average")){
        average(argc, argv);
    } else if (0 == strcmp(argv[1], "yolo")){
        run_yolo(argc, argv);
    } else if (0 == strcmp(argv[1], "super")){
        run_super(argc, argv);
    } else if (0 == strcmp(argv[1], "lsd")){
        run_lsd(argc, argv);
    } else if (0 == strcmp(argv[1], "detector")){
        run_detector(argc, argv);
    } else if (0 == strcmp(argv[1], "detect")){
        float thresh = find_float_arg(argc, argv, "-thresh", .5);
        char *filename = (argc > 4) ? argv[4]: 0;
        char *outfile = find_char_arg(argc, argv, "-out", 0);
        int fullscreen = find_arg(argc, argv, "-fullscreen");
        test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, .5, outfile, fullscreen);
    } else if (0 == strcmp(argv[1], "cifar")){
        run_cifar(argc, argv);
    } else if (0 == strcmp(argv[1], "go")){
        run_go(argc, argv);
    } else if (0 == strcmp(argv[1], "rnn")){
        run_char_rnn(argc, argv);
    } else if (0 == strcmp(argv[1], "coco")){
        run_coco(argc, argv);

 

可以看到当使用detect参数时会使用coco.data,所以应该是调用了coco.data的数据,查看coco.data,第一个类果然是person。

于是换回测试的指令使用test参数,(文件路径是自己的路径)

./darknet detector test cfg/coco.data cfg/yolov3.cfg yolov3.weights data/dog.jpg

测试成功

(训练步数少,只是用来测试的,所以效果不好,别介意,哈哈哈哈)

darknet训练自己的数据集_第8张图片

但是这次以后只是用detect参数也回复正常了,不知道是什么原因。如果您知道,恳请赐教。 

你可能感兴趣的:(darknet训练自己的数据集)