yolov4项目记录6-损失计算

yolov4项目记录6-损失计算,第1张

yolov4项目记录6-损失计算

目录

一、概述

二、计算

1.位置回归损失

2.物体置信度损失

3.分类损失

三、代码


一、概述

预测的内容,包含了物体所在的位置(位置回归损失),是否有物体(物体置信度损失),物体的分类(分类损失)三样内容,因此我们使用这三种数据来计算总体损失。物体所在位置主要使用IOU,而是否有物体以及分类的预测损失使用二分类交叉熵损失。

二、计算 1.位置回归损失

下面的式子就是位置回归损失的计算公式,意思就是对每一个网格(共S^2个网格),的每一个锚框(共B个,其实就是3个),去计算CIOU这样的一个数。同时前面有一个示性函数I,也就是说,只有网格里面有物体的时候,才会计算位置回归损失,没物体的话就不算,就是0。

下面是CIOU的计算细节。其中:

lambda: 损失的系数,可以调整。

d:两个框中心点的距离

c:两个框最小外包框的对角线长度

v:根据实际框宽高的夹角,以及预测框宽高的夹角,二者之差,所得的一个数,也能够表示出两个框的相似度。两个框越相似,夹角之差越小,这个v就越小,如果两个框一模一样,v就是0。

IOU:两个框的交并比

2.物体置信度损失

相当于对“这个网格是否有物体”这件事情进行分类,使用二分类交叉熵损失。注意这里对“有物体的网格”,以及“没有物体的网格”,全部都进行了计算。

 其中:

C hat是第i个网格第j个框,实际的物体置信度,通常是1或者0

C是第i个网格第j个框,预测的物体置信度

I依旧是示性函数,B, S^2等也和前面的一致。

3.分类损失

类似于逻辑回归,整体逻辑和上面的物体置信度损失一致,只不过这里是针对于有物体的那些网格,才会有物体分类这一说。

三、代码

这里代码需要和前面文章的目标构建结合起来,因为需要用到标签数据的构建。

class YOLOLoss(nn.Module):
    def __init__(self, anchors, num_classes, img_size, label_smooth=0, cuda=True):
        super(YOLOLoss, self).__init__()
        self.anchors = anchors
        self.num_anchors = len(anchors)
        self.num_classes = num_classes
        self.bbox_attr = 5 + num_classes
        self.img_size = img_size
        self.feature_length = [img_size[0] // 8, img_size[0] // 16, img_size[0] // 32]
        self.label_smooth = label_smooth

        self.ignore_thresh = 0.7
        # 损失函数用的lambda因子
        self.lambda_conf = 1.0
        self.lambda_cls = 1.0
        self.lambda_loc = 1.0
        self.cuda = cuda

    def forward(self, input: torch.Tensor, targets=None):
        # 一共有多少张图片
        bs = input.size(0)
        # 特征图的高、宽
        in_h = input.size(2)
        in_w = input.size(3)
        # 计算步长,有2个,分别是h和w的步长stride_h, stride_w,每一个网格的大小
        stride_h = self.img_size[0] / in_h
        stride_w = self.img_size[1] / in_w
        # scaled_anchors, 把anchor换成以网格为单位
        scaled_anchors = [(a_w/stride_w, a_h/stride_h) for a_w, a_h in self.anchors]
        # 对预测的形状调整成(B, num_anchors, H, W, n_ch)
        prediction = input.view(bs, int(self.num_anchors/3), self.bbox_attr, in_h, in_w).permute(0,1,3,4,2).contiguous()
        conf = torch.sigmoid(prediction[..., 4])
        pred_cls = torch.sigmoid(prediction[..., 5:])
        # # build_target1,构造掩码,填充掩码正样本
        mask, noobj_mask, t_box, tconf, tcls, box_loss_scale_x, box_loss_scale_y = self.get_target(targets,scaled_anchors,in_w, in_h)
        # # build_target2,筛选负样本,并对头部做decode
        noobj_mask, pred_boxes_for_ciou = self.get_ignore(prediction,targets,scaled_anchors,in_w, in_h,noobj_mask)
        if self.cuda:
            mask, noobj_mask = mask.cuda(), noobj_mask.cuda()
            box_loss_scale_x, box_loss_scale_y = box_loss_scale_x.cuda(), box_loss_scale_y.cuda()
            tconf, tcls = tconf.cuda(), tcls.cuda()
            pred_boxes_for_ciou = pred_boxes_for_ciou.cuda()
            t_box = t_box.cuda()

        # 计算ciou损失
        box_loss_scale = 2 - box_loss_scale_x * box_loss_scale_y
        ciou = box_ciou(pred_boxes_for_ciou[mask.bool()], t_box[mask.bool()])
        loss_ciou = 1-ciou
        loss_ciou = loss_ciou * box_loss_scale[mask.bool()]
        loss_loc = torch.sum(loss_ciou / bs)
        # 计算位置置信度损失
        loss_conf = torch.sum(BCELoss(conf, mask)*mask / bs) + 
            torch.sum(BCELoss(conf, mask)*noobj_mask / bs)
        # 计算分类置信度损失
        loss_cls = torch.sum(BCELoss(pred_cls[mask==1], smooth_labels(tcls[mask==1], self.label_smooth, self.num_classes))/bs)

        # 计算总损失
        loss = loss_conf*self.lambda_conf + loss_cls*self.lambda_cls + loss_loc*self.lambda_loc
        return loss, loss_conf.item(), loss_cls.item(), loss_loc.item()

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5689758.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存