YOLOV5代码详解之损失函数的计算

 更新时间:2022年03月28日 10:53:06   作者:云深安小生  
YOLOV4出现之后不久,YOLOv5横空出世,YOLOv5在YOLOv4算法的基础上做了进一步的改进,检测性能得到进一步的提升,这篇文章主要给大家介绍了关于YOLOV5代码详解之损失函数计算的相关资料,需要的朋友可以参考下

摘要:

神经网络的训练的主要流程包括图像输入神经网络, 得到模型的输出结果,计算模型的输出与真实值的损失, 计算损失值的梯度,最后用梯度下降算法更新模型参数。损失函数值的计算是非常关键的一个步骤。

本博客将对yolov5损失值的计算过程代码的实现做简要的理解。

def compute_loss(p, targets, model):  # predictions, targets, model
    device = targets.device
    lcls, lbox, lobj = torch.zeros(1, device=device), torch.zeros(1, device=device), torch.zeros(1, device=device)
    tcls, tbox, indices, anchors = build_targets(p, targets, model)  # targets
    h = model.hyp  # hyperparameters

    # Define criteria
    BCEcls = nn.BCEWithLogitsLoss(pos_weight=torch.Tensor([h['cls_pw']])).to(device)
    BCEobj = nn.BCEWithLogitsLoss(pos_weight=torch.Tensor([h['obj_pw']])).to(device)

    # Class label smoothing https://arxiv.org/pdf/1902.04103.pdf eqn 3
    cp, cn = smooth_BCE(eps=0.0)

    # Focal loss
    g = h['fl_gamma']  # focal loss gamma
    if g > 0:
        BCEcls, BCEobj = FocalLoss(BCEcls, g), FocalLoss(BCEobj, g)
   。。。。。。

yolov5代码用IOU指标评价目标框和预测框的位置损失损失。yolov5代码用nn.BCEWithLogitsLoss或FocalLoss评价目标框和预测框的类损失和置信度损失 .

yolov5代码用宽高比选择对应真实框的预测框,且每一个真实框对应三个预测框 。

1、位置损失

yolov5代码用IOU值评价预测框和真实框的位置损失, 本文介绍CIoU指标.

公式如下截图:

公式中参数代表的意义如下:

IOU: 预测框和真实框的叫并比

v是衡量长宽比一致性的参数,我们也可以定义为:

代码实现:

iou = bbox_iou(pbox.T, tbox[i], x1y1x2y2=False, CIoU=True)  # iou(prediction, target)
            lbox += (1.0 - iou).mean()  # iou loss
def bbox_iou(box1, box2, x1y1x2y2=True, GIoU=False, DIoU=False, CIoU=False, eps=1e-9):
    # Returns the IoU of box1 to box2. box1 is 4, box2 is nx4
    box2 = box2.T

    # Get the coordinates of bounding boxes
    if x1y1x2y2:  # x1, y1, x2, y2 = box1
        b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3]
        b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3]
    else:  # transform from xywh to xyxy
        b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2
        b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2
        b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2
        b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2

    # Intersection area
    inter = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \
            (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0)

    # Union Area
    w1, h1 = b1_x2 - b1_x1, b1_y2 - b1_y1 + eps
    w2, h2 = b2_x2 - b2_x1, b2_y2 - b2_y1 + eps
    union = w1 * h1 + w2 * h2 - inter + eps

    iou = inter / union
    if GIoU or DIoU or CIoU:
        cw = torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1)  # convex (smallest enclosing box) width
        ch = torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1)  # convex height
        if CIoU or DIoU:  # Distance or Complete IoU https://arxiv.org/abs/1911.08287v1
            c2 = cw ** 2 + ch ** 2 + eps  # convex diagonal squared
            rho2 = ((b2_x1 + b2_x2 - b1_x1 - b1_x2) ** 2 +
                    (b2_y1 + b2_y2 - b1_y1 - b1_y2) ** 2) / 4  # center distance squared
            if DIoU:
                return iou - rho2 / c2  # DIoU
            elif CIoU:  # https://github.com/Zzh-tju/DIoU-SSD-pytorch/blob/master/utils/box/box_utils.py#L47
                v = (4 / math.pi ** 2) * torch.pow(torch.atan(w2 / h2) - torch.atan(w1 / h1), 2)
                with torch.no_grad():
                    alpha = v / ((1 + eps) - iou + v)
                return iou - (rho2 / c2 + v * alpha)  # CIoU
        else:  # GIoU https://arxiv.org/pdf/1902.09630.pdf
            c_area = cw * ch + eps  # convex area
            return iou - (c_area - union) / c_area  # GIoU
    else:
        return iou  # IoU

2、置信度损失和类损失

yolov5代码用nn.BCEWithLogitsLoss或FocalLoss评价目标框和预测框的类损失和置信度损失,本节一一介绍这两个损失函数。

  • nn.BCEWithLogitsLoss:

首先对预测输出作sigmoid变换,然后求变换后的结果与真实值的二值交叉熵.

假设预测输出是3分类,预测输出:

预测输出sigmoid变换:

假设真实输出是:

两者的二值交叉熵的计算方法:

接口函数验证下上面的结果:

  • FocalLoss损失:

FocalLoss损失考虑的是:目标检测中正负样本严重不均衡的一种策略。该损失函数的设计思想类似于boosting,降低容易分类的样本对损失函数的影响,注重较难分类的样本的训练.

简而言之,FocalLoss更加关注的是比较难分的样本,何谓难分?若某一个真实类预测的概率只有0.2,我们认为它比较难分,相反若该真实类的预测概率是0.95,则容易分类.

FocalLoss通过提高难分类别的损失函数来实现,公式如下:

图像如下:

可以看出预测真实类概率越大,则损失函数越小,即实现了之前的想法.

为了能够平衡正负样本的重要性,我们可以给各个类别添加一个权重常数 α ,比如想使正样本初始权重为0.8,负样本就为0.2.
代码实现为:

class FocalLoss(nn.Module):
    # Wraps focal loss around existing loss_fcn(), i.e. criteria = FocalLoss(nn.BCEWithLogitsLoss(), gamma=1.5)
    def __init__(self, loss_fcn, gamma=1.5, alpha=0.25):
        super(FocalLoss, self).__init__()
        self.loss_fcn = loss_fcn  # must be nn.BCEWithLogitsLoss()
        self.gamma = gamma
        self.alpha = alpha
        self.reduction = loss_fcn.reduction
        self.loss_fcn.reduction = 'none'  # required to apply FL to each element

    def forward(self, pred, true):
        loss = self.loss_fcn(pred, true)
        # p_t = torch.exp(-loss)
        # loss *= self.alpha * (1.000001 - p_t) ** self.gamma  # non-zero power for gradient stability

        # TF implementation https://github.com/tensorflow/addons/blob/v0.7.1/tensorflow_addons/losses/focal_loss.py
        pred_prob = torch.sigmoid(pred)  # prob from logits
        p_t = true * pred_prob + (1 - true) * (1 - pred_prob)
        alpha_factor = true * self.alpha + (1 - true) * (1 - self.alpha)
        modulating_factor = (1.0 - p_t) ** self.gamma
        loss *= alpha_factor * modulating_factor

        if self.reduction == 'mean':
            return loss.mean()
        elif self.reduction == 'sum':
            return loss.sum()
        else:  # 'none'
            return loss

其中成员函数loss_fcn为nn.BCEWithLogitsLoss。

总结

到此这篇关于YOLOV5代码详解之损失函数计算的文章就介绍到这了,更多相关YOLOV5损失函数计算内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 五个有趣的Python整蛊小程序合集

    五个有趣的Python整蛊小程序合集

    Python 能做很多无聊,但有意思的事情。本文为大家精心准备了五个整蛊朋友的小程序,文中的示例代码讲解详细,感兴趣的小伙伴快动手试一试
    2022-04-04
  • python tkinter实现屏保程序

    python tkinter实现屏保程序

    这篇文章主要为大家详细介绍了python tkinter实现屏保程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07
  • python 调用js的四种方式

    python 调用js的四种方式

    这篇文章主要介绍了python 调用js的四种方式,帮助大家更好的理解和学习使用python,感兴趣的朋友可以了解下
    2021-04-04
  • Python利用PsUtil实现实时监控系统状态

    Python利用PsUtil实现实时监控系统状态

    PSUtil是一个跨平台的Python库,用于检索有关正在运行的进程和系统利用率(CPU,内存,磁盘,网络,传感器)的信息。本文就来用PsUtil实现实时监控系统状态,感兴趣的可以跟随小编一起学习一下
    2023-04-04
  • 详解Python虚拟机是如何实现闭包的

    详解Python虚拟机是如何实现闭包的

    Python中的闭包是一个强大的概念,允许函数捕获和访问其周围的作用域,即使这些作用域在函数执行完毕后也能被访问,这篇文章将着重讨论Python虚拟机是如何实现闭包的,文中有相关的代码示例供大家参考,具有一定的参考价值,需要的朋友可以参考下
    2023-12-12
  • python使用matplotlib的savefig保存时图片保存不完整的问题

    python使用matplotlib的savefig保存时图片保存不完整的问题

    这篇文章主要介绍了python使用matplotlib的savefig保存时图片保存不完整的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Python入门教程之三元运算符的使用详解

    Python入门教程之三元运算符的使用详解

    三元运算符也称为条件表达式,是根据条件为真或假来评估某些内容的运算符。它在2.5 版本中被添加到 Python 中。 本文将通过示例详细说说三元运算符的使用,需要的可以参考一下
    2022-09-09
  • 详解用pyecharts Geo实现动态数据热力图城市找不到问题解决

    详解用pyecharts Geo实现动态数据热力图城市找不到问题解决

    这篇文章主要介绍了详解用pyecharts Geo实现动态数据热力图城市找不到问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06
  • Python实现Event回调机制的方法

    Python实现Event回调机制的方法

    今天小编就为大家分享一篇Python实现Event回调机制的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-02-02
  • Python字典循环添加一键多值的用法实例

    Python字典循环添加一键多值的用法实例

    今天小编就为大家分享一篇Python字典循环添加一键多值的用法实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-01-01

最新评论