CV大作业29期-使用YOLOv10快速实现海上红外目标检测

使用YOLOv10做红外海洋目标识别

完整的视频教程将会于28号发布,敬请期待!

Hi,大家好!这里是肆十二!

视频教程地址:【2024毕设系列】Anaconda和Pycharm如何使用_哔哩哔哩

过去几年的时间中,YOLO系列的模型逐渐发展壮大,从原先的YOLOv1到YOLOv10,YOLO系列模型已经迭代了整个10个版本。YOLOv10模型于24年5月份正式提出,对过去YOLOs的结构设计、优化目标和数据增强策略进行了深入的了解和探索,并对YOLO模型中的各个组件进行了rethink,从后处理和模型结构入手进行了新的设计,在速度和精度上进行提升。根据论文中的叙述,在COCO数据集上,我们的YOLOv10-S在相似AP下比RT-DETR-R18快1.8倍,同时参数和浮点运算量(FLOPs)减少了2.8倍。与YOLOv9-C相比,YOLOv10-B在相同性能下延迟减少了46%,参数减少了25%

image-20240526171256371

在这里,我们正好有一个红外海洋目标检测的数据集,里面包含了7类海洋目标 ['liner', 'sailboat', 'warship', 'canoe', 'bulk carrier', 'container ship', 'fishing boat'],让我们看看不同版本的YOLO模型在其他数据集上速度和精度的表现如何!

val_batch1_labels

论文概述

背景

实时物体检测旨在以较低的延迟准确预测图像中的物体类别和位置。YOLO 系列在性能和效率之间取得了平衡,因此一直处于这项研究的前沿。然而,对 NMS 的依赖和架构上的低效阻碍了最佳性能的实现。YOLOv10 通过为无 NMS 训练引入一致的双重分配和以效率-准确性为导向的整体模型设计策略,解决了这些问题。

结构设计

YOLOv10 是清华大学研究人员在 UltralyticsPython 清华大学的研究人员在 YOLOv10软件包的基础上,引入了一种新的实时目标检测方法,解决了YOLO 以前版本在后处理和模型架构方面的不足。通过消除非最大抑制(NMS)和优化各种模型组件,YOLOv10 在显著降低计算开销的同时实现了最先进的性能。大量实验证明,YOLOv10 在多个模型尺度上实现了卓越的精度-延迟权衡,下面是YOLOV10论文中的结构图。

image-20240526171324075

主干网络的模型构成主要如下。

  1. 主干网YOLOv10 中的主干网负责特征提取,它使用了增强版的 CSPNet(跨阶段部分网络),以改善梯度流并减少计算冗余。
  2. 颈部颈部设计用于汇聚不同尺度的特征,并将其传递到头部。它包括 PAN(路径聚合网络)层,可实现有效的多尺度特征融合。
  3. 一对多头(训练时使用):在训练过程中为每个对象生成多个预测,以提供丰富的监督信号并提高学习准确性。
  4. 一对一头(推理时使用):在推理过程中为每个对象生成一个最佳预测,无需 NMS,从而减少延迟并提高效率。

主要优势

  1. 无 NMS 训练:利用一致的双重分配来消除对 NMS 的需求,从而减少推理延迟。
  2. 整体模型设计:从效率和准确性的角度全面优化各种组件,包括轻量级分类头、空间通道去耦向下采样和等级引导块设计。
  3. 增强的模型功能:纳入大核卷积和部分自注意模块,在不增加大量计算成本的情况下提高性能。

主要方法

YOLOv10 采用双重标签分配,在训练过程中将一对多和一对一策略结合起来,以确保丰富的监督和高效的端到端部署。一致匹配度量使两种策略之间的监督保持一致,从而提高了推理过程中的预测质量。

首先作者指出YOLO系列的模型为每个实例分配了多个阳性的样本,在一对多的匹配策略中会产生非常多的丰富的监督信号,但是他比较依赖NMS后处理,这会导致部署推理效率的不理想。作者在这里提出了具有双标签分配和一致性匹配度量的无NMS训练策略,可以提高效率和性能。

首先是双标签的分配策略,采用一对一匹配的时候只对一个实例分配一个预测结果,可以避免NMS的后处理,但是这会导致弱监督,但是这个缺点可以通过一对多的分配来进行弥补。那这样,方法就来了,就和在语义分割任务重,通过都会添加一个辅助头来提升模型对低尺度特征的捕捉,这里将两个分配方式结合起来一起使用。在原先的模型基础上,引入一个一对一的头部,训练的时候两个头部共同优化,但是在检测的过程中呢,抛弃掉一对多的头部,只保留一对一的头部进行预测。如下图所示,是NMS的示意图,首先先通过网络生成一堆候选框,然后通过分类网络为每个候选框附上类别,最终通过NMS算法,保留概率最大的那个锚点框,这个过程在物体比较多的时候计算时间会非常长,那通过一对一的头部,相当省略掉了中间的两个步骤,直接进行一对一的匹配,训练的时候两个策略同时存在,推理的时候去掉一对多的过程。

image-20240526180542749

这里我也给出NMS的处理过程,感兴趣的小伙伴可以了解一下。

NMS(非极大值抑制,Non-Maximum Suppression)是目标检测算法中的一个重要步骤,用于抑制重叠度较高的检测框,以确保每个目标只被检测一次。以下是NMS的详细过程:

  1. 排序检测框:
    • 根据所有检测框的置信度(或分类概率)进行排序,从高到低。
  2. 选择最高置信度的检测框:
    • 从排序后的检测框列表中,选择置信度最高的检测框作为当前处理的检测框。
  3. 计算IoU并抑制重叠检测框:
    • 计算当前处理检测框与其他所有检测框的交并比(IoU,Intersection over Union)。
    • 如果某个检测框与当前处理检测框的IoU超过预设的阈值(如0.5),则将该检测框从列表中移除或抑制,因为它与当前处理检测框重叠度较高,可能是检测到的同一个目标。
  4. 重复处理直至结束:
    • 重复步骤2和3,每次从未被抑制的检测框中选择置信度最高的一个,并抑制与其重叠度高的其他检测框。
    • 这个过程一直持续到没有更多的检测框需要处理为止。
  5. 输出结果:
    • 最终留下的未被抑制的检测框,就是NMS算法的输出结果,这些检测框代表了算法认为在图像中检测到的不同目标。

为了更好的实现上面的策略,作者还为两个头部提出了统一的匹配度量,定义如下。

image-20240526181712130

其中alpha和beta是两个重要的超参数,分别表示分类任务和位置的回归任务,b_hat和b表示的是预测和实例的边界框,那p表示的就是分类的分数,s表示预测的锚点是否在实例中。也就是你的IOU越大,你的分类分数越高,你的匹配程度就越高。

其中o2o表示的是one to one也就是一对一,o2m表示的是one2many表示的是一对多,两个分支之间的差距则可以表示为下面的公式,前面是一对一,后面是一对多。其中 t表示的是一对一和一对多的匹配分数。作者在论文的附录部分给出了这里的数学证明,有兴趣的小伙伴可以看论文最后的数学证明。

image-20240526182847850

  • 速度方面

    1. 轻量级分类头:通过使用深度可分离卷积,减少分类头的计算开销。

      分类的头部中使用了可分离的卷积,简单滴减少了分类头部的开销,在分类头部使用进行可分离卷积的使用主要是考虑到分类的头部参数量是回归鬼头的2.5倍。

    2. 空间通道解耦向下采样:将空间缩减与信道调制解耦,最大限度地减少信息损失和计算成本。

      这里的设计就是细节上设计了,传统的YOLO为了减少下采样的过程呢,通常使用步长为2的3×3的卷积,同时时间空间和通道上的下采样,这样就计算复杂度比较高。这里,作者将两个操作分开来做,先使用点装卷积完成通道的减少,然后使用深度卷积完成空间的下采样,可以保证参数量的减少。

    3. 梯级引导程序块设计:根据固有阶段冗余调整模块设计,确保参数的最佳利用。

      接着作者认为YOLO在所有的阶段都使用的相同的基本快,这种同质设计将会带来比较多的冗余,这里作者同样使用数学证明了每个阶段的冗余度为2。所以作者提出了CIB的模块,也就是DW卷积构成的模块,可以实现自适应的经凑块的设计,不影响性能的情况下实现更高的效率。

  • 精度方面

    1. 大核卷积扩大感受野,增强特征提取能力。

      大的卷积核可以扩大模型的感受野并且可以增强模型的能力,但是对于小物体的检测和IO的开销不利。所以作者为了避开大卷积的劣势,在深度的阶段给CIB使用大的卷积核,将3×3的卷积核增加到7×7,并且采用结构重参数化的技术引入DW卷积缓解优化的问题。并且作者提到,模型越大,感受野越大,所以只在小模型,比如n或者s模型中使用了大的卷积核。

    2. 部分自我关注(PSA):纳入自我关注模块,以最小的开销改进全局表征学习。

      这里就是使用Transformer的模块了,Transformer的模块具有卓越的全局建模能力,但是会有带来比较高的内存占用,为了解决这个问题,作者还是非常善用1×1卷积,通过1×1的卷积分为两个部分,将其中的一部分输入多头的自注意力中,另一部分输入到前馈网络FFn中,最后使用1×1的卷积将其进行连接和融合,增强模型能力的同时,提高性能。

最后放一下论文中给出的对比图,从图中可以看出,在coco数据集中,精度和速度yolov10均是最优。

image-20240526192609376

最后还有一些消融实验的结果供大家进行参考。

image-20240526192702214

核心代码

这里面放一些关键的代码,包括损失函数的实现和论文中提到的几个模块的实现。

  • CIB模块和PSA模块

    class CIB(nn.Module):
        """Standard bottleneck."""
    
        def __init__(self, c1, c2, shortcut=True, e=0.5, lk=False):
            """Initializes a bottleneck module with given input/output channels, shortcut option, group, kernels, and
            expansion.
            """
            super().__init__()
            c_ = int(c2 * e)  # hidden channels
            self.cv1 = nn.Sequential(
                Conv(c1, c1, 3, g=c1),
                Conv(c1, 2 * c_, 1),
                Conv(2 * c_, 2 * c_, 3, g=2 * c_) if not lk else RepVGGDW(2 * c_),
                Conv(2 * c_, c2, 1),
                Conv(c2, c2, 3, g=c2),
            )
    
            self.add = shortcut and c1 == c2
    
        def forward(self, x):
            """'forward()' applies the YOLO FPN to input data."""
            return x + self.cv1(x) if self.add else self.cv1(x)
    
    class C2fCIB(C2f):
        """Faster Implementation of CSP Bottleneck with 2 convolutions."""
    
        def __init__(self, c1, c2, n=1, shortcut=False, lk=False, g=1, e=0.5):
            """Initialize CSP bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups,
            expansion.
            """
            super().__init__(c1, c2, n, shortcut, g, e)
            self.m = nn.ModuleList(CIB(self.c, self.c, shortcut, e=1.0, lk=lk) for _ in range(n))
    
    
    class Attention(nn.Module):
        def __init__(self, dim, num_heads=8,
                     attn_ratio=0.5):
            super().__init__()
            self.num_heads = num_heads
            self.head_dim = dim // num_heads
            self.key_dim = int(self.head_dim * attn_ratio)
            self.scale = self.key_dim ** -0.5
            nh_kd = nh_kd = self.key_dim * num_heads
            h = dim + nh_kd * 2
            self.qkv = Conv(dim, h, 1, act=False)
            self.proj = Conv(dim, dim, 1, act=False)
            self.pe = Conv(dim, dim, 3, 1, g=dim, act=False)
    
        def forward(self, x):
            B, _, H, W = x.shape
            N = H * W
            qkv = self.qkv(x)
            q, k, v = qkv.view(B, self.num_heads, -1, N).split([self.key_dim, self.key_dim, self.head_dim], dim=2)
    
            attn = (
                (q.transpose(-2, -1) @ k) * self.scale
            )
            attn = attn.softmax(dim=-1)
            x = (v @ attn.transpose(-2, -1)).view(B, -1, H, W) + self.pe(v.reshape(B, -1, H, W))
            x = self.proj(x)
            return x
    
    class PSA(nn.Module):
    
        def __init__(self, c1, c2, e=0.5):
            super().__init__()
            assert(c1 == c2)
            self.c = int(c1 * e)
            self.cv1 = Conv(c1, 2 * self.c, 1, 1)
            self.cv2 = Conv(2 * self.c, c1, 1)
            
            self.attn = Attention(self.c, attn_ratio=0.5, num_heads=self.c // 64)
            self.ffn = nn.Sequential(
                Conv(self.c, self.c*2, 1),
                Conv(self.c*2, self.c, 1, act=False)
            )
            
        def forward(self, x):
            a, b = self.cv1(x).split((self.c, self.c), dim=1)
            b = b + self.attn(b)
            b = b + self.ffn(b)
            return self.cv2(torch.cat((a, b), 1))
    
    class SCDown(nn.Module):
        def __init__(self, c1, c2, k, s):
            super().__init__()
            self.cv1 = Conv(c1, c2, 1, 1)
            self.cv2 = Conv(c2, c2, k=k, s=s, g=c2, act=False)
    
        def forward(self, x):
            return self.cv2(self.cv1(x))
    
  • 损失函数

    class v10DetectLoss:
        def __init__(self, model):
            self.one2many = v8DetectionLoss(model, tal_topk=10)
            self.one2one = v8DetectionLoss(model, tal_topk=1)
        
        def __call__(self, preds, batch):
            one2many = preds["one2many"]
            loss_one2many = self.one2many(one2many, batch)
            one2one = preds["one2one"]
            loss_one2one = self.one2one(one2one, batch)
            return loss_one2many[0] + loss_one2one[0], torch.cat((loss_one2many[1], loss_one2one[1]))
    
    

环境配置

老规矩,环境配置之前请先自行熟悉Anaconda和Pycharm的使用:【2024毕设系列】Anaconda和Pycharm如何使用_哔哩哔哩

  • 配置国内镜像

    conda config --remove-key channels
    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/pytorch/
    conda config --set show_channel_urls yes
    pip config set global.index-url https://mirror.baidu.com/pypi/simple
    
  • 创建和激活虚拟环境

    conda create -n yolov10 python==3.8.5
    conda acctivate yolov10
    

    image-20240526163837733

  • 安装Pytorch

    conda install pytorch==1.8.0 torchvision torchaudio cudatoolkit=10.2 # 注意这条命令指定Pytorch的版本和cuda的版本
    conda install pytorch==1.10.0 torchvision torchaudio cudatoolkit=11.3 # 30系列以上显卡gpu版本pytorch安装指令
    conda install pytorch==1.8.0 torchvision==0.9.0 torchaudio==0.8.0 cpuonly # CPU的小伙伴直接执行这条命令即可
    
  • 安装项目所需要的其他依赖库

    激活环境之后直接执行下列这个一个指令就完成所有依赖库的安装了,非常之方便

    pip install -v -e .
    

    image-20240526165603423

  • 执行42-demo.py查看效果

    # -*-coding:utf-8 -*-
    
    """
    #-------------------------------
    # @Author : 肆十二
    # @QQ : 3045834499 可定制毕设
    #-------------------------------
    # @File : 42-demo.py
    # @Description: 文件描述
    # @Software : PyCharm
    # @Time : 2024/5/26 20:31
    #-------------------------------
    """
    from ultralytics import YOLOv10
    
    # Load a pretrained YOLOv10n model
    model = YOLOv10("../pretrained/yolov10n.pt")
    
    # Perform object detection on an image
    results = model("bus.jpg")
    
    # Display the results
    results[0].show()
    

    image-20240527004631495

    image-20240527004642432

  • 配置Pycharm享用代码

    image-20240527004736912

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

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

相关文章

Java面试题分享-敏感词替换 java 版本

入职啦最近更新了一些后端笔试、面试题目,大家看看能快速实现吗? 关注 入职啦 微信公众号,每日更新有用的知识,Python,Java,Golang,Rust,javascript 等语言都有 不要再用replaceAll做…

P10-P11【重载,模板,泛化和特化】【分配器的实现】

三类模板(类模板)(函数模板)(成员函数模板) 特化 偏特化:模板参数个数/模板范围 定义的分配器 以上分配器的性能和内存管理有很大不足(在分配内存时,会产生很大的内存开…

探索自动发邮件的奥秘:从配置到实现

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、引言:邮件自动化的魅力 二、配置环境:选择适合的SMTP服务器 示…

【制作100个unity游戏之27】使用unity复刻经典游戏《植物大战僵尸》,制作属于自己的植物大战僵尸随机版和杂交版6(附带项目源码)

最终效果 系列导航 文章目录 最终效果系列导航前言方法一、使用excel配置表excel转txt文本读取txt数据按配置信息生成僵尸 方法二、使用ScriptableObject 配置关卡信息源码结束语 前言 本节主要是推荐两种实现配置关卡信息,并按表生成僵尸和关卡波次 方法一、使用…

URL在线编码解码

URL在线编码解码 打开网站 在线工具网-梦幻加菲猫 选择“URL编码解码” 输入需要编码/解码的内容,点击“编码”/“解码”按钮 编码: 解码: 复制已经编码/解码后的内容。

【Uniapp微信小程序】自定义水印相机、微信小程序地点打卡相机

效果图 template 下方的image图片自行寻找替换&#xff01; <template><view><camerav-if"!tempImagePath && cameraHeight ! 0":resolution"high":frame-size"large":device-position"device":flash"f…

ModuleNotFoundError: No module named ‘osgeo‘

显示无osgeo模块 pip install osgeo显示失败 方法&#xff1a; 确保你已经安装了正确的依赖项&#xff0c;例如GDAL、GEOS和PROJ等。 方法1&#xff1a;pip install gdal 失败 方法2&#xff1a;官网下载失败&#xff0c;下载地址&#xff1a;https://www.lfd.uci.edu/~gohl…

vue3学习(四)

前言 接上篇学习笔记&#xff0c;分享3个内置组件&#xff1a;动态组件、缓存组件、分发组件基本用法。大家一起通过code的示例&#xff0c;从现象理解,注意再次理解生命周期。 一、code示例 组件A&#xff1a;CompA <script setup> import {onMounted, onUnmounted} f…

【CTF-Web】XXE学习笔记(附ctfshow例题)

XXE 文章目录 XXE0x01 前置知识汇总XMLDTD &#xff08;Document Type Definition&#xff09; 0x02 XXE0x03 XXE危害0x04 攻击方式1. 通过File协议读取文件Web373(有回显)Web374(无回显) Web375Web376Web377Web378 0x01 前置知识汇总 XML 可扩展标记语言&#xff08;eXtensi…

分享 - 树形dp

树形 d p dp dp 例1 - 基础 链接&#xff1a;树上子链 练手 分析 其实一看题就很显然的树形 d p dp dp子链在这里分为两种情况&#xff0c;如图黑链和红链 思路 d p [ i ] dp[i] dp[i] 表示以 i i i 开头的红链的最大权值易得&#xff1a; d p [ i ] m a x ( d p [ i…

SelfKG论文翻译

SelfKG: Self-Supervised Entity Alignment in Knowledge Graphs SelfKG&#xff1a;知识图中的自监督实体对齐 ABSTRACT 实体对齐旨在识别不同知识图谱&#xff08;KG&#xff09;中的等效实体&#xff0c;是构建网络规模知识图谱的基本问题。在其发展过程中&#xff0c;标…

ubuntu server版 虚拟机根目录磁盘扩容

之前一直使用桌面版ubuntu,因为项目原因需要拉取的代码太大了且项目比较多选择了体量更小的Ubuntu server版,在使用中发现根目录的磁盘很快就用满了 如上,明明分配的300G但是/dev/mapper/ubuntu--vg-ubuntu--lv 只有98G都用满了 server版本与桌面版不同的是在server版安装的时…

MySQL增删查改进阶

数据库约束表的关系增删查改 目录 一.数据库约束类型 NOT NULL约束类型 UNIQUE 唯一约束 DEFAULT 默认值约束 PRIMARY KEY&#xff1a;主键约束 FOREIGN KEY :W外键约束 二&#xff0c;查询 count&#xff08;&#xff09;两种用法 sum&#xff0c;avg&#xff0c;max…

leetcode-设计LRU缓存结构-112

题目要求 思路 双链表哈希表 代码实现 struct Node{int key, val;Node* next;Node* pre;Node(int _key, int _val): key(_key), val(_val), next(nullptr), pre(nullptr){} };class Solution { public: unordered_map<int, Node*> hash; Node* head; Node* tail; int …

朗读亭主要作用有哪些?

朗读亭的主要作用有以下几个方面&#xff1a; 1. 提供朗读服务&#xff1a;朗读亭是一个专门的场所&#xff0c;提供给人们朗读的环境和场地。人们可以在朗读亭中选择自己喜欢的书籍或文章&#xff0c;并通过朗读将其表达出来。这样可以帮助人们提高朗读能力&#xff0c;增强自…

C++学习~~对于二进制文件的读写命名空间再认识异常处理

目录 1.将数据以二进制形式放到磁盘 2.将上述的数据读入内存并且显示在显示器上面 3.异常处理机制 4.抛出异常的应用实例 1.将数据以二进制形式放到磁盘 &#xff08;1&#xff09;使用student定义结构体数组stud,并对其进行初始化&#xff0c;创建输出文件流对象outfile,这…

什么是React?

01 Why React? What is React? I think the one-line description of React on its home page (https://react.dev/) is concise and accurate: “A JavaScript library for building user interfaces.” 我认为React主页(https://react.dev/)上的一行描述既简洁又准确: …

微信聊天内容怎么监控? | 三款可以监控电脑微信聊天记录的软件大盘点

你是否听说过监控微信呢&#xff1f; 有时出于特定需求&#xff0c;比如家长对孩子上网行为的关心&#xff0c;或者企业对员工工作效率的监控&#xff0c;可能需要了解某些情况下的微信聊天记录。 但请注意&#xff0c;任何未经授权的监控行为都是违法的&#xff0c;并且可能…

PFC基础知识1

不同负载 1.当负载是电阻时&#xff0c; 阻值固定&#xff0c;阻性负载&#xff0c;相位相同&#xff0c;并且线性度非常好 &#xff0c;输出的电流全部被利用 2.当负载有电感时&#xff0c;相位有偏差&#xff0c;电流滞后于电压90。电源需要输出电流&#xff0c;但是电感并未…

java Web开发中采用Servlet登录验证,中文用户名始终提示“用户名密码错误”以及输出中文乱码问题

采用Servlet登录验证&#xff0c;中文乱码问题解决 在Java Web开发中&#xff0c;往往采用Servlet完成前后端直接的控制和处理&#xff0c;例如&#xff1a;用户登录验证功能。 在采用如下Servle源码t完成用户名登录验证时&#xff0c;只要用户名涉及中文&#xff0c;对于正确…