You only look once (YOLO) V3
-
相比于yolov2的不同
*v3使用逻辑回归为每个bbox预测一个objectness score,如果一个先验框与ground truth 有重叠并且大于其他任意一个先验框与gt的重叠,则objectness score应该为1。如果一个先验框和gt重叠并超过一定阈值,但却并不是最佳的,则v3中忽略该预测,即不认为其中含有目标(在众多的先验框中,和某一个gt框进行重叠计算,只取给具有最佳重叠的那个先验框分配objectness为1,即将该先验框分配给该gt框);如果一个先验框没有被分配给任何一个gt框表示的目标,则其不会产生坐标相关的损失、类别预测相关的损失,但是回产生objectness score的损失。
上面一个objectness score对应一个预测的bbox,objectness score的取值则依靠当前位置的先验anchor与当前预测位置的gt的重叠率进行判断,如果重叠比任何其他位置的anchor高,则当前预测的objectness score应该趋向于1,否则趋向于0。同时,如果当前anchor与gt重叠不是最高,但是超过了设定的0.5的阈值,则忽略该预测。v3为每个预测只分配一个anchor先验,但是每个grid预测三个bbox,相当于每个网格位置分配三个anchor,分别对应该位置的三个预测。如果该anchor先验没有分配给gt,则不会计入bbox预测损失和分类预测损失,仅仅计入obejctness损失。
-
v3中在预测类别的时候采用binary-entropy loss:v2中采用的是softmax loss用于预测类别并计算损失,但是作者发现一个bbox可能不止包含一个类别的目标,可能同时包含多种目标。如果还使用softmax,则是一次预测出bbox中的目标属于某一个类。但在有的数据集中,同一个bbox可能对应两个类别,如women和person。而binary-entropy损失则是可以独立预测每一个bbox的类别,这有利于对多标签的数据进行分类建模。如同一个bbox既表示Women也表示Person,如使用softmax则暗示每个bbox只能有一个类别,不能有别的类别。而BCELoss是对每个bbox的类别的编码最终只是映射到0和1上,没有其为哪一个类别的矛盾,则可以用于此种情况;
-
在三个不同尺度的特征上预测boxes,每个尺度上预测3个boxes,即最终的tensor为 N × N × [ 3 × ( 4 + 1 + c l a s s e s n u m ) ] N\times N\times [3\times (4+1+classes_{num})] N×N×[3×(4+1+classesnum)],分别对应4个与坐标相关的偏移,1个objectness prediction,类别数;
-
v3在IoU阈值为0.5时其性能很好,但随着IoU阈值的增加,其性能下降严重。这表明v3很难将预测的boxes和目标对齐;
-
网络结构
使用连续的3x3和1x1卷积层,再加上残差链接。新骨干网络比Darknet19表现更好,同时也比ResNet101和ResNet152效果更好。比较结果如下:
-
- 训练:
- 使用k-means聚类决定先验bbox,选择9个clusters和任意的三个尺度的排序,将之划分到多个level上。每一个level上有三个尺度的anchor先验;
- 与v2一样,采用多尺度训练,数据增广,BN,以及其他的一些标准的处理手段;
- polo
- 训练:
-
一些失败的尝试:
- anchor box x, y offset prediction: 使用常规的anchor box预测机制,使用线性激活来预测x,y的偏移为bbox的w和h的倍数。发现这使得模型的稳定性降低;
- 使用线性x,y的预测而非logistic:直接使用线性激活来预测x,y的偏移而非logistic激活,这会导致下降好几个点;
- 使用focal loss:导致mAP下降2个点。由于v3分离出了objectness预测和条件类别预测,这使得其focal要解决的问题已经很鲁棒了。或许对于来自类别预测的大部分样本可能就没有loss,也或许还有其他的问题;
- 双阈值和truth的分配:即0.7和0.3。Faster R-CNN中预测超过0.7的视为正样本,小于0.3的视为负样本,0.3-0.7之间的忽略。相同的策略用在v3中并不能获得更好的结果。
-
v3中的损失计算
-
获得预测的边界框:(b.x, b.y, b.w, b.h)
box pred = get_yolo_box(x, biases, n, index, i, j, lw, lh, w, h, stride);
b.x = (i + x[index + 0*stride]) / lw; b.y = (j + x[index + 1*stride]) / lh; b.w = exp(x[index + 2*stride]) * biases[2*n] / w; b.h = exp(x[index + 3*stride]) * biases[2*n+1] / h;
上述代码中, ( i , j ) (i,j) (i,j)即为 ( c x , c y ) (c_x,c_y) (cx,cy),即当前cell左上角的坐标。
-
获得gt box的(t.x, t.y, t.w, t.h):
**float** tx = (truth.x*lw - i); //和预测值匹配 **float** ty = (truth.y*lh - j); **float** tw = log(truth.w*w / biases[2 * n]); //log 使大框和小框的误差影响接近 **float** th = log(truth.h*h / biases[2 * n + 1]);
上述的i和j表示的是gt的cell偏离yolo层的输出坐上角的x和y方向的偏离位置,即 ( c x , c y ) (c_x ,c_y) (cx,cy)。计算得到的 t x t_x tx表示gt的中心点偏离当前cell边界的值。
-
v3在预测什么:实际上,监督v3中 ( t x , t y , t w , t h ) (t_x,t_y,t_w,t_h) (tx,ty,tw,th)的是 ( t x ∗ , t y ∗ , t w ∗ , t h ∗ ) (t^*_x,t^*_y,t^*_w,t^*_h) (tx∗,ty∗,tw∗,th∗),带星号的是通过gt box和当前gt所在cell位置与当前cell中的anchor计算出来的,而这个被选中的anchor则是cell中三个anchors与gt box的IoU最大的那一个。即:通过预测bbox与当前cell的偏移和选定anchor的 ( p w , p h ) (pw,ph) (pw,ph)的缩放因子,然后按照计算带星号的t的方式,反过来计算对应的 ( b x , b y , b w , b h ) (b_x,b_y,b_w,b_h) (bx,by,bw,bh);
-