Exemple #1
0
class RegressLoss(nn.Module):
    def __init__(self, func='smooth'):
        super(RegressLoss, self).__init__()
        self.box_coder = BoxCoder()
        if func == 'smooth':
            self.criteron = smooth_l1_loss
        elif func == 'mse':
            self.criteron = F.mse_loss
        elif func == 'balanced':
            self.criteron = balanced_l1_loss
        else:
            raise NotImplementedError
            
    def forward(self, regressions, anchors, annotations, iou_thres=0.5):
        losses = []
        batch_size = regressions.shape[0]
        all_pred_boxes = self.box_coder.decode(anchors, regressions, mode='xywht')
        for j in range(batch_size):
            regression = regressions[j, :, :]
            bbox_annotation = annotations[j, :, :]
            bbox_annotation = bbox_annotation[bbox_annotation[:, -1] != -1]
            pred_boxes = all_pred_boxes[j, :, :]
            if bbox_annotation.shape[0] == 0:
                losses.append(torch.tensor(0).float().cuda())
                continue
            indicator = bbox_overlaps(
                min_area_square(anchors[j, :, :]),
                min_area_square(bbox_annotation[:, :-1])
            )
            overlaps = rbox_overlaps(
                anchors[j, :, :].cpu().numpy(),
                bbox_annotation[:, :-1].cpu().numpy(),
                indicator.cpu().numpy(),
                thresh=1e-1
            )
            if not torch.is_tensor(overlaps):
                overlaps = torch.from_numpy(overlaps).cuda()

            iou_max, iou_argmax = torch.max(overlaps, dim=1)
            positive_indices = torch.ge(iou_max, iou_thres)
            # MaxIoU assigner
            max_gt, argmax_gt = overlaps.max(0) 
            if (max_gt < iou_thres).any():
                positive_indices[argmax_gt[max_gt < iou_thres]]=1

            assigned_annotations = bbox_annotation[iou_argmax, :]
            if positive_indices.sum() > 0:
                all_rois = anchors[j, positive_indices, :]
                gt_boxes = assigned_annotations[positive_indices, :]
                targets = self.box_coder.encode(all_rois, gt_boxes)
                loss = self.criteron(regression[positive_indices, :], targets)
                losses.append(loss)
            else:
                losses.append(torch.tensor(0).float().cuda())
        return torch.stack(losses).mean(dim=0, keepdim=True)
Exemple #2
0
class IntegratedLoss(nn.Module):
    def __init__(self, alpha=0.25, gamma=2.0, func = 'smooth'):
        super(IntegratedLoss, self).__init__()
        self.alpha = alpha
        self.gamma = gamma
        self.box_coder = BoxCoder()
        if func == 'smooth':
            self.criteron = smooth_l1_loss
        elif func == 'mse':
            self.criteron = F.mse_loss
        elif func == 'balanced':
            self.criteron = balanced_l1_loss
            
    def forward(self, classifications, regressions, anchors, annotations,iou_thres=0.5):
        
        cls_losses = []
        reg_losses = []
        batch_size = classifications.shape[0]
        all_pred_boxes = self.box_coder.decode(anchors, regressions, mode='xywht')
        for j in range(batch_size):
            classification = classifications[j, :, :]
            regression = regressions[j, :, :]
            bbox_annotation = annotations[j, :, :]
            bbox_annotation = bbox_annotation[bbox_annotation[:, -1] != -1]
            pred_boxes = all_pred_boxes[j, :, :]
            if bbox_annotation.shape[0] == 0:
                cls_losses.append(torch.tensor(0).float().cuda())
                reg_losses.append(torch.tensor(0).float().cuda())
                continue
            classification = torch.clamp(classification, 1e-4, 1.0 - 1e-4)
            indicator = bbox_overlaps(
                min_area_square(anchors[j, :, :]),
                min_area_square(bbox_annotation[:, :-1])
            )
            ious = rbox_overlaps(
                anchors[j, :, :].cpu().numpy(),
                bbox_annotation[:, :-1].cpu().numpy(),
                indicator.cpu().numpy(),
                thresh=1e-1
            )
            if not torch.is_tensor(ious):
                ious = torch.from_numpy(ious).cuda()
            
            iou_max, iou_argmax = torch.max(ious, dim=1)
           
            positive_indices = torch.ge(iou_max, iou_thres)

            max_gt, argmax_gt = ious.max(0) 
            if (max_gt < iou_thres).any():
                positive_indices[argmax_gt[max_gt < iou_thres]]=1
              
            # cls loss
            cls_targets = (torch.ones(classification.shape) * -1).cuda()
            cls_targets[torch.lt(iou_max, iou_thres - 0.1), :] = 0
            num_positive_anchors = positive_indices.sum()
            assigned_annotations = bbox_annotation[iou_argmax, :]
            cls_targets[positive_indices, :] = 0
            cls_targets[positive_indices, assigned_annotations[positive_indices, -1].long()] = 1
            alpha_factor = torch.ones(cls_targets.shape).cuda() * self.alpha
            alpha_factor = torch.where(torch.eq(cls_targets, 1.), alpha_factor, 1. - alpha_factor)
            focal_weight = torch.where(torch.eq(cls_targets, 1.), 1. - classification, classification)
            focal_weight = alpha_factor * torch.pow(focal_weight, self.gamma)
            bin_cross_entropy = -(cls_targets * torch.log(classification+1e-6) + (1.0 - cls_targets) * torch.log(1.0 - classification+1e-6))
            cls_loss = focal_weight * bin_cross_entropy 
            cls_loss = torch.where(torch.ne(cls_targets, -1.0), cls_loss, torch.zeros(cls_loss.shape).cuda())
            cls_losses.append(cls_loss.sum() / torch.clamp(num_positive_anchors.float(), min=1.0))
            # reg loss
            if positive_indices.sum() > 0:
                all_rois = anchors[j, positive_indices, :]
                gt_boxes = assigned_annotations[positive_indices, :]
                reg_targets = self.box_coder.encode(all_rois, gt_boxes)
                reg_loss = self.criteron(regression[positive_indices, :], reg_targets)
                reg_losses.append(reg_loss)

                if not torch.isfinite(reg_loss) :
                    import ipdb; ipdb.set_trace()
            else:
                reg_losses.append(torch.tensor(0).float().cuda())
        loss_cls = torch.stack(cls_losses).mean(dim=0, keepdim=True)
        loss_reg = torch.stack(reg_losses).mean(dim=0, keepdim=True)
        return loss_cls, loss_reg
Exemple #3
0
class IntegratedLoss(nn.Module):
    def __init__(self, alpha=0.25, gamma=2.0, func='smooth'):
        super(IntegratedLoss, self).__init__()
        self.alpha = alpha
        self.gamma = gamma
        self.box_coder = BoxCoder()
        if func == 'smooth':
            self.criteron = smooth_l1_loss
        elif func == 'mse':
            self.criteron = F.mse_loss
        elif func == 'balanced':
            self.criteron = balanced_l1_loss

    def forward(self, classifications, regressions, anchors, refined_achors, annotations, \
                md_thres=0.5, mining_param=(1, 0., -1), ref=False):

        das = True
        cls_losses = []
        reg_losses = []
        batch_size = classifications.shape[0]
        alpha, beta, var = mining_param
        #         import ipdb;ipdb.set_trace()
        for j in range(batch_size):
            classification = classifications[j, :, :]
            regression = regressions[j, :, :]
            bbox_annotation = annotations[j, :, :]
            bbox_annotation = bbox_annotation[bbox_annotation[:, -1] != -1]
            if bbox_annotation.shape[0] == 0:
                cls_losses.append(torch.tensor(0).float().cuda())
                reg_losses.append(torch.tensor(0).float().cuda())
                continue
            classification = torch.clamp(classification, 1e-4, 1.0 - 1e-4)
            sa = rbbx_overlaps(
                xyxy2xywh_a(anchors[j, :, :].cpu().numpy()),
                xyxy2xywh_a(bbox_annotation[:, :-1].cpu().numpy()),
            )
            if not torch.is_tensor(sa):
                # import ipdb;ipdb.set_trace()
                sa = torch.from_numpy(sa).cuda()
            if var != -1:
                fa = rbbx_overlaps(
                    xyxy2xywh_a(refined_achors[j, :, :].cpu().numpy()),
                    xyxy2xywh_a(bbox_annotation[:, :-1].cpu().numpy()),
                )
                if not torch.is_tensor(fa):
                    fa = torch.from_numpy(fa).cuda()

                if var == 0:
                    md = abs((alpha * sa + beta * fa))
                else:
                    md = abs((alpha * sa + beta * fa) - abs(fa - sa)**var)
            else:
                das = False
                md = sa

            iou_max, iou_argmax = torch.max(md, dim=1)

            positive_indices = torch.ge(iou_max, md_thres)

            max_gt, argmax_gt = md.max(0)
            # import ipdb;ipdb.set_trace(context = 15)
            if (max_gt < md_thres).any():
                positive_indices[argmax_gt[max_gt < md_thres]] = 1

            # matching-weight
            if das:
                pos = md[positive_indices]
                pos_mask = torch.ge(pos, md_thres)
                max_pos, armmax_pos = pos.max(0)
                nt = md.shape[1]
                for gt_idx in range(nt):
                    pos_mask[armmax_pos[gt_idx], gt_idx] = 1
                comp = torch.where(pos_mask, (1 - max_pos).repeat(len(pos), 1),
                                   pos)
                matching_weight = comp + pos
            # import ipdb; ipdb.set_trace(context = 15)

            # cls loss
            cls_targets = (torch.ones(classification.shape) * -1).cuda()
            cls_targets[torch.lt(iou_max, md_thres - 0.1), :] = 0
            num_positive_anchors = positive_indices.sum()
            assigned_annotations = bbox_annotation[iou_argmax, :]
            cls_targets[positive_indices, :] = 0
            cls_targets[positive_indices,
                        assigned_annotations[positive_indices, -1].long()] = 1
            alpha_factor = torch.ones(cls_targets.shape).cuda() * self.alpha
            alpha_factor = torch.where(torch.eq(cls_targets, 1.), alpha_factor,
                                       1. - alpha_factor)
            focal_weight = torch.where(torch.eq(cls_targets, 1.),
                                       1. - classification, classification)
            focal_weight = alpha_factor * torch.pow(focal_weight, self.gamma)
            bin_cross_entropy = -(
                cls_targets * torch.log(classification + 1e-6) +
                (1.0 - cls_targets) * torch.log(1.0 - classification + 1e-6))
            if das:
                soft_weight = (torch.zeros(classification.shape)).cuda()
                soft_weight = torch.where(torch.eq(cls_targets, 0.),
                                          torch.ones_like(cls_targets),
                                          soft_weight)
                soft_weight[positive_indices, assigned_annotations[
                    positive_indices,
                    -1].long()] = (matching_weight.max(1)[0] + 1)
                cls_loss = focal_weight * bin_cross_entropy * soft_weight
            else:
                cls_loss = focal_weight * bin_cross_entropy
            cls_loss = torch.where(torch.ne(cls_targets, -1.0), cls_loss,
                                   torch.zeros(cls_loss.shape).cuda())
            cls_losses.append(
                cls_loss.sum() /
                torch.clamp(num_positive_anchors.float(), min=1.0))
            # reg loss
            if positive_indices.sum() > 0:
                all_rois = anchors[j, positive_indices, :]
                gt_boxes = assigned_annotations[positive_indices, :]
                reg_targets = self.box_coder.encode(all_rois, gt_boxes)
                if das:
                    reg_loss = self.criteron(regression[positive_indices, :],
                                             reg_targets,
                                             weight=matching_weight)
                else:
                    reg_loss = self.criteron(regression[positive_indices, :],
                                             reg_targets)
                reg_losses.append(reg_loss)

                if not torch.isfinite(reg_loss):
                    import ipdb
                    ipdb.set_trace()
                k = 1
            else:
                reg_losses.append(torch.tensor(0).float().cuda())
        loss_cls = torch.stack(cls_losses).mean(dim=0, keepdim=True)
        loss_reg = torch.stack(reg_losses).mean(dim=0, keepdim=True)
        return loss_cls, loss_reg
Exemple #4
0
class IntegratedLoss(nn.Module):
    def __init__(self, alpha=0.25, gamma=2.0, func='smooth'):
        super(IntegratedLoss, self).__init__()
        self.alpha = alpha
        self.gamma = gamma
        self.box_coder = BoxCoder()
        if func == 'smooth':  # 损失函数转折处变得更加平滑
            self.criteron = smooth_l1_loss
        elif func == 'mse':
            self.criteron = F.mse_loss
        elif func == 'balanced':
            self.criteron = balanced_l1_loss

    def forward(self, classifications, regressions, anchors, refined_achors, annotations, \
                md_thres=0.5, mining_param=(1, 0., -1), ref=False):

        das = True
        cls_losses = []
        reg_losses = []
        batch_size = classifications.shape[0]
        alpha, beta, var = mining_param
        #         import ipdb;ipdb.set_trace()
        for j in range(batch_size):  #迭代每一张输入的图片
            # 分类和回归的特征图
            classification = classifications[
                j, :, :]  # classification的维度=batch-size,box—num,概率
            regression = regressions[
                j, :, :]  # regression的维度=batch-size,box-num,回归坐标值,包含角度
            # 真实的标注数据
            bbox_annotation = annotations[j, :, :]
            bbox_annotation = bbox_annotation[bbox_annotation[:, -1] !=
                                              -1]  #类别不为-1的框
            if bbox_annotation.shape[0] == 0:  # 如果目标数量为0
                cls_losses.append(torch.tensor(0).float().cuda())
                reg_losses.append(torch.tensor(0).float().cuda())
                continue
            classification = torch.clamp(classification, 1e-4,
                                         1.0 - 1e-4)  #修剪在规定的范围之内,框的數量×類別數(2)

            # 下面计算匹配度,sa空间对齐,和输入ROI有关
            sa = rbbx_overlaps(
                xyxy2xywh_a(anchors[j, :, :].cpu().numpy()),
                xyxy2xywh_a(bbox_annotation[:, :-1].cpu().numpy()),
            )
            if not torch.is_tensor(sa):
                # import ipdb;ipdb.set_trace()
                sa = torch.from_numpy(sa).cuda()
            if var != -1:
                # 下面计算特征对齐fa,是關於GT和回归之间的
                fa = rbbx_overlaps(
                    xyxy2xywh_a(refined_achors[j, :, :].cpu().numpy()),
                    xyxy2xywh_a(bbox_annotation[:, :-1].cpu().numpy()),
                )
                if not torch.is_tensor(fa):
                    fa = torch.from_numpy(fa).cuda()
                # 匹配度计算---空间对齐-特征对齐-惩罚项
                if var == 0:
                    md = abs((alpha * sa + beta * fa))
                else:  # 匹配度计算---空间对齐-特征对齐-惩罚项
                    md = abs((alpha * sa + beta * fa) - abs(fa - sa)**var)
            else:
                das = False
                md = sa

            # 然后将所有目标压缩,我们不关注目标,只关注我们的anchor box和位置的目标之间的iou,然后就取最大值,所以维度是anchor box
            iou_max, iou_argmax = torch.max(
                md,
                dim=1)  #应该是对于每一个gt中的目标,所有的anchor box都与其进行匹配,所以是anchor数量×目标数
            # 但是这里我们不关注每一个具体的目标类别-匹配度更加关注于是否阳性阴性样本-也就是重合度如何

            # 通过匹配性阈值来选取阳性样本,正样本-True的位置
            positive_indices = torch.ge(iou_max, md_thres)

            # 对于所有的anchor box计算匹配度后,max-gt返回的是对应目标数量的匹配度
            # argmax-gt返回的是相应的位置,也就是哪个预选框(其实下面这行代码就是选出和每一个gt目标匹配度最高的预选框)
            max_gt, argmax_gt = md.max(0)
            # import ipdb;ipdb.set_trace(context = 15)
            if (max_gt < md_thres).any():  # 都不及匹配度阈值
                positive_indices[argmax_gt[
                    max_gt < md_thres]] = 1  # 正样本中,超过阈值,最大阈值 = 1

            # matching-weight
            if das:
                pos = md[positive_indices]
                pos_mask = torch.ge(pos, md_thres)
                max_pos, armmax_pos = pos.max(
                    0)  # 这里就取得了阳性样本中的最大匹配值,以及其索引(位置),用于后面计算补偿因子
                nt = md.shape[1]  #gt中的目标数量
                for gt_idx in range(nt):
                    pos_mask[
                        armmax_pos[gt_idx],
                        gt_idx] = 1  # 这里的pos_mask对应维度 框数量×目标数量,也就是选出了每一个目标最大匹配度所对应的框,也就是一行一个True
                comp = torch.where(pos_mask, (1 - max_pos).repeat(len(pos), 1),
                                   pos)
                # 对于拥有最大的匹配度的阳性样本-其计算损失的补偿因子(权重w)=1
                matching_weight = comp + pos  # 然后再对其他的阳性样本进行补偿
            # import ipdb; ipdb.set_trace(context = 15)

            # cls loss
            cls_targets = (torch.ones(classification.shape) * -1).cuda()
            # 逐元素比较,小于md-thres -0.1就置零
            cls_targets[torch.lt(iou_max, md_thres - 0.1), :] = 0

            num_positive_anchors = positive_indices.sum()  #阳性样本数量
            assigned_annotations = bbox_annotation[iou_argmax, :]
            cls_targets[positive_indices, :] = 0
            cls_targets[positive_indices,
                        assigned_annotations[positive_indices, -1].long()] = 1

            alpha_factor = torch.ones(cls_targets.shape).cuda() * self.alpha

            # torch.where 类似于条件运算符,符合的保留第一个,否则第二个
            alpha_factor = torch.where(torch.eq(cls_targets, 1.), alpha_factor,
                                       1. - alpha_factor)
            focal_weight = torch.where(torch.eq(cls_targets, 1.),
                                       1. - classification, classification)
            focal_weight = alpha_factor * torch.pow(focal_weight, self.gamma)
            # 交叉熵损失函数
            bin_cross_entropy = -(
                cls_targets * torch.log(classification + 1e-6) +
                (1.0 - cls_targets) * torch.log(1.0 - classification + 1e-6))
            if das:
                soft_weight = (torch.zeros(classification.shape)).cuda()
                soft_weight = torch.where(torch.eq(cls_targets, 0.),
                                          torch.ones_like(cls_targets),
                                          soft_weight)
                soft_weight[positive_indices, assigned_annotations[
                    positive_indices,
                    -1].long()] = (matching_weight.max(1)[0] + 1)
                # focal-loss加一个权重,该权重关注阳性样本
                cls_loss = focal_weight * bin_cross_entropy * soft_weight
            else:
                cls_loss = focal_weight * bin_cross_entropy
            # 这里计算不等于-1处的损失
            cls_loss = torch.where(torch.ne(cls_targets, -1.0), cls_loss,
                                   torch.zeros(cls_loss.shape).cuda())
            # 好像这里的分类损失仅仅计算了补偿因子加权的损失
            cls_losses.append(
                cls_loss.sum() /
                torch.clamp(num_positive_anchors.float(), min=1.0))

            # reg loss---回归的损失函数使用smoothL1损失-在转折处更加平滑
            if positive_indices.sum() > 0:
                all_rois = anchors[j, positive_indices, :]  #阳性样本
                gt_boxes = assigned_annotations[
                    positive_indices, :]  #我们仅仅对阳性样本计算补偿加权的回归损失,所以这里按照positive-indices
                # reg-targets返回targets_dx, targets_dy, targets_dw, targets_dh, targets_dt用于计算回归损失
                reg_targets = self.box_coder.encode(all_rois, gt_boxes)
                if das:  #加入补偿因子的损失计算, reg_target是偏移量,用于计算损失
                    reg_loss = self.criteron(regression[positive_indices, :],
                                             reg_targets,
                                             weight=matching_weight)
                else:
                    reg_loss = self.criteron(regression[positive_indices, :],
                                             reg_targets)
                reg_losses.append(reg_loss)

                if not torch.isfinite(reg_loss):
                    import ipdb
                    ipdb.set_trace()
                k = 1
            else:
                reg_losses.append(torch.tensor(0).float().cuda())

        loss_cls = torch.stack(cls_losses).mean(dim=0, keepdim=True)  # 拼接后求均值
        loss_reg = torch.stack(reg_losses).mean(dim=0, keepdim=True)  # 拼接后求均值
        return loss_cls, loss_reg