YOLOv1

作者: leon_tly | 来源:发表于2022-12-12 11:27 被阅读0次

YOLOv1

  1. 实现原理
  • 将图像划分为SxS个网格(grid cell),如果某个object的中心点落在这个网格上 ,那么这个网格就负责预测该object。
  • 每个网格要预测B个bounding box,每个bounding box除了要回归自身的位置之外,还要附带预测一个confidence值。
    这个confidence代表了所预测的box中含有object的置信度和这个box预测的有多准两重信息,其值是这样计算的: Pr(object)*IoU_{pred}^{truth}
    其中如果有object落在一个grid cell里,第一项取1,否则取0。 第二项是预测的bounding box和实际的groundtruth之间的IoU值
  • 每个bounding box要预测(x, y, w, h)和confidence共5个值,每个网格还要预测一个类别信息,记为C类。则SxS个网格,每个网格要预测B个bounding box还要预测C个类别。输出就是S x S x (5*B+C)的一个tensor。
    注意:class信息是针对每个网格的,confidence信息是针对每个bounding box的。
  1. YOLOv1的损失函数
    \lambda_{coord}\sum_{i=0}^{S^2}\sum_{j=0}^{B}L_{ij}^{obj}[(x_i - x_{i}^{'})^2+(y_i - y_{i}^{'})^2 ]
    +\lambda_{coord}\sum_{i=0}^{S^2}\sum_{j=0}^{B}L_{ij}^{obj}[(\sqrt{w_i} - \sqrt{w_{i}^{'}})^2 + \sqrt{h_i} - \sqrt{h_{i}^{'}})^2]
    + \sum_{i=0}^{S^2}\sum_{j=0}^{B}L_{ij}^{obj}[(c_i - c_{i}^{'})^2]
    + \lambda_{noobj}\sum_{i=0}^{S^2}\sum_{j=0}^{B}L_{ij}^{noobj}[(c_i - c_{i}^{'})^2]
    + \sum_{i=0}^{S^2}L_{i}^{obj}\sum_{c=0}^{classes_num}(p_i(c) - p_{i}(c)^{'})^2

\lambda_{coord} = 5, \lambda_{noobj} = 0.5, S=7, B=2
L_{ij}^{obj} 表示第i个grid cell,第j个bounding box中是否存在目标,存在为1,不存在为0
L_{ij}^{noobj} 表示第i个grid cell,第j个bounding box中是否存在目标,存在为0,不存在为1
x_i, y_i, w_i, h_i 预测值 x_{i}^{'}, y_{i}^{'},w_{i}^{'}, h_{i}^{'}真实值
p_i(c)预测为类别i的概率值, p_{i}(c)^{'} 真实类别为i则为1, 否则为0
c_i预测confidence, c_{i}^{'} 预测框与ground truth的iou
L_{i}^{obj}第i个grid cell中是否包括物体,即真实ground truth的中心点是否落在该grid cell中

  1. pytorch loss实现
import torch
from torch import  nn

class Loss_yolov1(nn.Module):
    def __init__(self):
        super(self).__init__()  # 修改过
    def forward(self, pred, labels):
        """
        :param pred: (batchsize,30,7,7)的网络输出数据
        :param labels: (batchsize,30,7,7)的样本标签数据
        :return: 当前批次样本的平均损失
        """
        num_gridx, num_gridy = labels.size()[-2:]  # 划分网格数量 取最后两列数据    7*7
        num_b = 2  # 每个网格的bbox数量
        num_cls = 20  # 类别数量
        noobj_confi_loss = 0.  # 不含目标的网格损失(只有置信度损失)
        coor_loss = 0.  # 含有目标的bbox的坐标损失
        obj_confi_loss = 0.  # 含有目标的bbox的置信度损失
        class_loss = 0.  # 含有目标的网格的类别损失
        n_batch = labels.size()[0]  # batchsize的大小

        # 可以考虑用矩阵运算进行优化,提高速度,为了准确起见,这里还是用循环
        for i in range(n_batch):  # batchsize循环
            for n in range(7):  # x方向网格循环
                for m in range(7):  # y方向网格循环
                    if labels[i,4,m,n]==1:# 如果包含物体
                        # 将数据(px,py,w,h)转(换为x1,y1,x2,y2)
                        # 先将px,py转换为cx,cy,即相对网格的位置转换为标准化后实际的bbox中心位置cx,xy
                        # 然后再利用(cx-w/2,cy-h/2,cx+w/2,cy+h/2)转换为xyxy形式,用于计算iou
                        bbox1_pred_xyxy = ((pred[i,0,m,n]+m)/num_gridx - pred[i,2,m,n]/2,(pred[i,1,m,n]+n)/num_gridy - pred[i,3,m,n]/2,
                                           (pred[i,0,m,n]+m)/num_gridx + pred[i,2,m,n]/2,(pred[i,1,m,n]+n)/num_gridy + pred[i,3,m,n]/2)
                        bbox2_pred_xyxy = ((pred[i,5,m,n]+m)/num_gridx - pred[i,7,m,n]/2,(pred[i,6,m,n]+n)/num_gridy - pred[i,8,m,n]/2,
                                           (pred[i,5,m,n]+m)/num_gridx + pred[i,7,m,n]/2,(pred[i,6,m,n]+n)/num_gridy + pred[i,8,m,n]/2)
                        bbox_gt_xyxy = ((labels[i,0,m,n]+m)/num_gridx - labels[i,2,m,n]/2,(labels[i,1,m,n]+n)/num_gridy - labels[i,3,m,n]/2,
                                        (labels[i,0,m,n]+m)/num_gridx + labels[i,2,m,n]/2,(labels[i,1,m,n]+n)/num_gridy + labels[i,3,m,n]/2)
                        iou1 = calculate_iou(bbox1_pred_xyxy,bbox_gt_xyxy)
                        iou2 = calculate_iou(bbox2_pred_xyxy,bbox_gt_xyxy)
                        # 选择iou大的bbox作为负责物体
                        if iou1 >= iou2:
                            coor_loss = coor_loss + 5 * (torch.sum((pred[i,0:2,m,n] - labels[i,0:2,m,n])**2) \
                                        + torch.sum((pred[i,2:4,m,n].sqrt()-labels[i,2:4,m,n].sqrt())**2)) # 含有目标的bbox的坐标损失
                            obj_confi_loss = obj_confi_loss + (pred[i,4,m,n] - iou1)**2
                            # iou比较小的bbox不负责预测物体,因此confidence loss算在noobj中,注意,对于标签的置信度应该是iou2
                            noobj_confi_loss = noobj_confi_loss + 0.5 * ((pred[i,9,m,n]-iou2)**2)
                        else:
                            coor_loss = coor_loss + 5 * (torch.sum((pred[i,5:7,m,n] - labels[i,5:7,m,n])**2) \
                                        + torch.sum((pred[i,7:9,m,n].sqrt()-labels[i,7:9,m,n].sqrt())**2))
                            obj_confi_loss = obj_confi_loss + (pred[i,9,m,n] - iou2)**2
                            # iou比较小的bbox不负责预测物体,因此confidence loss算在noobj中,注意,对于标签的置信度应该是iou1
                            noobj_confi_loss = noobj_confi_loss + 0.5 * ((pred[i, 4, m, n]-iou1) ** 2)
                        class_loss = class_loss + torch.sum((pred[i,10:,m,n] - labels[i,10:,m,n])**2)
                    else:  # 如果不包含物体
                        noobj_confi_loss = noobj_confi_loss + 0.5 * torch.sum(pred[i,[4,9],m,n]**2)

        loss = coor_loss + obj_confi_loss + noobj_confi_loss + class_loss
        # 此处可以写代码验证一下loss的大致计算是否正确,这个要验证起来比较麻烦,比较简洁的办法是,将输入的pred置为全1矩阵,再进行误差检查,会直观很多。
        return loss/n_batch
def calculate_iou(bbox1,bbox2):
    """计算bbox1=(x1,y1,x2,y2)和bbox2=(x3,y3,x4,y4)两个bbox的iou"""
    intersect_bbox = [0., 0., 0., 0.]  # bbox1和bbox2的交集
    if bbox1[2]<bbox2[0] or bbox1[0]>bbox2[2] or bbox1[3]<bbox2[1] or bbox1[1]>bbox2[3]:
        pass
    else:
        intersect_bbox[0] = max(bbox1[0],bbox2[0])
        intersect_bbox[1] = max(bbox1[1],bbox2[1])
        intersect_bbox[2] = min(bbox1[2],bbox2[2])
        intersect_bbox[3] = min(bbox1[3],bbox2[3])

    area1 = (bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1])  # bbox1面积
    area2 = (bbox2[2] - bbox2[0]) * (bbox2[3] - bbox2[1])  # bbox2面积
    area_intersect = (intersect_bbox[2] - intersect_bbox[0]) * (intersect_bbox[3] - intersect_bbox[1])  # 交集面积
    # print(bbox1,bbox2)
    # print(intersect_bbox)
    # input()

    if area_intersect>0:
        return area_intersect / (area1 + area2 - area_intersect)  # 计算iou
    else:
        return 0

来源 https://github.com/qiujunlin/yolov1/blob/master/loss.py

相关文章

  • 详解 YOLOv2

    YOLOv2 简单回归 YOLOv1 yolov1 中存在问题 yolo 难以应付小目标 yolo 漏检,也就是召...

  • YOLOv1——YOLOv5

    YOLOv1 YOLOv1提出单阶段anchor-free的目标检测方法将图像分为SxS的grid cell,每个...

  • YOLOv1, SSD

    YOLOv1, SSD 今年四月份的时候,在一个研究院实习时学习了YOLOv1, SSD系列Object Dete...

  • YoloV1

    YOLO(You Only Look Once)是一种基于深度神经网络的对象识别和定位算法,其最大的特点是运行速度...

  • Yolov1

    贴两个yolov1写的比较好的链接: 目标检测|YOLO原理与实现:https://zhuanlan.zhihu....

  • YOLOv1 随笔

    YOLO 系列 YOLOv1 作者 AlexAB 计算机视觉 随着深度学习中卷积神经网络的发展,掀起了一次目标检测...

  • yolo

    https://pjreddie.com/darknet/yolo/ 一、是什么从YOLOv1到YOLOv3,目标...

  • detection_layer层的实现

    detection_layer对应Yolov1的实现,理解detection_layer的实现主要需要理解Yolo...

  • [图像算法]-死磕YOLO系列,YOLOv2的自我修养

    前言 系列文章:死磕YOLO系列,YOLOv1 的大脑、躯干和手脚[https://www.jianshu.com...

  • YOLOv1学习笔记

    YOLO 全称You Only Look Once,属于目标检测算法的One-Stage算法,One-Stage和...

网友评论

      本文标题:YOLOv1

      本文链接:https://www.haomeiwen.com/subject/atnqqdtx.html