在计算得到anchor之后, 需要将anchor与ground truth(gt)的bbox给绑定起来, 也就是Matching。
paper里说matching分为两步,逐层进行:
第一步:
We begin by matching each ground truth box to the default box with the best jaccard overlap. This is the matching approach used by the original MultiBox [7] and it ensures that each ground truth box has exactly one matched default box.
大意是为每个gt bbox找到一个最佳的anchor,保证每个gt bbox都有刚好有一个anchor来预测它。
代码: https://github.com/weiliu89/caffe/blob/ssd/src/caffe/util/bbox_util.cpp#L584
第二步:
Unlike MultiBox, we then match default boxes to any ground truth with jaccard overlap higher than a threshold (0.5). Adding these matches simplifies the learning problem: it allows the network to predict high confidences for multiple overlapping default boxes rather than requiring it to pick only the one with maximum overlap.
求出所有bbox与所有anchor的iou, 先留下最大iou值,然后去掉小于0.5的。
SSD-tensorflow只实现了第二步:
https://github.com/balancap/SSD-Tensorflow/blob/master/nets/ssd_common.py#L108
label = labels[i]
bbox = bboxes[i]
jaccard = jaccard_with_anchors(bbox)
# Mask: check threshold + scores + no annotations + num_classes.
mask = tf.greater(jaccard, feat_scores)
# mask = tf.logical_and(mask, tf.greater(jaccard, matching_threshold))
mask = tf.logical_and(mask, feat_scores > -0.5)
mask = tf.logical_and(mask, label < num_classes)
imask = tf.cast(mask, tf.int64)
fmask = tf.cast(mask, dtype)
# Update values using mask.
feat_labels = imask * label + (1 - imask) * feat_labels
feat_scores = tf.where(mask, jaccard, feat_scores)
注意:
- threshold检查那一句被注释掉, 并不是说没有用threshold过滤, 而是把过滤放到了后面:
https://github.com/balancap/SSD-Tensorflow/blob/master/nets/ssd_vgg_512.py#L543
pmask = gscores[i] > match_threshold
- 如果gt里有unlabeled bbox,jaccard score里可能会出现负值。详细 https://github.com/balancap/SSD-Tensorflow/issues/10#issuecomment-283694447