自学yolo入门到进阶

参考:

  1. 参考1
  2. 参考2
  3. 参考3
  4. YOLOv3之loss和iou可视化(横坐标和纵坐标与迭代次数完美对齐)
  5. darknet-YOLOv3 cfg参数定义
  6. 理解 YOLOv3 的训练输出日志信息
  7. 训练自己的数据集
  8. 实战

yolov3训练自定义数据集

自学yolo入门到进阶_第1张图片
自学yolo入门到进阶_第2张图片
自学yolo入门到进阶_第3张图片

在终端命令测试时遇到的错误与问题汇总:

./darknet detector train cfg/cup-obj.data cfg/cup-yolov3.cfg darknet53.conv.74
错误一
error: Assertion `0' failed.

办法:将.cfg文件中的batch值设置得更小一点

错误二
./src/parser.c:360: parse_region: Assertion `l.outputs == params.inputs' failed. 

办法:是由于粗心将.cfg文件中的与[yolo]层对应的classes值相对应的按照公式计算出来的filters=(classes+1)*3得到的某些[convolutional]层中的filters值输错了。

错误三

要把.txt标记文件与图片数据集放在同一个文件夹里,否则训练指令无法执行。

问题一:为什么数据集是很小的,数量有限,但是用模型训练的时候可以一直往下训练,不会自动停止。
答:至于说到训练过程不会自动停止,是因为在.cfg文件中有设置:max_batches = 500200,所以要达到训练迭代到第500200个batch时才会训练自动结束。
  1. 机器学习的目的在于更新参数,优化目标函数,SGD和Adam是两种常见的优化器,SGD根据每个batch的数据计算一次局部的估计,最小化代价函数,学习速率决定了每次步进的大小,因此需要选择合适的学习速率进行调优,学习速率太大会导致不收敛,速率太小又收敛速度慢。Adam优化器结合了Adagrad善于处理稀疏梯度和RMSprop善于处理非平稳目标的优点,能自动调整学习速率,则表现更优。
  2. 学习速率:学习速率第一次可以设置一个大一点的学习速率加快收敛,也可以采用动态变化学习速率的方法,比如每一轮都乘上一个衰减系数或者是根据损失的变化动态调整速率值。
  3. dropout:数据第一次跑模型的时候可以不加dropout,后期调优时加上dropout用于防止过拟合。特别是数据量相对较小的时候。
  4. 训练轮数:模型收敛即可停止迭代,一般可以采用验证集作为停止迭代的条件。
  5. 正则化:加入l1和l2正则化来防止过拟合,加入l1正则化的目的是为了加强权值的稀疏性,让更多值接近0,l2正则化是为了减小每次权重的调整幅度,避免模型训练过程中出现较大抖动。
  6. 激活函数:常用的有:sigmoid和tanh和relu和leaky relu和elu。采用sigmoid激活函数的计算量大,而且sigmoid饱和区变化缓慢,求导趋近于0,梯度消失,sigmoid函数的输出值恒大于0,这会导致模型训练的收敛速度变慢。tanh解决了zero-centered的输出问题,但是gradient vanishing和幂运算的问题仍然存在。relu从公式上可以看出,解决了gradient vanishing并且计算简单,但是某些神经元永远不会被激活,导致相应的参数永远不能被更新,即dead relu problem。lwaky relu有relu的所有优点,而且不会有dead relu problem。
  7. 特征学习函数:有CNN RNN LSTM等。CNN注重词位置上的特征,而具有时序关系的词采用其他特征学习函数更好。
  8. 特征抽取:max-pooling和avg-poiling是深度学习中最常用的两种特征提取方法。max-pooling是抽取最大的信息向量,但是当存在多个有用的信息向量时,这种方法会丢失大量有用的信息。avg-pooling是对所有信息向量求平均,当仅仅部分信息向量相关,而大部分向量无关时,会导致有用信息向量被大量噪声淹没。所以,在有多个有用向量的前提下尽量在最终的代表向量中保留这些有用向量,又想在只有一个显著相关向量的条件下直接提取该向量作为代表向量,解决办法是加权平均,即attention。
  9. 每轮训练数据乱序:每轮数据迭代保持不同的顺序,避免模型每轮都对相同的数据进行计算。
    10.batch_size选择:对于小数据量,可以全量训练,这样能更准确地朝着极值的方向更新,对于大数据,需要选择一个较小的batch_size,若此时batch_size=1,则为在线学习,每次修正方向为各自样本的梯度方向修正,难以达到收敛,batch_size增大,处理相同数据量的时间减少,但是达到相同精度的轮数增多,实际中可以逐步增大batch_size。
问题二:为什么执行检测指令之后,只会打开那张检测的图片,却并没有框出图片中的水杯。

检测指令:经验:测试时最好使用detect指令而不是与它一样作用的detector test指令

./darknet detect cfg/cup-yolov3.cfg backup/cup-yolov3_500.weights example1/TestData/少女风水杯_2.jpg

结果如下:
自学yolo入门到进阶_第4张图片

问题三:

摘抄: 刚train结束后的bug,就是coco数据的background类,yolov3默认是81分类啦,我在刚开始project.names只按照annotations中的class name写了,漏掉了背景类,于是出现了标签错乱的问题,detect的结果都是跟正确的label错1位,于是修改了project.name,把第一行默认为background,做成了81行的class name的签,就能对应上结果了。

输出log分析

输入终端测试命令后,在终端上显示出这样的输出内容:

layer     filters    size              input                output
    0 conv     32  3 x 3 / 1   608 x 608 x   3   ->   608 x 608 x  32  0.639 BFLOPs
    1 conv     64  3 x 3 / 2   608 x 608 x  32   ->   304 x 304 x  64  3.407 BFLOPs
    2 conv     32  1 x 1 / 1   304 x 304 x  64   ->   304 x 304 x  32  0.379 BFLOPs
……
  104 conv    256  3 x 3 / 1    76 x  76 x 128   ->    76 x  76 x 256  3.407 BFLOPs
  105 conv     18  1 x 1 / 1    76 x  76 x 256   ->    76 x  76 x  18  0.053 BFLOPs
  106 yolo
  
Loading weights from darknet53.conv.74...Done!
Learning Rate: 0.001, Momentum: 0.9, Decay: 0.0005

补充:
注意对比,后来执行权重文件backup/cup-yolov3_200.weights也是输出,如下:
Loading weights from backup/cup-yolov3_200.weights...Done!
Learning Rate: 0.001, Momentum: 0.9, Decay: 0.0005
补充完成

Resizing
352

Loaded: 0.000025 seconds
Region 82 Avg IOU: 0.618194, Class: 0.000000, Obj: 0.827718, No Obj: 0.559633, .5R: 0.500000, .75R: 0.500000,  count: 2
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.497142, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.412502, .5R: -nan, .75R: -nan,  count: 0
Region 82 Avg IOU: 0.256536, Class: 0.000000, Obj: 0.750111, No Obj: 0.563169, .5R: 0.000000, .75R: 0.000000,  count: 1
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.498241, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.413971, .5R: -nan, .75R: -nan,  count: 0
Region 82 Avg IOU: 0.173034, Class: 0.000000, Obj: 0.907149, No Obj: 0.558328, .5R: 0.000000, .75R: 0.000000,  count: 1
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.496366, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.415022, .5R: -nan, .75R: -nan,  count: 0
Region 82 Avg IOU: 0.526406, Class: 0.000000, Obj: 0.839134, No Obj: 0.555887, .5R: 1.000000, .75R: 0.000000,  count: 1
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.497250, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.414199, .5R: -nan, .75R: -nan,  count: 0
Region 82 Avg IOU: 0.271038, Class: 0.000000, Obj: 0.435728, No Obj: 0.562631, .5R: 0.000000, .75R: 0.000000,  count: 2
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.496236, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.412586, .5R: -nan, .75R: -nan,  count: 0
1: 586.982361, 586.982361 avg, 0.000000 rate, 0.267253 seconds, 5 images
……

解析:

  1. 上面截取的内容称为输出log。输出log在总体结构上是基于.cfg文件中的batch值和subdivisions值决定的。例如:若batch=32,subdivions=2,一次iteration有32张图,但是分成2部分来输出。那么输出log就会分成两部分,第一部分用到16张图,第二部分用到另外16张图。但是这里我自己的代码是设置的:batch=8,subdivions=5。
    在这里插入图片描述
  2. 对比上面的截图。补充:上面截图中count值的意思是:the amount of positives (objects to be detected) present in the current subdivision of images。当前subdivision图片中正样本的图片的数量。在我的实际输出中,平均IOU值是-nan。类概率值也是-nan。Obj值也是-nan。阈值0.5的召回也是-nan,阈值0.75的召回也是-nan。

自学yolo入门到进阶_第5张图片
对比上面的截图和输出log中的某一条

175: 11.040030, 27.602013 avg, 0.000001 rate, 0.343914 seconds, 875 images
Loaded: 0.000030 seconds

我的输出log表示:第175个batch,总loss是11.040030,平均loss是27.602013,学习率是0.000001,当前batch计算时间是0.343914秒,第875个batchsize。

总结输出log的规律
  1. 首先在输出log中输出loading weights from darknet53.conv.74……done
  2. 然后输出:learning rate:0.001
    momentum:0.9
    dacay:0.0005
  3. 然后输出resizing 352
  4. 然后输出loaded:0.000025秒。
  5. 然后是类似的15条相似格式的输出语句,类似如下:
Region 82 Avg IOU: 0.526406, Class: 0.000000, Obj: 0.839134, No Obj: 0.555887, .5R: 1.000000, .75R: 0.000000,  count: 1
  1. 15条以Region开头的语句之后是一句类似如下语句:
2: 590.584229, 587.342529 avg, 0.000000 rate, 0.294364 seconds, 10 images
  1. 然后是一条loaded语句,如下:
Loaded: 0.000029 seconds
  1. 然后又是像第五步中一样类似的15条以Region开头的语句
  2. 然后接着是循环上面的第六步、第七步。
  3. 然后是十组这样的1句loaded开头语句配上15句Region开头的语句的组合后,就又会输出Resizing语句,类似于
Resizing 352

训练过程中的知识点总结

  1. 可以通过修改/examples/detector.c中的train_detector函数来自己决定多少张图保存一次模型。例如训练的时候batch<1000时,每100张图片保存一次模型,当batch>1000时,每10000张图片保存一次模型。
  2. 若steps=1000,scale=.1,表示迭代到1000次时,学习率衰减10倍。若调整max_batches的值,那么需要同时调整steps值,scale值随便调整或不调整。
  3. 训练时若数据集小,则会大概率在输出log中出现nan的错误。若数据集足够大,那么出现nan可以通过调大batch或者调小learning_rate解决,yolo的调参是很麻烦的。
  4. yolo算法在pytorch框架下暂时没有发现好用的训练代码,所以最好使用darknet框架来训练。
  5. 官方权重文件是而进驻文件,以序列方式储存神经网络权重。
  6. 训练的时候用下面的命令保存训练内容
./darknet detector train cfg/cup-obj.data cfg/cup-yolov3.cfg darknet53.conv.74 2>1 | tee cup-train.txt
  1. 使用三个数据集一起训练但大幅输出nan,表示训练很糟糕。所以在原有第一个数据集训练最后保存的模型的基础上,进行后续训练。也就是把预训练权重换成自己的xxx.weights,训练的输出暂时看起来较为正常,等训练完成了看结果好坏。(同时需要调整cfg文件的max_batches,比如第一次训练完保存的是100000次,生成了final.weights,那么接下去训练就需要把cfg调大超过10w次,不然会直接保存。)
  2. cfg文件在测试和训练两种情况下batch和subdivision的值应该是不一样的。
  3. 输出log中是运行出现nan的,只要最后网络是收敛的。
  4. 在每次训练迭代后报告的平均损失(误差)值应该尽可能低,以这个值来判断什么时候应该停止训练模型。
  5. 如果训练有意或无意中断,您可以继续训练上次保存的.weights文件,在backup文件夹下产生的文件cup-yolov3_100.weights。如下所示:
./darknet detector train cfg/cup-obj.data cfg/cup-yolov3.cfg backup/cup-yolov3_100.weights

在这个权重文件上继续训练后又会得到一个新的更加好的权重文件backup/cup-yolov3_200.weights.

  1. 摘抄:“经过大约一个小时的训练后,达到了1000次迭代,平均损失(误差)为0.082204。”

  2. 下面的输出log中,第一列是表示是第几个batch。第二列表示总的loss。第三列表示平均loss。第四列表示学习率。第五列是当前batch的计算时间,第六列是第几张图片。

  3. 在每个batch的输出log之前,都有resize语句,是由于.cfg文件中,random为1时会启用Multi-Scale Training,随机使用不同尺寸的图片进行训练,所以会有resize语句。若random=0则每次训练大小与输入大小一致。

  4. 对比:我的输出log中可以看到,每一次bacth迭代都是5张图片5张图片的。在训练时设置了batch=8,subdivisions=5。

  5. 平均误差的变化情况为:
    平均误差值由第1次batch值由586到第12次batch值变成709,对应:初始学习率为0.000000
    到第30次batch值变成1260,对应学习率0.000000
    到第31次batch值开始下降,变成1243,对应学习率0.000000
    到第50次batch值变成924,对应学习率0.000000
    到第110次batch值变成332,对应学习率0.000000
    到第217次batch值变成6,对应学习率0.000002
    分析在cup-yolov3_400.weights权重文件基础上训练了8分钟后的输出log情况:
    到第768次batch值变成1.399962,对应学习率0.000348(到这一步batch时其实学习率已经过高了)

  6. 训练到平均误差降为6,到了第227次batch的时间大约5分钟。

  7. 训练了几乎1个小时后,迭代到了第7000多个batch,此时的平均loss值都变成了nan。

  8. 通过对比训练了1个小时的输出log和之前只训练了7分钟的输出log可以看出,后面的学习率提升了很多倍,所以可能是学习率过大导致不收敛的情况出现。

  9. 这次训练了1个小时后,在backup文件夹中,之前训练的时长很短的两次训练结束后分别产生了一个权重文件,第一次是cup-yolov3_100.weights,第二次是cup-yolov3_200.weights,但是这次训练时长很长的一次训练结束后(注意每次训练都是在上次产生的权重文件的基础上训练的)新增了7个权重文件,分别是:cup-yolov3_300.weights、cup-yolov3_400.weights、cup-yolov3_500.weights、cup-yolov3_600.weights、cup-yolov3_700.weights、cup-yolov3_800.weights、cup-yolov3_900.weights。

  10. 当训练到第900个batch时就会产生backup//cup-yolov3_900.weights

基于网上下载的权重文件训练5分钟的结果
1: 586.982361, 586.982361 avg, 0.000000 rate, 0.267253 seconds, 5 images
2: 590.584229, 587.342529 avg, 0.000000 rate, 0.294364 seconds, 10 images
12: 1228.810791, 709.375916 avg, 0.000000 rate, 0.492510 seconds, 60 images
30: 1395.137939, 1260.228516 avg, 0.000000 rate, 0.594338 seconds, 150 images
31: 1092.498535, 1243.455566 avg, 0.000000 rate, 0.398419 seconds, 155 images
50: 804.217285, 924.948730 avg, 0.000000 rate, 0.379187 seconds, 250 images
110: 229.943451, 332.805756 avg, 0.000000 rate, 0.300960 seconds, 550 images
217: 7.226011, 6.953908 avg, 0.000002 rate, 0.383689 seconds, 1085 images
219: 4.467210, 7.112023 avg, 0.000002 rate, 0.383818 seconds, 1095 images
220: 5.249475, 6.925768 avg, 0.000002 rate, 0.383752 seconds, 1100 images
224: 9.429196, 7.301046 avg, 0.000003 rate, 0.609718 seconds, 1120 images
225: 4.749487, 7.045890 avg, 0.000003 rate, 0.606195 seconds, 1125 images
227: 4.945302, 6.823396 avg, 0.000003 rate, 0.606311 seconds, 1135 images

训练大约1个小时的结果如下
7131: -nan, -nan avg, 0.001000 rate, 0.250000 seconds, 35655 images
7440: -nan, -nan avg, 0.001000 rate, 0.381908 seconds, 37200 images
在cup-yolov3_400.weights权重文件基础上训练了8分钟后的输出log情况:
768: 0.556964, 1.399962 avg, 0.000348 rate, 0.384204 seconds, 3840 images
836: 46.330509, 6.593365 avg, 0.000488 rate, 0.423186 seconds, 4180 images
889: 195.407013, 21.678837 avg, 0.000625 rate, 0.424788 seconds, 4445 images
900: 2.271802, 8.671995 avg, 0.000656 rate, 0.713107 seconds, 4500 images
Saving weights to backup//cup-yolov3.backup
Saving weights to backup//cup-yolov3_900.weights
从这里可以观察得到,当训练到第900个batch时就会产生backup//cup-yolov3_900.weights
950: 5263.906738, 718.365906 avg, 0.000815 rate, 0.615427 seconds, 4750 images
951: 13056.240234, 1952.153320 avg, 0.000818 rate, 0.535834 seconds, 4755 images
1000: 0.708008, 296.364410 avg, 0.001000 rate, 0.515960 seconds, 5000 images
Saving weights to backup//cup-yolov3.backup
从这里可以看出当迭代到第1000个batch时,不会再产生权重文件了。不知道为什么这里没有产生backup//cup-yolov3_1000.weights,但是说不会再产生权重文件的结论是错误的,后面是会继续有的,因为在其他地方有看到backup//cup-yolov3_2000.weights这样的权重文件。

1096: 70446.734375, 13425.520508 avg, 0.001000 rate, 0.344823 seconds, 5480 images
1108: 1170175005885535879168.000000, 117017504106990796800.000000 avg, 0.001000 rate, 0.339283 seconds, 5540 images
从第1109次batch开始,平均loss值开始变成nan
1109: -nan, -nan avg, 0.001000 rate, 0.337159 seconds, 5545 images
1110: nan, -nan avg, 0.001000 rate, 0.336276 seconds, 5550 images

在cup-yolov3_200.weights权重文件基础上训练了3分钟后的输出log情况:
243: 4.018680, 5.119147 avg, 0.000003 rate, 0.459128 seconds, 1215 images
360: 1.780453, 2.842503 avg, 0.000017 rate, 0.705736 seconds, 1800 images

在cup-yolov3_400.weights权重文件基础上训练了4分钟后的输出log情况:
468: 2.294378, 2.397950 avg, 0.000048 rate, 0.727073 seconds, 2340 images
531: 3.047993, 2.990965 avg, 0.000080 rate, 0.570293 seconds, 2655 images
687: 1.421806, 1.678364 avg, 0.000223 rate, 0.721503 seconds, 3435 images
699: 1.553484, 2.162127 avg, 0.000239 rate, 0.643578 seconds, 3495 images
703: 0.616968, 1.823786 avg, 0.000244 rate, 0.620547 seconds, 3515 images
752: 0.968440, 1.543288 avg, 0.000320 rate, 0.334344 seconds, 3760 images
798: 26.327856, 4.645860 avg, 0.000406 rate, 0.604878 seconds, 3990 images
853: 0.747405, 1.933562 avg, 0.000529 rate, 0.703774 seconds, 4265 images
870: 1.108501, 1.441449 avg, 0.000573 rate, 0.460056 seconds, 4350 images
908: 1.532592, 8.039704 avg, 0.000680 rate, 0.459946 seconds, 4540 images
927: 5.739350, 13.067078 avg, 0.000738 rate, 0.416476 seconds, 4635 images
929: 810.616150, 92.059631 avg, 0.000745 rate, 0.420621 seconds, 4645 images
像上面贴出来的输出log一样,最后loss变成nan。

总结:
基于上面所有情况下运行得到的输出log,发现最小的平均loss值为1.4附近波动。
第217次bacth时,总loss为7.2, 平均loss为6.9,学习率为0.000002。
第768次bacth时,总loss为0.5, 平均loss为1.39, 学习率为0.000348。
第752次batch时,总loss为0.9, 平均loss为1.5, 学习率为0.000320。
第870次batch时,总loss为1.1, 平均loss为1.4,学习率为 0.000573。
第929次batch时,总loss为810,平均loss为92, 学习率为0.000745。

训练深度学习网络时出现nan的原因汇总:

参考:参考

可能原因一:出现nan即说明训练不收敛了,梯度爆炸

解决办法:

  1. 数据归一化(减均值,除方差,加入normalization,例如:BN或者L2 norm)
  2. 更换参数的初始化方法(对于CNN一般用xavier或者msra的方法)
  3. 减小学习率,减小batch size。
  4. 加入gradient clipping,每当梯度达到一定的阈值,就把它们设置回一个小一点的值。
可能原因二:深度神经网络结构设计问题

解决办法:

  1. 弱化场景,让样本简化,各个学习率等参数采用典型配置,例如10万样本都是同一张图片复制得来,然后让这个网络去拟合,如果有问题的话就是网络的问题,否则的话就是各个参数的问题。
  2. 如果是网络的问题,则通过不断加大样本的复杂度和调整网络(调整拟合能力)来改变。
  3. 参数的微调,是要在网络的拟合能力和样本复杂度匹配的情况下,就是可以train到一定水平,然后想进行下一步优化时采用。
  4. 参数的微调(在上面原因一的解决办法中有给出),然后参数的微调是需要实践去总结的,另外将weights可视化也是一种参数微调的方法,digits tf中有相关的工具。
可能原因三:实际中存在很多脏数据

现象:
每次在固定的迭代次数段,loss都会突然变成nan,导致acc骤降,慢慢变成0。脏数据的出现导致logits计算出了0,0传给log(x|x=0)值趋近于无穷,即nan。
解决办法:
设置batch_size=1,shuffle=False,一步一步将sample定位到所有可能的脏数据,然后删掉。这个过程中,就重复一直定位一直删除,直到不出现nan。
总结:
现实的数据是非常脏的,所以在实际工作中,数据预处理就占到工作的80%.

汇总
  1. 在迭代的100轮以内,出现nan,一般是学习率过高,需要降低学习率,可以不断降低学习率,直到不出现nan为止,一般说低于现有学习率1-10倍即可。

  2. 若当前网络是类似RNN的循环神经网络的话,出现nan可能是梯度爆炸的原因,一个有效犯法是增加gradient clipping(梯度截断)来解决。

  3. 可能用0做了除数

  4. 可能0或者负数做了自然对数。

  5. 需要计算Loss的数组越界。尤其是当自定义了一个新网络时,是很容易出现这个问题。

  6. 在某些涉及指数运算,可能最后算的值为inf(无穷),比如不做其他处理的softmax中分子分母需要计算exp(x),值过大的话,可能最后值为inf,出现Nan,所以需要确认使用的softmax在计算exp(x)时做了相关处理,比如减去最大值等等。

  7. tensorflow中训练出现nan的问题: 深度学习对于网络的训练是参数更新的过程,需要注意的一种情况就是输入数据未做归一化的时候,如果前向传播已经是[0,0,0,1,0,0,0,0]这种形式,而真实结果是[1,0,0,0,0,0,0,0],此时得到的结论不具有概率性,是错误的估计值,此时反向传播会使得权重和偏置值变得无穷大,导致数据溢出,就出现nan的问题。
    解决办法:
    (1)对输入数据归一化处理,例如将输入的图片数据除以255将其转化为0-1之间的数据。
    (2)对于层数较多的情况,每层都做batch_normalization。
    (3)对设置weights权重采用tf.truncated_normal(0,0.01,[3,3,1,64]生成,同时值的均值为0,方差要小一些。
    (4)激活函数可以使用tanh
    (5)减小学习率

  8. 在标记数据的时候,一要注意被标记物体要完整,二是要注意在标记数据的时候框的大小尽量符合被检测物体的大小,尽量不要框到多余的物体,这样噪点会更大。

之前的训练集因为混杂了网上下载的各种图片还有摄像头拍摄的图片,而且数据量也小,所以就修改为全部用摄像头拍摄了两个物体,一个是水瓶,一个是乳液。共1000张数据,里面存在重复的图片。下面是修改训练集之后的训练结果:

1: 1227.480957, 1227.480957 avg, 0.000000 rate, 0.243873 seconds, 4 images
501: 2.108885, 2.108885 avg, 0.000063 rate, 0.246405 seconds, 2004 images
615: 3.421903, 1.555070 avg, 0.000143 rate, 0.172071 seconds, 2460 images
718: 0.850832, 0.992338 avg, 0.000266 rate, 0.294531 seconds, 2872 images
772: 27.615116, 3.862367 avg, 0.000355 rate, 0.199183 seconds, 3088 images
863: 0.562656, 0.971841 avg, 0.000555 rate, 0.310661 seconds, 3452 images
969: 44.149776, 7.621551 avg, 0.000882 rate, 0.202318 seconds, 3876 images
1814: 0.428668, 0.491803 avg, 0.000010 rate, 0.544996 seconds, 7256 images
4000: 0.483848, 0.527806 avg, 0.000010 rate, 0.504831 seconds, 16000 images
9000: 0.409073, 0.413204 avg, 0.000010 rate, 0.519575 seconds, 36000 images
12000: 0.220595, 0.333596 avg, 0.000010 rate, 0.508379 seconds, 48000 images
13000: 0.383652, 0.394776 avg, 0.000010 rate, 0.506586 seconds, 52000 images
14000: 0.431621, 0.338908 avg, 0.000010 rate, 0.532735 seconds, 56000 images
15000: 0.498119, 0.361371 avg, 0.000010 rate, 0.522756 seconds, 60000 images
16000: 0.333839, 0.284221 avg, 0.000010 rate, 0.507750 seconds, 64000 images
17000: 0.234287, 0.273595 avg, 0.000010 rate, 0.537022 seconds, 68000 images
18000: 0.295689, 0.313349 avg, 0.000010 rate, 0.511710 seconds, 72000 images
19000: 0.305686, 0.278494 avg, 0.000010 rate, 0.507369 seconds, 76000 images
20000: 0.151630, 0.290826 avg, 0.000010 rate, 0.507186 seconds, 80000 images
21000: 0.273733, 0.270584 avg, 0.000010 rate, 0.507230 seconds, 84000 images
22000: 0.133326, 0.265308 avg, 0.000010 rate, 0.507203 seconds, 88000 images
23000: 0.292121, 0.261696 avg, 0.000010 rate, 0.545719 seconds, 92000 images
24000: 0.223262, 0.205484 avg, 0.000010 rate, 0.537998 seconds, 96000 images
25000: 0.188407, 0.217402 avg, 0.000010 rate, 0.574772 seconds, 100000 images
26000: 0.346192, 0.252096 avg, 0.000010 rate, 0.524121 seconds, 104000 images
27000: 0.287275, 0.225132 avg, 0.000010 rate, 0.509380 seconds, 108000 images
30000: 0.204683, 0.231666 avg, 0.000010 rate, 0.519882 seconds, 120000 images
49350: 0.108591, 0.105451 avg, 0.000010 rate, 0.434735 seconds, 197400 images
50000: 0.130271, 0.179324 avg, 0.000010 rate, 0.508445 seconds, 200000 images
59975: 0.085559, 0.156788 avg, 0.000010 rate, 0.519048 seconds, 239900 images
60000: 0.116182, 0.179747 avg, 0.000010 rate, 0.563186 seconds, 240000 images
80000: 0.157307, 0.157761 avg, 0.000100 rate, 0.515238 seconds, 320000 images
100000: 0.118885, 0.084560 avg, 0.000100 rate, 0.518509 seconds, 400000 images
110000: 0.173661, 0.106153 avg, 0.000100 rate, 0.509563 seconds, 440000 images
119944: 0.086295, 0.067115 avg, 0.000100 rate, 0.517343 seconds, 479776 images
120000: 0.021340, 0.100389 avg, 0.000100 rate, 0.511548 seconds, 480000 images
129976: 0.030070, 0.063398 avg, 0.000100 rate, 0.509948 seconds, 519904 images
130000: 0.056544, 0.096625 avg, 0.000100 rate, 0.508922 seconds, 520000 images
139964: 0.026662, 0.059001 avg, 0.000100 rate, 0.507803 seconds, 559856 images
140000: 0.201191, 0.096713 avg, 0.000100 rate, 0.508453 seconds, 560000 images
150000: 0.085332, 0.096602 avg, 0.000100 rate, 0.507115 seconds, 600000 images
选择160000这个权重文件来测试
160000: 0.044543, 0.070178 avg, 0.000100 rate, 0.508458 seconds, 640000 images
从第160000个batch到第170000个batch大概用了两小时。
169966: 0.021125, 0.062861 avg, 0.000100 rate, 0.507765 seconds, 679864 images
170000: 0.055982, 0.082330 avg, 0.000100 rate, 0.507035 seconds, 680000 images
从第170000个batch到第180000个batch大概用了一个半小时。
180000: 0.153854, 0.078253 avg, 0.000100 rate, 0.509002 seconds, 720000 images
186824: 0.150794, 0.063261 avg, 0.000100 rate, 0.509802 seconds, 747296 images

总结训练时输出log的规律:
在cfg文件里设置的:batch=4 subdivisions=2
1. 6条region这样的语句之后出现一条检测batch的各个参数输出log语句
Region 82 Avg IOU: 0.644588, Class: 0.284318, Obj: 0.057900, No Obj: 0.000914, .5R: 1.000000, .75R: 0.000000,  count: 2
2. 10次batch迭代之后重新resize图片一次

修改了训练集之后利用训练得到的160000权重文件测试单张图片的结果。
cfg文件里设置classes=1

example1/TestData/750.jpg: Predicted in 0.059699 seconds.
person: 90%

自学yolo入门到进阶_第6张图片

cfg文件里设置classes=2
自学yolo入门到进阶_第7张图片

cfg文件里设置classes=3
自学yolo入门到进阶_第8张图片

问:我跑yolo3模型 最后输出的图像没有检测框,然后我将阈值调小到0.00002(默认是0.25),然后图像遍布满了框,权重换了好几种,都没有效果,请问问题出在了哪里?

答:你应该是在前向过程中没有修改cfg文件中的train和test模式,batchsize和subvision都设置为1。

测试并且返回评价指标的三类指令

在测试时,要把cfg文件里面关于test的取消注释,而且test的batch和subdivisions设置为1.

第一类:不显示评价指标,输入图片路径后只显示框好后的图片和类别、置信率
./darknet detector test cfg/voc.data cfg/yolo-voc.cfg ./svt/backup/yolo-voc_final.weights
第二类:在终端只返回测试耗时,结果生成在cup-obj.data的results指定的目录下以开头的若干文件中,若cup-obj.data没有指定results,那么默认为darknet/results,out_file是自己任意命名的输出文件,可以在终端指令中不写,直接使用默认生成的即可,默认在results文件夹下。
./darknet detector valid cfg/cup-obj.data cfg/cup-yolov3.cfg backup/yolo-voc_final.weights 

这条终端测试指令是使用的yolo网络自带的valid函数接口来测试大量图片,把检测结果保存在txt文件中。测试完成后,在results文件夹下打开文本,里面的书写格式是voc格式。其中每一行代表:图片名字、这一类框的置信度、坐标信息。

然后可以使用py-faster-rcnn下的voc_eval.py计算mAP。
把py-faster-rcnn/lib/datasets/voc_eval.py拷贝到darknet根目录。
下载地址:https://github.com/rbgirshick/py-faster-rcnn/blob/master/lib/datasets/voc_eval.py
新建自己的compute_mAP.py文件。如下:


第三类:依次ID:图片序号从0开始,correct:累计检测正确的总框数,total:累计的总ground truth数,RPs/Img: 累计的总proposals/已检测图片数,IOU,Recall: correct / total,proposals:累计的总框数,Precision: correct / proposals

输出在stderr里,重定向时要注意。
RPs/Img、IOU、Recall都是到当前测试图片的均值。
detector.c中对目录处理有错误,可以参照validate_detector对validate_detector_recall最开始几行的处理进行修改。
修改完成detector.c文件之后要先在darknet下make一下,再运行检测指令即这里的recall指令

./darknet detector recall cfg/cup-obj.data cfg/cup-yolov3.cfg backup/yolo-voc_final.weights(这个命令需修改dectector.c文件)

在终端输入这条recall测试指令之后,在终端上会显示

enter you image path

此时要输入的就是在cfg文件中valid参数对应的那个值,也就是存储所有测试集图片路径的那个txt文本。
执行完毕后,所有的测试图片都会保存在out文件夹下,我是把out文件夹创建在example1文件夹下,网上程序把out文件夹创建在darknet/data/out下。

因为在采集训练数据集时,图片的来源多种多样,有从网上爬虫的,有从opencv上截取的,而且爬虫得到的图片的图片源也是多样的。再加上水杯的样子各种各样,所以训练难度是很大的。再加上数据量又很少,所以才会导致训练的结果不收敛。解决办法两个:一是:可以采用这种多样的图片源,但是数据集的数据量必须要够大。第二种方法:选择最简单的数据集先训练,即用opencv先截取自己的水杯的各种样子的截图和乳液瓶子的截图(不是水杯),就这两类数据(一类是水瓶,一类不是),截取个几百张图片再来训练。

训练输出日志的理解

例如,如下是输出日志的一部分:

44579: 0.257759, 0.196168 avg, 0.000010 rate, 0.178815 seconds, 178316 images
Loaded: 0.000055 seconds
Region 82 Avg IOU: 0.761178, Class: 0.998803, Obj: 0.870125, No Obj: 0.003177, .5R: 1.000000, .75R: 0.500000,  count: 2
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000084, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000000, .5R: -nan, .75R: -nan,  count: 0
Region 82 Avg IOU: 0.728754, Class: 0.999666, Obj: 0.973296, No Obj: 0.003884, .5R: 1.000000, .75R: 0.000000,  count: 1
Region 94 Avg IOU: 0.659824, Class: 0.957042, Obj: 0.314952, No Obj: 0.000288, .5R: 1.000000, .75R: 0.000000,  count: 1
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000000, .5R: -nan, .75R: -nan,  count: 0
44580: 0.178447, 0.194396 avg, 0.000010 rate, 0.176078 seconds, 178320 images

在cfd文件中设置batch=4,subdivision=2。所以在训练输出中, 训练迭代包含了 2 组, 每组又包含了 2 张图片.
如下,这样一行的信息是由example/detector.c中的部分代码实现的

44580: 0.178447, 0.194396 avg, 0.000010 rate, 0.176078 seconds, 178320 images

这条输出语句表示第44580个batch,总loss是 0.178447,平均loss是0.194396,一般这个数值低于0.06就可以停止训练,如果达不到这个值也可以,只要是迭代了挺多次,返现loss值趋于平稳也可以停止训练。学习率是0.000010,当前这个bacth训练花费时间0.176078 seconds,截止目前,训练的总图片数目是178320。

实现的部分关键代码如下

...

if (avg_loss < 0) avg_loss = loss;
avg_loss = avg_loss*.9 + loss*.1;

i = get_current_batch(net);

printf("%ld: %f, %f avg, %f rate, %lf seconds, %d images\n", 
        get_current_batch(net), 
        loss, 
        avg_loss, 
        get_current_rate(net), 
        what_time_is_it_now()-time, 
        i*imgs);
...

IOU Intersection over Union 交并集之比
上面粘贴出来的输出log的另外一部分如下:

Region 82 Avg IOU: 0.761178, Class: 0.998803, Obj: 0.870125, No Obj: 0.003177, .5R: 1.000000, .75R: 0.500000,  count: 2
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000084, .5R: -nan, .75R: -nan,  count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000000, .5R: -nan, .75R: -nan,  count: 0
Region 82 Avg IOU: 0.728754, Class: 0.999666, Obj: 0.973296, No Obj: 0.003884, .5R: 1.000000, .75R: 0.000000,  count: 1
Region 94 Avg IOU: 0.659824, Class: 0.957042, Obj: 0.314952, No Obj: 0.000288, .5R: 1.000000, .75R: 0.000000,  count: 1
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000000, .5R: -nan, .75R: -nan,  count: 0

输出信息的数目是: subdivisions * ngpus * 3即2 * 1 * 3=6,如上正好是6条region语句。
上面这六条语句表示的是三个不同的尺度上(重复的两组)82/94/106上预测到的不同大小的框的参数。
82 卷积层为最大的预测尺度, 使用较大的 mask, 但是可以预测出较小的物体;
94 卷积层为中间的预测尺度, 使用中等的 mask;
106卷积层为最小的预测尺度, 使用较小的 mask, 可以预测出较大的物体.

上述输出信息的各个参数含义是(主要观察某一个尺度上的参数), 下面就 Region 82 分析:

Region 82 Avg IOU: 0.761178, Class: 0.998803, Obj: 0.870125, No Obj: 0.003177, .5R: 1.000000, .75R: 0.500000,  count: 2

Region Avg IOU:0.761178: 表示在当前 subdivision 内的图片的平均 IOU, 代表预测的矩形框和真实目标的交集与并集之比, 这里是 76.1%, 这个模型此时已经达到了很高的训练精度;

Class: 0.998803: 标注物体分类的正确率, 期望该值趋近于1;

Obj: 0.870125: 越接近 1 越好;

No Obj: 0.003177: 期望该值越来越小, 但不为零;

.5R: 1.000000: 是在 recall/count 中定义的, 是当前模型在所有 subdivision 图片中检测出的正样本与实际的正样本的比值。在本例中, 全部的正样本被正确的检测到。

count: 2: 所有当前 subdivision 图片(本例中一共 2张)中包含正样本的图片的数量。 在输出 log 中的其他行中。(在 subdivision 中含有不包含在检测对象 classes 中的图片)

实现代码在src/region_layer.c中,部分重要的实现部分如下:

*(l.cost) = pow(mag_array(l.delta, l.outputs * l.batch), 2);
printf("Region %d Avg IOU: %f, Class: %f, \ 
        Obj: %f, No Obj: %f,  \
        .5R: %f, .75R: %f, count: %d\n", 
        net.index, avg_iou/count, avg_cat/class_count, 
        avg_obj/count, avg_anyobj/(l.w*l.h*l.n*l.batch), 
        recall/count, recall75/count, count);

cfg文件中参数的解析

[net]层

参数:batch, subdivisions,max_batches
每batch个样本代表完成一次权重参数更新。max_batches是最大权重更新次数,完成max_batches次权重更新后停止训练。

参数:width, height, channel
输入图像的分辨率和通道数。width,height须设置成32的倍数。

梯度下降法相关的参数有:momentum, decay,以及学习率系列参数。
momentum是动量梯度下降法的动量参数,默认为0.9。decay是权重衰减正则项,每一次学习的过程中,将学习后的参数按照固定比例进行降低,防止过拟合,默认值0.0005。

学习率相关的参数包括:learning_rate,burn_in,policy,以及每种policy对应的参数。
learning_rate是权值更新的基础变化率,默认值0.001。在训练过程中,一般根据训练轮数动态更新学习率。在迭代次数小于burn_in时,学习率有一种更新策略。**大于burn_in时,**才采用policy的更新策略。policy包括:constant, steps, exp, poly, step, sig, random。
例如:

steps=40000,45000
scales=.1,.1

表示迭代到40000次时,学习率在learning_rate的基础上衰减10倍,45000次迭代时,学习率又会在前一个学习率的基础上衰减十倍。

数据增强参数包括:hue,saturation,exposure,分别对应HSV三个颜色通道的调整参数
数据增强会以50%的概率左右翻转图像(flip)。YOLOv3的目标检测未采用角度旋转数据增强angle。数据增强参数jitter定义在[yolo]层部分。

[YOLO]层

参数:anchors,mask,num
anchors定义了anchor的宽高,以像素为单位。只有mask索引到的anchors才会在当前yolo层中被使用。如果不设置anchors,默认是0.5。num=anchors数量。
例如

mask = 0, 1, 2
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326

mask数量是3,anchors数量是9,即num=9。mask定义第0,1,2个anchors在当前yolo层中被使用,其宽高分别是[10,13],[16,30],[33,23]。mask数量也是每个grid预测的boundingbox数。
每一个yolo层前的最后一个卷积层的filters=(mask数量)*(classes+4+1)。

参数:ignore_thresh,truth_thresh
ignore_thresh与truth_thresh是loss 的相关参数。YOLOv3的loss函数包括 分类误差、定位误差、loss obj(是否格子中存在物体) 三个部分。每一个grid有多个预测框(其数量即为mask的数量),其中与ground truth的IOU最大的预测框,当其IOU小于ignore_thresh的时候,即作为负样本参与 loss obj 的计算,否则,不参与 loss obj计算(不作为正样本)。而且,如果这个IOU大于truth_thresh,则作为样本参与 分类误差和 定位误差的计算。ignore_thresh一般选取0.5-0.7之间的一个值,默认为0.5。truth_thresh默认为1。

另外,对于每一个ground truth,其中心位置对应的grid上,与ground truth之间IOU最大的预测框,参与定位误差、分类误差、loss obj 的计算。

参数:random
random是多尺度训练使能参数。如果为1,那么每次10次迭代的图片大小在[320,608]区间内随机选择,步长为32。如果为0,图像尺寸为net定义的高宽。这也就可以解释在输出log中每10个bacth之后出现一条resize语句。

参数:jitter
jitter是随机crop的参数。jitter=.3,就是在宽高缩放1±0.3范围内进行crop

参数:max
每幅图像中使用的ground truth最大数量。

Region 82 Avg IOU: 0.816567, Class: 0.995740, Obj: 0.862174, No Obj: 0.003723, .5R: 1.000000, .75R: 0.500000,  count: 2
53418: 0.076606, 0.108589 avg, 0.000010 rate, 0.201794 seconds, 213672 images
Region 82 Avg IOU: 0.936451, Class: 0.999735, Obj: 0.992904, No Obj: 0.002856, .5R: 1.000000, .75R: 1.000000,  count: 2
53441: 0.052049, 0.125829 avg, 0.000010 rate, 0.160049 seconds, 213764 images
Loaded: 0.000029 seconds
^C
syy@syy1996:~/software/darknet$ 

正确显示出自己的分类类别的解决办法:不改动detection.c,只是在修改之前几个文本的基础上再把data/coco.names修改为自己的类别,然后就可以了。

自学yolo入门到进阶_第9张图片
自学yolo入门到进阶_第10张图片
自学yolo入门到进阶_第11张图片
上图:example1/TestData/625.jpg: Predicted in 0.059876 seconds.
Emulsion: 78%
WaterBottle: 58%
自学yolo入门到进阶_第12张图片
上图:example1/TestData/650.jpg: Predicted in 0.060006 seconds.
自学yolo入门到进阶_第13张图片
example1/TestData/675.jpg: Predicted in 0.060090 seconds.
WaterBottle: 95%
自学yolo入门到进阶_第14张图片
example1/TestData/700.jpg: Predicted in 0.061012 seconds.
Emulsion: 77%
WaterBottle: 89%
自学yolo入门到进阶_第15张图片
上图:example1/TestData/725.jpg: Predicted in 0.060916 seconds.
WaterBottle: 83%
自学yolo入门到进阶_第16张图片
上图:example1/TestData/750.jpg: Predicted in 0.060256 seconds.
WaterBottle: 96%

你可能感兴趣的:(计算机视觉)