YOLOv1 中的一些计算
位置参数计算
在训练过程中,需要分别计算真实框的位置参数 t x t_x tx、 t y t_y ty、 w w w、 h h h。
已知真实框的左上角点和右下角点坐标: g t = [ x 1 , y 1 , x 2 , y 2 ] gt = [x_1, y_1, x_2, y_2] gt=[x1,y1,x2,y2], t x t_x tx、 t y t_y ty 计算如下:
- 第一步,计算真实框的中心点坐标
- 第二步,计算中心点所在的网格坐标
- 第三步,计算中心点相对于网格左上角点的偏移量,偏移量的值域为 [0, 1)
( 1 ) C x = x 1 + x 2 2 , C y = y 1 + y 2 2 ( 2 ) g r i d x = ⌊ C x s t r i d e ⌋ , g r i d y = ⌊ C y s t r i d e ⌋ ( 3 ) t x = C x s t r i d e − g r i d x , t y = C y s t r i d e − g r i d y (1)\ C_x = \frac{x_1 + x_2}{2},\ C_y = \frac{y_1 + y_2}{2} \\ (2)\ grid_x = \left \lfloor \frac{C_x}{stride}\right \rfloor,\ grid_y = \left \lfloor \frac{C_y}{stride}\right \rfloor \\ (3)\ t_x = \frac{C_x}{stride} - grid_x,\ t_y = \frac{C_y}{stride} - grid_y (1) Cx=2x1+x2, Cy=2y1+y2(2) gridx=⌊strideCx⌋, gridy=⌊strideCy⌋(3) tx=strideCx−gridx, ty=strideCy−gridy
w w w、 h h h 计算如下:
- 用于训练的 w w w、 h h h 不能直接使用真实框的宽和高,因为数值较大,使得在训练期间很容易出现不稳定甚至发散的问题。因此,YOLOv1 会对真实框的宽和高做归一化处理,其中 W W W、 H H H 是图像的宽和高
w = x 2 − x 1 W , h = y 2 − y 1 H w = \frac{x_2 - x_1}{W},\ h = \frac{y_2 - y_1}{H} w=Wx2−x1, h=Hy2−y1
在考虑如何给边界框的置信度标签赋值时,一个很简单的想法是将包含目标中心点的网格处的边界框置信度标签置为 1,反之为 0,这是一个典型的二分类思想。但 YOLOv1 并没有采取如此简单的做法,YOLOv1 不仅希望边界框的置信度能够表征网格是否包含目标中心点,同时也希望边界框的置信度能表征所预测的边界框的定位精度。而对于边界框的定位精度,通常使用交并比(intersection of union,IoU)来衡量。
正负样本分配策略
正负样本分配策略如下:
- 计算真实框中心点所在网格的每个预测框与真实框的 IoU
- 将 IoU 最大的预测框标记为正样本,并将 IoU 值作为该预测框的置信度标签(计算正样本置信度损失时,置信度的预测值将与该置信度标签,即 IoU 值做计算);该预测框参与计算位置参数损失、置信度损失、类别损失
- 不包含目标的网格的所有预测框将被视为负样本,只参与计算置信度损失,且置信度标签为 0(计算负样本置信度损失时,置信度的预测值将与该置信度标签,即 0 做计算)
- 包含目标的网格的除 IoU 最大的其他预测框,不参与任何计算
损失函数透析
损失函数的第一、二行,计算的是位置参数损失;
损失函数的第三、四行,计算的是置信度损失,第三行表示的是正样本的置信度损失,第四行表示的是负样本的置信度损失,它们俩不会同时计算;
损失函数的第五行,计算的是类别损失,每个类别的损失都是 L2 损失,而不是交叉熵。
正样本参与所有的损失计算,负样本只参与置信度损失的计算。
推理
对于给定的一张大小为 448 ∗ 448 448*448 448∗448 的输入图像,YOLOv1 输出 7 ∗ 7 ∗ 30 7*7*30 7∗7∗30 的张量。其中每个网格位置都包含两个边界框的置信度输出 C 1 C_1 C1 和 C 2 C_2 C2、两个边界框的位置参数输出 ( t x 1 , t y 1 , w 1 , h 1 ) (t_{x_1}, t_{y_1}, w_1, h_1) (tx1,ty1,w1,h1) 和 ( t x 2 , t y 2 , w 2 , h 2 ) (t_{x_2}, t_{y_2}, w_2, h_2) (tx2,ty2,w2,h2) 以及 20 个类别置信度输出 p ( c 1 ) p(c_1) p(c1)~ p ( c 2 ) p(c_2) p(c2)。显然,这么多的预测不全是我们想要的,我们只关心那些包含目标的网格所给出的预测,因此在得到最终的检测结果之前,我们需要再按照以下四个步骤去做滤除和筛选:
-
计算所有预测的边界框的得分。在 YOLOv1 中,每个边界框的得分 score 被定义为该边界框的置信度 C C C 与类别的最高置信度 P c m a x P_{c_{max}} Pcmax 的乘积,其中 P c m a x = m a x [ p ( c 1 ) , p ( c 2 ) , . . . , p ( c 20 ) ] P_{c_{max}} = max[p(c_1), p(c_2), ..., p(c_{20})] Pcmax=max[p(c1),p(c2),...,p(c20)]。具体来说,对于 ( g r i d x , g r i d y ) (grid_x, grid_y) (gridx,gridy) 处的网格,边界框 B j B_j Bj 的得分计算公式如下:
s c o r e j = C j ∗ P c m a x score_j = C_j * P_{c_{max}} scorej=Cj∗Pcmax -
得分阈值筛选。计算了所有边界框的得分后,我们设定一个阈值去滤除那些得分低的边界框。显然,得分低的边界框通常都是背景框,不包含目标的中心点。比如,我们设置得分阈值为 0.3,滤除那些得分低于该阈值的低质量的边界框
-
计算边界框的中心点坐标以及宽和高。经过得分阈值筛选完后,我们即可计算剩下的边界框的中心点坐标以及宽和高
-
使用非极大值抑制进行第二次筛选。由于 YOLOv1 可能对同一个目标给出多个得分较高的边界框,因此我们需要对这种冗余检测进行抑制,以剔除那些不必要的重复检测。为了达到这一目的,常用的手段之一便是非极大值抑制(non-maximal suppression,NMS)。非极大值抑制的思想很简单,对于某一类别目标的所有边界框,先挑选出得分最高的边界框,再依次计算其他边界框与这个得分最高的边界框的 IoU,超过设定的 IoU 阈值的边界框则被认为是重复检测,将其剔除。对所有类别的边界框都进行上述操作,直到无边界框可剔除为止