双阶段与单阶段目标检测的区别:
双阶段(two-stage):第一级网络用于候选区域的提取;第二级网络对提取的候选区域进行分类和精确坐标回归,如RCNN系列。
单阶段(one-stage):摒弃了候选区域提取这一步骤,只用一级网络就完成了分类和回归两个任务,列如YOLO和SSD等。
YOLOv1
YOLOv1(CVPR2015)
You Only Look Once:Unified,Real-Time Object Detection
思路是:直接输出中心在grid内目标的所有信息,包括置信度、边框回归、分类类别

参考:
https://gitthhub.github.io/2019/03/17/yolov1/
https://zhuanlan.zhihu.com/p/70387154
网络结构

YOLOv1 的基本网络结构如上图所示,共有24层卷积层和2层全连接层,图片下方参数中的s-2指的是步长为2,这里要注意以下三点:
- 在ImageNet中预训练网络时,使用的输入是
224*224,用于检测任务时,输入大小改为448*448,这是通过调整第一个卷积层的步长来实现的;预训练时,网络结构使用前 20 个卷积层加上平均池化和全连接层进行训练。 - 网络的设计借鉴了 GoogLeNet,使用了很多
1*1的卷积层来进行特征降维; - 最后一个卷积层的输出为
(7, 7, 1024),经过flatten后紧跟两个全连接层,形成一个线性回归,最后一个全连接层又被reshape成(7, 7, 30),形成对2个box坐标及20个物体类别的预测 (PASCAL VOC) (源码中实际上是预测了3个box->7*7*35)。 - 最后一层采用线性激活函数,其他层采用 leaky rectified linear activation,并且在第一个 fc 后添加 dropout 层,丢弃率 0.5,防止过拟合。
网络的输出特征解码图:

如上图所示,这就是最后一层全连接经过reshape之后的(7, 7, 30)的张量,这张图需要结合论文中所述的Grid Cell来理解。 我们知道,YOLO网络输入的是448*448的正方形图片,最终输出的是一个7*7的特征图,下采样倍数为64倍,在输出的7*7的特征图上,每个格点对应原图中一个64*64的区域,也就是论文中所述的Grid Cell。 在上面的图片中,7*7特征图中的每一个格点都是一个1*30的向量,格点对应原图中的一个64*64的Grid Cell,格点中的参数就是对以该Grid Cell中心的物体类别和bounding box的预测,因此很容易理解,对一张图片,每个格点预测一个物体类别和两个bounding box,预测阶段选择置信度高的 bounding box,这里要注意,每个格点的两个bounding box预测的是同一类物体,要是分别负责预测不同物体,则最后一层的shape应该为7*7*(2*(5+20))=7*7*50 (YOLOv2)。
训练时如何根据 grouth truth 打标签
训练过程中,grouth truth 顺序 confidence,x,y,w,h,c1,c2,...,c20
gt预测类别标注:
预测边框在论文中被称为 predictor,yolov1 中每个 grid 中包含 2 个 predictor ,中心在 grid 的 gt 中与 任意 predictor 的 IOU 最大的 gt 类别作为标注类别。
It also only pe- nalizes bounding box coordinate error if that predictor is “responsible” for the ground truth box (i.e. has the highest IOU of any predictor in that grid cell).
其中 confidence 计算方法如下:*IOU%7Btruth%7D%5E%7Bpred%7D%0A#card=math&code=C%20%3D%20Pr%28obj%29%2AIOU%7Btruth%7D%5E%7Bpred%7D%0A)
是预测框和真实标注框的交并比。
#card=math&code=Pr%28obj%29) 是表示一个 grid 有物体(判断物体标准是物体中心在 grid内)的概率,再有物体时候值为 1,没有物体的时候值为 0。
grouth truth 坐标回归目标编码方式如下所示:
之所以处理除以分母是为了进行尺度上的缩放,对小物体检测有一定的适应性。#card=math&code=%28x%2Cy%29) 是目标中心坐标,在 grid 中的相对位置,值域为
#card=math&code=%28w%2Ch%29)是目标检测框的长宽和图像长宽的比,值域为

具体例子:
左上角的 grid 的 ground truth 是:0,?,?,?,?,?,...,?
中间的 grid 的 ground truth 是(假设该目标属于第一个类别):iou,0.48,0.28,0.5,0.32,1,0,...,0
预测阶段
计算 class-specific confidence score
公式如下,该结果不仅仅包含了类别的准确率,也包含了该预测边框置信度,输入结果更加可信。
%20%20%5Coperatorname%7BPr%7D(%5Ctext%20%7B%20Object%20%7D)%20%20%5Ctext%20%7B%20IOU%20%7D%7B%5Ctext%20%7Bpred%20%7D%7D%5E%7B%5Ctext%20%7Btruth%20%7D%7D%3D%5Coperatorname%7BPr%7D%5Cleft(%5Ctext%20%7B%20Class%20%7D%7Bi%7D%5Cright)%20*%20%5Ctext%20%7B%20IOU%20%7D%7B%5Ctext%20%7Bpred%20%7D%7D%5E%7B%5Ctext%20%7Btruth%20%7D%7D%0A#card=math&code=%5Coperatorname%7BPr%7D%5Cleft%28%5Ctext%20%7B%20Class%20%7D%7Bi%7D%20%5Cmid%20%5Ctext%20%7B%20Object%20%7D%5Cright%29%20%2A%20%5Coperatorname%7BPr%7D%28%5Ctext%20%7B%20Object%20%7D%29%20%2A%20%5Ctext%20%7B%20IOU%20%7D%7B%5Ctext%20%7Bpred%20%7D%7D%5E%7B%5Ctext%20%7Btruth%20%7D%7D%3D%5Coperatorname%7BPr%7D%5Cleft%28%5Ctext%20%7B%20Class%20%7D%7Bi%7D%5Cright%29%20%2A%20%5Ctext%20%7B%20IOU%20%7D_%7B%5Ctext%20%7Bpred%20%7D%7D%5E%7B%5Ctext%20%7Btruth%20%7D%7D%0A)
一种三项后面两项是 预测出来的 confidence,前一项是预测出来的类别概率。
使用 NMS 进行过滤多余的框
得到每个box的class-specific confidence score以后,设置阈值,滤掉得分低的 boxes,对保留的 boxes 进行NMS处理,就得到最终的检测结果。
损失函数
%5E%7B2%7D%2B%5Cleft(y%7Bi%7D-%5Chat%7By%7D%7Bi%7D%5Cright)%5E%7B2%7D%5Cright%5D%20%5C%5C%0A%5Cquad%2B%5Clambda%7B%5Ctext%20%7Bcoord%20%7D%7D%20%5Csum%7Bi%3D0%7D%5E%7BS%5E%7B2%7D%7D%20%5Csum%7Bj%3D0%7D%5E%7BB%7D%20%5Cmathbb%7B1%7D%7Bi%20j%7D%5E%7B%5Ctext%20%7Bobj%20%7D%7D%5Cleft%5B%5Cleft(%5Csqrt%7Bw%7Bi%7D%7D-%5Csqrt%7B%5Chat%7Bw%7D%7Bi%7D%7D%5Cright)%5E%7B2%7D%2B%5Cleft(%5Csqrt%7Bh%7Bi%7D%7D-%5Csqrt%7B%5Chat%7Bh%7D%7Bi%7D%7D%5Cright)%5E%7B2%7D%5Cright%5D%20%5C%5C%0A%5Cquad%2B%20%5Clambda%7B%5Ctext%7Bnoobj%7D%7D%20%5Csum%7Bi%3D0%7D%5E%7BS%5E%7B2%7D%7D%20%5Csum%7Bj%3D0%7D%5E%7BB%7D%20%5Cmathbb%7B1%7D%7Bi%20j%7D%5E%7B%5Ctext%20%7Bnoobj%20%7D%7D%5Cleft(C%7Bi%7D-%5Chat%7BC%7D%7Bi%7D%5Cright)%5E%7B2%7D%20%5C%5C%0A%5Cquad%2B%5Csum%7Bi%3D0%7D%5E%7BS%5E%7B2%7D%7D%20%5Csum%7Bj%3D0%7D%5E%7BB%7D%20%5Cmathbb%7B1%7D%7Bi%20j%7D%5E%7B%5Ctext%20%7Bobj%20%7D%7D%5Cleft(C%7Bi%7D-%5Chat%7BC%7D%7Bi%7D%5Cright)%5E%7B2%7D%20%5C%5C%0A%5Cqquad%2B%5Csum%7Bi%3D0%7D%5E%7BS%5E%7B2%7D%7D%20%5Cmathbb%7B1%7D%7Bi%7D%5E%7B%5Ctext%20%7Bobj%20%7D%7D%20%5Csum%7Bc%20%5Cin%20%5Ctext%20%7B%20classes%20%7D%7D%5Cleft(p%7Bi%7D(c)-%5Chat%7Bp%7D%7Bi%7D(c)%5Cright)%5E%7B2%7D%0A%5Cend%7Barray%7D%0A#card=math&code=%5Cbegin%7Barray%7D%7Bl%7D%0A%5Clambda%7B%5Ctext%20%7Bcoord%20%7D%7D%20%5Csum%7Bi%3D0%7D%5E%7BS%5E%7B2%7D%7D%20%5Csum%7Bj%3D0%7D%5E%7BB%7D%20%5Cmathbb%7B1%7D%7Bi%20j%7D%5E%7B%5Cmathrm%7Bobj%7D%7D%5Cleft%5B%5Cleft%28x%7Bi%7D-%5Chat%7Bx%7D%7Bi%7D%5Cright%29%5E%7B2%7D%2B%5Cleft%28y%7Bi%7D-%5Chat%7By%7D%7Bi%7D%5Cright%29%5E%7B2%7D%5Cright%5D%20%5C%5C%0A%5Cquad%2B%5Clambda%7B%5Ctext%20%7Bcoord%20%7D%7D%20%5Csum%7Bi%3D0%7D%5E%7BS%5E%7B2%7D%7D%20%5Csum%7Bj%3D0%7D%5E%7BB%7D%20%5Cmathbb%7B1%7D%7Bi%20j%7D%5E%7B%5Ctext%20%7Bobj%20%7D%7D%5Cleft%5B%5Cleft%28%5Csqrt%7Bw%7Bi%7D%7D-%5Csqrt%7B%5Chat%7Bw%7D%7Bi%7D%7D%5Cright%29%5E%7B2%7D%2B%5Cleft%28%5Csqrt%7Bh%7Bi%7D%7D-%5Csqrt%7B%5Chat%7Bh%7D%7Bi%7D%7D%5Cright%29%5E%7B2%7D%5Cright%5D%20%5C%5C%0A%5Cquad%2B%20%5Clambda%7B%5Ctext%7Bnoobj%7D%7D%20%5Csum%7Bi%3D0%7D%5E%7BS%5E%7B2%7D%7D%20%5Csum%7Bj%3D0%7D%5E%7BB%7D%20%5Cmathbb%7B1%7D%7Bi%20j%7D%5E%7B%5Ctext%20%7Bnoobj%20%7D%7D%5Cleft%28C%7Bi%7D-%5Chat%7BC%7D%7Bi%7D%5Cright%29%5E%7B2%7D%20%5C%5C%0A%5Cquad%2B%5Csum%7Bi%3D0%7D%5E%7BS%5E%7B2%7D%7D%20%5Csum%7Bj%3D0%7D%5E%7BB%7D%20%5Cmathbb%7B1%7D%7Bi%20j%7D%5E%7B%5Ctext%20%7Bobj%20%7D%7D%5Cleft%28C%7Bi%7D-%5Chat%7BC%7D%7Bi%7D%5Cright%29%5E%7B2%7D%20%5C%5C%0A%5Cqquad%2B%5Csum%7Bi%3D0%7D%5E%7BS%5E%7B2%7D%7D%20%5Cmathbb%7B1%7D%7Bi%7D%5E%7B%5Ctext%20%7Bobj%20%7D%7D%20%5Csum%7Bc%20%5Cin%20%5Ctext%20%7B%20classes%20%7D%7D%5Cleft%28p%7Bi%7D%28c%29-%5Chat%7Bp%7D%7Bi%7D%28c%29%5Cright%29%5E%7B2%7D%0A%5Cend%7Barray%7D%0A)
所有的损失都是使用平方和误差公式,暂时先不看公式中的 与
,输出的预测数值以及所造成的损失有:
- 预测框的中心点
#card=math&code=%28x%2Cy%29) 。造成的损失是图五中的第一行。其中
为控制函数,在标签中包含物体的那些格点处,该值为 1;若格点不含有物体,该值为 0。也就是只对那些有真实物体所属的格点进行损失计算,若该格点不包含物体,那么预测数值不对损失函数造成影响。
#card=math&code=%28x%2Cy%29)数值与标签用简单的平方和误差。
- 预测框的宽高
#card=math&code=%28w%2Ch%29)。造成的损失是图五的第二行。
的含义一样,也是使得只有真实物体所属的格点才会造成损失。这里对 在
#card=math&code=%28w%2Ch%29) 损失函数中的处理分别取了根号,原因在于,如果不取根号,损失函数往往更倾向于调整尺寸比较大的预测框。取根号是为了尽可能的消除大尺寸框与小尺寸框之间的差异。(主要是为了放大小物体的误差,根号函数相比线性函数,会缩小较大的数值,变相的放大小物体的误差)
- 第三行与第四行,都是预测框的置信度
。当该格点不含有物体时,该置信度的标签为 0;若含有物体时,该置信度的标签为预测框与真实物体框的 IOU 数值。
- 第五行为物体类别概率
,对应的类别位置,该标签数值为 1,其余位置为 0,与分类网络相同。
此时再来看 与
,YOLO 面临的物体检测问题,是一个典型的类别数目不均衡的问题。其中49个格点,含有物体的格点往往只有3、4个,其余全是不含有物体的格点。此时如果不采取点措施,那么物体检测的 mAP 不会太高,因为模型更倾向于不含有物体的格点。
与
的作用,就是让含有物体的格点,在损失函数中的权重更大,让模型更加“重视”含有物体的格点所造成的损失。在论文中,
与
的取值分别为 5 与 0.5。

缺点
- 图像下采样 64 倍,容易漏检小物体;
- 每张图像仅预测出 98 个 bounding box,且每个格点的 bounding box 负责预测的是同一个物体,若一幅图中有多个物体都落入同一个格点,则只能预测其中的一个,使得算法召回率不高;
YOLOv2
YOLOv2 (CVPR2017)
YOLO9000: Better, Faster, Stronger
效果
YOLOv2 使用 coco 数据集训练后,可以识别 80 个类别;
YOLO9000 可以使用 coco 数据集合 ImageNet 数据集联合训练,可以识别 9000多个类别;
结构
backbone 采用的 Darknet-19

改进
YOLOv2 是在 YOLOv1 基础上的改进,具体的改进如下:
- batch norm
YOLO 每个卷积层中加入 BN 后,mAP 提示了 2%,并且去除了 Dropout。
- high resolution classifier
高分辨率预训练
对于 YOLOv1 ,网络的 backbone 部分会在 ImageNet 数据集上进行预训练,训练时网络的输入图像的分辨率为 224*224
在 YOLOv2 中,将网络的 backone 部分在 ImageNet 数据集上以 分辨率 448*448 的图片预训练 10 个 epoch,再使用数据集(例如 coco)进行微调。
使得 mAP 提高了大约 4%
- 去掉了全连接层
V2 中 移除了 v1 的最后两个全连接层,全连接层计算量大耗时久。移除全连接层的另外一个优点是,能够进行多尺度训练。
- 引入了 anchor box
v2 中的 anchor box 不是人为设计的,是将训练集中的矩形框全部拿出来,用k-means聚类得到的先验宽和高;
K-means 聚类的具体步骤如下:
- 提取所有训练数据的 bounding boxes 的宽高数据,将坐标转化为宽高的大小,计算方法:长 = 右下角横坐标 - 左上角横坐标、宽 = 右下角纵坐标 - 左上角纵坐标。
- 初始化 k 个anchor box,在所有的 bounding boxes 中随机的选取 k 个值作为 k 个 anchor boxes 的初始值。
- 计算每个 bounding box 和 每个 anchor box 的 iou 值:
%20%3D%201%20-%20IOU(%5Ctext%7Bbox%7D%2C%5Ctext%7Bcentroid%7D)%0A#card=math&code=d%28%5Ctext%7Bbox%7D%2C%5Ctext%7Bcentroid%7D%20%29%20%3D%201%20-%20IOU%28%5Ctext%7Bbox%7D%2C%5Ctext%7Bcentroid%7D%29%0A)
- 分类:比较每个 bounding box 对于每个 anchor box 的误差大小
%2Cd(i%2C2)%2C…%2Cd(i%2Ck)%20%5C%7D#card=math&code=%5C%7B%20d%28i%2C1%29%2Cd%28i%2C2%29%2C…%2Cd%28i%2Ck%29%20%5C%7D) 选取误差最小的那个 anchor box,将这个 bounding box 分类给它,对于每个 bounding box 都做这个操作,最后记录下来每个 anchor box 有哪些 bounding box 属于它。
- Anchor box 更新:对于每个 anchor box 中的那些 bounding box ,再求这些 bounding box 宽高中值的大小。
- 重复 3 到 5 步,直到第 5 步中发现对于全部的 bounding box 其所属的 anchor box 类与之前所属的 anchor box 类完全一样。(指bounding box 的分类已经不再更新)
- 绝对位置预测
Direct location prediction
对于每个 bounding box 预测了 5 个值 %2C%5Csigma(t_y))#card=math&code=%28%5Csigma%28t_x%29%2C%5Csigma%28t_y%29%29) 预测的是相对于左上角坐标
#card=math&code=%28c_x%2Cc_y%29) 的偏置坐标 offset
%2Bc_x%20%5C%5C%0Ab_y%20%3D%20%5Csigma(t_y)%2Bc_y%20%5C%5C%0Ab_w%20%3D%20p_we%5E%7Bt_w%7D%20%5C%5C%0Ab_h%20%3D%20p_he%5E%7Bt_h%7D%20%5C%5C%0APr(object)*IOU(b%2Cobject)%3D%20%5Csigma(t_o)%0A#card=math&code=b_x%20%3D%20%5Csigma%28t_x%29%2Bc_x%20%5C%5C%0Ab_y%20%3D%20%5Csigma%28t_y%29%2Bc_y%20%5C%5C%0Ab_w%20%3D%20p_we%5E%7Bt_w%7D%20%5C%5C%0Ab_h%20%3D%20p_he%5E%7Bt_h%7D%20%5C%5C%0APr%28object%29%2AIOU%28b%2Cobject%29%3D%20%5Csigma%28t_o%29%0A)
其中 是先验框长宽,
通过
sigmoid 函数映射为置信度。

Fine-Grained Features
目的:为了保留较小对象的更多的信息,参考 Densnet 理念 ,构建了 passthrough 层,将更多细节的信息传递到后面的层。
具体来说,就是在最后一个pooling之前,特征图的大小是26*26*512,将其 1 拆 4,直接传递(passthrough)到pooling后(并且又经过一组卷积)的特征图,两者叠加到一起作为输出的特征图。

具体如何 1 拆 4 参考下图
- Multi-Scale Training
多尺度训练
YOLOv2 中只有卷积层和池化层,所以对于网络的输入大小,并没有限制,整个网络的降采样倍数是 32 倍,只要输入的特征图尺寸为 32 的倍数即可。
在每 10 个 epoch 后,就将图片 resize 成 中的一种。不同的输入最后产生的格点数不同。
引入多尺度后,迫使卷积核可以实现不同比例大小尺寸的特征。当输入设置为 544*544 甚至更大时,YOLOv2的 mAP 已经超过了其他物体检测方法。
YOLO9000:Stronger
Joint classification and detection
联合训练:当输入检测数据集时,标注信息有类别、有位置,那么对整个 loss 函数计算 loss,进行反向传播;当输入图片只包含分类信息时,loss 函数只计算分类 loss ,其余部分 loss 为零。
word tree 细节待续。。
YOLOv3
YOLOv3(arXiv 2018)
YOLOv3: An Incremental Improvement
参考:https://zhuanlan.zhihu.com/p/76802514
结构
backbone:Darknet-53
借鉴了 residual net

从 v1 到 v3 backbone 发生了哪些变化
v1 借鉴了 GoogLeNet 采用 1*1 进行降为,v2 去掉了全连接层引入全局平均池化,引入了多尺度,v3 引入了 residual 模块;并且 卷积核的大小 v2 开始卷积最大是 3*3 ,计算量小防止过拟合,网络深度也是逐步加深。
选择 Darknet-53 原因:
处理速度每秒 78 张图片,比 Darknet-19 慢不少,但比同精度的 Resnet 块很多。YOLOv3 依旧能保持高性能。速度和精度的权衡 tradeoff。

网络的整体结构:
- Yolov3中,只有卷积层,通过调节卷积步长控制输出特征图的尺寸。所以对于输入图片尺寸没有特别限制。流程图中,输入图片以
256*256作为样例。 - Yolov3借鉴了金字塔特征图思想,小尺寸特征图用于检测大尺寸物体,而大尺寸特征图检测小尺寸物体。特征图的输出维度为
%5D#card=math&code=N%20%5Ctimes%20N%20%5Ctimes%20%5B3%20%5Ctimes%20%284%2B1%2B80%29%5D),
为输出特征图格点数,一共3个Anchor框,每个框有4维预测框数值
,一个置信度
,80维物体类别数。所以第一层特征图的输出维度为 ,所以第一个输出特征图 。
8*8*255 - Yolov3总共输出3个特征图,第一个特征图下采样32倍,第二个特征图下采样16倍,第三个下采样8倍。输入图像经过Darknet-53(无全连接层),再经过 Yoloblock 生成的特征图被当作两用,第一用为经过
3*3卷积层、1*1卷积之后生成特征图一,第二用为经过1*1卷积层加上采样层,与 Darnet-53 网络的中间层输出结果进行拼接,产生特征图二。同样的循环之后产生特征图三。 - concat操作与加和操作的区别:加和操作来源于ResNet思想,将输入的特征图,与输出特征图对应维度进行相加,即
%2Bx#card=math&code=y%3Df%28x%29%2Bx) ;而 concat 操作源于 DenseNet 网络的设计思路,将特征图按照通道维度直接进行拼接,例如
8*8*16的特征图与8*8*16的特征图拼接后生成8*8*32的特征图。 - 上采样层(upsample):作用是将小尺寸特征图通过插值等方法,生成大尺寸图像。例如使用最近邻插值算法,将
8*8的图像变换为16*16。上采样层不改变特征图的通道数。
Yolo的整个网络,吸取了Resnet、Densenet、FPN的精髓。输出特征图解码
根据不同的尺寸会出处不同大小的特征图,以图中结构为例 256*256*3为例,输出的特征图为8*8*255、16*16*255、32*32*255。在Yolov3的设计中,每个特征图的每个格子中,都配置3个不同的先验框,所以最后三个特征图,这里暂且 reshape 为 8*8*3*85、16*16*3*85、32*32*3*85,这样更容易理解,在代码中也是 reshape 成这样之后更容易操作。
三张特征图就是整个Yolo输出的检测结果,检测框位置(4维)、检测置信度(1维)、类别(80维)都在其中,加起来正好是 85维。特征图最后的维度 85,代表的就是这些信息,而特征图其他维度 N*N*3,N*N代表了检测框的参考位置信息,3 是 3 个不同尺度的先验框。下面详细描述怎么将检测信息解码出来:
- 先验框
在Yolov1中,网络直接回归检测框的宽、高,这样效果有限。所以在 Yolov2 中,改为了回归基于先验框的变化值,这样网络的学习难度降低,整体精度提升不小。Yolov3 沿用了 Yolov2 中关于先验框的技巧,并且使用 k-means 对数据集中的标签框进行聚类,得到类别中心点的 9 个框,作为先验框。在 COCO 数据集中(原始图片全部resize为 416*416),九个框分别是 (10,13),(16,30),(33,23),(30,61),(62,45),(59,119), (116,90),(156,198),(373,326) ,顺序为w,h。
注:先验框只与检测框的w、h有关,与x、y无关。
- 检测框解码
有了先验框与输出特征图,就可以解码检测框 x,y,w,h。%2Bc_x%20%5C%5C%0Ab_y%20%3D%20%5Csigma(t_y)%2Bc_y%20%5C%5C%0Ab_w%20%3D%20p_we%5E%7Bt_w%7D%20%5C%5C%0Ab_h%20%3D%20p_he%5E%7Bt_h%7D%20%5C%5C%0APr(object)*IOU(b%2Cobject)%3D%20%5Csigma(t_o)%0A#card=math&code=b_x%20%3D%20%5Csigma%28t_x%29%2Bc_x%20%5C%5C%0Ab_y%20%3D%20%5Csigma%28t_y%29%2Bc_y%20%5C%5C%0Ab_w%20%3D%20p_we%5E%7Bt_w%7D%20%5C%5C%0Ab_h%20%3D%20p_he%5E%7Bt_h%7D%20%5C%5C%0APr%28object%29%2AIOU%28b%2Cobject%29%3D%20%5Csigma%28t_o%29%0A)
对于每个 bounding box 预测了 5 个值 %2C%5Csigma(t_y)%20)#card=math&code=%28%20%5Csigma%28t_x%29%2C%5Csigma%28t_y%29%20%29) 预测的是相对于左上角坐标
#card=math&code=%28c_x%2Cc_y%29) 的偏置坐标 offset,
是 sigmoid 激活函数;
是先验框长宽,通过上述公式,计算出实际预测框的宽高
#card=math&code=%28b_w%2Cb_h%29)。

- 置信度解码
由 sigmoid 函数进行解码
#card=math&code=c%3D%5Csigma%28t_o%29),解码后的数值在
#card=math&code=%280%2C1%29)
- 类别解码
COCO 数据集有80个类别,所以类别数在85维输出中占了80维,每一维独立代表一个类别的置信度。使用 sigmoid 激活函数替代了Yolov2 中的 softmax,取消了类别之间的互斥,可以使网络更加灵活。
三个特征图一共可以解码出 个 box 以及相应的类别、置信度。这 4032 个box,在训练和推理时,使用方法不一样:
- 训练时4032个box全部送入打标签函数,进行后一步的标签以及损失函数的计算。
- 推理时,选取一个置信度阈值,过滤掉低阈值box,再经过nms(非极大值抑制),就可以输出整个网络的预测结果了。
训练策略与损失函数
- 训练打标签策略
- 预测框一共分为三种情况:正例(positive)、负例(negative)、忽略样例(ignore)。
- 正例:任取一个 ground truth,与 4032 个框全部计算 IOU,IOU 最大的预测框,即为正例。并且一个预测框,只能分配给一个ground truth。例如第一个 ground truth 已经匹配了一个正例检测框,那么下一个 ground truth,就在余下的 4031 个检测框中,寻找IOU最大的检测框作为正例。ground truth 的先后顺序可忽略。正例产生置信度loss、检测框loss、类别loss。预测框为对应的 ground truth box 标签(需要反向编码,使用真实的x、y、w、h计算出
);类别标签对应类别为1,其余为0;置信度标签为1。
- 忽略样例:正例除外,与任意一个ground truth的IOU大于阈值(论文中使用0.5),则为忽略样例。忽略样例不产生任何loss。
- 负例:正例除外(与ground truth计算后IOU最大的检测框,但是IOU小于阈值,仍为正例),与全部ground truth的IOU都小于阈值(0.5),则为负例。负例只有置信度产生loss,置信度标签为0。
- loss 函数
特征图1的Yolov3的损失函数抽象表达式如下:
%5E2%2B(ty-t’_y)%5E2%5D%5C%5C%0A%20%20%26%20%2B%5Clambda%7Bbox%7D%5Csum%5E%7BN1%5Ctimes%7BN_1%7D%7D%7Bi%3D0%7D%5Csum%5E%7B3%7D%7Bj%3D0%7D1%5E%7Bobj%7D%7Bij%7D%5B(tw-t’_w)%5E2%2B(t_h-t’_h)%5E2%5D%5C%5C%0A%20%20%26%20-%5Clambda%7Bobj%7D%5Csum%5E%7BN1%5Ctimes%7BN_1%7D%7D%7Bi%3D0%7D%5Csum%5E%7B3%7D%7Bj%3D0%7D1%5E%7Bobj%7D%7Bij%7Dlog(c%7Bij%7D)%5C%5C%0A%20%20%26%20-%5Clambda%7Bnoobj%7D%5Csum%5E%7BN1%5Ctimes%7BN_1%7D%7D%7Bi%3D0%7D%5Csum%5E%7B3%7D%7Bj%3D0%7D1%5E%7Bnoobj%7D%7Bij%7Dlog(1-c%7Bij%7D)%5C%5C%0A%20%20%26%20-%5Clambda%7Bclass%7D%5Csum%5E%7BN1%5Ctimes%7BN_1%7D%7D%7Bi%3D0%7D%5Csum%5E%7B3%7D%7Bj%3D0%7D1%5E%7Bobj%7D%7Bij%7D%5Csum%7Bc%5Cin%7Bclasses%7D%7D%5Bp’%7Bij%7D(c)log(p%7Bij%7D(c))%2B(1-p’%7Bij%7D(c)%EF%BC%89log(1-p%7Bij%7D(c))%5D%5C%5C%0A%20%20
%20%26%20%0A%5Cend%7Balign*%7D%0A#card=math&code=~~~%5C%5C%0A%5Cbegin%7Balign%2A%7D%0Aloss%7BN1%7D%20%3D%20%26%20%5Clambda%7Bbox%7D%5Csum%5E%7BN1%5Ctimes%7BN_1%7D%7D%7Bi%3D0%7D%5Csum%5E%7B3%7D%7Bj%3D0%7D1%5E%7Bobj%7D%7Bij%7D%5B%28tx-t%27_x%29%5E2%2B%28t_y-t%27_y%29%5E2%5D%5C%5C%0A%20%20%26%20%2B%5Clambda%7Bbox%7D%5Csum%5E%7BN1%5Ctimes%7BN_1%7D%7D%7Bi%3D0%7D%5Csum%5E%7B3%7D%7Bj%3D0%7D1%5E%7Bobj%7D%7Bij%7D%5B%28tw-t%27_w%29%5E2%2B%28t_h-t%27_h%29%5E2%5D%5C%5C%0A%20%20%26%20-%5Clambda%7Bobj%7D%5Csum%5E%7BN1%5Ctimes%7BN_1%7D%7D%7Bi%3D0%7D%5Csum%5E%7B3%7D%7Bj%3D0%7D1%5E%7Bobj%7D%7Bij%7Dlog%28c%7Bij%7D%29%5C%5C%0A%20%20%26%20-%5Clambda%7Bnoobj%7D%5Csum%5E%7BN1%5Ctimes%7BN_1%7D%7D%7Bi%3D0%7D%5Csum%5E%7B3%7D%7Bj%3D0%7D1%5E%7Bnoobj%7D%7Bij%7Dlog%281-c%7Bij%7D%29%5C%5C%0A%20%20%26%20-%5Clambda%7Bclass%7D%5Csum%5E%7BN1%5Ctimes%7BN_1%7D%7D%7Bi%3D0%7D%5Csum%5E%7B3%7D%7Bj%3D0%7D1%5E%7Bobj%7D%7Bij%7D%5Csum%7Bc%5Cin%7Bclasses%7D%7D%5Bp%27%7Bij%7D%28c%29log%28p%7Bij%7D%28c%29%29%2B%281-p%27%7Bij%7D%28c%29%EF%BC%89log%281-p_%7Bij%7D%28c%29%29%5D%5C%5C%0A%20%20%20%26%20%0A%5Cend%7Balign%2A%7D%0A)
Yolov3 Loss为三个特征图Loss之和:
为权重常数,控制检测框Loss、obj置信度Loss、noobj置信度Loss之间的比例,通常负例的个数是正例的几十倍以上,可以通过权重超参控制检测效果。
若是正例则输出1,否则为0;
若是负例则输出1,否则为0;忽略样例都输出0。
- x、y、w、h使用 MSE 作为损失函数,也可以使用 smooth L1 loss(出自Faster R-CNN)作为损失函数。smooth L1可以使训练更加平滑。置信度、类别标签由于是0,1二分类,所以使用交叉熵作为损失函数。
- 训练策略解释:
- ground truth为什么不按照中心点分配对应的预测box?
在Yolov3的训练策略中,不再像 Yolov1 那样,每个cell负责中心落在该cell中的 ground truth。原因是 Yolov3 一共产生 3 个特征图,3个特征图上的cell,中心是有重合的。训练时,可能最契合的是特征图1的第3个box,但是推理的时候特征图2的第1个box置信度最高。所以 Yolov3 的训练,不再按照 ground truth 中心点,严格分配指定 cell,而是根据预测值寻找 IOU 最大的预测框作为正例。
- Yolov1 中的置信度标签,就是预测框与真实框的 IOU,Yolov3 为什么是1?
置信度意味着该预测框是或者不是一个真实物体,是一个二分类,所以标签是1、0更加合理。
两种方法进行置信标签,第一种:置信度标签取预测框与真实框的IOU;第二种:置信度标签取1。第一种的结果是,在训练时,有些预测框与真实框的IOU极限值就是0.7左右,置信度以0.7作为标签,置信度学习有一些偏差,最后学到的数值是0.5,0.6,那么假设推理时的激活阈值为0.7,这个检测框就被过滤掉了。但是IOU为0.7的预测框,其实已经是比较好的学习样例了。尤其是coco中的小像素物体,几个像素就可能很大程度影响IOU,所以第一种训练方法中,置信度的标签始终很小,无法有效学习,导致检测召回率不高。而检测框趋于收敛,IOU收敛至1,置信度就可以学习到1,这样的设想太过理想化。而使用第二种方法,召回率明显提升了很高。
- 为什么有忽略样例?
忽略样例是Yolov3中的点睛之笔。由于Yolov3使用了多尺度特征图,不同尺度的特征图之间会有重合检测部分。比如有一个真实物体,在训练时被分配到的检测框是特征图1的第三个box,IOU达0.98,此时恰好特征图2的第一个box与该ground truth的IOU达0.95,也检测到了该ground truth,如果此时给其置信度强行打0的标签,网络学习效果会不理想。
如果给全部的忽略样例置信度标签打0,那么最终的loss函数会变成, 和
置信度互相抵消。 而加入了忽略样例之后,网络才可以学习区分正负例。
