目标检测——YOLO系列学习(一)YOLOv1

这篇具有很好参考价值的文章主要介绍了目标检测——YOLO系列学习(一)YOLOv1。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

YOLO可以说是单阶段的目标检测方法的集大成之作,必学的经典论文,从准备面试的角度来学习一下yolo系列。


YOLOv1

1.RCNN系列回顾

RCNN系列,无论哪种算法,核心思路都是Region Proposal(定位)+ classifier(修正定位+分类)。所以也被称为两阶段算法。但是难以达到实时检测的效果,因此yolov1将其修改为单阶段的算法,yolov1虽然牺牲了一定的精度,但是检测速度大幅提升,而后续的yolo版本在其之上改进,现在已经有yolov9和yolo-world了,成为主流的目标检测模型。

2.YOLOv1

(部分内容和图参考保姆级教程:图解目标检测算法YOLOv1 - 知乎 (zhihu.com))

论文原文:

1506.02640.pdf (arxiv.org)https://arxiv.org/pdf/1506.02640.pdf在讲解过程中会出现很多专业词汇,会挨着进行说明。

YOLOv1的核心思路就是舍弃Region Proposal这个极其耗时的过程,转而进行回归。怎么实现舍弃RP的,就是学习的关键。

(1)核心思想

采用利用整张图作为网络的输入,将图像划分为S*S个grid,某一个grid只关注于预测物体中心在这个grid中的目标,整个网络最后直接在输出层回归 bounding box 的位置和 bounding box 所属的类别。

目标检测——YOLO系列学习(一)YOLOv1,目标检测,目标跟踪,人工智能

Grid和Bouding Box

这里可能会产生一点误解,故区分一下。

Grid:将图片直接划分为S*S个grid,位置是固定死的,比如上图中,划分为了7*7个grid。

Bouding Box:就是最后检测出物体的框,如上图中框住狗狗的红色框,在算法流程中,可以用两种数据形式表示,一种是使用中心坐标+长宽的形式(Cx,Cy,H,W),一种是使用左上和右下角点坐标的形式(x1,y1,x2,y2)。而每个框除了要包含位置信息,还包含了该框是否包含物体的置信度,这个置信度怎么计算的我们后面讲解,这里只需要记住每个Bounding Box其实对应了5个数据。

置信度(Confidence)的计算

置信度就是算法的自信心得分,这个值越高,代表这个BoundigBox里越有可能包含物体。计算方式如下:

Pr(Object)为边界框内存在对象的概率,若存在对象,Pr⁡(Object)=1,否则Pr⁡(Object)=0。

但是这里要注意一下,其实我们整个网络的计算中是不需要用这个公式计算的,网络输出一个0~1的值就好。

IOU(Intersection over Union ratio)

IOU又叫做交并比,其实很好理解,就是两个框计算出来的一个值,意义上来看,IOU值越大,表示两个框的重合度越高,从公式上来看:

一个实现代码如下:

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

按照这个思路,我们可以简要理一下网络的输入输出:

输入一张固定大小的图像,规定划分的格子数S*S,规定每个格子要预测几个框B。

输出为一个S*S*(B*5+Class),S和B对应输入,5就是boundingbox中包含的五个信息,class就是类别的预测,这里类别使用的是one-hot编码。

目标检测——YOLO系列学习(一)YOLOv1,目标检测,目标跟踪,人工智能

以作者在论文里提到的PASCAL VOC上的实验为例:

S=7,B=5,有20个类别,故输出tensor的维度为7*7*(5*2)

这里有个很容易错误理解的点,就是这个class的分类结果其实是对应了这一个grid的,一个grid输出一个20维的分类结果,而不是整个grid所得到的两个BoundingBox的分类结果,

(2)网络结构

YOLOv1的数据流如下:

  • resize图片尺寸(没有ROI)
  • 输入网络,输出tensor
  • 非极大值抑制(NMS)

网络的结构如下:

目标检测——YOLO系列学习(一)YOLOv1,目标检测,目标跟踪,人工智能

这里光看图可能很多初学的同学不是很看的懂,我们来看看一个简单的pytorch版本:

参考:动手学习深度学习pytorch版——从零开始实现YOLOv1_自己实现的yolov-CSDN博客

这一部分需要说明一下,由于原论文是采用自己设计的20层卷积层先在ImageNet上训练了一周,完成特征提取部分的训练。我们作为学习者而非发明者来说,花一周时间训练实在是太长了。因此,在这里我打算对原论文的结构做一点改变。YOLOv1的前20层是用于特征提取的,也就是随便替换为一个分类网络(除去最后的全连接层)其实都行。因此,我打算使用ResNet34的网络作为特征提取部分。这样做的好处是,pytorch的torchvision中提供了ResNet34的预训练模型,训练集也是ImageNet,等于说有先成训练好的模型可以直接使用,从而免去了特征提取部分的训练时间。然后,除去ResNet34的最后两层,再连接上YOLOv1的最后4个卷积层和两个全连接层,作为我们训练的网络结构。
  此外,还进行了一些小调整,比如最后增加了一个Sigmoid层,以及在卷积层后增加了BN层等等。具体代码如下:

import torchvision.models as tvmodel
import torch.nn as nn
import torch

class YOLOv1_resnet(nn.Module):
    def __init__(self):
        super(YOLOv1_resnet,self).__init__()
        resnet = tvmodel.resnet34(pretrained=True)  # 调用torchvision里的resnet34预训练模型
        resnet_out_channel = resnet.fc.in_features  # 记录resnet全连接层之前的网络输出通道数,方便连入后续卷积网络中
        self.resnet = nn.Sequential(*list(resnet.children())[:-2])  # 去除resnet的最后两层
        # 以下是YOLOv1的最后四个卷积层
        self.Conv_layers = nn.Sequential(
            nn.Conv2d(resnet_out_channel,1024,3,padding=1),
            nn.BatchNorm2d(1024),  # 为了加快训练,这里增加了BN层,原论文里YOLOv1是没有的
            nn.LeakyReLU(),
            nn.Conv2d(1024,1024,3,stride=2,padding=1),
            nn.BatchNorm2d(1024),
            nn.LeakyReLU(),
            nn.Conv2d(1024, 1024, 3, padding=1),
            nn.BatchNorm2d(1024),
            nn.LeakyReLU(),
            nn.Conv2d(1024, 1024, 3, padding=1),
            nn.BatchNorm2d(1024),
            nn.LeakyReLU(),
        )
        # 以下是YOLOv1的最后2个全连接层
        self.Conn_layers = nn.Sequential(
            nn.Linear(7*7*1024,4096),
            nn.LeakyReLU(),
            nn.Linear(4096,7*7*30),
            nn.Sigmoid()  # 增加sigmoid函数是为了将输出全部映射到(0,1)之间,因为如果出现负数或太大的数,后续计算loss会很麻烦
        )

    def forward(self, input):
        input = self.resnet(input)
        input = self.Conv_layers(input)
        input = input.view(input.size()[0],-1)
        input = self.Conn_layers(input)
        return input.reshape(-1, (5*NUM_BBOX+len(CLASSES)), 7, 7)  # 记住最后要reshape一下输出数据

这里我们主要关注最后两个fc层,是没有使用池化操作的,直接使用view和resize就实现了三维张量和二维张量的转换。

(3)非极大值抑制

非极大值抑制的目的就是去掉一些冗余框。

这一部分可以参考一下:目标检测入门之非最大值抑制(NMS)算法 - 知乎 (zhihu.com)

(4)损失函数

损失函数是理解YOLOv1训练的关键,具体形式如下:

目标检测——YOLO系列学习(一)YOLOv1,目标检测,目标跟踪,人工智能

这里的损失函数包括五项:

前两项对应BoundingBox的损失函数(针对x, y, H, W进行学习)

接下来两项对应Confidence的损失函数(针对置信度进行学习)

最后一项对应分类的损失(针对类别label进行学习)

细节上来说:

1.公式中每一个均方误差的系数: 表示的是第i个grid的第j个BoundingBox是否负责Object,每个grid对应的B个BoudingBox中,与GT的IOU最大的BoundingBox才负责这个Object,其余的为,这一部分可以简单看一下代码:

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))
    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)

这里计算obj_confi_loss和noobj_confi_loss使用的pred和IOU都是不一样的,pred[i,4,m,n]中的4对应的是IOU更大的框,9对应的是IOU更小的框。

2.这里对 (w,ℎ) 在损失函数中的处理分别取了根号,原因在于,如果不取根号,损失函数往往更倾向于调整尺寸比较大的预测框。例如,20 个像素点的偏差,对于 800x600 的预测框几乎没有影响,此时的IOU数值还是很大,但是对于 30x40 的预测框影响就很大。取根号是为了尽可能的消除大尺寸框与小尺寸框之间的差异。

3.此时再来看 与  ,YOLO 面临的物体检测问题,是一个典型的类别数目不均衡的问题(Focal Loss就是解决这个问题的,一个面试中常问的点)。其中 49 个格点,含有物体的格点往往只有 3、4 个,其余全是不含有物体的格点。此时如果不采取点措施,那么物体检测的mAP不会太高,因为模型更倾向于不含有物体的格点。 与 的作用,就是让含有物体的格点,在损失函数中的权重更大,让模型更加“重视”含有物体的格点所造成的损失。在论文中, 与 的取值分别为 5 与 0.5 。

最后整个Loss部分的代码如下:文章来源地址https://www.toymoban.com/news/detail-857092.html

class Loss_yolov1(nn.Module):
    def __init__(self):
        super(Loss_yolov1,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:]  # 划分网格数量
        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]+n)/num_gridx - pred[i,2,m,n]/2,(pred[i,1,m,n]+m)/num_gridy - pred[i,3,m,n]/2,
                                           (pred[i,0,m,n]+n)/num_gridx + pred[i,2,m,n]/2,(pred[i,1,m,n]+m)/num_gridy + pred[i,3,m,n]/2)
                        bbox2_pred_xyxy = ((pred[i,5,m,n]+n)/num_gridx - pred[i,7,m,n]/2,(pred[i,6,m,n]+m)/num_gridy - pred[i,8,m,n]/2,
                                           (pred[i,5,m,n]+n)/num_gridx + pred[i,7,m,n]/2,(pred[i,6,m,n]+m)/num_gridy + pred[i,8,m,n]/2)
                        bbox_gt_xyxy = ((labels[i,0,m,n]+n)/num_gridx - labels[i,2,m,n]/2,(labels[i,1,m,n]+m)/num_gridy - labels[i,3,m,n]/2,
                                        (labels[i,0,m,n]+n)/num_gridx + labels[i,2,m,n]/2,(labels[i,1,m,n]+m)/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))
                            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

3.YOLOv1的缺点

  • 由于输出层为全连接层,因此在检测时,YOLO训练模型只支持与训练图像相同的输入分辨率。
  • 虽然每个格子可以预测B个bounding box,但是最终只选择只选择IOU最高的bounding box作为物体检测输出,即每个格子最多只预测出一个物体。当物体占画面比例较小,如图像中包含畜群或鸟群时,每个格子包含多个物体,但却只能检测出其中一个。这是YOLO方法的一个缺陷。
  • YOLO loss函数中,大物体IOU误差和小物体IOU误差对网络训练中loss贡献值接近(虽然采用求平方根方式,但没有根本解决问题)。因此,对于小物体,小的IOU误差也会对网络优化过程造成很大的影响,从而降低了物体检测的定位准确性。

到了这里,关于目标检测——YOLO系列学习(一)YOLOv1的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深度学习||YOLO(You Only Look Once)深度学习的实时目标检测算法(YOLOv1~YOLOv5)

    目录 YOLOv1: YOLOv2: YOLOv3: YOLOv4: YOLOv5: 总结: YOLO(You Only Look Once)是一系列基于深度学习的实时目标检测算法。 自从2015年首次被提出以来,YOLO系列不断发展,推出了多个版本,包括YOLOv1, YOLOv2, YOLOv3, YOLOv4, 和YOLOv5等。下面是对YOLO系列的详解: 提出时间 : 2015年。 主要贡献 :

    2024年02月20日
    浏览(58)
  • 【目标检测——YOLO系列】YOLOv1 —《You Only Look Once: Unified, Real-Time Object Detection》

    论文地址:1506.02640] You Only Look Once: Unified, Real-Time Object Detection (arxiv.org) 代码地址:pjreddie/darknet: Convolutional Neural Networks (github.com) YOLOv1是一种end to end目标检测算法,由Joseph Redmon等人于2015年提出。它是一种基于单个神经网络的实时目标检测算法。 YOLOv1的中文名称是\\\"你只看一

    2024年02月08日
    浏览(47)
  • 目标检测YOLO算法,先从yolov1开始

    有一套配套的学习资料,才能让我们的学习事半功倍。 yolov1论文原址:You Only Look Once: Unified, Real-Time Object Detection 代码地址:darknet: Convolutional Neural Networks (github.com) one-stage(单阶段):YOLO系列 最核心的优势:速度非常快,适合做实时检测任务! 但是缺点也是有的,效果通常

    2024年02月09日
    浏览(48)
  • 【目标检测系列】YOLOV1解读

    从R-CNN到Fast-RCNN,之前的目标检测工作都是分成两阶段,先提供位置信息在进行目标分类,精度很高但无法满足实时检测的要求。 而YoLo将目标检测看作回归问题,输入为一张图片,输出为S*S*(5*B+C)的三维向量。该向量结果既包含位置信息,又包含类别信息。可通过损失函数,

    2024年02月13日
    浏览(43)
  • YOLOv5目标检测学习(1):yolo系列算法的基础概念

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 关于深度学习目标检测,有许多概念性的东西需要先了解一下。这里主要以基于深度学习的目标检测算法的部署实现来学习。 以yolov5为例: 使用YOLOv5进行车辆和行人的目标检测通常涉及以下步骤: 数据

    2024年04月09日
    浏览(60)
  • 【YOLO系列】YOLOv1论文超详细解读(翻译 +学习笔记)

    从这篇开始,我们将进入YOLO的学习。YOLO是目前比较流行的目标检测算法,速度快且结构简单,其他的目标检测算法如RCNN系列,以后有时间的话再介绍。 本文主要介绍的是YOLOV1,这是由以Joseph Redmon为首的大佬们于2015年提出的一种新的目标检测算法。它与之前的目标检测算法

    2024年02月04日
    浏览(61)
  • YOLO系列目标检测算法-YOLOv6

    YOLO系列目标检测算法目录 - 文章链接 YOLO系列目标检测算法总结对比- 文章链接 YOLOv1- 文章链接 YOLOv2- 文章链接 YOLOv3- 文章链接 YOLOv4- 文章链接 Scaled-YOLOv4- 文章链接 YOLOv5- 文章链接 YOLOv6 - 文章链接 YOLOv7- 文章链接 PP-YOLO- 文章链接 PP-YOLOv2- 文章链接 YOLOR- 文章链接 YOLOS- 文章链

    2023年04月08日
    浏览(48)
  • YOLO物体检测-系列教程1:YOLOV1整体解读(预选框/置信度/分类任/回归任务/损失函数/公式解析/置信度/非极大值抑制)

    YOLOV1整体解读 YOLOV2整体解读 YOLOV1提出论文:You Only Look Once: Unified, Real-Time Object Detection two-stage(两阶段):Faster-rcnn Mask-Rcnn系列 one-stage(单阶段):YOLO系列 最核心的优势:速度非常快,适合做实时检测任务! 但是缺点也是有的,效果通常情况下不会太好! 机器学习 分类任

    2024年02月09日
    浏览(44)
  • YOLO系列概述(yolov1至yolov7)

    参考: 睿智的目标检测53——Pytorch搭建YoloX目标检测平台 YoloV7 首先我们来看一下yolo系列的发展历史,yolo v1和yolox是anchor free的方法,yolov2,yolov3,一直到yolov7是anchor base的方法。首选我们来回顾下每个版本的yolo都做了些什么 yolo v1是将 416 ∗ 416 416*416 4 1 6 ∗ 4 1 6 的图片,分

    2024年02月05日
    浏览(45)
  • 人工智能详细笔记:计算机视觉、目标检测与R-CNN系列 YOLO系列模型

    计算机视觉概述 :计算机视觉是一种利用计算机算法和数学模型来模拟和自动化人类视觉的学科领域。 计算机视觉的地位 :计算机视觉(CV)与自然语言处理(NLP)、语音识别(SR)并列为机器学习方向的三大热点方向。 计算机视觉的常见任务 :下面将从粗粒度到细粒度介

    2024年02月08日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包