RetinaFace 因为其速度快,精度高,是工程中常用的人脸检测模型,和 SSD 一样,它在训练和预测阶段也采用了先验框。最近拿到一份 PyTorch 版本的 RetinaFace,在损失函数(loss function)部分,明显采用了 SSD 的 multibox loss 计算方法。
研究某个深度学习模型,除了它的网络设计之外,loss 的计算是最值得研究的了,因此本文将尝试对 multibox loss 计算过程中比较费解的 match() 函数逐行做一个比较深入的分析。
multibox loss 计算中的匹配过程
如前文所述,无论是 RetinaFace 还是 SSD 都采用了先验框,所谓“先验框”,其实就是依据事先的经验提出的一系列可能的目标框,这些先验框遍布整个特征图的位置,狭义的直观上来说,可以认为要检测的图中的每一个像素点都被事先预设了若干先验框,负责预测该像素点可能存在的目标。请注意“可能”这个词。
在预测和训练阶段,需要先对所有的先验框做分类,区分哪些先验框是背景,哪些是目标(在 RetinaFace 中,目标即人脸),而区分的标准就是看目标框与先验框的 IOU,如果先验框 p 与目标框 t 的 IOU 高于设定的阈值,就让先验框 p 负责预测目标 t。如果某个先验框与所有的目标框的 IOU 都低于设定的阈值,那么这个先验框就属于背景。这样的过程称作“匹配”,mutltibox loss 计算中的 match() 函数就是负责“匹配”过程的。
match() 函数原型及其参数
在我拿到的代码中,match() 函数的原型如下,请看:def match(threshold, truths, priors, variances, labels, landms, loc_t, conf_t, landm_t, idx):
# jaccard index
overlaps = jaccard(truths, point_form(priors))
# (Bipartite Matching)
# best prior for each ground truth
best_prior_overlap, best_prior_idx = overlaps.max(1, keepdim=True) # [num_obj, 1]
# ignore hard gt
valid_gt_idx = best_prior_overlap[:, 0