该代码测试是没有问题的,但是训练却有问题。鉴于用该代码来训练一直没有收敛,所以我怀疑该代码这里有个小问题?
在yolo3/model.py这样写到:
# Expand dim to apply broadcasting.
anchors = np.expand_dims(anchors, 0)
anchor_maxes = anchors / 2.
anchor_mins = -anchor_maxes
valid_mask = boxes_wh[..., 0]>0
for b in range(m):
# Discard zero rows.
wh = boxes_wh[b, valid_mask[b]]
if len(wh)==0: continue
# Expand dim to apply broadcasting.
wh = np.expand_dims(wh, -2)
box_maxes = wh / 2.
box_mins = -box_maxes
intersect_mins = np.maximum(box_mins, anchor_mins)
intersect_maxes = np.minimum(box_maxes, anchor_maxes)
intersect_wh = np.maximum(intersect_maxes - intersect_mins, 0.)
intersect_area = intersect_wh[..., 0] * intersect_wh[..., 1]
box_area = wh[..., 0] * wh[..., 1]
anchor_area = anchors[..., 0] * anchors[..., 1]
iou = intersect_area / (box_area + anchor_area - intersect_area)
按照我的理解是,这里计算图片每个boundingbox与9个anchor的iou,然后选出iou最大的那个boundingbox,可是这里这样计算iou不合适吧?
anchor_maxes = anchors / 2. # 以网格中心为原点, 然后分别计算出anchor左上角和右下角坐标
anchor_mins = -anchor_maxes
这里是没错的,但是这里不对吧?
wh = np.expand_dims(wh, -2)
box_maxes = wh / 2. # 假设 bouding box 的中心也位于网格的中心
box_mins = -box_maxes
你就确定每个图片里的object的中心刚好就是网格的中心 ? 原论文说的是
`将一幅图像分成SxS个网格(grid cell),如果某个object的中心 落在这个网格中,则这个网格就负责预测这个object。`
有人会说,假如将图片划分的单元网格像素较小(比如输入图片416时,那么最小的网格宽度就是416//52 = 8),那么就可以说object的中心刚好落在网格中心了。
但是鉴于yolov3一共有3个尺度,分别对应[13,13], [26, 26], [52,52]。每个尺度分别有3个不同的 anchor 。所以,与boundingbox重合率(iou)最大的那个anchor不一定刚好对应单元网格像素最小的那个吧?
而且yolov3输出的object中心坐标也是每个网格里的相对位置,根本就不是网格中心。所以,你这里不能这样处理!
所以,你这里是不是错了??????? 我觉得boundingbox的坐标不对!!!
希望有人能解决我的疑惑, 谢谢各位! 本人正在努力复现tensorflow版本的yolov3, 非常欢迎一起来讨论!
欢迎交流 [email protected]
晕,刚刚发现已经有人提出来了,可以参考这里
@YunYang1994 你是在COCO上训练的么?我也在训练,一直没有达到作者生成的效果,一起交流讨论啊
@muye5 私聊,留个联系方式?
@muye5 私聊,留个联系方式?
muyepiaozhou at gmail.com
好像在YOLO2中有提到,选取哪个anchor预测时,计算IOU值时不考虑坐标,只考虑形状,所以先将先验框(anchor)与ground truth的中心点都偏移到同一位置(原点),然后计算出对应的IOU值
@wzxyks 你计算iou的时候不考虑坐标,认真的吗?【我们在计算iou的时候,输进去的就是两个boundingbox的坐标】
@YunYang1994 我理解它这个地方只是为了确定应该把这个目标付给哪一个anchor来学习,所以没有考虑中心点
@muye5 是这样的:
首先找到对应iou值最大的那个anchor,然后以它为标准做回归,这点在yolov3的损失函数中已经提到过了。但这里作者计算iou的方法明显错误!误认为boundingbox的中心坐标也是cell的中心坐标,如果是这样的话,那yolov3还预测boundingbox的中心坐标干啥,直接预测在哪个cell里就可以了?
但事实上yolov3预测的正是boundingbox的中心坐标在该cell左上角的偏移量。不但如此,yolov3预测的boundingbox长宽也是所对应anchor长宽的偏移量!
所以,一句话:本质上而言,yolov3预测出来的boundingbox是对对应的cell左上角位置和对应的anchor长宽做回归的。
但这里,作者却根据错误的iou计算方式选择了错误的anchor来做回归,肯定是不对的。
@YunYang1994 他上面不也是这个逻辑么?没有get到点^_^
我理解他上面计算那一堆都是为了找到k,然后赋值给他
y_true[l][b, j, i, k, 0:4] = true_boxes[b,t, 0:4]
@muye5 它这里没有问题,我的意思是它计算ground truth box与anchor的iou方式不对,因为ground true box的中心不一定刚好是网格的中心。
for(t = 0; t < 30; ++t){
box truth = float_to_box(net.truth + t*(l.coords + 1) + b*l.truths, 1);
if(!truth.x) break;
float best_iou = 0;
int best_n = 0;
i = (truth.x * l.w);
j = (truth.y * l.h);
box truth_shift = truth;
truth_shift.x = 0;
truth_shift.y = 0;
for(n = 0; n < l.n; ++n){
int box_index = entry_index(l, b, n*l.w*l.h + j*l.w + i, 0);
box pred = get_region_box(l.output, l.biases, n, box_index, i, j, l.w, l.h, l.w*l.h);
if(l.bias_match){
pred.w = l.biases[2*n]/l.w;
pred.h = l.biases[2*n+1]/l.h;
}
pred.x = 0;
pred.y = 0;
float iou = box_iou(pred, truth_shift);
if (iou > best_iou){
best_iou = iou;
best_n = n;
}
}
https://github.com/pjreddie/darknet/blob/master/src/region_layer.c
在选取用哪个anchor来进行预测时,确实可以不考虑(x, y).只考虑(w, h).应该是为了给真实框选择一个大小接近的anchor来进行预测
@YunYang1994 楼上说的对,选最优anchor的时候不用关心中心点,它是活动的,只要能跟ground truth match最多就好,中心不用固定的
@muye5 @wzxyks 了解,谢谢!因为boundingbox只是用anchor做长宽回归,而用cell的左上角做位置回归,因此没有必要考虑anchor与boundingbox的位置。
@muye5 私聊,留个联系方式?
一同交流?我也在用tensorflow写YOLOV3,也是卡在这个候选框与真是框匹配规则上
晕,刚刚发现已经有人提出来了,可以参考这里
@S601327412 @muye5 我对于候选框与真实框匹配规则的理解是这样的:
yolov3跟faster-rcnn不一样,它只选择一个anchor[与gt-box的iou最高的那个]做size回归。一旦选择到最合适的anchor后,所选用的grid cell尺寸也就确定。此外,损失函数里计算iou是要考虑该grid cell其他两个anchor的置信度损失,如果高于阈值则认为这两个anchor所回归出来的predict box也成功检测到物体[此时是没有损失的],只不过预测的boundingbox只选择那个最优anchor来做size回归,如果低于阈值,那么是要计算noobject confidence loss损失的。其他两个layer所对应的6个anchor回归出来的predict box直接被认为没有物体,直接计算noobject confidence loss损失.。【因为每个网格只负责检测object的中心(center)落在该网格上的object】
欢迎一起交流!
@YunYang1994 对的,不过你说ignore_thresh的使用,它其实不太关心是不是同一个grid_cell,计算损失函数时它直接把所有预测结果和ground truth都计算了一遍iou,只要和任何一个ground truth的最大iou超过忽略阈值,这个位置都不会出现在noobject的损失内,不过你的理解应该也差不多一个意思。
@S601327412 @muye5 我对于候选框与真实框匹配规则的理解是这样的:
yolov3跟faster-rcnn不一样,它只选择一个anchor[与gt-box的iou最高的那个]做size回归。一旦选择到最合适的anchor后,所选用的grid cell尺寸也就确定。此外,损失函数里计算iou是要考虑该grid cell其他两个anchor的置信度损失,如果高于阈值则认为这两个anchor也成功检测到物体[此时是没有损失的],只不过预测的boundingbox只选择那个最优anchor来做size回归。假如那两个anchor低于阈值(ignore_thresh),则被认为没有检测到物体,是要计算noobject confidence损失的。那么剩下的其他6个anchor则直接计算noobject confidence损失。欢迎一起交流!
anchor只做尺寸匹配,xy根据真是框的位置索引来设置tensor,不过我发现这用numpy好写,但是用tensorflow来做的话不好实现,因为tensorflwo的constant tensor 和变量好像不能以[:,x,y,anchor[indx]]这种形式来赋值
@S601327412 @muye5 我对于候选框与真实框匹配规则的理解是这样的:
yolov3跟faster-rcnn不一样,它只选择一个anchor[与gt-box的iou最高的那个]做size回归。一旦选择到最合适的anchor后,所选用的grid cell尺寸也就确定。此外,损失函数里计算iou是要考虑该grid cell其他两个anchor的置信度损失,如果高于阈值则认为这两个anchor也成功检测到物体[此时是没有损失的],只不过预测的boundingbox只选择那个最优anchor来做size回归。假如那两个anchor低于阈值(ignore_thresh),则被认为没有检测到物体,是要计算noobject confidence损失的。那么剩下的其他6个anchor则直接计算noobject confidence损失。
欢迎一起交流!anchor只做尺寸匹配,xy根据真是框的位置索引来设置tensor,不过我发现这用numpy好写,但是用tensorflow来做的话不好实现,因为tensorflwo的constant tensor 和变量好像不能以[:,x,y,anchor[indx]]这种形式来赋值
我觉得该作者对这个ground truth box的处理是没问题的,不过你可以用这个数据集训练你代码试试。
200张图片,只有一个类别。
你們知道 YOLOv3 正常的 loss 應該要是多少嗎?
代码确实有错误,但不是这里这个问题,而是处理图像缩放的代码有问题,此外COCO数据集的锚框也要重新选
@GlassyWing 对的,处理图像缩放代码有问题
@GlassyWing 对的,处理图像缩放代码有问题
@ nwdxbx 你好,请问是那个图像缩放哪个地方的问题呢。该如何更改呢?
@wzxyks
# resize image
#new_ar = w/h * rand(1-jitter,1+jitter)/rand(1-jitter,1+jitter)
dw = iwjitter
dh = ihjitter
new_ar = (iw+rand(-dw,dw))/(ih+rand(-dh,dh))
@wzxyks
resize image
new_ar = w/h * rand(1-jitter,1+jitter)/rand(1-jitter,1+jitter)
dw = iw_jitter dh = ih_jitter
new_ar = (iw+rand(-dw,dw))/(ih+rand(-dh,dh))
dw = iw_jitter dh = ih_jitter?
dw = iw×jitter dh = ih×jitter?
@所有人 我的正确理解是:gt先和9个anchors对比(选出iou最大的那一个anchor,此时只需要wh信息),而选出的这个anchor在(1313 2626 52*52)里面已经被分配好了(确定了),然后再计算grid cell的位置,确定是哪个grid cell之后 计算loss的时候 用gt的x y 减去该grid cell左上角的位置。 不知道是不是正确理解了。
还有再说一句 在计算gridcell位置的时候,其实用的是GT的中心点坐标(x,y),遵循那一句译文:该目标落在哪个cell,就由哪个cell对她负责

@YunYang1994 @zhangyufei1995 所以两位老哥,这代码到底有问题还是没有?我用COCO2014的数据做训练,转了train.txt出来并且跑了kmeans.py之后,第一轮epochloss从75降到46,再往后又跑了40轮loss一直是46附近降不下去了啊
好像在YOLO2中有提到,选取哪个anchor预测时,计算IOU值时不考虑坐标,只考虑形状,所以先将先验框(anchor)与ground truth的中心点都偏移到同一位置(原点),然后计算出对应的IOU值
「选取哪个anchor预测时,计算IOU值时不考虑坐标,只考虑形状」
恍然大悟! 感谢~~
Most helpful comment
好像在YOLO2中有提到,选取哪个anchor预测时,计算IOU值时不考虑坐标,只考虑形状,所以先将先验框(anchor)与ground truth的中心点都偏移到同一位置(原点),然后计算出对应的IOU值