yolov2吸收faster rcnn的anchor box机制时遇到训练不稳定的问题,分析认为是bbox坐标回归时没有限制,导致anchor box可能会去预测一个距离很远的object,效率不高,因此yolov2对bbox的坐标进行一系列的处理,令anchor box只会对邻近的object负责。阅读论文和代码时难以理解这个机制,以下是个人的一些分析,不保证正确,欢迎讨论指正。
公式中 ( 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)到真实坐标 ( b x , b y , b w , b h ) (b_x,b_y,b_w,b_h) (bx,by,bw,bh)进行转换。需要注意的是 ( 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_x,t_y) (tx,ty)对应的是anchor box的中心点坐标(偏移),而不是通常的左上角。
box get_yolo_box(float *x, float *biases, int n, int index, int i, int j, int lw, int lh, int w, int h, int stride)
{
box b;
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;
return b;
}
float delta_yolo_box(box truth, float *x, float *biases, int n, int index, int i, int j, int lw, int lh, int w, int h, float *delta, float scale, int stride)
{
box pred = get_yolo_box(x, biases, n, index, i, j, lw, lh, w, h, stride);
float iou = box_iou(pred, truth);
float tx = (truth.x*lw - i); //输入特征图尺寸
float ty = (truth.y*lh - j);
float tw = log(truth.w*w / biases[2*n]); //网络输入图尺寸
float th = log(truth.h*h / biases[2*n + 1]);
//scale = 2 - groundtruth.w * groundtruth.h
delta[index + 0*stride] = scale * (tx - x[index + 0*stride]);
delta[index + 1*stride] = scale * (ty - x[index + 1*stride]);
delta[index + 2*stride] = scale * (tw - x[index + 2*stride]);
delta[index + 3*stride] = scale * (th - x[index + 3*stride]);
return iou;
}
上述两个函数来自yolov3的yolo层代码,其中函数参数float* x来自前一个卷积层的输出,shape = (C,H,W)
其中(H,W)表示特征图的宽高,通道C依次是 ( t x , t y , t w , t h , o b j e c t n e s s , s c o r e o f c l a s s i ) (t_x,t_y,t_w,t_h,objectness,score \ of \ class_i) (tx,ty,tw,th,objectness,score of classi), ( t x , t y , t w , t h , o b j e c t n e s s ) (t_x,t_y,t_w,t_h,objectness) (tx,ty,tw,th,objectness)利用sigmoid函数变换到了 [ 0 , 1 ] [0,1] [0,1]之间。
先来看函数get_yolo_box()的参数,biases中存储的是预定以的anchor box的宽和高(输入图尺度),(lw,lh)是yolo层输入的特征图尺度,(w,h)是整个网络输入图尺度,get_yolo_box()函数利用了论文截图中的公式,而且把结果分别利用特征图宽高和输入图宽高做了归一化。既然这个机制是用来限制回归,避免预测很远的目标,那么这个预测范围是多大呢?(b.x,by)最小是(i,j),最大是(i+1,x+1),即中心点在特征图上最多一定一个像素(假设输入图下采样n得到特征图,特征图中一个像素对应输入图的n个像素)(b.w,b.h)最大是(2.7 * anchor.w,2.7*anchor.h),最小就是(anchor.w,anchor.h),这是在输入图尺寸下的值。
delta_yolo_box()负责计算 ( t x , t y , t w , t h , o b j e c t n e s s ) (t_x,t_y,t_w,t_h,objectness) (tx,ty,tw,th,objectness)的误差,其参数和get_yolo_box()类似,truth是groundtruth box,也是用输入图宽高归一化后的(中心点,宽高)。但其中的scale很奇怪,根据代码
sclae = 2 - truth.w * truth.h, 其含义还没理解。