RT-DETRv4 是由北大、清华与百度联合推出的第四代实时端到端 Transformer 目标检测模型,2025 年 10 月发布,核心定位是兼顾高精度、低延迟与易部署,在 COCO 数据集上全面超越 YOLOv13、DEIM 等主流实时检测器,成为当前实时检测领域的 SOTA(State-of-the-Art)模型。

RT-DETRv4 继承 RT-DETR 系列无 NMS、端到端训练的核心优势,摒弃传统检测器的非极大值抑制后处理,直接输出目标类别与边框,推理速度稳定可预测。在此基础上,新增两大核心创新模块,实现 “训练时知识增强,推理时零成本”:
DSI(深度语义注入器):以 DINOv3 等视觉基础模型(VFM)为 “教师”,提取高层语义特征,精准注入检测器混合编码器的顶层特征层(F5),避免梯度冲突,高效迁移大模型的场景理解与细粒度特征能力。
GAM(梯度引导自适应调制):动态监测训练梯度范数,自适应调整 DSI 语义注入的权重,平衡知识迁移强度与检测任务优化,确保训练稳定收敛,不引入额外推理开销。其基础架构为:骨干网络→高效混合编码器(AIFI+CCFF)→不确定性最小化查询选择→动态解码器→输出,通过卷积与注意力的混合设计,在多尺度特征融合中兼顾速度与精度。
模型:RT-DETRv4
AI加速卡:910B3
CPU架构:ARM
CANN:8.5.0
docker run -it -u root -d --net=host \
--privileged \
--ipc=host \
--device=/dev/davinci_manager \
--device=/dev/devmm_svm \
--device=/dev/hisi_hdc \
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
-v /usr/local/dcmi:/usr/local/dcmi \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/sbin:/usr/local/sbin \
-v /usr/local/Ascend/driver/tools/hccn_tool:/usr/local/Ascend/driver/tools/hccn_tool \
--name detr \
quay.io/ascend/cann:8.5.0 \
/bin/bash后续的相关操作均是在容器中进行。
mkdir -p /root/RT-DETR/
cd /root/RT-DETR/
git clone https://github.com/RT-DETRs/RT-DETRv4.git
cd RT-DETRv4
将指导中的patch拷贝到路径下
git apply xx.patch
mkdir -p /root/dinov3
cd /root/dinov3
git clone https://github.com/facebookresearch/dinov3.git主要代码修改说明:
1. NPU 设备初始化顺序
最重要: NPU 设备绑定必须在以下操作之前:
(1)torch.distributed.init_process_group()
(2)导入 transfer_to_npu
(3)DDP 模型包装
原因: HCCL 通信库要求每个进程明确绑定到物理 NPU 设备。
2. 分布式安全加载
问题: 多进程同时加载同一文件会导致竞争条件
解决方案:
Rank 0 加载 checkpoint → 保存到临时文件
所有 rank 从临时文件读取
Rank 0 清理临时文件
3. Box 坐标健壮性
问题: 训练中可能产生无效 Box(x2 < x1 或 y2 < y1)
解决方案: sanitize_boxes() 自动修正无效坐标
权衡: 可能轻微影响精度(约 0.1-0.3% AP),但避免 NaN 导致训练崩溃
4. DINOv3 教师模型加载
问题: HuggingFace safetensors 键名与 DINOv3 torch 格式不同
解决方案:
(1)显式创建模型架构
(2)实现 _remap_hf_to_dinov3_keys() 进行键名转换
(3)合并 Q、K、V 权重
(4)处理缺失的键(使用模型初始化值)apt update
apt install libxcb1 libx11-xcb1
apt install -y libgl1-mesa-glx
apt install -y libglib2.0-0 libsm6 libxext6 libxrender-dev libgomp1
apt-get install -y zlib1g-dev build-essential
cd /root/RT-DETR/RT-DETRv4
pip install torch==2.5.1 torch-npu==2.5.1 torchvision==0.20.1
pip install faster-coco-eval>=1.6.5 PyYAML tensorboard scipy calflops transformers decorator attrs模型训练中需要下载教师模型DINOv3以及学生模型HGNetv2 backbone(从头训)或者RT-DETRv4-S/M/L/X(微调)(这几种暂未正式全面对外发布,可以选择基座模型自己训),可以提前下载好,参考:
pip install modelscope
mkdir -p /root/models/facebook/dinov3-vitb16-pretrain-lvd1689m
modelscope download --model facebook/dinov3-vitb16-pretrain-lvd1689m --local_dir /root/models/facebook/dinov3-vitb16-pretrain-lvd1689m
#下载好的权重文件路径: /root/models/facebook/dinov3-vitb16-pretrain-lvd1689m/model.safetensors
cd /root/RT-DETR/RT-DETRv4
wget https://github.com/Peterande/storage/releases/download/dfinev1.0/PPHGNetV2_B0_stage1.pth
mv PPHGNetV2_B0_stage1.pth ./pretrain/hgnetv2/
下载好数据,拷贝或者通过volume挂载到容器/root/RT-DETR/dataset/,这里使用COCO2017目标检测数据集进行验证

使用代码patch中已经适配过的配置文件
内容如下:
__include__: [
'../dfine/dfine_hgnetv2_s_coco.yml',
'../base/rtv4.yml'
]
output_dir: ./outputs/rtv4_hgnetv2_s_coco
teacher_model:
type: "DINOv3TeacherModel"
dinov3_repo_path: /root/dinov3/dinov3/
dinov3_weights_path: /root/models/facebook/dinov3-vitb16-pretrain-lvd1689m/model.safetensors
patch_size: 16
mean: [0.485, 0.456, 0.406]
std: [0.229, 0.224, 0.225]
HybridEncoder:
distill_teacher_dim: 768
RTv4Criterion:
weight_dict:
loss_distill: 5
distill_adaptive_params:
enabled: True
rho: 11
delta: 1
default_weight: 20
optimizer:
type: AdamW
params:
-
params: '^(?=.*backbone)(?!.*bn).*$'
lr: 0.0002
-
params: '^(?=.*(?:norm|bn)).*$'
weight_decay: 0.
lr: 0.0004
betas: [0.9, 0.999]
weight_decay: 0.0001
epoches: 132
flat_epoch: 64
no_aug_epoch: 12
train_dataloader:
dataset:
transforms:
policy:
epoch: [4, 64, 120]
collate_fn:
mixup_epochs: [4, 64]
stop_epoch: 120训练命令参考
nohup torchrun --nproc_per_node=4 --master_port=29900 train.py --config configs/rtv4/rtv4_hgnetv2_s_coco.yml --use-npu --use-amp --seed=0 --output-dir ./output/rtv4_ori > logs/train_rtv4_s_ori.log 2>&1 &
训练日志:

wget https://aisbench.obs.myhuaweicloud.com/packet/ais_bench_infer/0.0.2/ait/aclruntime-0.0.2-cp311-cp311-linux_aarch64.whl
wget https://aisbench.obs.myhuaweicloud.com/packet/ais_bench_infer/0.0.2/ait/ais_bench-0.0.2-py3-none-any.whl
pip install aclruntime-0.0.2-cp311-cp311-linux_aarch64.whl
pip install ais_bench-0.0.2-py3-none-any.whl
pip install onnx onnxsim onnxruntime
pip install opencv-pythonpython tools/deployment/export_onnx.py \
--config configs/rtv4/rtv4_hgnetv2_s_coco_correct.yml \
--resume outputs/rtv4_hgnetv2_s_coco_correct/test/best.pthatc \
--model=outputs/rtv4_hgnetv2_s_coco_correct/test/best.onnx \
--framework=5 \
--soc_version=Ascend910B3 \
--output=outputs/rtv4_hgnetv2_s_coco_correct/test/best \
--input_shape="images:1,3,640,640;orig_target_sizes:1,2" \
--output_type=FP16 \
--precision_mode=allow_mix_precision \
--log=info \
--enable_small_channel=0
使用 OM 模型对 COCO 验证集图片进行推理: 创建infer_om.py文件。内容参考:
"""
RT-DETR OM inference on COCO2017 images
"""
import os
import random
import numpy as np
import cv2
import argparse
from pathlib import Path
try:
from ais_bench.infer.interface import InferSession
except ImportError:
print("Error: ais_bench not installed. Install with: pip install ais_bench")
exit(1)
COCO_CLASSES = [
'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',
'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
'hair drier', 'toothbrush'
]
def preprocess_image(image_path, input_size=640):
"""Preprocess image for inference"""
img = cv2.imread(image_path)
orig_h, orig_w = img.shape[:2]
# Resize
img_resized = cv2.resize(img, (input_size, input_size))
# Convert to RGB and normalize
img_rgb = cv2.cvtColor(img_resized, cv2.COLOR_BGR2RGB)
img_normalized = img_rgb.astype(np.float32) / 255.0
# Transpose to CHW format
img_input = np.transpose(img_normalized, (2, 0, 1))
img_input = np.expand_dims(img_input, axis=0)
return img_input, img, (orig_h, orig_w)
def draw_boxes(image, labels, boxes, scores, threshold=0.5):
"""Draw bounding boxes on image"""
h, w = image.shape[:2]
for label, box, score in zip(labels, boxes, scores):
if score < threshold:
continue
x1, y1, x2, y2 = box
x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2)
# Draw box
cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
# Draw label
label_text = f"{COCO_CLASSES[int(label)]}: {score:.2f}"
cv2.putText(image, label_text, (x1, y1 - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
return image
def main():
parser = argparse.ArgumentParser(description='RT-DETR OM inference on COCO2017')
parser.add_argument('-m', '--model', required=True, help='OM model file')
parser.add_argument('-i', '--image', default=None, help='Image path (random if not specified)')
parser.add_argument('-d', '--data-path', default='./dataset/coco', help='COCO dataset path')
parser.add_argument('-o', '--output', default='result.jpg', help='Output image path')
parser.add_argument('-s', '--input-size', type=int, default=640, help='Input size')
parser.add_argument('-t', '--threshold', type=float, default=0.5, help='Confidence threshold')
parser.add_argument('--device', type=int, default=0, help='NPU device ID')
args = parser.parse_args()
# Select image
if args.image:
image_path = args.image
else:
val_dir = Path(args.data_path) / 'val2017'
images = list(val_dir.glob('*.jpg'))
if not images:
print(f"Error: No images found in {val_dir}")
exit(1)
image_path = str(random.choice(images))
print(f"Image: {image_path}")
# Load model
print(f"Loading OM model: {args.model}")
session = InferSession(device_id=args.device, model_path=args.model)
# Preprocess
img_input, orig_img, (orig_h, orig_w) = preprocess_image(image_path, args.input_size)
orig_target_sizes = np.array([[orig_w, orig_h]], dtype=np.int64) # [width, height] format
print(f"Original size: {orig_h}x{orig_w}")
print(f"Input shape: {img_input.shape}")
# Inference
print("Running inference...")
outputs = session.infer([img_input, orig_target_sizes])
labels = outputs[0][0]
boxes = outputs[1][0]
scores = outputs[2][0]
print(f"\nDetections: {len(labels)}")
print(f"Labels shape: {labels.shape}")
print(f"Boxes shape: {boxes.shape}")
print(f"Scores shape: {scores.shape}")
# Filter by threshold
valid_idx = scores >= args.threshold
labels = labels[valid_idx]
boxes = boxes[valid_idx]
scores = scores[valid_idx]
print(f"\nDetections above threshold {args.threshold}: {len(labels)}")
for i, (label, box, score) in enumerate(zip(labels, boxes, scores)):
print(f" {i+1}. {COCO_CLASSES[int(label)]}: {score:.3f} at {box}")
# Draw results
result_img = draw_boxes(orig_img.copy(), labels, boxes, scores, args.threshold)
cv2.imwrite(args.output, result_img)
print(f"\nResult saved to: {args.output}")
if __name__ == '__main__':
main()测试命令:
python infer_om.py -m outputs/rtv4_hgnetv2_s_coco_correct/test/best.om -i test.jpg -o result01.jpg测试结果:

官方的几个规格权重并未正式对外外部,但是公开了其backbone以及相关训练配置,以规格S为例,最终我们的训练精度如下:

官网的S精度如下:

结论:与官网文档精度保持一致(误差0.005)
1、从头训练时后验证AP为0
小规模数据集仅做训练流程的验证,精度的话规模过小会出现AP为0

问题分析:
从日志看100+epoch之后学习率几乎为0:warmup默认设置500 iterations,训练集只有100张图片,batchsize 32(4卡*8),每个epoch只有3个iterations,完成500 iterations需要大约166个epoch,所以120 epoch,学习率还在warmup阶段,模型还没有真正开始训练
2、模型数据增强导致的invalid boxes导致训练中断
例如RT-DETRv4中采用的RandomIoUCrop(源自SSD,默认启用)会导致生成一些invalid boxes从而造成训练的中断;当w/h为0时,IoU的计算NaN(NPU对零值、NaN更敏感),需要对box的最针对性适配,例如:

3、多卡DDP训练卡死
昇腾的HCCL(Huawei Collective Communication Library)与PyTorch DDP集成时,遵循对称性设计原则,所有rank必须执行相同的操作序列,这是保证梯度正确同步和模型参数一致性的基础,如果允许不对称barrier,极容易造成死锁。
4、蒸馏梯度稀释
适配过程中,多卡训练出现死锁后从报错现象本身出发,调整了模型的加载仅在rank0上,4卡在coco2017上训练模型似乎也能逐步收敛,但仔细分析后发现存在蒸馏梯度稀释问题,卡数越多越明显。因为最终的蒸馏loss是所有rank求平均,而仅rank0加载模型的话,其他rank的模型是None,按照RT-DETRv4的源码逻辑,对应的loss为0,所以整体去平均后,会导致最终的蒸馏梯度被稀释,卡数越多稀释约明显。
5、训练中间出现精度严重下降
训练中途发现训了70+epoch时,精度只有0.1,分析发现,训练在epoch39实际精度达到0.398,后面的训练精度出现下降。检查日志发现,在epoch50-60左右还存在高学习率震荡、强数据增强干扰、Mixup破坏训练。检查对比训练参数配置,发现flat_epoch等相关参数配置存在问题,官方的flat_epoch相关配置是经过精心设计的,决定了学习率衰减时机、数据增强停止的时机、训练阶段的切换。可以参考上述步骤,使用官方设置,自己调整简单参数时,有些参数不是孤立作用的,要结合在一起,比如看似只是调节了batch大小,但是有些和iteration固定数目的配置可能也会有影响。
6、训练任务中途崩溃
训练中途任务崩溃

分析发现:问题刚好发生在epoch50, 这是我们的stop_epoch配置值,此时触发了加载最佳模型刷新EMA的逻辑,8个 NPU进程同时读取通个文件,导致HCCL通信层无法处理多进程并发文件读取,触发错误崩溃。
方案:修改为分布式安全加载。由rank0加载,并通过barrier同步其他进程。
7、训练报错
训练报错如下

方案: /root/RT-DETR/RT-DETRv4/engine/rtv4/hybrid_encoder.py 245行
def with_pos_embed(self, tensor, pos_embed):
if pos_embed is not None:
# 强制把 pos_embed 放到 tensor 所在的设备(NPU)
pos_embed = pos_embed.to(tensor.device)
return tensor + pos_embed if pos_embed is not None else tensor