1. yolo v2很多文件和v1不一样,而且迭代了很多个版,网上现有的V2教程里的src/yolo_kernels.cu已经没有了,这一步改动不用管
2. 教程:http://blog.csdn.net/hysteric314/article/details/54097845(记得修改完要重新make)
3.有关于测试阈值改动、中间参数可视化(不能直接用,因为中间参数格式变了)的教程:
http://blog.csdn.net/hrsstudy/article/details/65644517?utm_source=itdadao&utm_medium=referral
4. 为了让YOLO v2能像训练VOC数据集一样训练自己的数据集,需要对代码进行以下三个方面的修改: (我在svt数据集上做图像文本检测,是1类text)
一:修改分类的个数:在代码中,默认VOC数据集是20类,而我要改成1类。
二:准备txt文档:VOC训练数据集中会自带几个txt文档,用来指明文件名或者路径地址,而如果你使用你自己的数据可能就需要自己生成这些文档。
三:修改代码中路径信息,把代码中VOC训练数据集的路径改成自己训练数据集的路径
5. 把20类改成1类
1) cfg/voc.data文件中:
classes 改成1。
names=data/svt.names。
svt.names这一个文件要存在于darknet目录下的data文件夹里,创建一个svt.names,加上内容,当然名字和路径都可以自己定义。这个文件中的行数要和类数一致,每一行都是一个类别的名字。比如我的这一文件中就只有一行数据:“text”。这个文件在测试你训练的model的时候会用到,系统会在图片上画出bounding box,bounding box上面的文字,也就是这个框中物体的名字,应该就来自这个文件。
2) cfg/yolo_voc.cfg文件中 :
【region】层中 classes 改成1。
【region】层上方第一个【convolution】层,其中的filters值要进行修改,改成(classes+ coords+ 1)* (NUM) ,我的情况中:(1+4+1)* 5=30,我把filters 的值改成了30。
3) src/yolo.c文件中 :
位置大约第14行左右改成:char *voc_names={“text”},原来里面有20类的名字,我改成了唯一1类的名字。
位置大约第328行左右,修改draw_detection这个函数最后一个参数:20改成1。这个函数用于把系统检测出的框给画出来,并把画完框的图片传回第一个参数im中,用于保存和显示。
位置大约第361行左右,demo函数中,倒数第三个参数把20改成了1。
scripts/voc_label.py 文件中 :
这里我不是用作者的代码,因为当时v1的这个文件跑不出来,所以找了另外的
# -*- coding: utf-8 -*-
import os
l=["text"]
for word in l:
os.system("convert -fill black -background white -bordercolor white -border 4 -font /usr/share/fonts/truetype/arphic/ukai.ttc -pointsize 18 label:\"%s\" \"%s.png\""%(word, word))
6. 数据格式转换(准备txt文档)
一共需要准备四种txt格式文档,分别是记录训练集和测试集的坐标和路径的annotation文件和list文件。
1) 每张图片一个annotation,但是存放路径和V1不同。
V1:需要的是labels的.png文件名称和放图片的文件夹以及放annotation的文件夹名称对应。至于annotation生成之后放在哪里,事实上路径是默认在train.txt的路径其中的JPEGImages改成labels,路径的其余部分不变。
V2:labels的.png文件名称就是和类别名称一样,测试集和训练集分别放在两个文件夹(不知是否也适用于多类),通过2) 中的list文件来指明每张图片的完整路径,那么每张图片annotation的txt文件放在哪呢?
因为在训练集中,一个图片文件和这一图片文件对应标记文件,他们俩除了后缀名之外其余的名称是一样的,所以src/yolo.c中有以下语句:
find_replace(path, "dout", "labels", labelpath);
find_replace(labelpath, "JPEGImages", "labels", labelpath);
find_replace(labelpath, ".jpg", ".txt", labelpath);
find_replace(labelpath, ".JPEG", ".txt", labelpath);
函数会找到路径中的图片后缀名.jpg,自动替换成.txt,所以只需要把这些txt格式的标记文件复制到图片所在的目录下即可。系统根据替换后的路径地址来读取对应标记文件。
2) 所有训练图片一个路径list,测试集也是一个list文件。下面会说明如何在代码中修改路径信息,指向这两个文件。
7. 修改路径
1) cfg/voc.data文件中:
train = /home/pjreddie/data/voc/train.txt //修改为训练list的路径
valid = /home/pjreddie/data/voc/2007_test.txt /*修改为测试list的路径,因为test不能返回评价指标,valid才行*/
backup = backup /* 这个路径是YOLO用于备份的,在训练过程中YOLO会不断地对产生的weights文件进行备份,darknet目录下就自带一个backup文件夹,这个路径指向那里。这里建议修改为自己的路径 */
2) src/yolo.c 文件中:
train_yolo函数中:
char *train_images = "/data/voc/train.txt"; //修改为训练list的路径
char *backup_directory = "/home/pjreddie/backup/"; //修改为上面的backup路径
validate_yolo函数中:
char *base = "results/comp4_det_test_"; /*可以修改自己的路径,comp4_det_test_[类名].txt用于保存valid命令的测试结果*/
list *plist = get_paths("/home/pjreddie/data/voc/2007_test.txt");//修改为测试list的路径
validate_yolo_recall函数中:
char *base = "results/comp4_det_test_"; //可以修改自己的路径
list *plist = get_paths("data/voc.2007.test"); //修改为测试list的路径
char *train_images = option_find_str(options, "train", "data/train.list"); //修改为训练list的路径
char *backup_directory = option_find_str(options, "backup", "/backup/"); //修改为自己的backup路径
validate_detector_flip函数中:
char *valid_images = option_find_str(options, "valid", "data/train.list"); //修改为测试list路径,该函数对应的测试命令为valid2
validate_detector函数中:
char *valid_images = option_find_str(options, "valid", "data/train.list"); /*修改为测试list路径,该函数对应的测试命令为valid*/
validate_detector_recall函数中:
list *plist = get_paths("data/voc.2007.test"); //修改成测试list路径
8. 调整评价指标
src/detector.c 文件中:
1) 修改评估阈值
评估模型可以使用命令valid或recall
修改valid2阈值(默认.005),validate_detector_flip函数中:
float thresh = .005; //修改为需要的阈值如.1
修改valid阈值(默认.005),validate_detector函数中:
float thresh = .005; //修改为需要的阈值如.1
修改recall阈值(默认为.001),validate_detector_recall函数中:
float thresh = .001; // 修改为需要的阈值如.25
2) 增加返回precision指标并注明指标名称
//fprintf(stderr, "%5d %5d %5d\tRPs/Img: %.2f\tIOU: %.2f%%\tRecall:%.2f%%\n", i, correct, total, (float)proposals/(i+1), avg_iou*100/total, 100.*correct/total);
fprintf(stderr, "ID:%5d Correct:%5d Total:%5d\tRPs/Img: %.2f\tIOU: %.2f%%\tRecall:%.2f%%\t", i, correct, total, (float)proposals/(i+1), avg_iou*100/total, 100.*correct/total);
fprintf(stderr, "proposals:%5d\tPrecision:%.2f%%\n",proposals,100.*correct/(float)proposals);
//评价指标都是累积的,而不是单张图片的
9. 修改完上面所有之后,就可以开始训练啦,最重要的别忘了先重新make:
make clean
make -j16
否则框不出东西别怪我哈哈哈,当然忘了重新make训练出来的权重是不受影响的
训练命令:
./darknet detector train cfg/voc.data cfg/yolo-voc.cfg darknet19_448.conv.23 | tee ./svt_train_log.txt
一般我都用| tee [路径+文件名] (后面加上-a是续写)命令,或者ls -l >[路径+文件名] (>>[路径+文件名]则是续写)命令,来导出中间过程,一方面备份方便查看,另一方面可以根据中间参数画出图表来分析,第2点的教程里有共享可视化中间参数的代码,但是不能直接用,因为中间参数格式变了
10. 测试并返回评价指标
1) ./darknet detector test cfg/voc.data cfg/yolo-voc.cfg ./svt/backup/yolo-voc_final.weights
/*不现实评价指标,输入图片路径,只显示框好后的图片和类别、置信率*/
2) ./darknet detector valid cfg/voc.data cfg/yolo-voc.cfg backup/yolo-voc_final.weights
/*在终端只返回用时,在./results/comp4_det_test_[类名].txt里保存测试结果*/
3) ./darknet detector recall cfg/voc.data cfg/yolo-voc.cfg backup/yolo-voc_final.weights
/*依次ID:图片序号从0开始,correct:累计检测正确的总框数,total:累计的总ground truth数,RPs/Img: 累计的总proposals/已检测图片数,IOU,Recall: correct / total,proposals:累计的总框数,Precision: correct / proposals*/