RT-DETR: Real-Time Detection Transformer

论文: DETRs Beat YOLOs on Real-time Object Detection (CVPR 2024)
作者: Yian Zhao, Wenyu Lv, Shangliang Xu, et al. (Baidu / 百度)
代码: PaddlePaddle/PP-DETR / lyuwenyu/RT-DETR

一句话总结:RT-DETR 是第一个实时端到端目标检测器–它用混合编码器(CNN + 稀疏 Transformer)解决 DETR 太慢的问题,用 IoU-aware 查询初始化 + CDN 训练加速收敛,全程无 NMS,在同等速度下超越 YOLOv8。


一、概述

1.1 为什么要有 RT-DETR

DETR(2020)开创了端到端检测(无 NMS、无 anchor、匈牙利匹配),但有两个致命问题:

  • 太慢:Transformer 编码器处理所有特征图的所有位置,计算量巨大;
  • 收敛慢:从头训需要 500 epoch,远多于 YOLO 的 ~100 epoch。

YOLO 系列(v1-v8)靠 NMS + anchor/anchor-free 做到了实时,但 NMS 有超参(IoU 阈值)、对密集场景不稳定。

RT-DETR 的定位:把 DETR 的端到端优势(无 NMS)做到实时速度,同时超过 YOLOv8。

1.2 与 DETR / YOLO 的定位对比

原版 DETR YOLO 系列 RT-DETR
NMS ❌ 无(端到端) ✅ 需要 ❌ 无(端到端)
标签分配 匈牙利匹配(1对1) 静态/动态(1对多) 匈牙利匹配(1对1)
预测方式 稀疏查询(~100-300) 密集预测(~8400) 稀疏查询(~300)
编码器 Transformer 处理所有特征 CNN FPN/PAN 混合编码器(CNN + 稀疏 Transformer)
实时性 ❌ 非3实时 ✅ 实时 ✅ 实时
收敛速度 ❌ 慢(500ep) ✅ 快(~100ep) ✅ 较快(CDN 加速)

RT-DETR = DETR 的端到端框架 + YOLO 的实时速度。它填补了”端到端但实时”这个空白。


二、整体架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
输入图像

Backbone: ResNet/HGNetv2
↓ 输出 C3, C4, C5 (stride 8/16/32)
Hybrid Encoder ⭐
├─ 通道投影: C3/C4/C5 -> 256 维 (1×1 Conv+BN)
├─ Transformer 编码器: 仅对 P5 (stride=32) 做自注意力 ← 稀疏,不全做
├─ FPN (自顶向下): 上采样 + CSPRep 融合
└─ PAN (自底向上): 下采样 + CSPRep 融合
↓ 输出 3 级增强特征 (256 维)
IoU-aware Query Selection
↓ 从编码器输出选 top-k 个查询(按 cls+obj 分数)
Transformer Decoder
├─ 自注意力(查询间交互)
├─ 交叉注意力(查询 -> 编码器特征)
├─ 迭代框精修(每层精修一次框)
└─ 输出 ~300 个 (类别 + 框)

无 NMS 后处理
↓ 直接取 top-k,不做 NMS
最终检测结果

源码结构极简(rtdetr.py):

1
2
3
4
5
6
7
8
9
10
11
12
class RTDETR(nn.Module):
__inject__ = ['backbone', 'encoder', 'decoder']
def __init__(self, backbone, encoder, decoder, multi_scale=None):
self.backbone = backbone
self.encoder = encoder # HybridEncoder
self.decoder = decoder # RTDETRDecoder

def forward(self, x, targets=None):
x = self.backbone(x) # C3, C4, C5
x = self.encoder(x) # Hybrid Encoder -> 3 级增强特征
x = self.decoder(x, targets) # Transformer Decoder -> 检测结果
return x

三层结构:backbone 提特征 -> hybrid encoder 融合+增强 -> decoder 预测。全程无 NMS。


三、Hybrid Encoder:核心创新 ⭐

这是 RT-DETR 能做到实时的关键。原版 DETR 对所有特征图的所有位置做 Transformer(太慢),RT-DETR 改为混合策略:CNN 做大部分融合,Transformer 只做少量关键尺度的全局增强

3.1 “混合”体现在哪

步骤 用什么 为什么
通道投影 1×1 Conv+BN 统一到 256 维
Transformer 自注意力 仅对 P5(stride=32)做 1 层 P5 特征图最小(20×20=400 位置),算得动;且大目标需全局上下文
FPN 融合(自顶向下) CNN(上采样 + CSPRep) 高效,CNN 做多尺度融合足够
PAN 融合(自底向上) CNN(下采样 + CSPRep) 同上

关键洞察:不是所有特征都需要 Transformer 的全局注意力。小目标(P3,80×80=6400 位置)用 CNN 融合就够,只有大目标(P5,400 位置)才需要 Transformer 全局建模。只在 P5 上放 1 层 Transformer,既获得全局信息又控制了计算量。

3.2 源码(HybridEncoder)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class HybridEncoder(nn.Module):
def __init__(self, in_channels=[512,1024,2048], feat_strides=[8,16,32],
hidden_dim=256, use_encoder_idx=[2], num_encoder_layers=1, ...):
# 1. 通道投影: 每级特征 -> 256 维
self.input_proj = [Conv2d(in_ch, 256, 1) + BN for in_ch in in_channels]

# 2. Transformer 编码器: 仅对 use_encoder_idx 指定的层(默认 [2] = P5)
self.encoder = [TransformerEncoder(layer, num_encoder_layers=1)
for _ in use_encoder_idx]

# 3. FPN (top-down): lateral_conv + CSPRepLayer
self.lateral_convs = [ConvNormLayer(256, 256, 1) for _ in range(2)]
self.fpn_blocks = [CSPRepLayer(512, 256) for _ in range(2)]

# 4. PAN (bottom-up): downsample_conv + CSPRepLayer
self.downsample_convs = [ConvNormLayer(256, 256, 3, stride=2) for _ in range(2)]
self.pan_blocks = [CSPRepLayer(512, 256) for _ in range(2)]

def forward(self, feats):
# 1. 通道投影
proj_feats = [self.input_proj[i](feat) for i, feat in enumerate(feats)]

# 2. ★ Transformer 仅对 P5 做(use_encoder_idx=[2])
for i, enc_ind in enumerate(self.use_encoder_idx): # enc_ind=2 -> P5
src_flatten = proj_feats[enc_ind].flatten(2).permute(0,2,1) # [B, H*W, C]
pos_embed = build_2d_sincos_position_embedding(w, h, 256) # 2D 位置编码
memory = self.encoder[i](src_flatten, pos_embed=pos_embed) # 1 层 Transformer
proj_feats[enc_ind] = memory.reshape(B, 256, H, W) # 写回

# 3. FPN top-down: P5 -> 上采样 -> 拼接 P4 -> CSPRep -> 上采样 -> 拼接 P3 -> CSPRep
# 4. PAN bottom-up: P3 -> 下采样 -> 拼接 P4 -> CSPRep -> 下采样 -> 拼接 P5 -> CSPRep
return outs # 3 级增强特征

3.3 CSPRepLayer + RepVGG

编码器中的 CNN 融合块用 CSPRepLayer(CSP 结构 + RepVGG 块):

  • RepVGG:训练时 3×3 + 1×3 双分支(精度好),部署时融合成单 3×3 卷积(速度快);
  • CSP 结构:输入分两路,一路过 bottleneck 一路直通,拼接后融合(参数效率高)。
1
2
3
4
5
6
class CSPRepLayer(nn.Module):
def forward(self, x):
x_1 = self.conv1(x) # 一路
x_1 = self.bottlenecks(x_1) # RepVGG blocks
x_2 = self.conv2(x) # 另一路直通
return self.conv3(x_1 + x_2) # 融合

四、IoU-aware Query Selection + Decoder

4.1 IoU-aware Query Selection

原版 DETR 的查询(query)是随机初始化的,收敛慢。RT-DETR 从编码器输出中按分数选 top-k 个位置作为初始查询

1
编码器输出 -> 每个位置算 cls_score × obj_score -> 排序 -> 取 top-300 作为查询初始

查询不再是”从零学”,而是”从一个有希望的起点开始学”,大幅加速收敛。这类似 YOLOX 的 SimOTA”从预测质量出发分配”,但 RT-DETR 用它来初始化查询而非标签分配。

4.2 Transformer Decoder

解码器是标准 Transformer Decoder(L 层),每层:

  1. 自注意力:查询之间交互(让不同查询学会负责不同物体,避免重复);
  2. 交叉注意力:查询 -> 编码器特征(Q 来自查询,K/V 来自编码器输出);
  3. 迭代框精修:每层在前一层基础上精修框坐标(不是从零预测);
  4. FFN:非线性变换。
1
2
3
4
5
6
7
8
9
初始查询 (300 个, IoU-aware 选出)
↓ 自注意力 (查询间避免重复)
↓ 交叉注意力 (从编码器特征读信息)
↓ 框精修 + 类别预测
Decoder Layer 1
↓ ... 重复 L 层
Decoder Layer L

300 个 (类别 logit + 框坐标)

五、训练:匈牙利匹配 + VFL + CDN

5.1 匈牙利匹配(一对一)

与 YOLO 的”一对多”不同,RT-DETR 用匈牙利匹配:每个 GT 只匹配 1 个查询(一对一),从根源上避免了重复检测,所以不需要 NMS。

匹配 cost = 分类 loss + 回归 loss(GIoU + L1),用匈牙利算法求全局最优分配。

5.2 VFL(Varifocal Loss)

分类损失用 Varifocal Loss:对正样本用 IoU 作权重(预测越准权重越大),对负样本用 focal 式衰减。比标准 Focal Loss 更好地平衡了分类与定位质量。

5.3 CDN(Contrastive DeNoising)

CDN 是 RT-DETR 加速收敛的关键训练技巧

  • 在正常查询之外,额外加入一批去噪查询:把 GT 框加噪声作为输入,让网络学习”还原”成 GT;
  • 对比去噪:正样本去噪(轻微噪声)+ 负样本去噪(大噪声),防止查询互相干扰;
  • 作用:给网络一个”已知答案”的辅助任务,加速学习如何从查询预测框。

CDN 不改变推理结构(推理时只用正常查询),纯粹是训练时的加速技巧。


六、无 NMS 端到端推理

RT-DETR 的后处理没有 NMS(源码 RTDETRPostProcessor):

1
2
3
4
5
6
7
8
9
10
class RTDETRPostProcessor(nn.Module):
def forward(self, outputs, orig_target_sizes):
logits, boxes = outputs['pred_logits'], outputs['pred_boxes']
# 解码框: cxcywh -> xyxy, 缩放到原图尺寸
bbox_pred = box_convert(boxes, 'cxcywh', 'xyxy') * orig_target_sizes
# focal loss 模式: sigmoid + top-k
scores = sigmoid(logits).flatten(1)
# ★ 直接取 top-k,不做 NMS!
topk_values, topk_indexes = torch.topk(scores, num_top_queries, dim=1)
return results # 直接输出 top-k 个检测

为什么能无 NMS:匈牙利匹配的一对一训练让每个查询学会负责不同物体,推理时不会产生大量重复框。只需取 top-k 个高分数查询即可。

对比 YOLO 的 NMS 流程

  • YOLO:8400 个框 -> obj 阈值过滤 -> NMS(IoU>0.65 抑制)-> 结果
  • RT-DETR:300 个查询 -> 直接 top-k -> 结果(无 NMS,更简洁、无超参)

七、性能

模型 AP (COCO) FPS (T4) NMS?
YOLOv8-S 44.9 128 ✅ 需要
YOLOv8-M 50.2 102
YOLOv8-L 52.9 71
RT-DETR-R18 46.7 108 ❌ 无
RT-DETR-R34 48.9 74 ❌ 无
RT-DETR-R50 53.1 74 ❌ 无
RT-DETR-R101 54.3 36 ❌ 无

RT-DETR-R50(53.1 AP)在同等速度下超越 YOLOv8-L(52.9 AP),且无需 NMS。


八、总结

RT-DETR 的核心贡献是把 DETR 的端到端框架做到实时,靠三个关键设计:

  1. 混合编码器:CNN FPN/PAN 做大部分融合 + Transformer 只在 P5 做 1 层全局增强(实时的关键);
  2. IoU-aware 查询初始化 + CDN 训练:解决 DETR 收敛慢的问题;
  3. 匈牙利一对一匹配 + 无 NMS:端到端推理,比 YOLO 的 NMS 更简洁、更稳定。

RT-DETR 证明了”端到端(无 NMS)也能实时”,在速度-精度曲线上首次让 DETR 超越 YOLO。它开启了 DETR 系列的实时化路线(后续 RT-DETRv2、DFINE 等延续)。


相关链接

  • 📝 [[20.notes/感知算法/2D检测/单阶段/YOLOX/YOLOX 详解|YOLOX 详解]] - 对比:YOLOX 用 NMS,RT-DETR 无 NMS
  • 📝 [[20.notes/感知算法/2D检测/单阶段/RetinaNet/RetinaNet 详解|RetinaNet 详解]] - 匈牙利匹配 vs IoU 阈值分配
  • 📋 论文原文: arxiv.org/abs/2304.08069
  • 📋 官方代码: lyuwenyu/RT-DETR
  • 📦 源码参考: deeplearning/detect/RT-DETR/rtdetr_pytorch/src/zoo/rtdetr/(hybrid_encoder / rtdetr_decoder / matcher / criterion / postprocessor)
  • 📋 [[10.clippings/感知算法/2D检测/DETR系列/RT-DETR/DETR系列:RT-DETR(一) 论文解析_rt-detr论文-CSDN博客]]
  • 📋 [[10.clippings/感知算法/2D检测/DETR系列/RT-DETR/RT-DETR 1、网络结构详解]]
  • 📋 [[10.clippings/感知算法/2D检测/DETR系列/RT-DETR/RT-DETR全解析:超越 YOLO,实时物体检测更快更精准(附代码)]]
  • 📋 [[10.clippings/感知算法/2D检测/DETR系列/RT-DETR/RT-DETR网络结构图]]
  • 📋 [[10.clippings/感知算法/2D检测/DETR系列/RT-DETR/RT-DETR:实时检测 Transformer]]
  • 📋 [[10.clippings/感知算法/2D检测/DETR系列/RT-DETR/《目标检测大杂烩》-第14章-浅析RT-DETR]]