Hard Negatie Mining与Online Hard Example Mining(OHEM)都属于难例挖掘,它是解决目标检测老大难问题的常用办法,运用于R-CNN,fast R-CNN,faster rcnn等two-stage模型与SSD等(有anchor的)one-stage模型训练时的训练方法。
OHEM和难负例挖掘名字上的不同。
- Hard Negative Mining只注意难负例
- OHEM 则注意所有难例,不论正负(Loss大的例子)
难例挖掘的思想可以解决很多样本不平衡/简单样本过多的问题,比如说分类网络,将hard sample 补充到数据集里,重新丢进网络当中,就好像给网络准备一个错题集,哪里不会点哪里。
难例挖掘与非极大值抑制 NMS 一样,都是为了解决目标检测老大难问题(样本不平衡+低召回率)及其带来的副作用。
根据每个RoIs的loss的大小来决定哪些是难样例, 哪些是简单样例, 通过这种方法, 可以更高效的训练网络, 并且可以使得网络获得更小的训练loss
OHEM和focal loss的作用类似
实现技巧:
论文,作者将该方法是现在 Fsat R-CNN 目标检测方法中。最简单做法是更改损失函数层,损失函数层首先计算所有 ROI 的 loss, 然后根据 loss 对 ROI 进行排序,并选择 hard RoIs, 让 那些 non-RoIs的损失变为0. 这种方法虽然很简单,但是非常不高效,因为还需要为所有的 RoIs 分配进行反向传播时需要的内存空间。
为了克服这个缺点,作者对下面的 Figure 1 进行改进, 如下面的 Figure 2.该改进时使用两份同样的 RoI network。 其中一个是只读的(readonly), 即只进行前向计算,不进行反向传播优化,所以只需要为前向传播分配内存,它的参数实时保持和另一个 RoI network(regular RoI network)保持一样。在每次迭代时,首先使用 readonly RoI network 对每个 ROI 计算起 loss,然后用上面描述的选择 hard RoIs 的方法选择 hard RoIs. 然后利用 regular RoI network来对选择的 hard RoIs 进行前向和后向计算来优化网络。
Pytorch实现
def ohem_loss( batch_size, cls_pred, cls_target, loc_pred, loc_target, smooth_l1_sigma=1.0 ): """ Arguments: batch_size (int): number of sampled rois for bbox head training loc_pred (FloatTensor): [R, 4], location of positive rois loc_target (FloatTensor): [R, 4], location of positive rois pos_mask (FloatTensor): [R], binary mask for sampled positive rois cls_pred (FloatTensor): [R, C] cls_target (LongTensor): [R] Returns: cls_loss, loc_loss (FloatTensor) """ ohem_cls_loss = F.cross_entropy(cls_pred, cls_target, reduction='none', ignore_index=-1) ohem_loc_loss = smooth_l1_loss(loc_pred, loc_target, sigma=smooth_l1_sigma, reduce=False) #这里先暂存下正常的分类loss和回归loss loss = ohem_cls_loss + ohem_loc_loss #然后对分类和回归loss求和 sorted_ohem_loss, idx = torch.sort(loss, descending=True) #再对loss进行降序排列 keep_num = min(sorted_ohem_loss.size()[0], batch_size) #得到需要保留的loss数量 if keep_num < sorted_ohem_loss.size()[0]: #这句的作用是如果保留数目小于现有loss总数,则进行筛选保留,否则全部保留 keep_idx_cuda = idx[:keep_num] #保留到需要keep的数目 ohem_cls_loss = ohem_cls_loss[keep_idx_cuda] ohem_loc_loss = ohem_loc_loss[keep_idx_cuda] #分类和回归保留相同的数目 cls_loss = ohem_cls_loss.sum() / keep_num loc_loss = ohem_loc_loss.sum() / keep_num #然后分别对分类和回归loss求均值 return cls_loss, loc_loss
OHEM(Online Hard Example Mining)在线难例挖掘(在线困难样例挖掘) & Pytorch实现 & HNM (目标检测)
于 2021-08-02 20:32:16 首次发布