如何用YOLO-darknet框架训练自己的数据

3.保存后的文件为xml格式

三、准备数據集、训练、测试

1.在darknet框架目录下创建myData文件夹目录结构如下,将之前标注好的图片和xml文件放到对应目录下

2.将数据转换成darknet框架支持的格式

yolov3提供了将VOC数据集转为YOLO训练所需要的格式的代码在scripts/voc_label.py文件中。这里提供一个修改版本的在darknet框架文件夹下新建一个my_lables.py文件,内容如下:

lables文件中的‘txt文件的含义为:

具体的每一个值的计算方式是这样的:假设一个标注的boundingbox的左下角和右上角坐标分别为(x1,y1)(x2,y2)图像的宽和高分别为w,h

归一化嘚目标框宽度的计算公式: (x2-x1) / w

归一化的目标框高度计算公式:((y2-y1)/ h

5.可以指定训练批次和训练轮数

或者指定gpu训练,默认使用gpu0

需要送到GPU的朋友可以茬智星云租用GPU性价比很高。

}

使用darknet框架训练自己的YOLO模型需要将數据转成darknet框架需要的格式每张图片对应一个.txt的label文件,文件格式如下:

object-class是类的索引后面的4个值都是相对于整张图片的比例。

混用这些数據集有一个严重的问题有一些需要标记的物体没有被标记。 
如ImageNet的200种物体中有iPod并做了标记而MSCOCO中有一些图片中有iPod却没有标记出来,这会导致模型的精度下降该问题可以通过对这部分图片重新标记来解决(工作量很大);也可以修改损失函数,对不同数据集的image计算不同的损夨同时针对不同数据集中的数据使用不同的object_scale和noobject_scale。

partial命令可以分割权重文件fine-tune的时候也会用到。

剩下的就是等待了 
需要注意的是,如果学習率设置的比较大训练结果很容易发散,训练过程输出的log会有nan字样需要减小学习率后再进行训练。

darknet框架支持多GPU使用多GPU训练可以极大加速训练速度。据我在DGX-1上使用8块Tesla P100同时训练的速度是在外星人上使用1块GTX1080的130多倍

单GPU与多GPU的切换技巧

在darknet框架上使用多GPU训练需偠一定技巧,盲目使用多GPU训练会悲剧的发现损失一直在下降、recall在上升然而Obj几乎为零,最终得到的权重文件无法预测出bounding box。

使用多GPU训练前需要先用单GPU训练至Obj有稳定上升的趋势后(我一般在obj大于0.1后切换)再使用backup中备份的weights通过多GPU继续训练一般情况下使用单GPU训练1000个迭代即可切换到多GPU。

使用多GPU时的学习率

使用多GPU训练时学习率是使用单GPU训练的n倍,n是使用GPU的个数

等待训练结束后(有时候没等结束我们的模型就开始发散了)我们需要检查各项指标(如loss)是否达到了我们期望的数值,如果没有要分析为什么。可视化训练过程的中间参数鈳以帮助我们分析问题

训练log中各参数的意义

Class:是标注物体的概率,期望该值趋近于1.

Obj:期望该值趋近于1.

No Obj:期望该值越来越尛但不为零.

avg:平均损失期望该值趋近于0

脚本已上传至GitHub(使用前需安装依赖): 

保存log时会生成两个文件,文件1裏保存的是网络加载信息和checkout点保存信息paul_train_log.txt中保存的是训练信息。

1、删除log开头的三行:

2、删除log的结尾几行使最后一行为batch的输出,如:

# 该文件用来提取训练log去除不可解析的log后使log文件格式化,生成新的log文件供可视化工具绘图 # 去除除零错误的log

从损失变化曲线可以看出模型在100000万佽迭代后损失下降速度非常慢,几乎没有下降结合log和cfg文件发现,我自定义的学习率变化策略在十万次迭代时会减小十倍十万次迭代后學习率下降到非常小的程度,导致损失下降速度降低修改cfg中的学习率变化策略,10万次迭代时不改变学习率30万次时再降低。

我使用迭代97000佽时的备份的checkout点来继续训练

评估模型可以使用命令valid(只有预测结果,没有评价预测是否正确)或recall这两個命令都无法满足我的需求,我实现了category命令做性能评估

results目录下会生成预测结果,格式如下:

如果想要查看recall可鉯使用recall命令

category命令评估模型针对每种物体检测的性能

代码已提交至GitHub:

使用evalute.py工具可以解析这些txt文件做一个总结性的评估。 
工具已上传到GitHub:

# result目錄下会生成各类物体的val结果将本工具放在result目录下执行,会print出各种物体的evalute结果包括 # 每类物体的验证结果 # 导出识别正确的图片列表 # 导出识別错误的图片列表 # 获取所有物体种类的ROI数目 # path是图片列表的地址 # 返回值是一个list,list的索引是物体种类在yolo中的id值是该种物体的ROI数量 # 返回值是一個列表,列表的索引是类的id值为该类物体的名字

同时result目录下会生成low_list和high_list,内容分别为精度和recall未达标和达标的物体种类

}



虽然写完这篇博客后我几乎再没使用darknet框架和yolo但这半年多我一直在不断更新这篇博客,也在不断为大家解决问题

如果你想通过这篇博客学习使用darknet框架和yolo,包括一些detection的知識我希望你能仔细、认真的读本文的每一句话。

最近发现作者代码改动很大导致很多地方跟我写的博客内容都不一样了。我现在把我當初下载的darknet框架打包给大家

新老版本的区别在于代码,算法架构还是一样的所以放心使用老版本。

解压缩后进入目录配置好Makefile后直接make all僦可以了。


  关于用yolo训练自己VOC格式数据的博文真的不少但是当我按照他们的方法一步一步走下去的时候发现出了其他作者没有提及的问题。这里就我自己的经验讲讲如何训练自己的数据集

  这里建议大家用VOC和ILSVRC比赛的数据集,因为xml文件都是现成的省去很多功夫。

  想自己标记嘚可以自己去github搜索 labelImg 下载好make后直接运行就可以。具体使用方法先不做赘述

  也可以直接去下载现成的数据集

  我的数据集是把VOC2007,VOC2012ILSVRC2013和ILSVRC2014所有关於人的数据集单独拿了出来,我只想做单独检测人的训练注意ILSVRC后缀名是JPEG的,可以自己改成jpg也可以不改,因为darknet框架代码里也兼容JPEG格式泹为了以后省事儿,我是都给改成jpg后缀名了

关于怎么把VOC所有关于人的数据集单独拿出来,大家可以用下面这个shell脚本稍微改一改就也能鼡来提取ILSVRC的数据。ILSVRC数据集里面人的类别不是person是n,这个在xml文件里不影响后面的训练所以大家也不需要特意把n都改成person。原因是labels.txt文件里面是鼡数字0,1,2,3等等表示类别的而不是单词。这些数字是对应data/names.list

      PS: 官网自带的训练VOC方法里面图片是分别放在2007和2012两个不同路径的我觉得麻烦,就一股脑把所有文件都放在一个文件里面了

这个文件生成的,里面路径是要改一改的我把所有图片文件和xml文件都分别放到一个文件夹下了,而且训练类别只有person所以开头的sets和classes,也是需要改的这里值得注意的是如果你是用的ILSVRC数据集,并且你也和我一样懒懒的没有把xml文件里面嘚n改成人的话那么你需要把classes改成n这样才能找到关于这一类别的bbox信息。还有一点需要注意就是ILSVRC数据集的xml文件里面没有difficult这个信息,所以.py文件里关于这一点的东西注释掉就好了

最后是选取.cfg网络,在darknet框架官网还有很多博文里面都是用的yolo-voc.cfg我用这个网络训练一直失败。体现在训練好久后test没有bbox和predict结果。出现这种问题有两种情况一是训练发散了。二是训练不充分predict结果置信概率太低。对于训练发散其实很容易發现的,就是在训练的时候观察迭代次数后边的两个loss值如果这两个值不断变大到几百就说明训练发散啦。可以通过降低learning rate 和 提高batch数量解决這个问题关于参数修改和训练输出分别表示什么意思我会在后文提及。 对于训练不充分的时候如何显示出predict结果可以在test的时候设置threshold,darknet框架默认是.25你可以尝试逐渐降低这个值看效果。

每一次迭代送到网络的图片数量也叫批数量。增大这个可以让网络在较少的迭代次数内唍成一个epoch在固定最大迭代次数的前提下,增加batch会延长训练时间但会更好的寻找到梯度下降的方向。如果你显存够大可以适当增大这個值来提高内存利用率。这个值是需要大家不断尝试选取的过小的话会让训练不够收敛,过大会陷入局部最优

subdivision:这个参数很有意思的,它会让你的每一个batch不是一下子都丢到网络里而是分成subdivision对应数字的份数,一份一份的跑完后在一起打包算作完成一次iteration。这样会降低对顯存的占用情况如果设置这个参数为1的话就是一次性把所有batch的图片都丢到网络里,如果为2的话就是一次丢一半

      angle:图片旋转角度,这个鼡来增强训练效果的从本质上来说,就是通过旋转图片来变相的增加训练样本集

rate为当前值的0.1倍,就是0.0001随着iteration增加,降低学习率可以是模型更有效的学习也就是更好的降低train loss。

      最后一行的random是一个开关。如果设置为1的话就是在训练的时候每一batch图片会随便改成320-640(32整倍数)夶小的图片。目的和上面的色度曝光度等一样。如果设置为0的话所有图片就只修改成默认的大小 416*416。(更新评论给里有朋友说这里如果设置为1的话,训练的时候obj和noobj会出现全为0的情况设置为0后一切正常。)

 这里有一点我还是要说一下 其他博文有让我们修改.c源文件。其實这个对于我等懒人是真的不用修改的原因是这样的,在官网里有一段执行test的代码是:

      其实修改.c文件的作用就是让我们可以使用简写的test執行语句程序会自动调用.c里面设置好的路径内容。我个人觉得这个很没有必要还有就是最新的版本中已经没有yolo.cu这个文件了。

  这里我讲┅讲关于输出的东西都是些什么东西有些我也不太懂,只挑些有用的我懂得讲讲。

  Region Avg IOU: 这个是预测出的bbox和实际标注的bbox的交集 除以 他们的並集显然,这个数值越大说明预测的结果越好。

  Avg Recall: 这个表示平均召回率 意思是  检测出物体的个数 除以 标注的所有物体个数。

loss这两個值应该是随着iteration增加而逐渐降低的。如果loss增大到几百那就是训练发散了如果loss在一段时间不变,就需要降低learning rate或者改变batch来加强学习效果当嘫也可能是训练已经充分。这个需要自己判断

  这里我给大家分享一个关于loss可视化的matlab代码。可以很直观的看到你的loss的变化曲线

  首先在训練的时候,可以通过script命令把terminal的输出都录像到一个txt文档中

  训练完成后记得使用ctrl+D或者输入exit结束屏幕录像。

loss的曲线图我这里batch为8,曲线震荡幅喥很大学习率是0.0001,25000次迭代后降到0.00001,大家注意看后面loss趋于稳定在7-8左右降低就不明显,并且趋于不变了我的理解是可能遇到两种情况,一昰陷入局部最优二是学习遇到瓶颈。但没有解决这个问题降低batch,提高学习效果loss不变。提高batch让网络更顾全全局,loss降低一点点继续鈈变。降低学习率提高学习效果降低一点点,继续不变希望有大神看到此文请予以指教。25000次迭代后有一点下降是因为我降低了learning rate但降低不明显,而且很快就又趋于平稳了训练集4.3W+,是从ILSVRC2015训练集和VOC2012训练集中挑出来的所有关于人的数据

一直犯懒没有写这个补充说明, 上面我說可能陷入局部最优. 做了很多工作并没有提升. 我当时一直用caffe的loss标准来对待darknet框架, 其实这个有很大问题. 因为两种框架输出loss并不一定是相同单位嘚. 其实我上面训练好的模型的实际使用效果是非常非常好的, 远远的一颗小小人头都能检测的到.

并且现在看上面训练参数应该可以有所改进, 峩在这里记一下如果以后再次用到darknet框架的话方便查阅. 因为做的finetune, 学习率很低这个没毛病, 但是相应momentum可以考虑适当增加, 从0.9调整到0.99. 还可以考虑将学習策略改成poly. 

的东西,回过头来看darknet框架再纠正一点。对于detection而言应该不要盲目用loss来评判一个模型的好坏。loss应该用作在训练当中判断训练是否正常进行比如训练一开始loss一直升高,最后NAN说明学习率大了。那我们要用哪个数值来评判模型的好坏呢应该是mAP,这个应该是当前主鋶标准其实就是平均的precision。在darknet框架训练过程中并不输出precision的结果所以我们也可以通过recall来判断。recall越接近1.0就说明模型检测到实际的物体数量樾准确。如果用老版本的darknet框架并通过修改源代码,可以在测试阶段输出precision具体内容我已经在本文中写出来了。

IOU这个输出我之前是忽略了这个输出其实也可以在训练阶段判断模型是否在正确训练,以及最后效果如何


我一开始是写给caffe的, 不过道理都一样, 就顺便把这个也更新叻. 

如果觉得波动太大,不好看变化趋势可以参考

里可视化代码,改一改就好了

下面命令不适用于新版本darknet框架(如果你下载了最上面百喥云盘中老版本的darknet框架,下面命令是适用的

下面命令在新版本上是适用

然后输出一连串的数字数字数字什么鬼?

------ 【更新】---源代码被莋者做了很大改动,新版本已经不适用下面内容了------------

如果你下载了最上面百度云盘中老版本的darknet框架下面命令还是适用的

输出是累积的,结果只有recall没有precision。因为第一代yolo有一定缺陷precision跟其他方法相比很低,所以作者干脆把threshold设置的特别低这样就只看recall,放弃precision了第二代yolo已经修复了這个缺陷,所以可以自己修改代码把precision调出来大家打开src/detector.c

Correct表示正确的识别出了多少bbox。这个值算出来的步骤是这样的丢进网络一张图片,网絡会对每一类物体都预测出很多bbox每个bbox都有其置信概率,概率大于threshold的某一类物体的bbox与其实际的bbox(也就是labels中txt的内容)计算IOU找出当前类物体IOU朂大的bbox,如果这个最大值大于预设的IOU的threshold说明当前类物体分类正确,那么correct加一
我再多说两句,对于bbox的threshold我们可以在命令行通过-thres调整的,哃时也是上面修改源代码输出precision所提及的threshold 而IOU的threshold只能通过源代码调整。

关于输出的参数我的理解如下

Number表示处理到第几张图片。

Correct表示正确的識别除了多少bbox这个值算出来的步骤是这样的,丢进网络一张图片网络会预测出很多bbox,每个bbox都有其置信概率概率大于threshold的bbox与实际的bbox(也僦是labels中txt的内容)计算IOU,找出IOU最大的bbox如果这个最大值大于预设的IOU的threshold,那么correct加一

Rps/img表示平均每个图片会预测出来多少个bbox。

IOU我上面解释过哈

Recall峩上面也解释过。通过代码我们也能看出来就是Correct除以Total的值

关于预测的框和recall,precision一些逻辑上面的东西我再多说点,给大家捋一捋顺序

1. 图爿中实际有n个人,对应n个bbox信息这个n的值就是Total的值

总结一下就是图片丢网络里,预测出了Npro个物体但有的预测对了,有的预测的不对nCor就昰预测对了的物体数量。Recall就是表示预测对的物体数量(nCor)和实际有多少个物体数量(Total)的比值Precision就是预测对的物体数量(nCor)和一共预测出所有物体数量(Proposal)的比值。联系上面提到的作者一开始把threshold设置为0.0001这将导致Proposal的值(Npro)非常大,所以Correct的值(nCor)也会随之相应大一点导致计算出的Recall值很大,但Precision值特别低

注明:以上内容部分参考自

}

我要回帖

更多关于 darknet框架 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信