目标检测算法之YOLO(YOLOv10)

news2024/11/16 0:45:54

yolo算法理解

  • Background
  • Consistent Dual Assignments for NMS-free Training
  • Holistic Efficiency-Accuracy Driven Model Design
    • Efficiency driven model design
      • Lightweight classification head
      • Spatial-channel decoupled downsampling
      • Rank-guided block design
    • Accuracy driven model design
  • Conclusion

Background

yolov10是清华大学发布的一个新yolo算法,作者认为NMS是影响yolo实时推理的一个主要问题,针对这个问题提出了dual assignments的方法来训练NMS-free的yolo模型。同时作者从速度和精度入手,提出了几个改进模型的方法。yolov10在推理速度以及参数量上都优于现有的模型,且仍具有不弱于其他模型的精度。接下来主要分析yolov10中的dual asignments和 Efficiency-Accuracy优化策略。

yolov10的论文地址:https://arxiv.org/abs/2405.14458
yolov10的代码地址:https://github.com/THU-MIG/yolov10

Consistent Dual Assignments for NMS-free Training

作者认为one-to-many label assign需要NMS进行后处理,从而影响模型部署后的推理速度,然而one-to-one label assign会带来额外的推理开销并且没有太好的表现。
基于这俩个原因,提出了dual label assignmets的策略,即在yolo中同时采用one-one和one-to-many。模型的结构见下图
在这里插入图片描述
从上图可以看出,相较于普通的yolo头,这里的yolo头有俩个,分别用于one-to-one和one-to-many。同时每个头都采用了解耦头的方式,即回归和分类分开。这里的思想跟v7中的辅助头是挺像的,通过一个aux head实现one-to-many,lead head实现one-to-one。最后在推理阶段丢弃aux head。

引入了俩个头之后,最大的问题就是如何去分配标签。这里作者对俩个头都用了一样的匹配度量。这里匹配度量的仍然是考虑了分类头和回归头,这里匹配损失记为 m m m,具体计算如下 m ( α , β ) = s ⋅ p α ⋅ I O U ( b ^ , b ) β m(\alpha,\beta) = s\cdot p^{\alpha}\cdot IOU(\hat{b},b)^{\beta} m(α,β)=spαIOU(b^,b)β其中 p p p是指分类分数, b ^ \hat{b} b^为预测框, b b b为真实框, α \alpha α β \beta β是超参数。
这样度量就同时考虑了分类任务和回归任务。对于one-to-one的任务记为 m o 2 o = m o 2 o ( α o 2 o , β o 2 o ) m_{o2o} = m_{o2o}(\alpha_{o2o},\beta_{o2o}) mo2o=mo2o(αo2o,βo2o),对于one-to-many的任务记为 m o 2 m = m o 2 m ( α o 2 m , β o 2 m ) m_{o2m}=m_{o2m}(\alpha_{o2m},\beta_{o2m}) mo2m=mo2m(αo2m,βo2m)

作者认为o2m能够提供更丰富的监督信息,同时希望o2m能够引导o2o。所以作者分析了o2o和o2m的差距,发现它们在回归任务上的表现没什么大的差异,所以认为它们的差距主要体现在分类任务上。然后就是针对分类任务进行改进。

先给定一个目标,然后记俩个头预测的最大IOU为 u ∗ u^* u(由于回归任务差不多,所任可以认为俩个头预测的最大IOU相等),然后记俩个头的最大匹配分数为 m o 2 o ∗ m^{*}_{o2o} mo2o m o 2 m ∗ m^{*}_{o2m} mo2m

同时假设 o 2 m o2m o2m的最佳匹配为 Ω \Omega Ω,而 o 2 o o2o o2o的最佳匹配为第 i i i个,并记为 m o 2 o , i = m o 2 o ∗ m_{o2o,i}=m_{o2o}^* mo2o,i=mo2o。然后有以下的等式关系 t o 2 m , j = u ∗ m o 2 m , j m o 2 m ∗ ≤ u ∗ t o 2 o , i = u ∗ m o 2 o , i m o 2 o ∗ = u ∗ \begin{align*}t_{o2m,j} =& u^*\frac{m_{o2m,j}}{m^{*}_{o2m}}\leq u^*\\ t_{o2o,i}=&u^*\frac{m_{o2o,i}}{m^*_{o2o}} = u^*\end{align*} to2m,j=to2o,i=umo2mmo2m,juumo2omo2o,i=u这里的等式是采取了跟TOOD中类似的归一化度量,首先这里认为分类损失匹配 t o 2 o ∣ o 2 m t_{o2o|o2m} to2oo2m m o 2 o ∣ o 2 m m_{o2o|o2m} mo2oo2m是等价的(这里不能用公式中的 p p p来看做 t t t)。然后借助TOOD中的归一化方法处理 m m m,即 n o r m ( u ) = max ⁡ ( i o u ) ∗ u max ⁡ ( u ) norm(u) = \max(iou)*\frac{u}{\max(u)} norm(u)=max(iou)max(u)u

然后定义了俩个头的差距用 1-Wasserstein distance表示,具体为 A = t o 2 o , i − 1 i ∈ Ω t o 2 m , i + ∑ k ∈ Ω ∖ { i } t o 2 m , k A =t_{o2o,i}-1_{i\in\Omega}t_{o2m,i}+\sum_{k\in{\Omega}\setminus \{i\}}t_{o2m,k} A=to2o,i1iΩto2m,i+kΩ{i}to2m,k直观地说,这个公式是使 t o 2 o t_{o2o} to2o越来越接近 t o 2 m t_{o2m} to2m。同使 t o 2 m , i t_{o2m,i} to2m,i尽可能地大(这里有点奇怪,不过合理的解释是当A的权重不大时,这里可以使 t o 2 o , i t_{o2o,i} to2o,i接近 t o 2 m , i t_{o2m,i} to2m,i,使 t o 2 o , k t_{o2o,k} to2o,k稍微抑制使其变小)

具体上,作者是对one2one和one2many都采用了TAL作为分配策略,但是对one2one采用top1,对one2many采用top10。这里v10是延续了v8的分配方式。

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

在源码中没有找到对齐损失1-Wasserstein distance的实现(有读者发现的话可以在评论说一下)。其余的loss function跟v8类似,就是引入了一个one2many。

Holistic Efficiency-Accuracy Driven Model Design

作者认为yolo架构存在较多的计算冗余,这样会阻碍它的能力。所以作者希望在速度和精度俩个方面对模型进行改进。

Efficiency driven model design

作者认为在yolo中下采样、basic building blocks和头部三个部分对速率影响较大。所以分别对这三部分进行改进。

Lightweight classification head

第一个是头部进行改进,作者通过实验验证了改进回归头对模型的表现影响较大,然后分类头的参数和计算量是回归头的俩倍多,所以作者使用了俩个深度可分离卷积( depthwise separable convolutions)替代了原来的分类头。具体代码如下

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

Spatial-channel decoupled downsampling

第二个是对下采样部分进行改进,简单而言就是用了pointwise convolution和depthwise convolution进行下采样,替代了kernel为3x3且stride为2的卷积。假设对图像大小为 ( H × W × C ) (H\times W\times C) (H×W×C)的图像进行下采样得到 ( H 2 × W 2 × C 2 ) (\frac{H}{2}\times \frac{W}{2}\times C^2) (2H×2W×C2),在不替换前需要的计算量和参数量分别为 O ( 18 H W C 2 4 ) = O ( 9 H W C 2 2 ) O(\frac{18HWC^2}{4})=O(\frac{9HWC^2}{2}) O(418HWC2)=O(29HWC2) O ( 9 ∗ 2 C 2 ) = O ( 18 C 2 ) O(9*2C^2)=O(18C^2) O(92C2)=O(18C2)

使用pointwise convolution的将其 ( H × W × C ) → ( H × W × 2 C ) (H\times W\times C)\rightarrow(H\times W\times 2C) (H×W×C)(H×W×2C),计算量和参数分别为 O ( 2 H W C 2 ) O(2HWC^2) O(2HWC2) O ( 2 C 2 ) O(2C^2) O(2C2),然后使用3x3的depthwise convolution将其 ( H × W × 2 C ) → ( H 2 × W 2 × 2 C ) (H\times W\times 2C)\rightarrow(\frac{H}{2}\times \frac{W}{2}\times 2C) (H×W×2C)(2H×2W×2C),计算量和参数量分别为 O ( 9 W H ∗ 2 C 4 ) = O ( 9 W H C 2 ) O(\frac{9WH*2C}{4}) =O(\frac{9WHC}{2}) O49WH2C)=O(29WHC) O ( 18 C ) O(18C) O(18C)。所以总的计算量和参数量为 O ( 2 H W C 2 + 9 W H C 2 ) O(2HWC^2+\frac{9WHC}{2}) O(2HWC2+29WHC) O ( 2 C 2 + 18 C ) O(2C^2+18C) O(2C2+18C)

总的而言这个方式可以使计算量从 O ( 9 H W C 2 2 ) O(\frac{9HWC^2}{2}) O(29HWC2)降至 O ( 2 H W C 2 + 9 W H C 2 ) O(2HWC^2+\frac{9WHC}{2}) O(2HWC2+29WHC),参数量从 O ( 18 C 2 ) O(18C^2) O(18C2)降至 O ( 2 C 2 + 18 C ) O(2C^2+18C) O(2C2+18C)

Rank-guided block design

第三部分是basic building block。作者认为模型在重复使用同个模块拼接后,会带来较大的信息冗余。所以作者对yolov8各个大小的模型的每个阶段的最后一个卷积进行秩的分析,通过下图可以发现模型较大且较深时,秩相对较小。说明了大模型存在较多的信息冗余,也就是说有用的信息不多。所以作者提出了CIB模块,CIB模块由3个3x3的DW卷积和2个1x1的卷积组成,下图展示了将CIB模块嵌入ELAN的方法。作者希望通过CIB模块降低模型的复杂度,同时保证模型的ap值。
在这里插入图片描述
具体的操作方式,就是先训练一个模型,然后对模型的每个阶段进行分析,选取秩最小的那个阶段,插入CIB模块,判断是否能带来AP增益,是的话则继续替换(替换过的不在参加),不然就直接输出。具体的流程如下
在这里插入图片描述
这个方法可以帮助模型降低参数量,同时保持模型的精度。这个思想是值得借鉴的,在许多大参数量的模型中,借助这种方法可以实现参数量的下降。

Accuracy driven model design

作者从大卷积核和self-attention俩个部分提高模型的准确率。

第一部分,作者将CIB模块中第二个 3 × 3 3\times3 3×3的卷积核换成了7x7,并采用了重参数化的方式,代码部分如下

class RepVGGDW(torch.nn.Module):
    def __init__(self, ed) -> None:
        super().__init__()
        self.conv = Conv(ed, ed, 7, 1, 3, g=ed, act=False)
        self.conv1 = Conv(ed, ed, 3, 1, 1, g=ed, act=False)
        self.dim = ed
        self.act = nn.SiLU()
    
    def forward(self, x):
        return self.act(self.conv(x) + self.conv1(x))
    
    def forward_fuse(self, x):
        return self.act(self.conv(x))

    @torch.no_grad()
    def fuse(self):
        conv = fuse_conv_and_bn(self.conv.conv, self.conv.bn)
        conv1 = fuse_conv_and_bn(self.conv1.conv, self.conv1.bn)
        
        conv_w = conv.weight
        conv_b = conv.bias
        conv1_w = conv1.weight
        conv1_b = conv1.bias
        
        conv1_w = torch.nn.functional.pad(conv1_w, [2,2,2,2])

        final_conv_w = conv_w + conv1_w
        final_conv_b = conv_b + conv1_b

        conv.weight.data.copy_(final_conv_w)
        conv.bias.data.copy_(final_conv_b)

        self.conv = conv
        del self.conv1

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),
            #lk为true时使用大卷积核
            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)

同时作者主要将其应用小模型上,因为大模型的感受野比较大,卷积核的作用就会比较小。

第二部分是Partial self-attention,其模型结构如下
在这里插入图片描述
从上述结构图可以看出,其采用了于CSP类似的方法,将输入的 x x x 1 × 1 1\times 1 1×1的卷积后分成俩个部分(有的是直接用1x1的卷积实现)。然后将其中的一部分直接输出至最后,另一部分输入 N p s a N_{psa} Npsa模块,并将query和key的channel砍半,显而易见这种方式是能够降低参数量。其他就是正常的self-attention和csp部分了。这部分的代码如下

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
        #原本是3*dim,现在变成了2*dim
        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, C, H, W = x.shape
        N = H * W
        qkv = self.qkv(x)
        q, k, v = qkv.view(B, self.num_heads, self.key_dim*2 + self.head_dim, 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, C, H, W) + self.pe(v.reshape(B, C, 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))

作者只将这部分用于低分辨率的部分,由于低分辨率的长度 ( H × W ) (H\times W) (H×W)会比较短,所以这样能够使这块的复杂度不会太高。

Conclusion

yolov10借助了许多轻量化卷积的方法嵌入到模型中,降低模型的参数量和计算量。同时提出了dual assigment的方法用于模型训练,从而实现了NMS-free。个人认为yolov10的意义主要在于其在NMS上的改进。NMS是目标检测模型很难避开的一个算法,当然以前也有许多NMS-free的模型,但是都会面对巨大的计算量或者训练不收敛等问题,

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

适用于智慧城市、智慧文旅等在线场景的轻量级3D数字人引擎MyAvatar简介

本人研发的国内首个纯面向web应用和小程序的轻量级3D虚拟人引擎MyAvatar。 功能简述 支持3D模型定制(写实或卡通风格均可,人物模型需实现绑定和变形)动画可以内置于模型中,也可以单独以glb或fbx格式导出并动态加载支持readyplay…

【区间动态规划】1771. 由子序列构造的最长回文串的长度

本文涉及知识点 动态规划汇总 LeetCode1771. 由子序列构造的最长回文串的长度 给你两个字符串 word1 和 word2 ,请你按下述方法构造一个字符串: 从 word1 中选出某个 非空 子序列 subsequence1 。 从 word2 中选出某个 非空 子序列 subsequence2 。 连…

图像、色彩波和抗混叠

阮一峰的博文图像与滤波中分析了图像和波的关系,主要结论如下: 图像本质上就是各种色彩波的叠加。图像就是色彩的波动:波动大,就是色彩急剧变化;波动小,就是色彩平滑过渡。色彩剧烈变化的地方,…

Android 简单的so层逆向

前言 最近搞了一下安卓。简单学习记录一下。 目标程序: xiao shui mian 也就是某个参数的逆向 准备环境 安卓机scrcpyadbfrida解包软件(不列举了) 这种环境安装这里就不多说了。教程也很多。 参数逆向分析 先抓包看看参数 这里我使用…

时序预测双飞轮,全面超越Transformer,纯MLP模型实现性能效能齐飞

本文作者简介:王世宇,蚂蚁集团算法专家,在AI创新技术部NextEvo主要负责时序算法研究方向,主导时序预测平台建设和时序算法创新研发和架构工作,推动预测与决策联动的双引擎能力。在ICLR, IJCAI, KDD, AAAI, WSDM, ICDM,…

C++面试八股文:std::deque用过吗?

100编程书屋_孔夫子旧书网 某日二师兄参加XXX科技公司的C工程师开发岗位第26面: 面试官:deque用过吗? 二师兄:说实话,很少用,基本没用过。 面试官:为什么? 二师兄:因为使…

OverTheWire Bandit 靶场通关解析(上)

介绍 OverTheWire Bandit 是一个针对初学者设计的网络安全挑战平台,旨在帮助用户掌握基本的命令行操作和网络安全技能。Bandit 游戏包含一系列的关卡,每个关卡都需要解决特定的任务来获取进入下一关的凭证。通过逐步挑战更复杂的问题,用户可…

Unity开发者转UE 新手必读

前言 本页面为熟悉Unity的用户概述了 虚幻引擎(UE)。如果你具备一些Unity知识,而且想学习如何运用自己所学的知识在虚幻引擎中工作,下面各小节将帮助你入门。 下面的截图并排显示了Unity和虚幻编辑器。各个区域采用相同的颜色来表示相同的功能。每个区…

评估大型语言模型生成文章的能力

1. AI解读 1.1. 总体概要 本文探讨了大型语言模型(LLMs)如GPT-4在生成特定领域(如计算机科学中的自然语言处理NLP)教育调查文章方面的能力和局限性。研究发现,尽管GPT-4能够根据特定指导生成高质量的调查文章&#x…

商城积分系统的设计方案(上)-- 需求分析

一、背景 用户在参与公司的促销活动,比如邀请用户下单支付,可以获得虚拟货币。它可以用于解锁学习课程。 商品在定价的时候,需支持虚拟货币,用户在购买该商品的时候,可使用虚拟货币进行支付。 在电商体系中&#xf…

logging 模块简单使用记录

文章目录 1、logging 基本架构2、Logger 日志记录器及基础配置2.1 基础配置函数logging.basicConfig() 3、Handler 日志处理器 、 Formatter 格式化器和 Filterer 日志过滤器3.1 logging 模块提供的 Handler:[官方网址](https://docs.python.org/2/howto/logging.ht…

拍照就用华为Pura 70系列,后置真实感人像轻松出片!

平时喜欢用手机记录生活的人是不是总有个烦恼,想要拍出媲美单反的完美人像,又怕照片失真,经过近期对手机摄影的探索,我发现了华为Pura70系列的真实感人像之美,它给予每个热爱生活的人直面镜头的自信,记录真…

基于AiService实现智能文章小助手

顾名思义,这个应用就是希望能利用大模型的能力来帮助我写文章,那这样一个应用该如何利用LangChain4j来实现呢?接下来我们来利用AiService进行实现。 AiService代理 首先,我们定义一个接口Writer,表示作家&#xff1a…

002 使用kibana操作ElasticSearch7.x

文章目录 4.使用kibana操作es4.1.文档操作1.put方式发送数据2.post方式发送数据3.查看索引文档 GET4.更新文档 POST5.删除文档&索引 DELETE6.批量添加数据_bulk 4.2.Query DLS(查询领域对象语言)1.url 检索数据语法2.查询所有数据3.查询全部数据并排序4.查询全部数据排序并…

面试-java异常体系

1.java异常体系 error类是指与jvm相关的问题。如系统崩溃,虚拟机错误,内存空间不足。 非runtime异常不处理,程序就没有办法执行。 一旦遇到异常抛出,后面的异常就不会进行。 (1)常见的error以及exception 2.java异常要点分析…

安全感爆棚,锁定六氟化硫SF6气体泄漏报警监测系统

一、概述 六氟化硫SF6气体已有百年历史,它是法国两位化学家Moissan和Lebeau于1900年合成的人造惰性气体, 1947年提供商用。当前SF6气体主要用于电力工业中。化学性质稳定。微溶于水、醇及醚,可溶于氢氧化钾。不与氢氧化钠、液氨、盐酸及水起…

【Knowledge Graph Context-Enhanced Diversified Recommendation(MSDM2024)】

Knowledge Graph Context-Enhanced Diversified Recommendation 摘要 推荐系统(RecSys)领域已被广泛研究,以通过利用用户的历史交互来提高准确性。 尽管如此,这种对准确性的持续追求常常导致多样性的减少,最终导致众所…

阿里Qwen-2成全球开源大模型排行榜第一,中国处于领导地位。

6月27日凌晨,全球著名开源平台huggingface(笑脸)的联合创始人兼首席执行官Clem在社交平台宣布,阿里最新开源的Qwen2-72B指令微调版本,成为开源模型排行榜第一名。 他表示,为了提供全新的开源大模型排行榜…

KubeCon 香港:移动云与云猿生联合议题《在没有专用 Operator 的情况下管理数据库集群》

KubeCon CloudNativeCon 开源峰会 AI_dev 中国大会将于 2024 年 8 月 21 日至 23 日在香港举行。来自全球的云原生技术专家与爱好者在这里相会,探讨云原生领域的技术创新与最佳实践。此外,本次 KubeCon CloudNativeCon 和开源峰会将与 AI_dev&#x…

使用ESP32开发一款chat机器人

目的:使用语音对话的方式实现和ai机器人对话,核心硬件如下 主板: ESP32S3 语音(拾音器-麦克风):INMP441全向麦克风模块 购买记录: https://oshwhub.com/shukkkk/esp32s3_tft_mp3