Yolov10笔记

一、前言

        清华大学团队设计的Yolov10.

        在这项工作中,我们主要从后处理和模型结构两方面进一步优化YOLO系列模型的性能和延迟平衡。我们首先为YOLO引入了端到端训练的一致双重分配,这在大大降低推理延迟的情况下保证了性能。此外,我们针对YOLO的各组件使用效率和精度驱动的模型设计策略。这大大减少了计算冗余,并增强了模型能力。

        最终,我们获得了一个新的实时的端到端目标检测模型,即YOLOv10。广泛的实验表明,YOLOv10在各种模型规模上达到了最先进的性能和效率平衡。例如,YOLOv10-S在COCO上的类似AP下比RT-DETR-R18快1.8倍,同时有2.8倍更少的参数和FLOPs。与YOLOv9-C相比,YOLOv10-B在相同性能下延迟减少了46%,参数减少了25%。

二、创新点

1、一致双重匹配

        与一对多匹配不同,一对一匹配只为每个物体分配一个预测,避免了NMS后处理。然而,这会带来较弱的监督信息,导致次优的准确性和收敛速度[19]。另一方面,一对多策略则可以引入更多的正样本和监督信号,可有效弥补一对一匹配的不足[23]。因此,我们为YOLOs引入了双重标签匹配,如下图,以充分结合两种策略的优点。

2、效率精度驱动的模型设计

效率驱动的模型设计

(1)、轻量级分类头

(2)、空间-通道解耦下采样

(3)、秩引导的块设计

精度驱动的模型设计

(1)、大核卷积

(2)、部分自注意力(PSA)

三、代码解读

1、网络结构图

以yolov10s模型为例。

# Parameters
nc: 80 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
  # [depth, width, max_channels]
  s: [0.33, 0.50, 1024]

backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
  - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
  - [-1, 3, C2f, [128, True]]
  - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
  - [-1, 6, C2f, [256, True]]
  - [-1, 1, SCDown, [512, 3, 2]] # 5-P4/16
  - [-1, 6, C2f, [512, True]]
  - [-1, 1, SCDown, [1024, 3, 2]] # 7-P5/32
  - [-1, 3, C2fCIB, [1024, True, True]]
  - [-1, 1, SPPF, [1024, 5]] # 9
  - [-1, 1, PSA, [1024]] # 10

# YOLOv8.0n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  - [-1, 3, C2f, [512]] # 13

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  - [-1, 3, C2f, [256]] # 16 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 13], 1, Concat, [1]] # cat head P4
  - [-1, 3, C2f, [512]] # 19 (P4/16-medium)

  - [-1, 1, SCDown, [512, 3, 2]]
  - [[-1, 10], 1, Concat, [1]] # cat head P5
  - [-1, 3, C2fCIB, [1024, True, True]] # 22 (P5/32-large)

  - [[16, 19, 22], 1, v10Detect, [nc]] # Detect(P3, P4, P5)

由于完整的模型图太长,这里只截取头部处理的模型图。

2、代码分析

class v10Detect(Detect):

    max_det = -1

    def __init__(self, nc=80, ch=()):
        super().__init__(nc, ch)
        c3 = max(ch[0], min(self.nc, 100))  # channels
        self.cv3 = nn.ModuleList(nn.Sequential(nn.Sequential(Conv(x, x, 3, g=x), Conv(x, c3, 1)), \
                                               nn.Sequential(Conv(c3, c3, 3, g=c3), Conv(c3, c3, 1)), \
                                               nn.Conv2d(c3, self.nc, 1)) for i, x in enumerate(ch))

        self.one2one_cv2 = copy.deepcopy(self.cv2)
        self.one2one_cv3 = copy.deepcopy(self.cv3)
    
    def forward(self, x):
        one2one = self.forward_feat([xi.detach() for xi in x], self.one2one_cv2, self.one2one_cv3)
        if not self.export:
            one2many = super().forward(x)

        if not self.training:
            one2one = self.inference(one2one)
            if not self.export:
                return {"one2many": one2many, "one2one": one2one}
            else:
                assert(self.max_det != -1)
                boxes, scores, labels = ops.v10postprocess(one2one.permute(0, 2, 1), self.max_det, self.nc)
                return torch.cat([boxes, scores.unsqueeze(-1), labels.unsqueeze(-1)], dim=-1)
        else:
            return {"one2many": one2many, "one2one": one2one}
def v10postprocess(preds, max_det, nc=80):
    # preds: shape[1,8400,84]
    assert(4 + nc == preds.shape[-1])
    boxes, scores = preds.split([4, nc], dim=-1)  # [1,8400,4]  [1,8400,80]
    max_scores = scores.amax(dim=-1)  # [1,8400]
    max_scores, index = torch.topk(max_scores, max_det, axis=-1)  # [1,300]
    index = index.unsqueeze(-1)  # [1,300,1]
    boxes = torch.gather(boxes, dim=1, index=index.repeat(1, 1, boxes.shape[-1]))     # [1,300,4]
    scores = torch.gather(scores, dim=1, index=index.repeat(1, 1, scores.shape[-1]))  # [1,300,80]
    scores, index = torch.topk(scores.flatten(1), max_det, axis=-1)  # 1*300
    labels = index % nc  # 1*300
    index = index // nc  # 1*300
    boxes = boxes.gather(dim=1, index=index.unsqueeze(-1).repeat(1, 1, boxes.shape[-1]))  # 1*300*4
    return boxes, scores, labels
    def inference(self, x):
        # Inference path
        shape = x[0].shape  # BCHW
        x_cat = torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2)
        if self.dynamic or self.shape != shape:
            self.anchors, self.strides = (x.transpose(0, 1) for x in make_anchors(x, self.stride, 0.5))
            self.shape = shape

        if self.export and self.format in ("saved_model", "pb", "tflite", "edgetpu", "tfjs"):  # avoid TF FlexSplitV ops
            box = x_cat[:, : self.reg_max * 4]
            cls = x_cat[:, self.reg_max * 4 :]
        else:
            box, cls = x_cat.split((self.reg_max * 4, self.nc), 1)

        if self.export and self.format in ("tflite", "edgetpu"):
            # Precompute normalization factor to increase numerical stability
            # See https://github.com/ultralytics/ultralytics/issues/7371
            grid_h = shape[2]
            grid_w = shape[3]
            grid_size = torch.tensor([grid_w, grid_h, grid_w, grid_h], device=box.device).reshape(1, 4, 1)
            norm = self.strides / (self.stride[0] * grid_size)
            dbox = self.decode_bboxes(self.dfl(box) * norm, self.anchors.unsqueeze(0) * norm[:, :2])
        else:
            dbox = self.decode_bboxes(self.dfl(box), self.anchors.unsqueeze(0)) * self.strides

        y = torch.cat((dbox, cls.sigmoid()), 1)
        return y if self.export else (y, x)

记录各个模块返回参数的shape

*** one2one = self.forward_feat([xi.detach() for xi in x], self.one2one_cv2, self.one2one_cv3)  ===>
1*128*80*80 ==> 1*64*80*80 + 1*80*80*80 = 1*144*80*80
1*256*40*40 ==> 1*64*40*40 + 1*80*40*40 = 1*144*40*40
1*512*20*20 ==> 1*64*20*20 + 1*80*20*20 = 1*144*20*20

*** one2one = self.inference(one2one)  ===>  
1*144*6400 + 1*144*1600 + 1*144*400 = 1*144*8400
box: 1*64*8400  ==>  dbox: 1*4*8400
cls: 1*80*8400
output: 1*4*8400 + 1*80*8400 = 1*84*8400

*** boxes, scores, labels = ops.v10postprocess(one2one.permute(0, 2, 1), 300, 80)
1*84*8400  ==> boxes:1*300*4   scores:1*300   labels:1*300

*** torch.cat([boxes, scores.unsqueeze(-1), labels.unsqueeze(-1)], dim=-1) ===>
boxes:1*300*4   scores:1*300   labels:1*300  ==>  1*300*6

四、参考

1、博客:YOLOv10:实时的端到端目标检测 (qq.com)

2、论文:[2405.14458] YOLOv10: Real-Time End-to-End Object Detection (arxiv.org)

3、code:THU-MIG/yolov10: YOLOv10: Real-Time End-to-End Object Detection (github.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/668264.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DBeaver添加DM8驱动(maven下载和jar包下载配置)

DBeaver 24.0.3添加DM8驱动 下载DBeaver下载DM达梦驱动下载 安装配置使用自带Dameng自行添加达梦驱动 因为最近公司项目有信创要求,所以下载了达梦数据库。使用自带的达梦管理工具不是很方便,于是换了DBeaver。 哼哧哼哧安装好后,创建数据库连…

前端功能拖拽篇:dragleave拖拽事件穿透子元素的优雅解决方案

文章目录 前情提要应用场景⭐拖拽改变元素位置⭐拖拽改变目标区域的样式⭐dragleave拖拽事件穿透子元素的优雅解决方案 最后 前情提要 在前端工作过程中,避免不了要接触各种技术,拖拽就是其中一个,大部分关于拖拽的基础知识和Demo都在MDN中写…

【智能算法】吸引-排斥优化算法(AROA)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献5.代码获取 1.背景 2024年,K Cymerys受到自然界中吸引-排斥现象启发,提出了吸引-排斥优化算法(Attraction–Repulsion Optimization Algorithm, AROA)。 2.算法…

Verilog HDL基础知识(二)

引言:本文继续介绍Verilog HDL基础知识,重点介绍赋值语句、阻塞与非阻塞、循环语句、同步与异步、函数与任务语法知识。 1. 赋值语句 在Verilog中,有两种进行赋值的方法,即连续赋值语句和过程赋值语句(块&#xff09…

[vue2项目]vue2+supermap[mapboxgl]+天地图之地图的初始化

Supermap参考教程 天地图 一、安装 1、终端:npm install @supermap/vue-iclient-mapboxgl 2、在package.json文件的dependencies查看@supermap/vue-iclient-mapboxgl依赖是否安装成功。 3、在mian.js全局引入 import VueiClient from @supermap/vue-iclient-mapboxgl; Vue.u…

新一代目标检测来了:YOLOv10 | 理论概要

点击下方卡片,关注“小白玩转Python”公众号 YOLO的简史 在我们深入探讨YOLOv10之前,让我们回顾一下YOLO的发展历程。YOLO在实时目标检测领域一直是先驱,兼顾速度和准确性。从YOLOv1到YOLOv9,每个版本在架构、优化和数据增强方面都…

Ansible04-Ansible Vars变量详解

目录 写在前面6 Ansible Vars 变量6.1 playbook中的变量6.1.1 playbook中定义变量的格式6.1.2 举例6.1.3 小tip 6.2 共有变量6.2.1 变量文件6.2.1.1 变量文件编写6.2.1.2 playbook编写6.2.1.3 运行测试 6.2.2 根据主机组使用变量6.2.2.1 groups_vars编写6.2.2.2 playbook编写6.…

场外个股期权零门槛开户安全吗?

一般来说场外个股期权是需要5000w门槛验资20个交易日的,但门槛对于大多数散户而言是很难达到的,因此场外个股期权零门槛开户因此产生,个人散户参与场外个股期权可以通到机构通道方直接下单交易,下文为大家揭秘场外个股期权零门槛开…

基于SpringBoot的旅游攻略信息系统的设计与实现

文档介绍 用户群体 针对已经学习过SpringBoot的同学,希望通过一个项目来加强对框架的应用能力,增加项目经验 针对需要完成大学期间的毕设项目的同学,可以通过此文档了解整个系统技术架构,为自己的毕设论文提供指导性建议 文档内容 此文档内容可以让学习此实战项目的同学有一…

2024年5月月终总结

一转眼4月份又过去了,按照年初的承诺,每月照例要写一个月总结,简单回顾下: 1) 英语学习继续进行: 百词斩: 不背单词: 每日英语听力: 2)中医学习每天15分钟,没有中断。 …

数据库系统概论(超详解!!!)第十节 过程化SQL

1.Transact-SQL概述 SQL(Structure Query Language的简称,即结构化查询语言) 是被国际标准化组织(ISO)采纳的标准数据库语言,目前所有关系数据库管理系统都以SQL作为核心,在JAVA、VC、VB、Delphi等程序设计语言中也可使用SQL,它是…

AIGC全面揭秘:人工智能内容生成的无限可能!

一、引言 随着人工智能技术的不断发展,AIGC(人工智能生成内容)技术逐渐受到广泛关注。本文将全面介绍AIGC的相关知识。 二、AIGC简介 AIGC是利用人工智能技术自动生成内容的一种技术。它可以根据给定的输入数据和规则,自动产生符…

详解 Spark 编程之 RDD 依赖关系

一、依赖与血缘关系 依赖:两个相邻 RDD 之间的关系血缘关系:多个连续的 RDD 的依赖由于 RDD 不会保存数据,为了提高容错性,每个 RDD 都会保存自己的血缘关系,一旦某个转换过程出现错误,可以根据血缘关系重新…

开源VS闭源:AI未来的十字路口

人工智能领域的发展日益加速,其中关于模型的开源和闭源策略引起了业界的广泛关注。开源策略指的是将软件的源代码公开,允许任何人自由使用、研究甚至改进;而闭源策略则是指软件的源代码不公开,只有特定的个体或组织有权访问和修改…

【IPFS应用开发】基于IPFS的视频播放器

本系列文章是针对 https://blog.csdn.net/weixin_43668031/article/details/83962959 内容的实现所编写的。开发经历包括思考过程、重构和推翻重来。 基于IPFS的视频播放器 想写一个真正的、基于IPFS的,可以播放IPFS上的视频的程序支持多种数据加载格式同时支持单文…

docker部署Minio对象存储及使用

1.拉取镜像 docker pull minio/minio2.创建数据目录 mkdir -p /data/minio/data3.启动容器 docker run -p 39000:9000 -p 39090:9090 \ --name minio \ -d --restartalways \ -e "MINIO_ACCESS_KEYjyadmin" \ -e "MINIO_SECRET_KEYjyzx2023" \ -v /data…

C++数据结构之:链List

摘要: it人员无论是使用哪种高级语言开发东东,想要更高效有层次的开发程序的话都躲不开三件套:数据结构,算法和设计模式。数据结构是相互之间存在一种或多种特定关系的数据元素的集合,即带“结构”的数据元素的集合&am…

用esp prog烧录ESP32-C3板踩坑

附ESP32C3的GPIO一览: vscode选择Jtag烧录,终端输出esp_usb_jtag: could not find or open device: D:\Devtools\Espressif\tools\openocd-esp32\v0.12.0-esp32-20230921\openocd-esp32\bin\openocd.exe -f board/esp32s3-builtin.cfgOpen O…

xxl-job的使用

介绍 在分布式中,很多微服务可能存在多实例部署的现象,如果在某个具体的微服务中实现一个定时任务,而该微服务存在多个实例的话,那么会导致该定时任务在不同实例中都会进行执行!这很容易导致脏数据、数据重复等问题&am…

黑白群晖激活AME(Advanced Media Extention)

黑群晖激活Advanced Media Extensions(AME)解码HEVC视频和HEIC图片 声明:此教程在正版群晖系统中进行的操作,虽然也能用于非正版系统中AME的安装,但是在非正版系统中安装AME属于破解行为,对系统造成的影响和…