Date: 2020/03/29
Author: CW
前言:
Hard Negative Mining 属于训练过程中的一个 trick,通常是指把模型预测错误得比较严重的一批样本筛选出来,放到训练集中训练,从而让模型的预测效果不断改善,而具体实现方法会根据不同的任务有所差异。
前段时间在阅读 FaceBoxes 源码时发现,其中对于 Hard Negative Mininig 的实现还挺巧妙,如果你热爱 coding,应该会感受到这其中的魅力。这部分的源码也一并附上,大家可以去感受下是什么feel~
本文仅对 Hard Negative Mining 部分进行讲解,先把代码和相应的注释贴上来,大家先揣摩几分钟,前面部分属于上下文相关,比较好懂,我也做了对应的中文注释,关键在于最后一句,十分巧妙!
Hard Negative Mining in FaceBoxes简单概述下这部分代码的内容,第一句里的 conf_data 是模型对一个 batch 里的所有 anchor 预测的每一个类别的置信度,这里就两个类别,以区分是否为人脸。loss_c 通过减法计算得到,前半部分 log_sum_exp 实际计算的是对所有类别预测的置信度之和,后半部分是取出预测的 anchor 对应的真实类别的置信度,conf_t 就是每个 anchor 对应的 label,于是这两部分相减即得到预测的不是真实类别的其它类别的置信度之和,这个值越大则说明预测得越不准,因此在这里可将其当做 loss 来看待,变量名 loss_c 就是这个意思,其中 c 代表 confidence。
除最后一句外,剩余部分相信各位人才看注释(甚至不看)就能秒懂,这里就不再阐述了。
neg 代表的是 loss 最大的一批负样本对应的位置,现举个例子来对最后一行代码进行说明:
# indices: 0 1 2 3 4
# loss_idx: 3 4 0 2 1
# idx_rank: 2 4 3 0 1
# num_neg = 3
假设情况如上,indices 是 loss_c 的索引,假设这里只有5个元素,根据 loss 由大到小排序后,对应的原始索引为 loss_idx,loss 最大的是 loss_c[3],第二是 loss_c[4],...,最后是 loss_c[1],接着对 loss_idx 有小到大排序得到索引序列 idx_rank,这里或许你会感到迷惑,为何要对一个索引序列 loss_idx 进行排序呢?别急,稍后即真相大白。
如上 num_neg = 3,代表要筛选3个 loss 最大的负样本,那么 idx_rank 小于 num_neg 的位置的值是 2, 0, 1,代表的是 loss_idx 的前3个元素,而 loss_idx 的前3个元素代表的是什么呢?就是 loss 最大的3个样本对应的索引呀!如此一来,idx_rank 中对应为 True 的 位置在 indices 中就也对应为 True 了。
第一次看,可能会感觉到很神奇(我就是这样...),但是冷静下来后发现,这也是理所当然的事情嘛!
想想 idx_rank 的意义就会明白,它是根据 loss 排序后索引序列 loss_idx 的 索引序列,而 idx_rank < num_neg 会产生什么结果呢?其实就是把 idx_rank 中 0, 1, 2, ..., num_neg - 1 这些值对应位置设置为 True,背后的意义就是取出 loss_idx 中前 num_neg 个元素对应值,将其在 indices 中的位置设置为 True。
再度冷静后,会发现,咦,为什么要这么做呢?按道理我根据 loss 排序得到 loss_idx 后就可以取出前 num_neg 个元素作为索引,就 ok 了呀!是的,确实没毛病,我想作者之所以这么做应该是为了能够直接使用和原索引序列 indices 位置关系一致的布尔类型索引序列来处理吧,可能感觉这样会更优雅(亦或是更高端?)...
看到这里,不知道你有没感觉被我坑了,Em..,反正,我是被作者坑了。
网友评论