用简洁的语言来阐述YOLO算法

描述

YOLO算法,英文全称是You Only Look Once,直接谷歌英文全称就能找到那篇论文,同时作者也在github上开源了代码。需要说明的是这篇推文是关于yolo v1,还有一个升级版。

顾名思义,这个算法就是只看一遍图片就能把所有的物体都识别出来,这个算法能够做到实时的物体检测,大约能达到40帧每秒,速度是非常快的。那如何去入手这个算法呢?相信大家已经看过不少介绍YOLO算法的文章了,所以我在这里也不打算深入去讲解这个算法了,而是尽量用简洁的语言去阐述一下这个如此迷人的算法。

算法

和其它推文最大的不同是,我会介绍如何从实战的角度去自己去做一个数据集,如何让电脑识别特定的一个物体。

那先来看一下我实现的效果是怎么样的。首先我随手找了我桌上的蓝色水杯,收集了两百多张自己水杯的图片,为了减少工作量,我用水杯的数据集去替换了原来是车辆(car)的所有数据。经过十几个小时的训练之后,效果如下:

算法

那怎么去实现呢?首先我觉得你要先“懂”这个算法,至少你要了解它是怎么实现的,原理是什么,输入输出是什么。为了学习这个算法,我也是花了大量时间去看作者的论文和代码。我觉得论文配合代码是一个很好的学习方式。通过代码可以很清晰去了解它是如何去实现这个算法的。

这个算法的核心在于它把图片划分成了7*7个网格,注意这7*7个网格不是将一张图片切割成49个小块,而是说一个网格会对应一个输出结果。可能会觉得有点抽象,我们先来看图。

算法

比如说上面这张图,一共有49个网格,每个网格的任务就是去判断这个物体的中心点是否落在该网格,如果是落在自身网格,那好,那这个网格就会跟系统汇报。假定上图中被标记的红色网格我们把它命名为小格,然后小格发现这里好像有条狗,于是乎它跟系统汇报说:我这里有条狗,然后系统问了一句:那这条狗有多宽有多高?小格好像有点懵,但是根据它的经验,小格大概能猜出来,于是回答了系统:这条狗大概100像素宽,250像素高吧。到这里,小格的任务就基本完成了,小格只是49个网格之一,其它的网格也一样。于是系统就收集了49个网格的意见,然后就得到了下图。

算法

其实在这张图片中可以出现49*2=81个预测框,也就是说没一个网格可以有对目标有两个预测,因此最多可以出现81个预测框。可以在图中看到,其实会出现很多无用框,相邻的网格可能会出现相似的结果,以此我们可以通过极大值抑制过滤一部分的预测框。然后就可以得到下图结果。

算法

但是相信我,即使你已经全部理解了上面我说的,你也不一定能一下子看懂代码,在我阅读代码的时候发现虽然代码不多,逻辑也比较清晰,但是有一些细节还是让人难以理解。那我就带大家来捋一下吧!

比较重要的代码主要是在pasal_voc.py、config.py、yolo_net.py和train.py。加载数据的代码在pasal_voc.py里面,代码并不是很难,不过要注意一点的就是一张图片的label其实是一个7*7*25的矩阵,一个25的向量组成是这样的:第一位是0或1,表示是否有物体,然后接下来的四位是边界框的信息,也就是(x,y,w,h),剩下的就是one-hot编码表类别。而预测的结果是7*7*30的,因为要预测两个框。

算法

还有一个比较精髓的是它损失函数的定义,它对每一个预测值都计算了均方误差,但是惩罚程度却是不一样的。

算法

其中λcoord = 5.0, λnoobj = 1.0, λclasses = 2.0,但是这组数字是这么得来的小编就不知道了,有可能是从大量测试中得到的一组最优解,也可能是从数学公式推算出来的吧。其实还有很多小细节,是很难描述出来的,如果要把一个小细节说明白可以就会牵扯到无数个细节,所以我建议你们自己通过代码去把细节搞懂。

在你已经了解了代码之后,就很容易做到文章开头的那个效果了。那我讲解一下我的思路和过程,最重要的还是要自己动手。当你去研究过它的数据集之后,你会发现这个数据集的标注是一个xml文件,每一个图片就对应一个xml文件。当你收集好数据集之后就可以去做数据集标记了,但是最简单的xml文件的格式是要求如下的:

算法

这个是我数据集中的标注,也是能满足代码的最简单的标注,我是自己写了一个程序帮助我完成标记的,但是我推荐你们可以用别人的标注工具,因为毕竟别人已经写好了就没有必要再去重复造车轮。

这个就是一个标注的工具 ,但是我也没用过,但是看描述应该是符合要求的。做好图片标注之后就要考虑如何去修改它的数据集呢?难不成一张张粘贴进去,当然你可以这样做,但是工作量是很大的,好吧,那就交给计算机去解决吧。我在加载数据集的时候做了一个判断,如果一旦这张图片里面有车,我就不加载这个数据了,指定一个路径让它去加载我们做好的数据集。

findcar = 0for obj in objs: cls_ind = obj.find('name').text.lower().strip() if cls_ind == 'car': findcar = 1        break

接下来就是你们思考如何去解决了。当你解决这个问题并能训练的时候,如无意外你应该能得到和我一样的结果,祝你们好运!

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分