yolov1是一个快速的one-stage目标检测器,独树一帜的用划分网格的策略实现目标检测,本文将详细解释yolov1算法,并简述如何用pytorch复现该算法。pytorch-yolov1 github 本文属于作者的理解,难免出现错误或者瑕疵,还请谅解与指正。
基本思想
简单回顾一下目标检测的做法,1.采用滑动窗口,对每个窗口分类和位置修正;2.RPN的方式先提取候选区域,特征图对应候选区域范围经过roipooling得到所需特征;3.SSD继承RPN类似的anchor机制,设定预设框并对每个预设框赋予groundtruth,全卷积网络训练目标。
yolo将输入图像划分为 $ S\times S $ 的网格,物体的中心落在哪一个网格内,这个网格就负责预测该物体的置信度,类别以及位置。
网络最后的输出是 $ S\times S\times 30 $ 的数据块,yolov1是含有全连接层的,这个数据块可以通过reshape得到。也就是说,输出其实已经丢失了位置信息(在v2,v3中用全卷积网络,每个输出点都能有各自对应的感受野范围)。这么一看,yolov1根据每张图像的目标label,编码出一个 $ S\times S\times 30 $ 的数据块,然后让卷积网络去拟合这个target,简单粗暴。
来看看 $ S\times S\times 30 $ 的数据块的具体含义。
$ S\times S $是图像位置,比如第一行第二列的网格,回到原图的位置也是如此。(有全连接层的时候,其实随意,只要你预测时每个位置的网格对应你编码时的网格就可以。全卷积层由于每个点的感受野的问题,最好是一一对应,否则原理上说不通,效果应该会差很多)
30的通道上分别是两个box的cxcy,wh,confidence,这就占了10个,再加上20个类别正好是30
cxcy表示物体的中心点坐标与对应网格左上角的偏差,注意归一化到0-1,需要除以网格大小;wh是物体相对于图片的大小,也在0-1之间;confidence是 \(P(object) \times IOU_{truth}^{pred}\),其中IOU在训练过程中是在线计算的
网络结构
网络结构在分类网络的基础上改进,v1的结构很简单,在v2,v3中,或者其他检测网络中,普遍会用特征层跨层连接融合,分层检测不同尺度大小目标的思路。主要是考虑浅层特征语义信息不充分,而小目标在深层特征图丢失的问题吧(个人理解)。
为了方便使用pytorch的预训练模型,我采用了resnet50,删除stage5后的全局池化和全连接层,增加一个带有空洞卷积的网络block(模仿detnet网络,增加感受野而不改变输出特征图大小)。
输入图像大小为448时,输出大小为14,所以我的网格设计要密集一点,这也是我增加空洞卷积block的原因,我担心输出点的感受野范围不够而影响大目标的检测,实际情况可能不会,未验证。
损失函数
yolov1的损失函数全是均方误差,需要理解的是其含义。
首先要明确两个概念,一是网格中有无目标,二是网格中的一个目标只有一个box负责(responsible)另一个box也算没有目标,根据在线计算IOU的大小确定哪一个负责。
confidence损失:负责检测的box的label是在线计算的IOU,不负责和无目标的都为0,为了平衡,加入\(\lambda _{noobj}\)
位置损失:容易理解,负责检测的才有位置损失,其他的都不需回传损失,也就不需要计算,此外小目标对于预测wh的误差更敏感,用开根的方法缓解。举例来说,大小为10和大小为100的目标,预测大小分别为20和110,损失一样但是显然小目标检测的更差一些,开根后,\((\sqrt{20} - \sqrt{10})^{2} = 1.7\),而\((\sqrt{110} - \sqrt{100})^{2} = 0.24\),相当于强化了小目标的wh的损失。
类别损失:容易理解,含有目标的网格才有类别损失,其他都不需要回传损失,也就不需要计算。默认网格只出现一种类别,这当然是有缺陷的。yolov1对于一些聚集的目标,检测效果会不好。其实聚集目标本身也算很难检测的情况吧。
复现总结
有了yolov1的基本概念,就可以开始写自己的检测器了,我采用了pytorch0.2的框架(等待1.0中),下面介绍一些重要的点。
数据流
数据流是指送入训练的每一个batch,一般都是(imgs_tensor,target_tensor),img部分需要做一些数据增强,比如颜色抖动,随机裁剪,平移变换,水平反转,做完数据增强最好可视化一下输出结果,确保box_label经过变换后是正确的。数据增强完后,根据box_label进行编码(就是按照yolo的思想生成$ S\times S\times 30 $ 的数据块作为target,含有目标的confidence先设置为1,用于区别不含目标的,IOU target在线计算)。
网络结构
在resnet50基础上按前文所述改进,输出为(batch_size, C, H, W),为了与之后的Yololoss匹配,改变一下顺序为 (batch_size, H, W, C),C为30。
YOLOLoss
pred_tensor和target_tensor形状一致,通过mask选取对应部分分别计算mesloss,最后按照公式相加起来。好在只需要写出前向传播过程就可以了。
数据块在30个通道上的含义为(cx,cy,w,h,contain_obj,cx,cy,w,h,contain_obj,cls1,cls2,...,cls20)
预测
网络的输出是 $ S\times S\times 30 $ 的数据块,首先用一个阈值选取含有目标的box,再用一个阈值筛选\(confidence\times P(cls)\),筛选后的框的cxcy从距离所在网格左上角的偏差解码为相对于图像左上角的距离,最后由NMS去除一些重叠的框。
NMS是大部分深度学习目标检测网络所需要的,大致算法流程为:
1.对所有预测框的置信度降序排序
2.选出置信度最高的预测框,确认其为正确预测(下次就没有他了,已经被确认了),并计算他与其他预测框的IOU
3.根据2中计算的IOU去除重叠度高的,IOU>threshold就删除
4.剩下的预测框返回第1步,直到没有剩下的为止
所有评论(0)