YOLOv3训练过程中重要参数的理解和输出参数的含义

原英文地址: https://timebutt.github.io/static/understanding-yolov2-training-output/

原中文翻译地址:https://blog.csdn.net/dcrmg/article/details/78565440

最近有人问起在YOLOv2训练过程中输出在终端的不同的参数分别代表什么含义,如何去理解这些参数?本篇文章中我将尝试着去回答这个有趣的问题。


刚好现在我正在训练一个YOLOv2模型,拿这个真实的例子来讨论再合适不过了,下边是我训练中使用的 .cfg 文件(你可以在cfg文件夹下找到它):




以下是训练过程中终端输出的一个截图:


以上截图显示了所有训练图片的一个批次(batch),批次大小的划分根据我们在 .cfg 文件中设置的subdivisions参数。在我使用的 .cfg 文件中 batch = 64 ,subdivision = 8,所以在训练输出中,训练迭代包含了8组,每组又包含了8张图片,跟设定的batch和subdivision的值一致。

(注: 也就是说每轮迭代会从所有训练集里随机抽取 batch = 64 个样本参与训练,所有这些 batch 个样本又被均分为 subdivision = 8 次送入网络参与训练,以减轻内存占用的压力)

批输出


针对上图中最后一行中的信息,我们来一步一步的分析。如下的输出是由 detector.c 生成的,具体代码见:点击打开链接


 

  • 9798: 指示当前训练的迭代次数
  • 0.370096: 是总体的Loss(损失)
  • 0.451929 avg: 是平均Loss,这个数值应该越低越好,一般来说,一旦这个数值低于0.060730 avg就可以终止训练了。
  • 0.001000 rate: 代表当前的学习率,是在.cfg文件中定义的。
  • 3.300000 seconds: 表示当前批次训练花费的总时间。
  • 627072 images: 这一行最后的这个数值是9798*64的大小,表示到目前为止,参与训练的图片的总量。

分块输出


在分析分块输出之前,我们得了解一下IOU(Intersection over Union,也被称为交并集之比:点击打开链接),这样就能理解为什么分块输出中的参数是一些重要且必须要输出的参数了。


 

可以看到,IOU(交集比并集)是一个衡量我们的模型检测特定的目标好坏的重要指标。100%表示我们拥有了一个完美的检测,即我们的矩形框跟目标完美重合。很明显,我们需要优化这个参数。


回归正题,我们来分析一下这些用来描述训练图集中的一个批次的训练结果的输出。那些想自己深入源代码验证我所说的内容的同学注意了,这段代码:点击打开链接  执行了以下的输出:

  • Region Avg IOU: 0.326577: 表示在当前subdivision内的图片的平均IOU,代表预测的矩形框和真实目标的交集与并集之比,这里是32.66%,这个模型需要进一步的训练。
  • Class: 0.742537: 标注物体分类的正确率,期望该值趋近于1。
  • Obj: 0.033966: 越接近1越好。
  • No Obj: 0.000793: 期望该值越来越小,但不为零。
  • Avg Recall: 0.12500: 是在recall/count中定义的,是当前模型在所有subdivision图片中检测出的正样本与实际的正样本的比值。在本例中,只有八分之一的正样本被正确的检测到。
  • count: 8:count后的值是所有的当前subdivision图片(本例中一共8张)中包含正样本的图片的数量。在输出log中的其他行中,可以看到其他subdivision也有的只含有6或7个正样本,说明在subdivision中含有不含检测对象的图片。

总结

在这篇短文里,我们回顾了一下YOLOv2在终端输出的不同的参数的含义,这些参数也在告诉我们YOLOv2的训练过程是怎样进行的。这个能在一定程度上解答大家关于YOLOv2的训练输出的大部分问题,但请记住,对YOLOv2的探索决不应该到此为止。

跟以往一样,欢迎大家在评论区留言,进一步讨论关于YOLOv2的相关问题,我也会不断优化改进这篇文章,所以,别忘了留言评论哦!

原英文地址: https://timebutt.github.io/static/understanding-yolov2-training-output/

Yolo v2 训练 NAN解决过程

主要参考https://zhuanlan.zhihu.com/p/25110930

问题描述

今天在用yolo训练自己的数据集的时候,一开始训练过程中的loss还很正常地在下降。结果到了几个个batch的地方突然就出现loss = nan的情况。其实到现在自己也没有发现到底是什么导致了nan,但是参考上面这篇文章,至少暂时解决了这个问题。

解决过程

1)首先检查了代码是不是对的。一般出现nan,第一反应是:会不会哪里出现了分母为0,或者log的真值为负数这样的情况。然后在自己修改过的源码里面检查了一遍,发现并没有出现这个问题。

2)然后参考上面这篇文章,检查了一下我的数据集有没有问题。首先图片自己看过是没有问题的,然后拿另外一个模型在这个数据集上跑,也没有问题。因此排除数据集出问题的可能。

3)最后担心是不是梯度在某一个batch的时候突然爆炸了。因此修改源码detector.c,训练的时候每一个batch都打印一下当前的loss。发现出现nan之前都会有一个batch的loss=inf。因为yolo的loss函数的定义就是均方差,因此,loss就等于梯度的平方。所以判断应该是某一个batch使得梯度突然增大。参考caffe的方法。设定一定的阈值,使得当梯度超过这个阈值的时候,直接设置为该阈值大小。暂时解决了nan的问题

yolo-v3 github: https://github.com/pjreddie/darknet 
参考博客: YOLOv3 ubuntu 配置及训练自己的VOC格式数据集


  1. 下载源码,编译。
  2. 运行demo: 
    a ./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg 
    b ./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights 
    c ./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights my.mp4 
    咋看参数给的很奇怪,仔细研究,example/darknet.c 中的mian函数就了然了。
int main(int argc, char **argv)
{
    if(argc < 2){
        fprintf(stderr, "usage: %s <function>\n", argv[0]);
        return 0;
    }
    gpu_index = find_int_arg(argc, argv, "-i", 0);
    if(find_arg(argc, argv, "-nogpu")) {
        gpu_index = -1;
    }

#ifndef GPU
    gpu_index = -1;
#else
    if(gpu_index >= 0){
        cuda_set_device(gpu_index);
    }
#endif

    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);
        ...
    return 0;
}

给不同的参数,对应跳转到不同的函数执行。 
3. 用作者训练好的通用目标模型检测效果图: 
a. 略 
b. 略 
可以看到,在简单场景下,通用检测检测效果还行,但是复杂场景正对特定目标,会有一些问题(比如误检、小目标无法检测等) 
4. 训练自己的数据集,以头肩为例,训练自己的数据集。 
a. 首先,利用voc_label.py将voc格式的数据转换为训练所需要的数据格式。 
b. 训练 
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74 
训练出现问题:

Region 82 Avg IOU: 0.259673, Class: 0.593880, Obj: 0.831784, No Obj: 0.515905, .5R: 0.000000, .75R: 0.000000,  count: 1
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.494105, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.412357, .5R: -nan, .75R: -nan,  count: 0
1: 579.859924, 579.859924 avg, 0.000000 rate, 0.039695 seconds, 1 images
Loaded: 0.008419 seconds
Region 82 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.515768, .5R: -nan, .75R: -nan,  count: 0
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.494756, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: 0.224065, Class: 0.304794, Obj: 0.247472, No Obj: 0.415191, .5R: 0.000000, .75R: 0.000000,  count: 4
2: 594.244812, 581.298401 avg, 0.000000 rate, 0.092844 seconds, 2 images
Loaded: 0.000024 seconds

输入416,anchor聚类: 
(29,31),(7,9),(18,30),(44,82),(119,212),(72,110),(28,56),(47,45),(14,17) 
于是anchor = 7,9, 14,17, 18,30, 29,31, 28,56, 47,45, 44,82, 72,110, 119,212

时隔很久。。又开始训练yolo的代码。yolov2训练成功了,可是yolov3怎么也不成功。。

[net]
# Testing
# batch=1 #注释
# subdivisions=1 #注释
# Training
batch=8
# subdivisions=16
width=416
height=416
channels=3
momentum=0.9
decay=0.0005
angle=0
saturation = 1.5
exposure = 1.5
hue=.1

结果把#Testing 后面的batch以及subdivisions注释就成功了… 
没注释之前,按照batch=1在计算,注释之后,按照batch=8在计算。因为我的训练样本中有很多小目标,所以batch太小是有问题的。唉。。

YOLOV3 COCO数据集训练,Avg: nan

2018年05月01日 10:49:57

阅读数:1280

YOLO V3 Region 94 Avg IOU: nan

将Bach_size 修改到128以上。

这个数据是正常的,因为在小bach中没有找到object.

改大了就可以了

猜你喜欢

转载自blog.csdn.net/maweifei/article/details/81148414