来自 | 知乎  作者 | 科技猛兽链接 | https://zhuanlan.zhihu.com/p/183781646编辑 | 深度学习这件小事公众号本文仅作学术交流,如有侵权,请联系后台删除。上篇文章我们介绍了YOLO v1的设计和演变过程(你一定从未看过如此通俗易懂的YOLO系列(从v1到v5)模型解读 (上)),从本文开始我们继续介绍YOLO series接下来的工作,但是因为YOLO下面的工作内容太多,所以本文只介绍YOLO v2 v3 v4 v5对于检测头head和损失函数loss的优化,剩下的backbone方面的优化留到下一篇文章吧。

为了使本文尽量生动有趣,我仍然用葫芦娃作为例子展示YOLO的过程(真的是尽力了。。。)。

葫芦娃

下面进入正题,首先回顾下YOLO v1的模型结构,忘记了的同学请看上面的文章并点赞,如下面2图所示:

YOLO

YOLO

我们认为,检测模型=特征提取器+检测头

在YOLO v1的模型中检测头就是最后的2个全连接层(Linear in PyTorch),它们是参数量最大的2个层,也是最值得改进的2个层。后面的YOLO模型都对这里进行改进:

YOLO v1一共预测49个目标,一共98个框。

5 YOLO v2

  • 检测头的改进:

YOLO v1虽然快,但是预测的框不准确,很多目标找不到:

  • 预测的框不准确:准确度不足。

  • 很多目标找不到:recall不足。

我们一个问题一个问题解决,首先第1个:

  • 问题1:预测的框不准确:

当时别人是怎么做的?

同时代的检测器有R-CNN,人家预测的是偏移量。

什么是偏移量?

YOLO v2

之前YOLO v1直接预测x,y,w,h,范围比较大,现在我们想预测一个稍微小一点的值,来增加准确度。

不得不先介绍2个新概念:基于grid的偏移量和基于anchor的偏移量。什么意思呢?

基于anchor的偏移量的意思是,anchor的位置是固定的,偏移量=目标位置-anchor的位置。

基于grid的偏移量的意思是,grid的位置是固定的,偏移量=目标位置-grid的位置。

Anchor是什么玩意?

Anchor是R-CNN系列的一个概念,你可以把它理解为一个预先定义好的框,它的位置,宽高都是已知的,是一个参照物,供我们预测时参考。

上面的图就是YOLO v2给出的改进,你可能现在看得一脸懵逼,我先解释下各个字母的含义:

 :模型最终得到的的检测结果。

 :模型要预测的值。

 :grid的左上角坐标,如下图所示。

 :Anchor的宽和高,这里的anchor是人为定好的一个框,宽和高是固定的。


通过这样的定义我们从直接预测位置改为预测一个偏移量,基于Anchor框的宽和高和grid的先验位置的偏移量,得到最终目标的位置,这种方法也叫作location prediction。

这里还涉及到一个尺寸问题:

刚才说到  是模型要预测的值,这里  为grid的坐标,画个图就明白了:

图1:原始值

如图1所示,假设此图分为9个grid,GT如红色的框所示,Anchor如紫色的框所示。图中的数字为image的真实信息。

我们首先会对这些值归一化,结果如下图2所示:

图2:要预测的值

归一化之后你会发现,要预测的值就变为了:

这是一个偏移量,且值很小,有利于神经网络的学习。

你可能会有疑问:为什么YOLO v2改预测偏移量而不是直接去预测  ?

上面我说了作者看到了同时代的R-CNN,人家预测的是偏移量。另一个重要的原因是:直接预测位置会导致神经网络在一开始训练时不稳定,使用偏移量会使得训练过程更加稳定,性能指标提升了5%左右。

位置上不使用Anchor框,宽高上使用Anchor框。以上就是YOLO v2的一个改进。用了YOLO v2的改进之后确实是更准确了,但别激动,上面还有一个问题呢~

  • 问题2:很多目标找不到:

你还记得上一篇讲得YOLO v1一次能检测多少个目标吗?答案是49个目标,98个框,并且2个框对应一个类别。可以是大目标也可以是小目标。因为输出的尺寸是:[N, 7, 7, 30]。式中N为图片数量,7,7为49个区域(grid)。

YOLO v2首先把  个区域改为  个区域,每个区域有5个anchor,且每个anchor对应着1个类别,那么,输出的尺寸就应该为:[N,13,13,125]。

这里面有个bug,就是YOLO v2先对每个区域得到了5个anchor作为参考,那你就会问了:每个区域的5个anchor是如何得到的?

下图可以回答你的问题:

methods to get the 5 anchor

方法:对于任意一个数据集,就比如说COCO吧(紫色的anchor),先对训练集的GT bounding box进行聚类,聚成几类呢?作者进行了实验之后发现5类的recall vs. complexity比较好,现在聚成了5类,当然9类的mAP最好,预测的最全面,但是在复杂度上升很多的同时对模型的准确度提升不大,所以采用了一个比较折中的办法选取了5个聚类簇,即使用5个先验框。

所以到现在为止,有了anchor再结合刚才的  ,就可以求出目标位置。

anchor是从数据集中统计得到的。

  • 损失函数为:

YOLO v2损失函数

这里的W=13,H=13,A=5。
每个  都是一个权重值。c表示类别,r表示rectangle,即(x,y,w,h)。
第1,4行是confidence_loss,注意这里的真值变成了0和IoU(GT, anchor)的值,你看看这些细节。。。
第5行是class_loss。
第2,3行:t是迭代次数,即前12800步我们计算这个损失,后面不计算了。这部分意义何在?
意思是:前12800步我们会优化预测的(x,y,w,h)与anchor的(x,y,w,h)的距离+预测的(x,y,w,h)与GT的(x,y,w,h)的距离,12800步之后就只优化预测的(x,y,w,h)与GT的(x,y,w,h)的距离,为啥?因为这时的预测结果已经较为准确了,anchor已经满足我了我们了,而在一开始预测不准的时候,用上anchor可以加速训练。你看看这操作多么的细节。。。 是什么?第k个anchor与所有GT的IoU的maximum,如果大于一个阈值,就  ,否则的话:  。

好,到现在为止,YOLO v2做了这么多改进,整体性能大幅度提高,但是小目标检测仍然是YOLO v2的痛。直到kaiming大神的ResNet出现,backbone可以更深了,所以darknet53诞生。

最后我们做个比较:

YOLO v1和v2的比较


6 YOLO v3

  • 检测头的改进:

之前在说小目标检测仍然是YOLO v2的痛,YOLO v3是如何改进的呢?如下图所示。

YOLO v3

我们知道,YOLO v2的检测头已经由YOLO v1的  变为 了,我们看YOLO v3检测头分叉了,分成了3部分:

  • 13*13*3*(4+1+80)

  • 26*26*3*(4+1+80)

  • 52*52*3*(4+1+80)

预测的框更多更全面了,并且分级了。

我们发现3个分支分别为32倍下采样,16倍下采样,8倍下采样,分别取预测大,中,小目标。为什么这样子安排呢?

因为32倍下采样每个点感受野更大,所以去预测大目标,8倍下采样每个点感受野最小,所以去预测小目标。专人专事。

发现预测地更准确了,性能又提升了。

又有人会问,你现在是3个分支,我改成5个,6个分支会不会更好?

理论上会,但还是那句话,作者遵循recall vs. complexity的trade off。

图中的123456789是什么意思?

答:框。每个grid设置9个先验框,3个大的,3个中的,3个小的。

每个分支预测3个框,每个框预测5元组+80个one-hot vector类别,所以一共size是:

3*(4+1+80)

每个分支的输出size为:

  • [13,13,3*(4+1+80)]

  • [26,26,3*(4+1+80)]

  • [52,52,3*(4+1+80)]

当然你也可以用5个先验框,这时每个分支的输出size为:

  • [13,13,5*(4+1+80)]

  • [26,26,5*(4+1+80)]

  • [52,52,5*(4+1+80)]

就对应了下面这个图:

YOLO v3

检测头是DBL,定义在图上,没有了FC。

还有一种画法,更加直观一点:


YOLO v3 head

anchor和YOLO v2一样,依然是从数据集中统计得到的。

  • 损失函数为:

YOLO v3损失函数

第4行说明:loss分3部分组成:
第1行代表geo_loss,S代表13,26,52,就是grid是几乘几的。B=5。
第2行代表class_loss,和YOLO v2的区别是改成了交叉熵。
第3行代表confidence_loss,和YOLO v2一模一样。

最后我们做个比较:

YOLO v1 v2和v3的比较

7 疫情都挡不住的YOLO v4

第一次看到YOLO v4公众号发文是在疫情期间,那时候还来不了学校。不得不说疫情也挡不住作者科研的动力。。。

  • 检测头的改进:

YOLO v4的作者换成了Alexey Bochkovskiy大神,检测头总的来说还是多尺度的,3个尺度,分别负责大中小目标。只不过多了一些细节的改进:

1.Using multi-anchors for single ground truth

之前的YOLO v3是1个anchor负责一个GT,YOLO v4中用多个anchor去负责一个GT。方法是:对于  来说,只要  ,就让  去负责  。

这就相当于你anchor框的数量没变,但是选择的正样本的比例增加了,就缓解了正负样本不均衡的问题。

2.Eliminate_grid sensitivity

还记得之前的YOLO v2的这幅图吗?YOLO v2,YOLO v3都是预测4个这样的偏移量

图3:YOLO v2,YOLO v3要预测的值

这里其实还隐藏着一个问题:

模型预测的结果是:  ,那么最终的结果是:  。这个  按理说应该能取到一个grid里面的任意位置。但是实际上边界的位置是取不到的,因为sigmoid函数的值域是:  ,它不是  。所以作者提出的Eliminate_grid sensitivity的意思是:将  的计算公式改为:

这里的1.1就是一个示例,你也可以是1.05,1.2等等,反正要乘上一个略大于1的数,作者发现经过这样的改动以后效果会再次提升。

3.CIoU-loss

之前的YOLO v2,YOLO v3在计算geo_loss时都是用的MSE Loss,之后人们开始使用IoU Loss。

 它可以反映预测检测框与真实检测框的检测效果。

但是问题也很多:不能反映两者的距离大小(重合度)。同时因为loss=0,没有梯度回传,无法进行学习训练。如下图4所示,三种情况IoU都相等,但看得出来他们的重合度是不一样的,左边的图回归的效果最好,右边的最差:

图4:IoU Loss不能反映两者的距离大小

  • 所以接下来的改进是:

 ,  为同时包含了预测框和真实框的最小框的面积。

图4:GIoU Loss

GIoU Loss可以解决上面IoU Loss对距离不敏感的问题。但是GIoU Loss存在训练过程中发散等问题。

  • 接下来的改进是:

其中,  ,  分别代表了预测框和真实框的中心点,且代表的是计算两个中心点间的欧式距离。代表的是能够同时包含预测框和真实框的最小闭包区域的对角线距离。

图5:DIoU Loss

DIoU loss可以直接最小化两个目标框的距离,因此比GIoU loss收敛快得多。

但是DIoU loss依然存在包含的问题,即:

这2种情况 和 是重合的,DIoU loss的第3项没有区别,所以在这个意义上DIoU loss依然存在问题。

  • 接下来的改进是:

惩罚项如下面公式:

 其中  是权重函数,

而  用来度量长宽比的相似性,定义为

完整的 CIoU 损失函数定义:

最后,CIoU loss的梯度类似于DIoU loss,但还要考虑  的梯度。在长宽在  的情况下,  的值通常很小,会导致梯度爆炸,因此在  实现时将替换成1。

CIoU loss实现代码:

def bbox_overlaps_ciou(bboxes1, bboxes2):    rows = bboxes1.shape[0]    cols = bboxes2.shape[0]    cious = torch.zeros((rows, cols))if rows * cols == 0:return cious    exchange = Falseif bboxes1.shape[0] > bboxes2.shape[0]:        bboxes1, bboxes2 = bboxes2, bboxes1        cious = torch.zeros((cols, rows))        exchange = True

    w1 = bboxes1[:, 2] - bboxes1[:, 0]    h1 = bboxes1[:, 3] - bboxes1[:, 1]    w2 = bboxes2[:, 2] - bboxes2[:, 0]    h2 = bboxes2[:, 3] - bboxes2[:, 1]

    area1 = w1 * h1    area2 = w2 * h2

    center_x1 = (bboxes1[:, 2] + bboxes1[:, 0]) / 2    center_y1 = (bboxes1[:, 3] + bboxes1[:, 1]) / 2    center_x2 = (bboxes2[:, 2] + bboxes2[:, 0]) / 2    center_y2 = (bboxes2[:, 3] + bboxes2[:, 1]) / 2

    inter_max_xy = torch.min(bboxes1[:, 2:],bboxes2[:, 2:])    inter_min_xy = torch.max(bboxes1[:, :2],bboxes2[:, :2])    out_max_xy = torch.max(bboxes1[:, 2:],bboxes2[:, 2:])    out_min_xy = torch.min(bboxes1[:, :2],bboxes2[:, :2])

    inter = torch.clamp((inter_max_xy - inter_min_xy), min=0)    inter_area = inter[:, 0] * inter[:, 1]    inter_diag = (center_x2 - center_x1)**2 + (center_y2 - center_y1)**2    outer = torch.clamp((out_max_xy - out_min_xy), min=0)    outer_diag = (outer[:, 0] ** 2) + (outer[:, 1] ** 2)    union = area1+area2-inter_area    u = (inter_diag) / outer_diag    iou = inter_area / unionwith torch.no_grad():        arctan = torch.atan(w2 / h2) - torch.atan(w1 / h1)        v = (4 / (math.pi ** 2)) * torch.pow((torch.atan(w2 / h2) - torch.atan(w1 / h1)), 2)        S = 1 - iou        alpha = v / (S + v)        w_temp = 2 * w1    ar = (8 / (math.pi ** 2)) * arctan * ((w1 - w_temp) * h1)    cious = iou - (u + alpha * ar)    cious = torch.clamp(cious,min=-1.0,max = 1.0)if exchange:        cious = cious.Treturn cious

所以最终的演化过程是:

MSE Loss  IoU Loss GIoU Loss DIoU Loss CIoU Loss


8 代码比论文都早的YOLO v5

  • 检测头的改进:

head部分没有任何改动,和yolov3和yolov4完全相同,也是三个输出头,stride分别是8,16,32,大输出特征图检测小物体,小输出特征图检测大物体。

但采用了自适应anchor,而且这个功能还可以手动打开/关掉,具体是什么意思呢?

加上了自适应anchor的功能,个人感觉YOLO v5其实变成了2阶段方法。

先回顾下之前的检测器得到anchor的方法:

Yolo v2 v3 v4:聚类得到anchor,不是完全基于anchor的,w,h是基于anchor的,而x,y是基于grid的坐标,所以人家叫location prediction。

R-CNN系列:手动指定anchor的位置。

基于anchor的方法是怎么用的:

anchor是怎么用的

有了anchor的  ,和我们预测的偏移量  ,就可以计算出最终的output:  。

之前anchor是固定的,自适应anchor利用网络的学习功能,让  也是可以学习的。我个人觉得自适应anchor策略,影响应该不是很大,除非是刚开始设置的anchor是随意设置的,一般我们都会基于实际项目数据重新运用kmean算法聚类得到anchor,这一步本身就不能少。

最后总结一下:


本文只介绍了YOLO v2 v3 v4 v5对于检测头head和损失函数loss的优化,剩下的backbone方面的优化实在是写不动了,放到下一篇吧。

为您推荐你一定从未看过如此通俗易懂的YOLO系列解读 (上)这21张深度学习速查表让你代码能力突飞猛进22课时、19大主题,CS 231n进阶版课程视频上线数据分析入门常用的23个牛逼Pandas代码如何在科研论文中画出漂亮的插图?

yolo迭代次数_你一定从未看过如此通俗易懂的YOLO系列(从v1到v5)模型解读 (中)相关推荐

  1. 你一定从未看过如此通俗易懂的YOLO系列(从v1到v5)模型解读 (中)

    你一定从未看过如此通俗易懂的YOLO系列(从v1到v5)模型解读 (中) https://zhuanlan.zhihu.com/p/183781646 你一定从未看过如此通俗易懂的YOLO系列(从v1 ...

  2. yolo如何降低loss_你一定从未看过如此通俗易懂的YOLO系列(从v1到v5)模型解读 (上)...

    转载请务必注明出处. 科技猛兽:你一定从未看过如此通俗易懂的YOLO系列(从v1到v5)模型解读 (上)​zhuanlan.zhihu.com 0 前言 本文目的是用尽量浅显易懂的语言让零基础小白能够 ...

  3. 你一定从未看过如此通俗易懂的YOLO系列(从V1到V5)模型解读!

    ↑ 点击蓝字 关注极市平台 作者丨科技猛兽@知乎 来源丨https://zhuanlan.zhihu.com/p/183261974(上) https://zhuanlan.zhihu.com/p/1 ...

  4. yolo如何降低loss_从未看过如此通俗易懂的YOLO系列

    公众号关注 "程序IT圈" 设为 "星标",公众号消息即可送达! 来自 | 知乎  作者 | 科技猛兽链接 | https://zhuanlan.zhihu.c ...

  5. ga设置迭代次数_种群进化+邻域搜索的混合算法(GA+TS)求解柔性作业车间调度问题(FJSP)算法介绍...

    程序猿声 代码黑科技的分享区 过去小编简单了解过作业车间调度问题(JSP),这两个月简单接触了柔性车间调度问题(FJSP),但是因为一些原因打算暂时研究到这里.在研究的时候,小编发现网上这方面的中文资 ...

  6. python实现牛顿法和梯度下降法求解对率回归_最优化问题中,牛顿法为什么比梯度下降法求解需要的迭代次数更少?...

    多图预警 本文讲你肯定能懂的机器学习多维极值求解,主要讲梯度下降和牛顿法的区别应该能够完美的回答题主的问题 事先说明 本文面向学习过高等数学统计学和线性代数基础知识的本科生,并假设读者拥有基本的矩阵运 ...

  7. 归并排序执行次数_十大排序算法,看这篇就够了

    排序算法分类[1][2] 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序. 非比较类排序:不通过比较来决定元素间的相对次序,它可以 ...

  8. 我从未看过荒原写作背景_您从未听说过的最佳数据科学认证

    我从未看过荒原写作背景 重点 (Top highlight) **Update 8/15: it's recently come to my attention that the certificat ...

  9. python实现yolo目标检测_从零开始PyTorch项目:YOLO v3目标检测实现

    在过去几个月中,我一直在实验室中研究提升目标检测的方法.在这之中我获得的最大启发就是意识到:学习目标检测的最佳方法就是自己动手实现这些算法,而这正是本教程引导你去做的. 在本教程中,我们将使用 PyT ...

  10. 智能算法中终止条件: “最大评估次数” or “最大迭代次数”

    使用 最大迭代次数依据: 智能算法既然是通过迭代,一步步的趋向最优解,那就应该在同样的代数下一代'进行对比 使用 评估次数依据: 一般  种群大小*迭代次数=评价次数.当种群大小一样时,可以使用迭代次 ...

最新文章

  1. Android中的复制粘贴
  2. html文件里的scr是什么,HTML中关于url、scr、href的区别
  3. Mysql 优化器内部JOIN算法hash join Nestloopjoin及classic hash join CHJ过程详解
  4. 安装Python readline模块
  5. win10cmd计算机管理界面,Win10命令提示符cmd在哪 Win10以管理员身份运行方法
  6. 归并算法(Java实现)
  7. 苹果cookie是打开还是关闭_关闭手机广告的几个操作
  8. 刘宇凡:让白茶陪你一起熬夜看世界杯
  9. 24段魔尺拼图指南_拼图项目动手指南
  10. 汽车电瓶电压12V验证
  11. Tomcat部署及优化
  12. python解决数学问题
  13. 网站的服务器ip变动,网站切换服务器IP,如何快速快速刷新DNS以获得测试?
  14. java理论_java入门——基础理论
  15. 桃词典 Peach Dictionary 简易英语词典app开发 安卓软件开发 Part 2
  16. 美柚如何精准引流?怎么通过美柚引流?美柚引流技巧
  17. 伯克利AI实验室最新发文:公布用于机器人抓取的Dexterity Network (Dex-Net) 2.0数据集...
  18. YV12toI420 yuv420、NV12、YV12相互转换
  19. 尝试在电脑端使用调试模式修改手机游戏的参数达到外挂效果
  20. Python学习笔记 - Python数据类型

热门文章

  1. 部分关键字--this/extends/super/static/final/abstract/访问权限总结
  2. 用PHP ping 一个 IP
  3. 大型企业网络配置系列课程详解(七) --NAT的配置与相关概念的理解
  4. 如何快速高效的群发Email
  5. SpringMVC Ⅰ
  6. 有效解决RaycastTarget勾选过多的烦恼
  7. python中append和insert_python append、extend与insert的区别
  8. postgresql是如何求年龄的_负债累累如何度过难关?她依靠此法三年还清300多万债务!...
  9. python多线程下载编程_Python多线程结合队列下载百度音乐代码详解
  10. C# 读取json文件与写json文件