本文基于: https://github.com/YunYang1994/tensorflow-yolov3.对YoLov3的原理及trick做一个总结。
1.多尺度feature map
输入图像经过Darknet-53后得到三个分支,并经过upsampling、concat等操作得到 [13, 13, 255]、[26, 26, 255] 和 [52, 52, 255]三尺度的feature map。其中255=3x(1+4+80)(3—每个grid cell有三个anchor,即每个grid cell最多预测三个物体,1—置信度,4—位置坐标,tx、ty、tw、th,80—COCO数据集80个类别的概率)。
1.1多尺度feature map的作用
[13, 13, 255]、[26, 26, 255] 和 [52, 52, 255]三尺度的feature map分别用于检测大、中、小目标(三尺度feature map与输入相比,分别被缩放了32、16、8倍,缩放的倍数越大,其提取的特征信息越容易忽略小目标)。
1.2如何得到anchor大小与如何分配anchor
anchor的大小是由k-means对ground truth聚类得到的。k-means第一个问题是度量距离的选取,距离度量如果使用标准的欧氏距离,大框会产生较多错误(例如宽为3、高为1的框与宽为1、高为3的框最终被聚为同一类)。在目标检测领域,我们度量两个边界框之间的相似度往往以 IOU 大小作为标准(如果两个ground truth之间的IOU值越大,那么它们之间的距离就会越小)。k-means第二个问题是聚类中心,当聚类中心为5时,能较好地实现高召回率与模型复杂度之间的平衡,但在YoLov3中,聚类中心必须是3的倍数(因为有三个尺度),最终聚类中心选为9(每个尺度分配3个anchor,即每个grid cell中最多预测三个物体)。
在COCO数据集上,anchor大小为(10x13),(16x30),(33x23),(30x61),(62x45),(59x119),(116x90),(156x198),(373x326),前三个anchor分配给 [52, 52, 255]的feature map,中间三个anchor分配给 [26, 26, 255]的feature map,最后三个anchor分配给 [13, 13, 255]的feature map
2.正负样本分配
首先,ground truth中的物体中心落在哪个格子中,就由哪个格子做预测,并且每个格子中有9个anchor,分别计算9个anchor与ground truth的IOU,若IOU大于0.3,则为正样本,其余的为负样本(不把IOU最大的作为正样本的原因:正负样本数量比为1:8,正负样本不均衡)。focal loss中的α是用于降低样本数量多的那类样本的权重,而这里正负样本基本均衡,所以αt可设置为0.5。
3.非极大值抑制(NMS)
首先得明确score的概念,score=置信度*类别概率。在 YOLO 算法中,NMS 的处理有两种情况:一种是所有的预测框一起做 NMS 处理,另一种情况是分别对每个类别的预测框做 NMS 处理。后者会出现一个预测框既属于类别 A 又属于类别 B 的现象,这比较适合于一个小单元格中同时存在多个物体的情况。
NMS 的算法迭代流程如下:
流程1: 判断边界框的数目是否大于0,如果不是则结束迭代;
流程2: 按照 socre 排序选出评分最大的边界框 A 并取出;
流程3: 计算这个边界框 A 与剩下所有边界框的 iou 并剔除那些 iou 值高于阈值的边界框,重复上述步骤;
4.损失函数
YoLov3的损失函数包含三个部分:置信度损失,判断预测框有无物体;
框回归损失,仅当预测框内包含物体时计算;分类损失,判断预测框内的物体属于哪个类别。
4.1置信度损失
这里置信度损失使用的是focal loss,focal loss中的γ降低简单样本的权重,增加困难样本的权重。
4.2分类损失与框回归损失
分类损失采用的是二分类的交叉熵,即把所有类别的分类问题归结为是否属于这个类别,这样就把多分类看做是二分类问题。这样做的好处在于排除了类别的互斥性,特别是解决了因多个类别物体的重叠而出现漏检的问题。
框回归损失使用的是GIOU loss。首先先来直观的理解一下GIOU。
上面三幅图的 IoU = 0.33, 但是 GIoU 值分别是 0.33, 0.24 和 -0.1, 这表明如果两个边界框重叠和对齐得越好,那么得到的 GIoU 值就会越高。下图是GIOU的计算公式,其中C可以理解为包含A与B的最小闭合区域。