Keras-yolo3: 这代码写错了吧,我怎么训练不出来!

Created on 8 Jan 2019  ·  30Comments  ·  Source: qqwweee/keras-yolo3

该代码测试是没有问题的,但是训练却有问题。鉴于用该代码来训练一直没有收敛,所以我怀疑该代码这里有个小问题?

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]

Most helpful comment

好像在YOLO2中有提到,选取哪个anchor预测时,计算IOU值时不考虑坐标,只考虑形状,所以先将先验框(anchor)与ground truth的中心点都偏移到同一位置(原点),然后计算出对应的IOU值

All 30 comments

晕,刚刚发现已经有人提出来了,可以参考这里

@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,也是卡在这个候选框与真是框匹配规则上

晕,刚刚发现已经有人提出来了,可以参考这里

[email protected]

@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 = ih
jitter
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对她负责

image

@YunYang1994 @zhangyufei1995 所以两位老哥,这代码到底有问题还是没有?我用COCO2014的数据做训练,转了train.txt出来并且跑了kmeans.py之后,第一轮epochloss从75降到46,再往后又跑了40轮loss一直是46附近降不下去了啊

好像在YOLO2中有提到,选取哪个anchor预测时,计算IOU值时不考虑坐标,只考虑形状,所以先将先验框(anchor)与ground truth的中心点都偏移到同一位置(原点),然后计算出对应的IOU值

「选取哪个anchor预测时,计算IOU值时不考虑坐标,只考虑形状」
恍然大悟! 感谢~~

Was this page helpful?
0 / 5 - 0 ratings