Showing Posts From
Detr
- 17 Apr, 2026
百度RT-DETRv2模型的训练以及在RK3588平台上的适配
百度RT-DETRv2模型的官方Github地址为:https://github.com/lyuwenyu/RT-DETR,在该项目中包含了该模型基于Pytorch和百度paddlepaddle的两套独立实现。本文记录了该模型pytorch实现的自定义数据训练、推理测试、ONNX导出以及在RK3588开发板上适配的完整记录。 源码下载和训练数据集的准备 百度RT-DETRv2模型的官方Github地址为:https://github.com/lyuwenyu/RT-DETR,首先从以上地址下载源代码。可以看到该项目中实际上分别包含了RTDETR和RTDETRv2两个模型各自的paddlepaddle和pytorch的两种实现。此处只关注其中rtdetrv2_pytorch这个目录,如红框所标记。 !331b29d9-52fd-470e-ba95-31042d04f330.png 因为RTDETR模型的训练数据默认采用COCO标注格式,所以在训练之前要提前要把自己的数据集标注格式转换为COCO格式。 在Roboflow上找到一个baby五官检测的数据集,以COCO标注格式下载该数据集,后续使用这个数据集对RT-DETRv2模型进行训练:https://universe.roboflow.com/pavel-txwf8/baby_monitoring-x30nd-1hjmq/dataset/1。 下一步开始修改训练和数据集的配置文件。在 RT-DETRv2 的源码中,rtdetrv2_pytorch\configs\rtdetrv2 在目录下包含有多个训练模型和数据集的配置文件: !image.png 这些配置文件的命名遵循了典型的 “模型缩放 + 骨干网络 + 训练策略” 的工程化逻辑。 - 模型 Backbone 核心版本: - rtdetrv2_r18vd / rtdetrv2_r34vd / rtdetrv2_r50vd:其中的r18、r34、r50 指的是Backbone部分使用的 ResNet 骨干网络的层数。其中的vd 表示使用了 ResNet-vd 结构。相比原始 ResNet,它在下采样部分做了优化,这对保持特征信息更有利,且对 NPU 非常友好。 - hgnetv2:百度自研的轻量化骨干网络。 - 模型缩放: - rtdetrv2_s / rtdetrv2_m / rtdetrv2_l:其中的s、m、l类似于 YOLO 的 Small/Medium/Large 缩放。通常涉及到隐藏层维度和编码器层数的设置。 - 训练周期数量: - 120e / 72e / 30e:其中的 e 代表 Epochs(训练轮数)。120e 表示训练120个epoch,一般用于从零开始训练或者长周期微调,精度最高;30e 训练30个epoch,通常用于快速验证或基于预训练模型的微调。 - 数据集标注格式: - coco:表示该配置默认适配 MS-COCO 数据集的标注格式。 此处以其中的rtdetrv2_r18vd_120e_coco.yml为基础进行自定义数据集的训练配置文件的修改。主要的修改内容,就是在以上配置文件的末尾增加自己数据集的相关配置信息如下: RTDETRv2模型的训练以及本地推理测试 训练之前要提前下载好模型的预训练文件,后续基于这个预训练文件进行继续训练。因为我们训练配置文件选择的是rtdetrv2_r18vd_120e_coco ,因此此处下载的预训练文件应该是rtdetrv2_r18vd_120e_coco.pth。下载地址为:https://github.com/lyuwenyu/storage/releases/download/v0.1/rtdetrv2_r18vd_120e_coco.pth。 至此,训练的数据配置文件以及预训练文件都已经准备好,下一步就是调用rtdetrv2_pytorch\tools\train.py脚本来执行训练过程: 训练命令: 训练中断后继续训练: 训练过程中和完成后生成的文件保存在rtdetrv2_r18vd_120e_coco.yml 中设置的output_dir目录中,其中包含的文件: - checkpoint0xxx.pth:训练过程中每一轮的权重文件。 - last.pth: 最后一轮的权重文件。 - best.pth: 训练过程中 mAP 最高的那一轮权重,即训练结果文件。推理测试和后续的模型转换应使用这个模型权重文件。 - log.txt: 该文件中记录了训练全过程的 Loss 和 AP 变化。 训练完成后可以使用以下命令进行推理测试,以确认训练结果的有效性。该项目中包含了一个本地推理脚本文件:rtdetrv2_pytorch\references\deploy\rtdetrv2_torch.py 。 训练过程中存在的问题: 因为训练数据集中有一些图片的分辨率太大了(6000x4000),需要修改train.py的代码,解除对输入图像分辨率大小的限制,否则在训练过程中会报错。在train.py的开头部分包含: 模型的ONNX导出 在百度的RTDETRv2_pytorch的实现中提供了一个onnx模型文件导出的脚本:rtdetrv2_pytorch\tools\export_onnx.py。但是因为我们后续要移植到RK3588平台上,需要对这个文件做一下改动,去掉其中后处理部分的逻辑,这一点对于后续进行RK3588的模型转换和板端推理而言至关重要。 基于rtdetrv2_pytorch\tools\export_onnx.py 对onnx转换脚本进行修改,主要涉及到Model的声明以及onnx导出配置方面的修改 当然因为该模型中包含有Grid Sample算子,与 RT-DETR模型的自定义数据训练以及在RK3588上的适配 一文遇到的问题相同,最新版本的RKNN运行时库(v2.3.2)不支持这个算子,所以按照相同的处理路径,在导出模型之前仍然使用Monkey Patch的办法替换掉Grid Sample算子: 然后执行以上脚本进行ONNX格式的导出(每次导出ONNX以后最好再使用onnxsim进一步简化模型文件中的算子): RK3588板端模型转换与板端运行 后续针对RK3588平台所进行的RKNN模型的转换流程和板端运行的流程与步骤与RT-DETR模型的自定义数据训练以及在RK3588上的适配 没有差异,只不过需要注意,模型转换应设置为FP16量化格式。如果设置为W8A8这样的量化模式,在板端运行的结果很差,应该是量化影响了算法的精度。
- 15 Apr, 2026
RT-DETR模型的自定义数据训练以及在RK3588上的适配
本文完整的记录了基于Ultralytics项目中的 RT-DETR 预训练模型在自定义数据集上进行的训练、ONNX导出,以及在RK3588硬件平台上的适配流程。 对于 RT-DETR 模型的实现而言,目前主要有两套独立的实现,即 Baidu 的 PaddleDetection 和 Ultralytics (YOLOv8/v11 生态)。因为我自己对于 Ultralytics/YOLO 较为熟悉,所以本文以 Ultralytics/YOLO 的实现进行试验和记录。 !image.png 1.自定义数据集的训练 因为这里使用的是Ultralytics项目下的RT-DETR实现,所以其训练过程、训练所生成的中间文件组织结构以及对训练数据的表格格式、目录结构等都与YOLO模型没有任何区别,只需要把之前在YOLO模型上训练所使用的数据集目录以及其 data.yaml 直接拷贝过来使用即可。所以如果对YOLO模型的训练流程有经验的话,在这个项目中训练RT-DETR就很容易上手了。可参考一文总结YOLOv5模型的自定义训练、测试与模型导出的全过程。 训练流程的代码也与Ultralytics项目下的其他YOLO模型类似,训练过程的代码如下: 训练流程基本上与普通的YOLO没有多大区别,有两点注意事项: - 在Windows环境中进行训练的话,训练代码需要包裹在__main__里面。这是因为在 Linux 系统中,进程的创建通常使用 fork,它会直接克隆当前的内存状态,不需要重新导入模块;而 Windows 不支持 fork,只能 spawn(冷启动一个新的 Python 解释器并导入以上脚本),这样的话,子进程启动时会再次运行一遍整个 train.py,从而又触发了一个新的训练请求,形成死循环。系统为了保护内存不被耗尽,主动抛出 RuntimeError来结束整个程序。而把训练代码包裹在__main__里面以后,只有主进程会执行train_model函数,子进程只负责执行训练过程,这样就不会进入反复新建子进程的死循环。 - batch和workers设置相对小一点,否则训练过程中很容易卡死。我一开始设置了batch为16,结果发现程序很容易卡死并报显存不足,所以如果出现训练过程稳定性问题的时候可以尝试把workers和batch这两个参数设置小一点。 以上的训练执行过程明显比使用相同数据集训练的YOLOv8模型耗时要长一些,应该是RT-DETR模型的计算复杂度要高于 YOLOv8。训练结果同样保存在runs目录下的best.pt文件。 2.Grid Sample算子的梦魇与Monkey Patch 在RK3588硬件上跑AI模型,大致的路径无非是: - 在PC端基于Pytorch等框架完成模型的训练; - 把训练的pt格式模型文件转换为更通用的ONNX格式; - 使用瑞芯微的RKNN-Toolkit2工具进行板端模型转换,把ONNX格式的模型转换为RKNN格式; - 在RK3588板端使用rknn-toolkit-lite2 工具(Python)或者C/C++语言把模型跑起来,在板端完成推理测试得到结果。 所以既然前面的训练过程已经完成,那么下一步自然就是进行ONNX格式的模型转换。但是这一步出现了一个由Grid Sample算子所导致的很大的问题: - Grid Sample算子是在Opset 16中被支持的,所以要能够导出ONNX成功,必须要设置Opset版本为16。设置为低于16的Opset版本,在导出ONNX模型这一步会报错。 - 如果把Opset设置为16的话,使用RKNN-Toolkit2工具(2.3.2版本)确实可以成功导出RKNN模型,但是这个模型放在RK3588板端跑的话,配合2.3.2版本的librknnrt.so文件会出现段错误的问题,原因是2.3.2版本的librknnrt.so文件根本不支持Grid Sample这个算子。也就是说,2.3.2版本的RKNN-Toolkit2工具认为Grid Sample算子是可以支持的,所以模型转换通过;而2.3.2版本的librknnrt.so文件根本就没有实现这个算子,所以板端运行会出现段错误的问题。瑞芯微的算法团队发布版本的时候不需要同步一下吗? 对于以上问题,当然是可以修改模型的结构,使用其他更通用的算子替换掉Grid Sample算子,然后重新训练,就可以从根本上解决这个问题。 但是,如果不考虑算法在板端的运行速度的话,其实是可以用一个简单的办法绕过这个算子:Monkey Patch。 所谓的Monkey Patch就是对于要导出ONNX的模型,在导出之前,先把某个板端不支持的算子用更常用的算子替换掉,这样在ONNX导出的时候,根本就看不到这个Grid Sample算子。具体来讲,就是在导出ONNX模型之前先用以下的代码进行Grid Sample算子(F.grid_sample)的替换: 3.ONNX模型的导出与RKNN转换 解决了以上的Grid Sample算子的问题,后续的ONNX导出就比较简单了。如如何理解ONNX模型导出的Opset版本?一文所总结的:在 Rockchip NPU的2.3.2版本的模型转换工具和板端NPU驱动上最高能够支持的Opset版本就是15。实际的部署过程中,最好的Opset版本设置应该是12或者13,避免版本过新有可能带来的稳定性和兼容性问题。 以上导出的ONNX格式的模型就是能够在RK3588上得到良好支持的OPSet=13的版本,接下来就是使用RKNN-Toolkit2工具进行板端模型转换,把ONNX格式的模型转换为RKNN格式: 4.板端推理运行 最后在RK3588板端使用rknn-toolkit-lite2 工具进行板端推理就可以看到运行的结果了。不过感觉推理执行的速度比较慢,可能跟手动替换了Grid Sample算子有关: !result_fp16_final.jpg
- 14 Apr, 2026
RT-DETR(RealTime DEtection TRansformer)网络架构与计算流程详细总结
本文详细介绍了Baidu提出的基于Transformer架构的图像目标检测模型RT-DETR的网络结构及其数据在网络中的计算流程。 RT-DETR模型简介 之前在DETR(DEtection TRansformer)网络架构与计算流程详细总结整理了基于Transformer的计算机视觉目标检测模型DETR的网络架构。 RT-DETR(Real-Time DEtection Transformer) 由百度团队开发,旨在解决传统 DETR 模型由于计算量巨大而无法满足实时场景需求的问题,RT-DETR 的出现标志着 Transformer 架构正式进入了工业级实时检测的战场,实际上 RT-DETR 是第一个真正实现实时性能的端到端 Transformer 检测器。 !image.png 与 YOLO 系列通过缩放逻辑提供不同规模的模型版本相同,RT-DETR模型也包含有两个版本:RT-DETR Large(32M参数)和RT-DETR Extra-Large(67M参数),前者性能稍差,但对于算力资源的需求也相对较低,适合在嵌入式边缘端部署。 与Facebook的DETR模型相同,RT-DETR模型的整体架构也由三个部分组成: - 由卷积网络组成的主干网络Backbone。 - 混合编码器。 - 解码器与检测头。 下文对上面三个部分的结构以及数据在其中的计算流程进行详细总结和解释。 Backbone 与DETR架构相同,在RT-DETR模型中的Backbone 是整个模型的特征提取引擎,负责从输入的原始图像中提取多尺度(标准的DETR模型只会提取最小分辨率的尺度特征)的特征图。 RT-DETR 官方实现的Backbone支持两种网络结构选项:HGNetv2 和 ResNet 系列。 - DETR的Backbone网络使用的也是相同的ResNet50和ResNet101。与DETR在主干网络只输出一个 1/32 尺度的特征图不同的是,RT-DETR 的主干网络会输出三个不同比例的特征图(如上图标记的 S3, S4, S5),分别对应原图尺寸的 1/8, 1/16, 1/32,这些特征图包含了从局部纹理到全局语义的不同层级信息。 - HGNetv2 (Higher-order Geometric Network)是百度自研的基于卷积神经网络的Backbone网络结构。它的核心思想是利用深度可分离卷积和特定的结构重参数化来提升精度,同时保持低延迟。 无论主干网络是使用 ResNet 还是 HGNetv2 ,输入的图像数据进入主干网络后,都会经历 5 个阶段(Stage 1-5),而每经过一个 Stage,特征图的长宽减半,通道数增加(这一点跟YOLO模型的主干网络也是相同的)。在输入图像分辨率为640x640的情况下,主干网络的输出为: - Stage 3 (S3): 输出特征图尺寸为 (C_3, 80, 80) —— 尺度为 1/8。 - Stage 4 (S4): 输出特征图尺寸为 (C_4, 40, 40) —— 尺度为 1/16。 - Stage 5 (S5): 输出特征图尺寸为 (C_5, 20, 20) —— 尺度为 1/32. 以上的C_3,C_4,C_5分别为三个阶段的通道数。 位置编码 在特征图的位置编码方面,RT-DETR 与 DETR的计算公式与流程相同,两者默认都使用正余弦位置编码 (Sine-Cosine Positional Encoding)。 对于特征图上的一个点 (x, y),其编码由不同频率的 sin 和 cos 函数生成,每个x和y各生成128维的向量,最后两个向量合并成一个长度为256的向量。具体的计算公式和流程可以参考DETR(DEtection TRansformer)网络架构与计算流程详细总结的相关部分。 但是需要注意的是,对于 RT-DETR Backbone部分输出的特征图而言,只会将 S5 特征图拉平(Flatten)成一个长序列,对这个最小分辨率的特征图上的所有像素点应用位置编码,并送入 Encoder 进行自注意力计算,因为 RT-DETR 认为只在最低分辨率特征图上做全局注意力计算最划算。S3和S4这两个分辨率较大的特征图会直接进入会直接进入混合编码器中的CCFM模块进行融合计算,不会参与全局注意力运算,如下所述。 混合编码器:AIFI_+CCFM 接下来就是 RT-DETR 的混合编码器部分,这是 RT-DETR 模型最核心的部分,这是这部分的设计能够使得模型兼顾 Transformer 的全局建模能力与实时性。 !image.png 如上图所示,混合编码器主要由两个核心模块组成:AIFI 和 CCFM。其中主干网络输出的 S5 特征图会送入AIFI模块进行处理,输出相同维度的 F5 特征图;而 F5 特征图与主干网络输出的S4,S5 这两个特征图一起送入CCFM模块进行更充分的特征融合。 但无论是在AIFI还是CCFM中进行处理之前,首先要对主干网络输出的 S3, S4, S5 特征图进行维度对齐。 维度对齐 为什么要进行维度对齐?这是因为,主干网络(如前述的 ResNet 或 HGNetv2)的不同阶段输出的通道数( C_3,C_4,C_5 )是不一致的: - S3 层输出 512 通道 - S4 层输出 1024 通道 - S5 层输出 2048 通道 在 RT-DETR 的架构中,为了让不同尺度的特征能够进行在后续的处理过程中相加融合以及送入统一维度的解码器,所有尺度的特征图最终都必须统一到相同的通道数(在 RT-DETR 中默认为 256)。 因此,这一步就是要把不同阶段输出的通道数都统一对齐到256。具体的对齐方式很简单,就是对 S3, S4, S5 的每一层分别应用一个 1 x 1 的卷积层,将其通道数从 512/1024/2048 统一压缩到 256 通道即可。经过这个1 x 1卷积后,就得到了三组通道数完全相同(即数据维度)、但空间分辨率不同的特征图。 AIFI AIFI:基于注意力的内尺度特征交互模块(Attention-based Intra-scale Feature Interaction)。该模块专门负责处理来自主干网络最深层、分辨率最低的特征图(也就是主干网络输出的最小分辨率特征图S5)。 > AIFI的核心本质上就是一个单层的 Transformer 编码器结构,这个编码器的输入只有Backbone的 S5 特征图。 为什么不需要对 S3 和 S4 进行自注意力计算? 这是因为,高分辨率特征图(S3, S4)包含的是局部细节,只有最低分辨率的特征图(S5)才包含了丰富的语义信息和全局上下文,因此全局相互作用只需要在低分辨率特征图中进行提取。最重要的是,编码器部分往往是计算瓶颈,如果对所有尺度的特征图进行全量的自注意力计算,复杂度随像素数量呈平方级增长,只在最低分辨率的 S5 特征图上进行自注意力计算,极大地降低了计算量(FLOPs),同时确保了模型能提取到图像中目标之间的全局关系。 经过以上的维度对齐操作后,输入到AIFI模块的 S5 特征图的维度是(256, 20, 20)。接下来的计算流程与标准的Vision Tranformer Encoder的计算流程相同,首先把这个(256, 20, 20) 特征图展平为长度400,维度为256的向量序列,然后给这个向量序列叠加位置编码信息。在特征图的位置编码方面,RT-DETR 与 DETR的计算公式与流程相同,两者默认都使用正余弦位置编码 (Sine-Cosine Positional Encoding)。具体的计算公式和流程可以参考DETR(DEtection TRansformer)网络架构与计算流程详细总结的相关部分。 然后就是标准化的多头注意力计算(默认为8个头)和前馈网络(FFN)的处理,最终经过 AIFI 处理后的 S5 特征序列会重新 Reshape 回 (256, 20, 20) 的张量形状,这就是上面架构图中的 F5 。 CCFM 在 RT-DETR 中,CCFM 舍弃了传统 DETR 计算复杂的自注意力计算,转而使用基于卷积神经网络的结构来处理不同分辨率特征图之间的融合,这一点与YOLO中使用的PANet的概念非常类似。既然是融合不同尺度的特征,自然也就包含两个融合路径: - Top-down (自上而下):将高层语义特征向下传递。 - Bottom-up (自下而上):将底层定位特征向上传递。 CCFM进行两个方向的特征融合操作的核心,在于其 Fusion 模块,如下图所示。 !image.png 假设输入Fusion模块的两个特征图分别为 F_high(来自高层的特征)和 F_low(低层的原始特征),且它们的通道数都已经对齐为 c,并且高层和低层特征图的分辨率已经通过之前的 Upsample或者Downsample 环节变换成了相同的分辨率。那么Fusion模块的工作流程如下: - 特征拼接 (Concatenate):将两个输入通道数为 c 的特征图在通道维度合并,输出一个通道数为 2c 的特征张量。 - 支路分流(Feature Splitting):拼接后的通道数为 2c 的特征图进入两个并行的支路,这两个支路都分别使用了一个 1 x 1 卷积处理,把通道数由 2c 压回到 c。 - 对于下支路而言,还要额外进行连续N个RepBlock的处理。这个RepBlock本质上就是一个3 x 3的卷积,通过连续的卷积层提取局部空间特征。 - 特征融合 (Element-wise Add):将上支路的基础特征图与下支路经过 RepBlock 处理后的增强特征图逐元素进行相加,通道数和分辨率均保持不变。 因此,对于每个Fusion模块而言,其输入的两个特征图的分辨率与通道数,与其输出的特征图的分辨率和通道数相同。 而对于整个CCFM模块而言,其输入可以分为三个部分:AIFI 模块对S5特征图处理后的输出F5,主干网络 S4 和 S3 特征图降维后的特征图。那么CCFM要实现的功能就是充分融合三个不同尺度的特征图中的信息,融合方式与YOLO的PANet大同小异,都是通过UpSample(下图中的黄色方块)和DownSample(下图中的蓝色方块)把不同尺度的特征图分辨率变换到相同的分辨率,然后再Fusion Block中进行融合操作。 !image.png 经过 CCFM 模块的双向充分融合,混合编码器部分最终从三个Fusion Block上输出了三个融合增强后的特征图: - P3 (80 x 80 x 256):包含丰富的细节,利于检测小目标。 - P4 (40 x 40 x 256):中等尺度。 - P5 (20 x 20 x 256):包含深层语义,利于检测大目标。 最后,再将这三个特征图进行展平操作,得到三个维度为256的序列化向量(6400 x 256,1600 x 256,400 x 256),然后把三个序列拼接(这就是CCFM模块的输出C的作用)起来,最终输出一个 8400 x 256 的长序列。 解码器与检测头 RT-DETR 最后部分负责基于前一阶段(即混合编码器部分的输出)输出的 8400 x 256 长序列(针对640x640分辨率的图像输入)进行目标检测的端到端检测,这部分主要由 IoU 感知查询选择模块 (IoU-aware Query Selection) 和 Transformer Decoder 组成。即混合编码器输出的数据并不会直接送入解码器,而是要先使用一个IoU 感知查询选择的模块对其进行筛选,从Encoder的输出里挑选最有希望的query作为Decoder的输入,以此来降低Decoder的运算量。 !image.png IoU 感知查询选择 IOU-aware Query Selection这个部分的整体工作逻辑就是:利用混合编码器的输出结果(8400 x 256),按预测 IoU 质量筛选出 Top-K 个(默认为前300个)最可能是真实目标的候选,作为 Decoder 的 queries。 首先,为了实现 IoU 的感知,RT-DETR 在 混合编码器的输出端设计了一个轻量级的检测头。这个检测头并不是一个深层次的网络,而是一个极其精简的线性预测层集合,以混合编码器输出的 8400x256(可以认为是三张特征图包含有8400个patch) 的长序列做为输入,通过3个独立的分支,分别使用各自的线性预测层,得到8400个Patch对应的分类预测、边界框预测以及IOU预测结果。 三个分支都把输入的256维特征映射为其输出的目标维度: - 分类分支:输出维度 8400 x num_classes,预测每个点属于各个类别的置信度。 - 回归分支:输出维度 8400 x 4,预测每个点相对于其坐标原点的偏移量 (x, y, w, h)。 - IoU 分支: 输出维度 8400 x 1,预测该点对应的预测边界框与潜在检测目标真值框之间的IoU 质量分。 有了以上三个分支的输出数据后,就可以按照以下公式构建出来8400个质量分数: 前者为当前Patch在分类分支上置信度数值最大的那个类别对应的置信度数值,后者则是这个Patch的IoU质量分。通过这个质量分数来进行评估,只有当模型既确定它是这个类别,又确信自己能框准它时,这个点才会被选入后续的 Decoder。 然后对以上的8400个质量分数进行 Top-K 降序排序,然后选出质量分数最高的300个做为该阶段的输出。因此,通过以上流程,就相当于从8400个候选框中,以质量分数作为标准,选出来其中的300个作为后续进一步筛选的基础,而不是把所有的8400个候选框全部作为备选框,这样就大幅度的降低了Deocder阶段的计算量。 最终 IoU-aware Query Selection 模块的输出不是一个张量,而是一组结构化信息。对于以上的 Tok-k 计算流程中选择出来的每个 query,在这一环节都输出两部分信息: - Content Query:每个特征点对应的 256 维特征,这些向量被用作下一阶段Decoder中自注意力模块的输入,维度为 300 x 256。 - Reference Points:由前述回归分支所输出的坐标位置 (x, y, w, h),维度为 300 x 4。 Decoder Decoder部分的结构仍然是标准的:自注意力模块+交叉注意力模块+前馈模块。只不过为了兼顾计算速度,这里的交叉注意力模块并没有采用标准 Transformer 那种全量的 Cross-Attention(即每个 Query 都要和 8400 个点算一遍),而是采用了Deformable Attention(可变形注意力)。 与标准的Transformer Decoder的架构类似,RT-DETR模型的Decoder部分的网络结构包含有6层相同网络模块的堆叠结构,每一层的包含有独立的自注意力计算模块+跨尺度采样交叉注意力模块+前馈网络FFN模块+由线性层构成的分类头和回归头。 1. 自注意力模块 这一步的作用是让 300 个 Content Query 之间充分地进行信息交换。 这个自注意力模块以 300 x 256 维度的Content Query作为初始输入,以Reference Points作为参考生成对应的位置编码,与Content Query相加后,作为自注意力计算模块的输入,自注意力模块的计算流程可以参考一文彻底搞懂Transformer模型的Encoder结构与计算流程。 自注意力模块的输出为经过充分信息交换后的Content Query,维度仍然为 300 x 256。 1. 跨尺度采样交叉注意力模块 交叉注意力模块的输入数据包含三个部分: - 前面的自注意力模块输出的更新后的Content Query,维度为 300 x 256。 - 300个预测框的位置坐标Reference Points,来自于IOU-aware Query Selection模块的输出(第一个decoder层)或者来自于前一个decoder模块回归头的更新坐标(后面的五个decoder层)。 - Encoder Features,混合编码器部分输出的全局特征序列(包含 S3, S4, S5 三个尺度),其维度为 8400 x 256。 需要注意的是,RT-DETR模型Decoder部分中的交叉注意力模块,不同于标准的Decoder中的交叉注意力运算,它所进行的交叉注意力运算不会对Encoder Features所包含的所有的 8400 x 256 维度的数据做矩阵乘法,而是以 300 个预测框的中心作为参考点,在这个参考点的附近有选择地进行采样,在每个参考点附近的采样点对其进行交叉注意力运算(也就是所谓的Deformable Attention,可变形注意力运算),这样就大大减少了交叉注意力的运算复杂度,从而实现了计算效率与精度之间的平衡。 这个可变形交叉注意力模块的设计,是RT-DETR模型能够实现实时性能的关键之一。 无论如何,经过了以上这个可变形交叉注意力模块的计算之后,其输出数据为融合了多尺度局部图像特征后的新的 Content Query 向量,维度仍然是 300 x 256。 1. 前馈网络FFN模块 该模块的目的是增强特征的非线性表达能力,类似于 CNN 中的全连接层。 与标准的Encoder以及Decoder模块相同,FFN 模块的输入数据为上一步交叉注意力计算输出的 Content Queries (维度为[300, 256])。 FFN模块的计算流程是标准的 Linear -> ReLU -> Linear 结构,通常中间维度会扩大(如 1024 或 2048)。而输出数据则是深度映射后的 Content Queries,维度仍然保持为 [300, 256]。 1. 分类头/回归头 输入数据均为前一层前馈网络模块输出的Content Query,维度为 300 x 256。分布通过独立的线性层映射分类预测值和坐标偏移量。 - 分类头:经过线性层映射到目标类别数量 num_classes。输出数据为分类概率 Pred Logits,维度为 [300, num_classes]。 - 回归头:同样通过线性层预测一个预测框坐标的偏移量 ,然后将这个坐标偏移量更新于本层的输入 Reference Points上,下一个模块使用的 Reference Points就是经过偏移量更新后的值。 模型输出 RT-DETR模型最终的输出,就是Decoder部分最后一个Decoder block的分类头和回归头,这两个独立的检测头分布输出300个检测框的分类判断值和检测框的坐标值。 - 分类头输出分类预测分数 (Pred Logits): 维度为 [300, num_classes]。每一个 Query 都会对所有类别给出一个得分。 - 回归头输出预测坐标 (Pred Boxes): 维度为 [300, 4]。这是经过Decoder部分 6 层Decoder Block的不断修正后的最终坐标 (x, y, w, h)。 接下来如何从这300个检测框得到最终呈现给检测结果呢? 首先,对以上分类头输出的 Pred Logits 进行 Sigmoid 处理,将其转化为 0 到 1 之间的概率值。然后以每个 Query 在所有类别中的最大得分作为该框的置信度。此时,就拥有了 300 个带类标和置信度的预测框。 然后进行阈值过滤 。通常会设置一个置信度阈值 (例如 0.5)。系统会直接丢弃所有得分低于该阈值的框,并输出置信度大于该阈值的检测框。 - 这一部分的关键点在于,由于 Transformer 的自注意力机制已经在内部完成了去重(抑制了指向同一目标的重复 Query),所以理论上剩下的检测框通常就是互不重叠的高质量检测结果。 参考资料 - RT-DETR: Paper Explanation and Inference - lyuwenyu/RT-DETR: [CVPR 2024] Official RT-DETR (RTDETR paddle pytorch), Real-Time DEtection TRansformer, DETRs Beat YOLOs on Real-time Object Detection. 🔥 🔥 🔥
- 18 Mar, 2026
DETR(DEtection TRansformer)网络架构与计算流程详细总结
本文详细介绍了Facebook在2020年提出的基于Transformer架构的图像目标检测模型DETR的网络结构及其数据在网络中的计算流程。 DETR简介 DETR 是由 Facebook AI Research (FAIR) 在 2020 年提出的针对计算机视觉领域中目标检测方向的AI模型,首次把NLP领域中广泛应用的 Transformer 架构引入到了计算机视觉领域。它彻底改变了目标检测领域的传统设计范式,将目标检测任务从繁琐的各种组件和处理流程的堆砌简化为了一个真正的端到端的集合预测问题。 在 DETR 模型出现之前,在目标检测领域的主流检测器(如 Faster R-CNN, YOLO, SSD)都高度依赖各种设计组件: - Anchor Boxes (锚框):基于训练数据集的总体情况预设检测目标的不同尺度和比例。 - NMS (非极大值抑制):用于在模型输出数据的后处理过程中消除重复的检测框。 - 极其复杂的正负样本匹配策略。 而DETR 的核心创新则在于:通过利用 Transformer 结构的全局建模能力,直接输出一个固定数量的预测集合(通常是 100 个),然后通过二分图匹配 (Bipartite Matching) 算法与真实标签(Ground Truth)进行一对一匹配。 从架构上讲,DETR 网络主要由三个部分组成:CNN Backbone,Tranformer编解码器,检测头。 !image.png CNN Backbone DETR网络架构以卷积神经网络CNN结构的BackBone部分开始,Backbone网络采用标准的Resnet网络(原始论文中,作者使用的 Backbone 网络是Resnet50和Resnet101)。该Bonebone网络作为输入图像的特征提取器,用于处理原始输入图像以产生丰富的视觉特征向量。 - 有关 Resnet 的网络结构可参考:CNN经典网络模型架构学习之Resnet。 在图像处理的处理维度上,假设 Backbone 的输入图像尺寸为 (3, H, W),那么该部分经过多阶段 Resnet 进行的特征提取后会输出一个降维后的特征图。在标准的 DETR 实现中,特征图下采样的倍数通常是 32 倍,因此输出特征图的维度是 (C, H/32, W/32)。而通道数 C 通常使用一个1x1卷积投影到256,用以匹配 Transformer 的输入维度。 - 如果输入图像分辨率为 800 x 800,输出特征图的分辨率就是 25 x 25。 参考ViT架构中Transformer在计算机视觉领域中的应用(一文入门Vision in Transformer(ViT)模型的架构),Transformer 接收的是序列数据(Sequence),而不是矩阵形式的向量。因此,Backbone 中Resnet网络所输出的 (25,25,256) 的特征图会被展平拉直成一个长度为 625 的向量序列,其中的每个元素为长度256的向量。 !image.png 位置编码 同样的,卷积神经网络本身由于平移不变性和局部感知,能隐式的感知位置信息。但 Transformer 处理的序列数据需要额外在展平的向量序列上增加位置编码信息,这一点跟自然语言处理中对文本信息增加位置编码信息是一致的。 DETR 对BackBack输出特征图序列的位置信息采用了固定正余弦二维位置编码(Fixed 2D Sinusoidal Positional Encodings)。大致的做法是:将特征图每个像素位置的编码信息分为 x 方向和 y 方向,分别进行编码,最后将它们拼接(Concatenate)起来。如上所述,特征图经过展平拉直后每个像素的向量长度为256,那么就分配 128 维来编码 x 坐标,另外的 128 维来编码 y 坐标,将两者拼接后形成最终的 256 维位置特征向量。 对于特征图上每个像素的 (x,y) 坐标,每个 x 对应一个 128 维的向量,这个向量由 64 组正余弦对组成,其正余弦对的计算公式分别为: 同样是由64组正余弦对组成的128维向量,采用相同的计算公式计算。两个128维向量再拼接得到一个256维的位置向量,这样得到的向量维度正好与经过 1 x 1 卷积后的特征向量维度对齐,位置编码信息的维度同样是长度为 625 的向量序列,其中的每个元素为长度256的向量。。 Transformer Encoder-Decoder 如上所述,经过Backbone对图像的特征提取、特征图展平拉直以后,送入Transformer Encoder的数据维度就是长度为 625 的序列向量,序列中每个元素的维度维 256。需要注意,BackBone 输出的数据与并不会与位置编码向量直接相加,而是在计算注意力时将位置向量注入到 Query 和 Key 的计算中,这一点是与标注的自然语言处理的Transformer计算流程不同的地方。 下图是 DETR 的Transformer Encoder与Decoder的处理流程架构: !image.png Encoder Encoder的多头自注意力模块采用了 8 个 Head,因此每个 Head 的维度为 。每一个 Head 的Q、K、V矩阵的计算如下: - Query (Q): → 维度: 625 x 32 - Key (K): → 维度: 625 x 32 - Value (V): → 维度: 625 x 32 > 注意:在计算Query和Key的时候,把 Backbone 提取出来的特征向量 Src 与其位置编码 Pos 相加进行计算,Value 的计算不需要加入位置编码,因为 Value 负责提供内容信息,而 Q 和 K 负责定位和匹配。 接下来对于多头注意力模块的计算仍然遵循标准的计算流程,在如何理解Transformer架构中的多头注意力机制?一文中已经非常详细的总结了多头注意力模块的计算步骤。 总之,从输入和输出数据的维度上讲,每个 Encoder 模块(上面架构图左侧虚线框部分)输入的特征图展平向量和位置编码向量的维度是 625 x 256 , 而其输出数据的维度同样是 625 x 256 。DETR 模型默认包含有连续的6个Encoder模块,最终 Encoder 部分输出的数据维度同样是 625 x 256 。 Encoder 的工作逻辑就是:利用全局注意力机制,对前面的Backbone卷积网络提取的局部特征进行上下文建模,最终输出一个与输入尺寸相同的增强特征序列,其中每个点都包含了全局的上下文信息和语义特征。 Decoder 对于 Decoder 部分架构的理解,首先定义Decoder的输入。Decoder 的输入包含两个部分: - Encoder的输出,这一部分比较好理解,就是前面最后一个 Encoder 模块输出的维度为 625 x 256 的张量。 - Object Queries (对象查询向量):这是一个维度为 100 x 256 的张量。在训练阶段,它是可学习的参数(类似于 Embedding),训练完成后这个100 x 256维度的张量就作为固定的参数用于后续图片的推理流程。这 100 个向量就代表着 100 个候选框。 如下图所示的Decoder Block的架构,每个Decoder Block从下到上依次包含有三个部分:多头自注意力模块(Multi-Head Self-Attention),多头交叉注意力模块(Multi-Head Attention),前馈模块(FFN)。 !image.png 首先是自注意力模块(上图中的Multi-Head Self-Attention模块)。这个自注意力模块的计算流程与标准的Transformer自注意力的计算流程稍有差异:标准的Transformer自注意力模块的输入是增加了位置编码信息的输入向量,然后基于这个输入向量分别与 这三个参数矩阵运算得到 Q,K,V 向量;而以上自注意力模块的计算逻辑则是: 以上自注意力计算的逻辑,实际上把输入的Object Queries同时作为输入数据和其位置编码向量来使用,这就是为什么在自注意力计算Q和K的过程中要对Object Queries进行自加操作的原因所在。 > 为什么是对相同的输入Object Queries进行自加,而不是对这个输入直接乘以2呢?这是因为,实际上Decoder部分有6个连续叠加的Decoder block,而只有第一层的decoder在计算Q和K的时候用的是Object Queries的自加作为输入,后续的decoder在进行自注意力模块计算的时候是使用Object Queries(作为位置向量信息)和前一层Decoder的输出相加来作为其输入的。 经过以上自注意力模块的计算后,其输出数据的维度为 100 x 256。 接下来是交叉注意力模块Multi-head Attention部分的计算。在交叉注意力模块中,Decoder 自注意力模块的输出扮演的是主动提问者的角色,而 Encoder 输出的特征图则是知识库。 交叉注意力模块的输入数据有三个部分:Decoder 自注意力模块输出的object_queries(维度为(100,256)),Encoder输出的特征图信息encoder_features(维度为(625,256)),以及与Encoder部分相同的空间位置编码信息(维度为(625,256))。在这种情况下,Q,K,V 三个张量的计算逻辑及其数据维度如下: - Q (Query): → (100, 256) - K (Key): → (625, 256) - V (Value): → (625, 256) 交叉注意力模块后续的计算逻辑以及前馈网络模块FFN仍然与标准的Decoder Block的计算流程相同,具体可以参考一文彻底搞懂Transformer模型的Decoder结构与计算流程,最终以上的整个Decoder Block的输出维度与其输入维度相同,都是(100,256)。DETR网络结构右侧的Decoder部分总共包含有6个连续叠加的Decoder Block,每个block的输出作为下一个block的object queries输入,最终整个Decoder部分的输出数据维度仍然是 (100,256)。 检测头 如上所述,经过整个 Decoder 部分的连续6个Decoder Block的叠加处理后,最终Decoder部分输出的数据维度是(100,256)。那么DETR模型最后的检测头部分的任务,就是将这 100 个高维向量映射为人类可读的类别标签和边界框坐标。 在检测头结构的设计上,DETR 采用了两个并行的 FFN(前馈神经网络)分支,它们共享 Decoder 的输出,但负责不同的任务。 !image.png 分类头 (Classification Head)的结构是一个简单的线性层(Linear Layer)。该线性层的输入数据维度为 100 x 256,输出数据为 100 x (K+1)。其中 K 是目标数据集的类别数(如 COCO 的 80 类),+1 代表背景类(no object)。最后的激活函数使用Softmax,它会为每个 Query 分配一个概率分布,指示该 Query 对应的物体属于哪一类。 回归头 (Bounding Box Regression Head)的结构是一个具有 3 个隐藏层的多层感知机(MLP),每层之间带有 ReLU 激活函数。整个回归头的输入数据维度为100 x 256,输出数据维度为 100 x 4。其数值的含义是归一化后的中心坐标及宽高。 在以上输出头结构的情况下,对于每张图片,DETR模型会输出100个检测框的坐标信息(回归头),每个检测框对应一个长度为 K+1 的分类信息。在进行背景框过滤时,只需要设定一个阈值(例如 0.5),过滤掉那些分类结果为背景类别(no object)或得分过低的预测框即可,不再需要YOLO模型非常复杂的NMS计算流程了。 参考资料 - facebookresearch/detr: End-to-End Object Detection with Transformers - Introduction to DETR - Part 1 | DigitalOcean