RT-DETR 详解之查询去噪( DeNoise)

2024-06-11 04:36
文章标签 详解 查询 rt detr denoise

本文主要是介绍RT-DETR 详解之查询去噪( DeNoise),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引言

前面我们已经讲解了RT-DETR的基本结构与Efficient Hybrid Encoder部分,在这篇博客里,博主将主要记录RT-DETR的第二个创新点:Uncertainty-minimal Query Selection

在这里插入图片描述

查询向量选择为什么重要?

关于 Query Selection(查询向量选择),大家应该并不陌生,这个方法可谓在DETR领域大杀四方,如DAB-DETR对查询向量进行重构理解,将其解释为AnchorDN-DETR通过查询降噪来应对匈牙利匹配的二义性所导致的训练时间长的问题,DINO提出从Encoder中选择Top-k特征进行学习等一系列方法,这都无疑向我们证明,查询向量很重要,选择好的Query能够让我们事半功倍。

RT-DETR改进查询选择的思路

在RT-DETR中,Query selection 的作用是从 Encoder 输出的特征序列中选择固定数量的特征作为 object queries ,其经过 Decoder 后由预测头映射为置信度和边界框。

前面已经说过,现有的 DETR 变体都是利用这些特征的分类分数直接选择 Top-K 特征。然而,由于分类分数和 IOU 分数的分布存在不一致,分类得分高的预测框并不一定是和 GT 最接近的框,这导致髙分类分数低 IOU 的框会被选中,而低分类分数高 IOU 的框会被丢弃,这将会损害检测器的性能。

因此,RT-DETR考虑通过在训练期间约束检测器对高 IOU 的特征产生高分类分数,对低 IOU 的特征产生低分类分数。故而,作者提出了 Iou-aware Query selection。从而使得模型根据分类分数选择的 Top-K 特征对应的预测框同时具有髙分类分数和高 IOU 分数。

那么,RT-DETR到底是怎么做的呢?大家且听我娓娓道来。

RT-DETR预处理特征

进入到Decoder中后,首先是对Encoder输入的特征进行一个特征融合,将原本的三层特征展平拼接,得到扁平特征。

Encoder输入特征:

在这里插入图片描述

扁平融合后的特征:

在这里插入图片描述

随后,便可以进行真正的Decoder中的运算了。
在讲解Uncertainty-minimal Query Selection之前,RT-DETR还做了一个DeNoise的操作,该方法并非是RT-DETR所提出的,但其在这里使用了,这个方法便是查询去噪方法。

查询去噪方法

denoising 方法并非是RT-DETR所提出的,其是由DN-DETR所提出的,用于改善由于匈牙利匹配的二义性所导致的模型训练收敛慢的问题,在这里,RT-DETR使用了,denoising是一个很好的创新点,并且也具有十分大的改进空间,大家在想创新点时可以考虑它。
其实,在博主先前的博客DN-DETR详解中,博主已经讲解过DeNoising的实现过程了,今天就带着大家回顾一遍:

参数讲解

首先关于DeNoising的相关参数,都是在rtdetr_r50中定义好的。

在这里插入图片描述

随后便是判断是否使用DeNoising,该方法只在训练时使用:

在这里插入图片描述

接着便是如何生成噪声查询向量了,该部分代码的实现在denoising.py中。

加噪思路

在讲解这部分代码前,大家可以看一下博主画的这张图,了解一下DeNoising的实现思路

在这里插入图片描述

噪声组设计

我们进入denosing.py文件中,首先看一下传入的参数
label_noise_ratio为类别添加噪声的比例,此处设置为0.5,即有一半的类别要改变

在这里插入图片描述

这块代码是十分具有代表性的

首先是确定每张图像中标注样本的个数,保存在num_gts中,随后选出最大的,这个是方便我们在后面划分组时使用,因为num_denoising的熟练为100,是我们确定好的,每个batch(批次)内划分创建噪声,因此,噪声组的数目num_group=num_denoising//max(num_gts)

在这里插入图片描述

随后,生成对应的输入类别,输入标注框以及真值掩膜,其维度为:

  • input_query_class:(4,11)第一个3代表batch大小,11为该batch内图像中标注样本的最大值
  • input_query_box:(4,11,4)最后一个四代表w,h,x,y
  • input_gt_mask:(4,11)真值掩膜

这里类别初始化值 num_class3,代表背景

在这里插入图片描述

为其赋予对应的值

在这里插入图片描述

其对应位置会被赋值(绿色),比如input_class则会是对应类别,mask则是True
在这里插入图片描述
随后开始创建噪声了,要分正负样本,还要分9组,所以为 2*9,这里用到了一个torch提供的函数:

tile函数(A,reps)

A:输入的数组(array
reps:数组A重复的次数;可以有两种形式(数字和二维元组)
tile的本意有“铺以瓷砖,铺以瓦”的意思,即将数组视为瓷砖,在一个平面上将此数组平铺开来(数字对应一维,元组对应二维 tuple(纵铺个数,横铺个数)
这里使用的是元组,即纵铺为1,横铺为2*9,这很好理解,其要生成的是很多batch

在这里插入图片描述
得到的变量对应维度为:

在这里插入图片描述

可以看到,此时input_query_class的值如下,其是按照图像来划分的,第一张图像中只有两个样本,因此每11个数中只有2个不为3,而第二张图像中有11个样本,则没有出现3

在这里插入图片描述

如下图所示(注意,这里我为方便显示,将设置num_group=3,则生成的样本组数为2*3=6)绿色代表有样本,白色代表无样本。

在这里插入图片描述

生成对应的正负样本掩膜,划分正负样本,隔一组切换一次正负样本。

在这里插入图片描述

生成的掩膜如下,黄色为正样本,红色为负样本,这意味着红色样本的标注框偏移,大小变化会更大,即噪声更大

在这里插入图片描述

将正负样本掩膜与标注位置掩膜结合,并获取每个正样本的坐标

在这里插入图片描述

dn_positive_idx的值如下:,我们以第一张图片为例,其内有2个标注,则在第一组正样本的坐标为0,1,第二组正样本为22,23,(中间隔了一个负样本组)

生成

添加类别噪声

接下来便是生成类别噪声了,首先是生成噪声比例的掩膜mask,随后根据掩膜生成随机类别new_label,最后判断判断input_query_class对应位置是不是应该添加噪声,最终生成噪声input_query_class

在这里插入图片描述

在这里插入图片描述

添加标注框噪声

添加标注框噪声,完整代码如下:

在这里插入图片描述

首先进行一个转换,因为原本的标注文件中给出的是中心点坐标与宽高的标注个数,我们先将其转变为左上和右下坐标,方便添加噪声。

在这里插入图片描述

diff是根据目标框的宽高获取一个缩放的比例,其维度为torch.Size([4, 198, 4]),其中使用宽高乘以0.5,能够保证将来中心点偏移不会超出原本的标注框。

 diff = torch.tile(input_query_bbox[..., 2:] * 0.5, [1, 1, 2]) * box_noise_scale

rand_sign是目标框位移的方向,torch.randint_like(input_query_bbox, 0, 2) * 2.0 - 1.0生成的值在-1到1之间,将其作用在坐标上,即可实现上下作用的平移
随后对正样本以及负样本添加不同程度的噪声区别:

 rand_part = (rand_part + 1.0) * negative_gt_mask + rand_part * (1 - negative_gt_mask)

将偏移方向(rand_sign)与缩放程度(diff)相乘可以得到两个坐标点偏移后的位置:

rand_part *= rand_sign
known_bbox += rand_part * diff

最终将偏移后的坐标转换为中心点宽高的形式,并构造查询向量:

 input_query_bbox = box_xyxy_to_cxcywh(known_bbox)input_query_bbox = inverse_sigmoid(input_query_bbox)

遮蔽掩膜设计

这是DN-DETR中最精巧的设计了,这个屏蔽掩膜是什么东西呢,其实是为了让真值加噪生成的查询向量与Encoder输入的查询向量有所区分,因为如果Decoder对上述两者不区分的话,虽然加噪组添加了噪声,但相比于Encoder输出的查询向量也是十分强的,这就会导致作弊,因此,加噪组查询向量与原始查询向量需要加以区分,而这个做法便是遮蔽掩膜,其实这个掩膜与前面噪声构造时的很相似。

同时,不同的噪声组之间也是需要相互屏蔽的。

在这里插入图片描述

如下图所示,绿色即为True,即为可见的,白色即为不可互相见的。
在这里插入图片描述

最终,加噪完成后得到的数据为:

在这里插入图片描述

在这里插入图片描述

至此,便完成了查询加噪的过程,随后这些查询向量会与Encoder输出的特征向量进行Uncertainty-minimal Query Selection操作,这个我们下一章再讲。

码字不易,给个赞呗。

这篇关于RT-DETR 详解之查询去噪( DeNoise)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1050211

相关文章

Redis中6种缓存更新策略详解

《Redis中6种缓存更新策略详解》Redis作为一款高性能的内存数据库,已经成为缓存层的首选解决方案,然而,使用缓存时最大的挑战在于保证缓存数据与底层数据源的一致性,本文将介绍Redis中6种缓存更... 目录引言策略一:Cache-Aside(旁路缓存)策略工作原理代码示例优缺点分析适用场景策略二:Re

Java注解之超越Javadoc的元数据利器详解

《Java注解之超越Javadoc的元数据利器详解》本文将深入探讨Java注解的定义、类型、内置注解、自定义注解、保留策略、实际应用场景及最佳实践,无论是初学者还是资深开发者,都能通过本文了解如何利用... 目录什么是注解?注解的类型内置注编程解自定义注解注解的保留策略实际用例最佳实践总结在 Java 编程

MySQL数据库约束深入详解

《MySQL数据库约束深入详解》:本文主要介绍MySQL数据库约束,在MySQL数据库中,约束是用来限制进入表中的数据类型的一种技术,通过使用约束,可以确保数据的准确性、完整性和可靠性,需要的朋友... 目录一、数据库约束的概念二、约束类型三、NOT NULL 非空约束四、DEFAULT 默认值约束五、UN

Python使用Matplotlib绘制3D曲面图详解

《Python使用Matplotlib绘制3D曲面图详解》:本文主要介绍Python使用Matplotlib绘制3D曲面图,在Python中,使用Matplotlib库绘制3D曲面图可以通过mpl... 目录准备工作绘制简单的 3D 曲面图绘制 3D 曲面图添加线框和透明度控制图形视角Matplotlib

MySQL中的分组和多表连接详解

《MySQL中的分组和多表连接详解》:本文主要介绍MySQL中的分组和多表连接的相关操作,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录mysql中的分组和多表连接一、MySQL的分组(group javascriptby )二、多表连接(表连接会产生大量的数据垃圾)MySQL中的

Java 实用工具类Spring 的 AnnotationUtils详解

《Java实用工具类Spring的AnnotationUtils详解》Spring框架提供了一个强大的注解工具类org.springframework.core.annotation.Annot... 目录前言一、AnnotationUtils 的常用方法二、常见应用场景三、与 JDK 原生注解 API 的

redis中使用lua脚本的原理与基本使用详解

《redis中使用lua脚本的原理与基本使用详解》在Redis中使用Lua脚本可以实现原子性操作、减少网络开销以及提高执行效率,下面小编就来和大家详细介绍一下在redis中使用lua脚本的原理... 目录Redis 执行 Lua 脚本的原理基本使用方法使用EVAL命令执行 Lua 脚本使用EVALSHA命令

MyBatis模糊查询报错:ParserException: not supported.pos 问题解决

《MyBatis模糊查询报错:ParserException:notsupported.pos问题解决》本文主要介绍了MyBatis模糊查询报错:ParserException:notsuppo... 目录问题描述问题根源错误SQL解析逻辑深层原因分析三种解决方案方案一:使用CONCAT函数(推荐)方案二:

SpringBoot3.4配置校验新特性的用法详解

《SpringBoot3.4配置校验新特性的用法详解》SpringBoot3.4对配置校验支持进行了全面升级,这篇文章为大家详细介绍了一下它们的具体使用,文中的示例代码讲解详细,感兴趣的小伙伴可以参考... 目录基本用法示例定义配置类配置 application.yml注入使用嵌套对象与集合元素深度校验开发

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑