0


YOLOX改进之损失函数修改(上)

文章内容:如何在YOLOX官网代码中修改–置信度预测损失

环境:pytorch1.8

损失函数修改内容

(1)置信度预测损失更换:二元交叉熵损失替换为FocalLoss或者VariFocalLoss

(2)定位损失更换:IOU损失替换为GIOU、CIOU、EIOU以及a-IOU系列

提示:使用之前可以先了解YOLOX及上述损失函数原理

参考链接

YOLOX官网链接:https://github.com/Megvii-BaseDetection/YOLOX

YOLOX原理解析(Bubbliiiing大佬版):https://blog.csdn.net/weixin_44791964/article/details/120476949

FocalLoss损失解析:https://cyqhn.blog.csdn.net/article/details/87343004

VariFocalLoss损失解析:https://blog.csdn.net/weixin_42096202/article/details/108567189

GIOU、CIOU、EIOU等:https://blog.csdn.net/neil3611244/article/details/113794197

a-IOU:https://blog.csdn.net/wjytbest/article/details/121513560

使用方法:直接替换即可

代码修改过程

1、置信度预测损失更换之FocalLoss(不需要创建新的py文件)

使用:直接在YOLOX-main/yolox/models/yolo_head.py的YOLOXHead类中创建focal_loss方法

(1)首先找到置信度预测损失计算位置loss_obj,并进行替换(位置在386-405行左右)

# loss_iou:定位损失;loss_obj:置信度预测损失;loss_cls:预测损失
        loss_iou =(
            self.iou_loss(bbox_preds.view(-1,4)[fg_masks], reg_targets)).sum()/ num_fg
        #loss_obj = (  #    self.bcewithlog_loss(obj_preds.view(-1, 1), obj_targets)#).sum() / num_fg
        loss_obj =(
            self.focal_loss(obj_preds.sigmoid().view(-1,1), obj_targets)).sum()/ num_fg
        loss_cls =(
            self.bcewithlog_loss(
                cls_preds.view(-1, self.num_classes)[fg_masks], cls_targets
            )).sum()/ num_fg

(2)创建focal_loss方法,放到def get_l1_target(…)之前即可,代码如下:

deffocal_loss(self, pred, gt):
        pos_inds = gt.eq(1).float()
        neg_inds = gt.eq(0).float()
        pos_loss = torch.log(pred+1e-5)* torch.pow(1- pred,2)* pos_inds *0.75
        neg_loss = torch.log(1- pred+1e-5)* torch.pow(pred,2)* neg_inds *0.25
        loss =-(pos_loss + neg_loss)return loss

2、置信度预测损失更换之VariFocalLoss(代码较多,所以额外创建新的py文件)

步骤一:YOLOX-main/yolox/models文件夹下创建varifocalloss.py文件,内容如下:

import torch.nn as nn
import torch.nn.functional as F
 
defreduce_loss(loss, reduction):"""Reduce loss as specified.
    Args:
        loss (Tensor): Elementwise loss tensor.
        reduction (str): Options are "none", "mean" and "sum".
    Return:
        Tensor: Reduced loss tensor.
    """
    reduction_enum = F._Reduction.get_enum(reduction)# none: 0, elementwise_mean:1, sum: 2if reduction_enum ==0:return loss
    elif reduction_enum ==1:return loss.mean()elif reduction_enum ==2:return loss.sum()defweight_reduce_loss(loss, weight=None, reduction='mean', avg_factor=None):"""Apply element-wise weight and reduce loss.
    Args:
        loss (Tensor): Element-wise loss.
        weight (Tensor): Element-wise weights.
        reduction (str): Same as built-in losses of PyTorch.
        avg_factor (float): Avarage factor when computing the mean of losses.
    Returns:
        Tensor: Processed loss values.
    """# if weight is specified, apply element-wise weightif weight isnotNone:
        loss = loss * weight

    # if avg_factor is not specified, just reduce the lossif avg_factor isNone:
        loss = reduce_loss(loss, reduction)else:# if reduction is mean, then average the loss by avg_factorif reduction =='mean':
            loss = loss.sum()/ avg_factor
        # if reduction is 'none', then do nothing, otherwise raise an errorelif reduction !='none':raise ValueError('avg_factor can not be used with reduction="sum"')return loss

defvarifocal_loss(pred,
                   target,
                   weight=None,
                   alpha=0.75,
                   gamma=2.0,
                   iou_weighted=True,
                   reduction='mean',
                   avg_factor=None):"""`Varifocal Loss <https://arxiv.org/abs/2008.13367>`_
    Args:
        pred (torch.Tensor): The prediction with shape (N, C), C is the
            number of classes
        target (torch.Tensor): The learning target of the iou-aware
            classification score with shape (N, C), C is the number of classes.
        weight (torch.Tensor, optional): The weight of loss for each
            prediction. Defaults to None.
        alpha (float, optional): A balance factor for the negative part of
            Varifocal Loss, which is different from the alpha of Focal Loss.
            Defaults to 0.75.
        gamma (float, optional): The gamma for calculating the modulating
            factor. Defaults to 2.0.
        iou_weighted (bool, optional): Whether to weight the loss of the
            positive example with the iou target. Defaults to True.
        reduction (str, optional): The method used to reduce the loss into
            a scalar. Defaults to 'mean'. Options are "none", "mean" and
            "sum".
        avg_factor (int, optional): Average factor that is used to average
            the loss. Defaults to None.
    """# pred and target should be of the same sizeassert pred.size()== target.size()
    pred_sigmoid = pred.sigmoid()
    target = target.type_as(pred)if iou_weighted:
        focal_weight = target *(target >0.0).float()+ \
            alpha *(pred_sigmoid - target).abs().pow(gamma)* \
            (target <=0.0).float()else:
        focal_weight =(target >0.0).float()+ \
            alpha *(pred_sigmoid - target).abs().pow(gamma)* \
            (target <=0.0).float()
    loss = F.binary_cross_entropy_with_logits(
        pred, target, reduction='none')* focal_weight
    loss = weight_reduce_loss(loss, weight, reduction, avg_factor)return loss
 
 
classVarifocalLoss(nn.Module):def__init__(self,
                 use_sigmoid=True,
                 alpha=0.75,
                 gamma=2.0,
                 iou_weighted=True,
                 reduction='mean',
                 loss_weight=1.0):"""`Varifocal Loss <https://arxiv.org/abs/2008.13367>`_
        Args:
            use_sigmoid (bool, optional): Whether the prediction is
                used for sigmoid or softmax. Defaults to True.
            alpha (float, optional): A balance factor for the negative part of
                Varifocal Loss, which is different from the alpha of Focal
                Loss. Defaults to 0.75.
            gamma (float, optional): The gamma for calculating the modulating
                factor. Defaults to 2.0.
            iou_weighted (bool, optional): Whether to weight the loss of the
                positive examples with the iou target. Defaults to True.
            reduction (str, optional): The method used to reduce the loss into
                a scalar. Defaults to 'mean'. Options are "none", "mean" and
                "sum".
            loss_weight (float, optional): Weight of loss. Defaults to 1.0.
        """super(VarifocalLoss, self).__init__()assert use_sigmoid isTrue, \
            'Only sigmoid varifocal loss supported now.'assert alpha >=0.0
        self.use_sigmoid = use_sigmoid
        self.alpha = alpha
        self.gamma = gamma
        self.iou_weighted = iou_weighted
        self.reduction = reduction
        self.loss_weight = loss_weight
 
    defforward(self,
                pred,
                target,
                weight=None,
                avg_factor=None,
                reduction_override=None):"""Forward function.
        Args:
            pred (torch.Tensor): The prediction.
            target (torch.Tensor): The learning target of the prediction.
            weight (torch.Tensor, optional): The weight of loss for each
                prediction. Defaults to None.
            avg_factor (int, optional): Average factor that is used to average
                the loss. Defaults to None.
            reduction_override (str, optional): The reduction method used to
                override the original reduction method of the loss.
                Options are "none", "mean" and "sum".
        Returns:
            torch.Tensor: The calculated loss
        """assert reduction_override in(None,'none','mean','sum')
        reduction =(
            reduction_override if reduction_override else self.reduction)if self.use_sigmoid:
            loss_cls = self.loss_weight * varifocal_loss(
                pred,
                target,
                weight,
                alpha=self.alpha,
                gamma=self.gamma,
                iou_weighted=self.iou_weighted,
                reduction=reduction,
                avg_factor=avg_factor)else:raise NotImplementedError
        return loss_cls

步骤二:在YOLOX-main/yolox/models/yolo_head.py中调用VarifocalLoss

(1)导入

from.varifocalloss import VarifocalLoss

(2)在init中实例化

self.varifocal = VarifocalLoss(reduction='none')

(3)替换原有的置信度预测损失loss_obj

# loss_iou:定位损失;loss_obj:置信度预测损失;loss_cls:预测损失
        loss_iou =(
            self.iou_loss(bbox_preds.view(-1,4)[fg_masks], reg_targets)).sum()/ num_fg
        #loss_obj = (  #    self.bcewithlog_loss(obj_preds.view(-1, 1), obj_targets)#).sum() / num_fg
        loss_obj =(self.varifocal(obj_preds.view(-1,1), obj_targets)).sum()/ num_fg
        loss_cls =(
            self.bcewithlog_loss(
                cls_preds.view(-1, self.num_classes)[fg_masks], cls_targets)).sum()/ num_fg

效果:根据个人数据集而定。FocalLoss与VariFocalLoss在我的数据集上均能提升,模型越大效果越明显。(但是在yolox-tiny上FocalLoss效果AP50会低于原来)

以上代码链接
链接:https://pan.baidu.com/s/1ee1sQ9Eulz_mUdHTOnBe7w
提取码:8v8r


本文转载自: https://blog.csdn.net/weixin_45679938/article/details/122343945
版权归原作者 你的陈某某 所有, 如有侵权,请联系我们删除。

“YOLOX改进之损失函数修改(上)”的评论:

还没有评论