yolov算法详解_YOLO原理及代码整理以及学习笔记 (v1-v3)

总体来说我的学习顺序是YOLOV1 文章及代码 –> YOLOv1-v3演进原理 –> YOLOV3文章及代码

YOLO-V1文章及代码

原理:

这个对应代码里的第一个

这个对应代码里的第三个比较简单的实现inference

代码:

这个star比较多,正在跟进改结构

这个网络结构写法是和第一个一样的,有一些注释,可以参考

这个是一个简单实现版本,可以玩玩,看看原理,但是scope name有点问题,感觉比较难嵌入到已有模型中。

YOLOv1-v3演进原理

主要参考:

yolo-v1

yolov1中有一点,每一个框预测的是(x,y,width,height),那么有一点,对不同大小的box预测中,相比于大box预测偏一点,小box预测偏一点肯定更不能被忍受的。而sum-square error loss中对同样的偏移loss是一样。为了缓和这个问题,作者用了一个比较取巧的办法,就是将box的width和height取平方根代替原本的height和width,小box的横轴值较小,发生偏移时,反应到y轴上相比大box要大。例如16开根之后是4, 0.25开根之后反而变成了更大的0.5。

yolov1损失函数:

另外有一点,模型使用imagenet的前20层加了几层卷积层作为它的网络架构,一般来说要先经过分类训练然后再做目标检测训练。

yolov1缺点:

这里个有问题,预训练非常重要,因为首先要【知道什么东西是什么】,才能【识别什么东西在哪里】,人的理解过程尚且是这样的,模型更不用说了。yolov1公开的分类预训练模型一般都是在voc2007,voc2012数据集上与训练的,类别只有20类,如人、摩托之类的。拿这个预训练权重来对新的图片做前向inference,可想而知效果不好,这个不好并不是说我们的box选择的不好(yolov1中box有98个),可以说这98个box都不会好,因为预训练的问题。

小物体,相互靠的很近的物体,还有很小的群体识别不了,这个是由于它的设计理念导致的,详见yolov1原文以及解读博客等。另外在loss函数中,大物体IOU误差和小物体IOU误差对网络训练中loss贡献值接近(虽然采用求平方根方式,但没有根本解决问题)。因此,对于小物体,小的IOU误差也会对网络优化过程造成很大的影响,从而降低了物体检测的定位准确性。

同一类物体出现的新的不常见的长宽比和其他情况时,泛化能力偏弱。这是因为YOLO方法模型训练依赖于物体识别标注数据,对于非常规的物体形状或比例,YOLO的检测效果并不理想。

yolo9000 yolov2

yolo2代的改进比较多,总的来说下面几点比较重要:

添加了BN层,在神经网络的每一层,在网络(线性变换)输出后和激活函数(非线性变换)之前增加一个BN层

在imagenet上fine-tune的时候就使用了448×448,而不是224×224。准确来说,YOLO2在采用 224*224 图像进行分类模型预训练后,再采用 448*448 的高分辨率样本对分类模型进行微调(10个epoch),使网络特征逐渐适应 448*448 的分辨率。然后再使用 448*448 的检测样本进行训练,缓解了分辨率突然切换造成的影响。

取消全连接层,改用Fast R-CNN中的anchor boxes(是先验框!)来预测目标方框。使用聚类方法获得5个anchor box宽高的比例(而不是Faster R-CNN中固定比例)。 图像的输入从448×448改为416×416,这样是为了下采样32倍之后得到13×13奇数的特征图。 从这13×13特征图上每一个点映射回原图得到13×13×5个目标框。 并且从预测目标相对坐标改为预测目标相对于网格单元的直接位置坐标(sigmoid约束到0~1)

特征融合: 把倒数第二层26×26×512卷积层的特征,经过隔行和隔列提取,得到4个13×13×512的特征,再联合成13×13×2048的特征图,跟最后一层13×13×1024特征图融合起来检测,使得结果对小目标敏感

训练技巧上,每训练10个batch后随机选择新的不同尺寸的图像训练,图像大小以32的倍数增加或减小,以提高系统对不同尺寸图像的适应能力

检测类别的提升: (论文中使用设置)v1的种类最多可以有7×7×2=98个boxes(种类),v2中可以有13×13×5=745个boxes(种类)

因为整合演进的文章可能会写的比较泛,这边还看了一些关于YOLO二代的文章:

BN的文章:

关于YOLO2的anchor box的详细理解:

借鉴Faster RCNN的做法,YOLO2也尝试采用先验框(anchor)。在每个grid预先设定一组不同大小和宽高比的边框,来覆盖整个图像的不同位置和多种尺度,这些先验框作为预定义的候选区在神经网络中将检测其中是否存在对象,以及微调边框的位置。

同时YOLO2移除了全连接层。另外去掉了一个池化层,使网络卷积层输出具有更高的分辨率。

之前YOLO1并没有采用先验框,并且每个grid只预测两个bounding box,整个图像98个。YOLO2如果每个grid采用9个先验框,总共有13*13*9=1521个先验框。所以,相对YOLO1的81%的召回率,YOLO2的召回率大幅提升到88%。同时mAP有0.2%的轻微下降。

不过YOLO2接着进一步对先验框进行了改良。

聚类提取先验框尺度

之前先验框都是手工设定的,YOLO2尝试统计出更符合样本中对象尺寸的先验框,这样就可以减少网络微调先验框到实际位置的难度。YOLO2的做法是对训练集中标注的边框进行聚类分析,以寻找尽可能匹配样本的边框尺寸。

聚类算法就需要一个距离函数嘛,这里的距离函数:

centroid就是被选为聚类中心的那个anchor box。这个距离函数比较直观,IOU越大,距离越近。

约束预测边框的位置

具体可以见上面分享的那篇YOLO二代的详解博客。简单来说就是预测anchor box的中心bx, by, 宽高bw, bh以及置信度,并且约束中心点在单个网格之内(这里网格的概念和yolo1一样的)

passthrough层检测细粒度特征

这个比较悬,就是在最后一个pooling之前,特征图的大小是26*26*512,将其1拆4,直接传递(passthrough)到pooling后(并且又经过一组卷积)的特征图,两者叠加到一起作为输出的特征图,这个操作说是可以使mAP提升1,具体可以看分析博客或原文。

多尺度图像训练

每10个epoch换一个尺寸。尺寸只要是32的倍数就行,320,352……等等。

其实yolov2虽然做了超多改进,但是大多数都是已有论文中的方法运用上去,核心的一个创新还是多尺度图像训练这点。

yolov3

yolov3的改进的话主要是:

更深的网络,特征提取更充分,参考了ResNet,增加了直接连接 shortcut connections,层数达到53层(darknet-53)。

在多个尺度上的预测(类似FPN),在倒数第二和倒数第三层26×26和52×52层的特征上分别进行预测,每个尺度预测3个box,一共3个尺度共9个。由v2中每个点预测5个bbox改为预测9个。

对每个建议框使用多个逻辑回归而不是softmax进行分类,这是考虑到实际中物体间叠加的情况很常见,softmax只能给出最大分类,导致漏检,并且实际上softmax可被独立的多个logistic分类器替代,且准确率不会下降.分类损失采用binary cross-entropy loss.

YOLO-V3文章及代码

YOLOv3论文的干货并不多,用作者自己的话说是一篇“Tech Report”。这篇主要是在yolov2的基础上的一些trick尝试,有的trick成功了,有的trick失败了

文章:

这一份里面有一些keras源码

这篇文章中有一幅图比较好地展示了yolov3是怎么从三个尺度预测的:

简单的来说,yolov3中,对于一个416*416的输入图像,在每个尺度的特征图的每个网格设置3个先验框,总共有 13*13*3 + 26*26*3 + 52*52*3 = 10647 个预测。每一个预测是一个(4+1+80)=85维向量,这个85维向量包含边框坐标(4个数值),边框置信度(1个数值),对象类别的概率(对于COCO数据集,有80种对象)。来看看之前的发展,YOLO1采用7*7*2=98个预测,YOLO2采用13*13*5 = 845个预测,YOLO3的尝试预测边框数量来到了10647 个,而且是在不同分辨率上进行,mAP以及对小物体的检测效果很自然的是会有提升。

如果说要从具体模型结构上来看,我觉得还是要结合代码。

光看代码可能有点懵,下面有一些博客是对这份复现的部分解析(可以先看一下,再自己通读代码)

backbone网络结构:

整个Yolov3网络结构:

YOLO3-YunYang1994版本的这个代码也不复杂,自己从头到尾读一下就能读懂,这边也找到一系列对这个代码的详细解读(因为我是直接读的源码,没看文章,不保证这系列文章描述的一定正确哈!)

下面记录几个代码实现上的点:

k-means具体做法。我看到github上有一个抽象写法 anchor-kmeans,这种方法k-means细节是先随机选k个框作为中心点,在将每一个点绑定到具体聚类后,是采用中位数的方法来更新聚类中心的,而不是平均计算聚类中每个anchor box的w,h。

yolov3中很有意思的一点是把所有东西都用卷积替代了,池化换成了卷积(通过步长设置成(2,2)来缩小一倍),全连接也用全卷积来代替了,看代码:

conv_lbbox = common.convolutional(conv_lobj_branch, (1, 1, 1024, 3*(self.num_class + 5)), trainable=self.trainable, name='conv_lbbox', activate=False, bn=False)

要说这样做的好处,我觉得一个最大的好处就是输入分辨率可以任意,因为不用摊平嘛。。

Post Views:

1,679

你可能感兴趣的:(yolov算法详解)