赞
踩
目录
预测的内容,包含了物体所在的位置(位置回归损失),是否有物体(物体置信度损失),物体的分类(分类损失)三样内容,因此我们使用这三种数据来计算总体损失。物体所在位置主要使用IOU,而是否有物体以及分类的预测损失使用二分类交叉熵损失。
下面的式子就是位置回归损失的计算公式,意思就是对每一个网格(共S^2个网格),的每一个锚框(共B个,其实就是3个),去计算CIOU这样的一个数。同时前面有一个示性函数I,也就是说,只有网格里面有物体的时候,才会计算位置回归损失,没物体的话就不算,就是0。
下面是CIOU的计算细节。其中:
lambda: 损失的系数,可以调整。
d:两个框中心点的距离
c:两个框最小外包框的对角线长度
v:根据实际框宽高的夹角,以及预测框宽高的夹角,二者之差,所得的一个数,也能够表示出两个框的相似度。两个框越相似,夹角之差越小,这个v就越小,如果两个框一模一样,v就是0。
IOU:两个框的交并比
相当于对“这个网格是否有物体”这件事情进行分类,使用二分类交叉熵损失。注意这里对“有物体的网格”,以及“没有物体的网格”,全部都进行了计算。
其中:
C hat是第i个网格第j个框,实际的物体置信度,通常是1或者0
C是第i个网格第j个框,预测的物体置信度
I依旧是示性函数,B, S^2等也和前面的一致。
类似于逻辑回归,整体逻辑和上面的物体置信度损失一致,只不过这里是针对于有物体的那些网格,才会有物体分类这一说。
这里代码需要和前面文章的目标构建结合起来,因为需要用到标签数据的构建。
- 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()

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。