Yolo系列论文:https://pjreddie.com/
Yolov1
动机
许多目标检测算法使用two-stage的方式,首先生成潜在的bbox,然后对bbox的内容进行分类,再进行后处理优化bbox、删除重复的检测并为这些bbox重新打分。这些流程使得检测过程很慢,难以加速
贡献
提出一个新的目标检测框架,视目标检测为一个回归问题,能够实现直接从图片像素到bbox坐标和分类概率的预测,具有检测速度快、图片全局推理预测、泛化表达能力强
算法
将图片分成SxS的网格,yolo会在每个格子检测是否有目标。如果有目标的中心位置落在一个格子内,则yolo需要对这个格子内容进行目标检测。
yolo会在每个格子中预测B个bbox和B个置信度。置信度反应了格子包含有目标的可能性。置信度的定义如下:
yolo为每个bbox预测5个值,分别是相对于bbox所在网格中心的x方向和y方向偏移占网格宽高的比例(x, y)(范围在0-1之间),bbox的宽和高分别占图片宽和高的比例(w, h)(范围在 0-1之间),表示预测bbox和GT bbox的IoU的置信度confidence。同时yolo会预测该网格内(注意:是针对网格,不是针对bbox)目标分类预测时属于C个类的C个概率值。。
网络结构
输入:448x448 RGB图片
输出:7x7x(2x5+20)形状的Tensor输出(7x7的网格,每个网络预测2个bbox,为每个bbox预测5个值x, y, w, h, cofidence,为每个网格预测目标分类概率20个类(pascal voc数据集))
网络训练
- 网络前20个卷积层在ImageNet 1000类数据集上进行预训练,输入图片大小224x224
- leaky relu
- 使用dropout防止过拟合
损失函数
普通的平方和误差对定位误差和分类误差看得同等重要,这不符合yolo最大化AP的目标,造成模型训练不稳定。由于图片中大部分网格中没有目标需要检测,所以为了防止无目标的网格对有目标的网格中置信度的预测的负面影响,本文提出一个新的损失函数。该损失函数主要是为了解决正负样本不平衡的问题。
优缺点
优点:
- 实现one-stage的目标检测,速度快,检测效果也好
缺点:
- 一个网格中只能检测一个目标,如果有多个目标,则难以同时检测
- 难以检测成群的各个小目标
- 对于特殊宽高比的目标检测效果不佳
- 对于小bbox的误差和大bbox的误差同等对待,但事实上对比小bbox和大bbox的等值误差,小bbox的误差的权重要远大于大bbox的误差
实验
数据集
Pascal Voc 2007
评价指标
mAP,FPS
结果
Yolov2(Yolo9000)
动机
当前的目标检测数据集规模远小于分类数据集规模。由于标注bbox代价较高,难以制作和分类数据集一样规模的大型目标检测数据集,也导致检测的目标类别数量有限
贡献
本文提出一个新方法,能够将大规模分类数据集应用于目标检测系统,使得检测类别更多。新的联合训练算法能够同时使用目标检测数据集和分类数据集训练yolov2
算法
Better
Yolov1算法存在定位不够准以及低召回率的问题。为了提高定位准确度和召回率,在yolov1的基础上做了如下改进:
- 为所有卷积层添加Batch Normalization,取代dropout,mAP提高2%
- 在ImageNet上预训练网络时输入图片由224x224改为448x448,mAP提高4%
- 不再直接预测x,y,w,h,而是引入anchor机制,在每个网格对不同大小的anchor bbox进行预测。mAP从69.5降到69.2,recall从81%升到88%
- 不再手工选择anchor大小和数量,而是使用k-means聚类算法对所有标签bbox进行聚类,得到k个类簇即为k个anchor box。box的聚类的距离计算:
- 在region proposal network中,box定位中使用的anchor box能够获得任意的偏移,从而可以偏移很远,这造成训练的不稳定。所以这里继续使用yolov1中的输出格式,预测相对于网格中心的bbox位置。yolov2对每个网格的每个anchor box预测5个值:,转换为预测的bbox的真正的中心点坐标(x, y)以及宽w和高h的公式:
其中使用了一个sigmoid函数和以e为底的指数函数,就是利用预测值对anchor box的cx,cy,pw,ph进行微调
- 为了更好地检测小目标,使用了一个跳跃连接,将低层细粒度的26x26的特征图concat到高层13x13特征图,带来1%的性能提升
- 训练时每隔10batch就换一个图片输入尺度输入网络,使得网络能很好的在不同规格的图片上进行预测。
Faster
为了实现更加高效的检测,Yolov2使用了darknet-19网络作为backbone
Stronger
提出一个新的训练机制,能够让分类数据集和目标检测数据集共同用于网络训练。分类数据集中的标签范围更加广泛,比如狗这个大类中也分好几个不同的狗的品种,而在目标检测中无论是什么品种的狗,只需要狗这个大类标签。这使得让分类数据集和目标检测数据集共同用于网络训练变得困难。所以本文提出一个多标签模型来整合分类数据集和目标检测数据集,忽略数据集原本的结构特点。
将ImageNet中的WordNet的图结构改为WordTree的树结构。在分类预测某个树节点的概率时,首先预测该节点的子节点的条件概率:
如果想计算某个树节点的绝对概率,则使用概率论中的链式法则:
这里假设
当对图片进行分类时,对该图片进行多标签的预测,所以1000类图片分类时使用softmax要预测1369个类,多出来的369个类就是一些大类标签,也就是WordTree的非叶节点。
使用darknet19训练并预测,得到71.9%的top1准确率,90.4%的top5准确率。在检测时,也可以使用yolov2进行目标检测,预测存在某个目标的概率树和bbox,然后根据概率树得到目标类别。
通过WordTree能够组合多个不同的数据集,比如COCO和ImageNet
将COCO目标检测数据集和ImageNet前9000类整合为一个数据集,用于YOLO9000的训练。当在目标检测图片上做检测时,损失被正常反向传播,当在分类图片上做分类时,只反向传播标签在WordTree中所在层以及更高层的祖先标签的分类损失。
实验
数据集
Pascal voc 2007,Pascal voc 2012,COCO
评价指标
mAP,FPS
结果
优缺点
优点:
- 在Yolov1的基础上做了很多改进,比如提出darknet19、设计新的预测输出等等,在速度和mAP上都得到了提升
- 在选择anchor box时使用了k-means的方法,这为一些特定目标的检测中anchor的设计提供了很好的思路
- 通过构建WordTree实现了目标检测数据集和分类数据集的联合训练,使得yolo9000可以检测更多目标
缺点:
- ImageNet和COCO数据集较大,构建WordTree应该是一个工作量很大的任务
- 在混合数据集上训练时,网络是如何判断当前输入的分类图片还是检测图片的?这个感觉没说清楚(有时间仔细去看看代码)
- 既然网络的输出变了,那么损失函数是否在yolov1的基础上有所改变?文中没有仔细说清楚(有时间仔细去看看代码)
Yolov3
动机
参考已有的研究,yolov2应该有进一步改进提升效果的空间
贡献
对yolov2进行了升级,在一系列算法设计上做了改进,并也实验验证了一些无效的改进措施
算法改进
将结合pytorch版本的yolov3代码进行详细讲解,代码链接https://github.com/eriklindernoren/PyTorch-YOLOv3
Bbox的预测
改进了预测tx, ty, tw, th的损失函数,使用了预测值和标签值的平方误差和作为损失函数,代码如下:
loss_x = self.mse_loss(x[obj_mask], tx[obj_mask])
loss_y = self.mse_loss(y[obj_mask], ty[obj_mask])
loss_w = self.mse_loss(w[obj_mask], tw[obj_mask])
loss_h = self.mse_loss(h[obj_mask], th[obj_mask])
yolov3也会为每个bbox预测一个置信值,然后使用sigmoid函数(也就是论文中所说的逻辑回归)转换为置信度:
pred_conf = torch.sigmoid(prediction[..., 4]) # Conf
bbox有目标的置信度和没有目标置信度分别计算二值交叉熵损失:
loss_conf_obj = self.bce_loss(pred_conf[obj_mask], tconf[obj_mask])
loss_conf_noobj = self.bce_loss(pred_conf[noobj_mask], tconf[noobj_mask])
训练时希望那些和标签bbox的mIoU很大的预测的bbox的置信度尽量接近1。
在寻找最佳匹配标签bbox的anchor box的时候,直接选择和标签bbox的mIoU最大的anchor bbox作为唯一一个预测bbox。但同时也存在一些anchor box和标签bbox的mIoU是次大的,且mIoU大于某个设定的threshold(论文中设为0.5),则这个anchor box不会去匹配任何标签bbox,也不会产生损失函数,这个设计体现在util.py文件中的build_targets函数,其中有这么两句代码:
# Set masks
obj_mask[b, best_n, gj, gi] = 1
noobj_mask[b, best_n, gj, gi] = 0
# Set noobj mask to zero where iou exceeds ignore threshold
for i, anchor_ious in enumerate(ious.t()):
noobj_mask[b[i], anchor_ious > ignore_thres, gj[i], gi[i]] = 0
上述代码其实就是将那些和标签bbox的mIoU是次大的,且mIoU大于某个设定的threshold的anchor box所对应的obj_mask以及noobj_mask都设置为0,这样在后续的loss计算中就会忽略这些anchor box的损失。
分类预测
不再使用softmax损失函数对每个预测bbox进行多分类预测,而是使用了二值交叉熵损失函数。这样的损失函数能够方便在其他数据集上进行多标签分类预测
loss_cls = self.bce_loss(pred_cls[obj_mask], tcls[obj_mask])
跨尺度预测
yolov3在三个不同的尺度上进行目标检测。在一个NxN的尺度上预测的tensor为
N × N × [3 ∗ (4 + 1 + 80)] (3个anchor box,bbox的tx,ty,tw,th四个值,1个置信值,80个类的分类值,特别注意:这里和yolov1和v2的不同之处在于80个分类值不是针对每一个grid,而是针对每一个anchor box)。使用k-means聚类获得9个anchor box:
每个尺度上各使用3个anchor box
特征提取器
在分类任务darknet-53比darknet-19更加强大,也比resnet101和resnet152更加高效
无效的改进
以下改进均没有获得性能的提升:
- 对anchor box的中心点(x, y)的偏移进行预测
- 对anchor box的中心点(x, y)直接线性预测
- Focal loss
- 设置两个mIoU界限,mIoU大于0.7为正样本,在0.3-0.7忽略,小于0.3为抚养比
实验
数据集
COCO
评价指标
mAP,time
结果
优缺点
优点
- 在多尺度特征图上进行了多次目标检测,充分使用了粗细粒度的特征来增强检测效果
- 尝试了很多改进措施,也分别验证了哪些措施是有效的,哪些是无效的,为后续进一步的改进奠定基础
缺点
在yolov2的基础上进行了改进,但一些改进不够突出,比如yolov1和v2是对每个grid预测80个分类值,而yolov3是对每一个anchor box预测80个分类值。个人感觉这是一个比较重要的改进,但是作者并没有对这一点做一些对比实验验证效果。
反思
- 对yolov3整体流程的梳理:(1)输入一张rgb图片,然后输出三个不同尺度的tensor,包含三个不同尺度上的检测结果。(2)假设某个尺度为NxN,则tensor中元素个数为N × N × [3 ∗ (4 + 1 + C)](3个anchor box,bbox的tx,ty,tw,th四个值,1个置信值,C个类的分类值)。(3)训练:首先使用anchor box和标签bbox进行匹配,为每一个标签bbox匹配一个mIoU最大的anchor box,再将一些anchor box和标签bbox的mIoU是次大的,且mIoU大于某个设定的threshold(论文中设为0.5)的anchor box直接忽略,不计算损失。然后对匹配好的每一对bbox计算对应的标签tx,ty,tw,th,然后对标签tx,ty,tw,th和预测的tx,ty,tw,th计算loss用于反向传播。对于有匹配标签bbox的anchor box使用二值交叉熵计算obj loss,使其尽可能提高目标存在的概率,而对于没有匹配标签bbox的anchor box使用二值交叉熵计算nonobj loss,使其尽可能降低目标存在的概率。在计算分类损失时,只计算有匹配标签bbox的anchor box的分类损失,使用二值交叉熵计算loss。(4)测试:筛选出存在目标概率大于obj_threshold的预测bbox,将这些bbox的tx,ty,tw,th转换为真正的bbox角点的坐标值。然后使用nms对每个类的所有bbox进行进一步筛选,得到最后的预测bbox。
- 从yolov1到v3的演化中,我们可以看到在网络结构改进、anchor机制、训练数据增广、损失函数设计等方面都可以提高目标检测效果。这些措施也同样可以用到其他任务上进行改进。