论文要点
DEIM(DETR with Improved Matching for Fast Convergence)是一套面向实时目标检测的训练框架,核心目标很明确:在保留 DETR 系列端到端思路的前提下,把原本偏慢的收敛速度拉起来。
研究背景
目标检测一直是计算机视觉里的基础任务,在自动驾驶、机器人导航、无人机巡检这些场景里都离不开它。DETR 的思路很干净,直接用 Transformer 做端到端检测,通过匈牙利匹配完成一对一监督,省掉了手工设计的 NMS。不过,这套方案的短板也很突出——训练收敛慢,尤其在小目标场景里,学习效率不够理想。
DEIM 解决了什么问题
DEIM 主要围绕两个方向做改进:
- Dense O2O Matching:通过让一张图里出现更多目标实例,增加正样本密度,让训练信号更充足。论文里提到可以借助马赛克、混合增强这类常见数据增强手段,在不破坏一对一匹配框架的前提下扩大有效监督。
- MAL(Matchability-Aware Loss):针对不同质量的匹配样本设计更合理的损失权重,尤其照顾低质量匹配,让模型在训练早期也能更稳定地学到东西。

实验结论
论文实验显示,DEIM 能明显加快 DETR 系列的收敛,并在精度和训练效率之间取得更好的平衡。它和 RT-DETR、D-FINE 等实时检测器结合后,性能依然有竞争力,尤其在小目标检测上表现更突出。
在不额外依赖新数据的情况下,DEIM 训练出的实时模型已经能超过不少主流实时检测器。论文里给出的结果也说明,这套训练策略对'想要保留 DETR 思路,又不想忍受漫长训练周期'的场景很有吸引力。
基于 DEIM-D-FINE-S 训练 VisDrone2019 无人机数据集
这部分我直接用 DEIM-D-FINE-S 在 VisDrone2019 上做了一次实战。环境是 NVIDIA RTX 4090 24G,Python 3.8,PyTorch 2.3.1 + cu121。
数据集说明
VisDrone 是天津大学团队发布的无人机视角数据集,训练集、验证集、测试集规模分别为 6471、548、1610 张。原始标注里一共有 12 类,但其中'忽略区域'和 'others' 并不算有效目标,所以实际训练时只保留 10 个类别:
- pedestrian
- people
- bicycle
- car
- van
- truck
- tricycle
- awning-tricycle
- bus
- motor
为了省去繁琐的数据转换,这里直接使用已经整理好的 COCO 格式数据集进行训练。
环境安装
先建一个独立环境:
conda create -n deim python=3.8.13
安装 PyTorch 时,版本要求大于 2.0.1,这里直接用 2.3.1:
# CUDA 11.8
conda install pytorch==2.3.1 torchvision==0.18.1 torchaudio==2.3.1 pytorch-cuda=11.8 -c pytorch -c nvidia
# CUDA 12.1
conda install pytorch==2.3.1 torchvision==0.18.1 torchaudio==2.3.1 pytorch-cuda=12.1 -c pytorch -c nvidia
# CPU Only
conda install pytorch==2.3.1 torchvision==0.18.1 torchaudio==2.3.1 cpuonly -c pytorch
接着安装项目依赖:
conda activate deim
pip install -r requirements.txt
如果后面遇到 calflops 相关问题,先别急着往训练本身上怀疑,大概率是环境依赖冲突引起的,后面会单独说。
数据集配置
这里新建 configs/dataset/custom_xulvisdrone.yml,重点只改四处:
num_classes- 训练集
img_folder - 训练集
ann_file - 验证集
img_folder - 验证集
ann_file
如果只是做验证或测试,通常只需要把验证集相关路径改对就行。
task: detection
evaluator:
type: CocoEvaluator
iou_types: ['bbox']
num_classes: 10
# your dataset classes
remap_mscoco_category: False
train_dataloader:
type: DataLoader
dataset:
type: CocoDetection
img_folder: DEIM-main/visdrone2019_coco/train2017
ann_file: DEIM-main/visdrone2019_coco/annotations/instances_train2017.json
return_masks: False
transforms:
type: Compose
ops: ~
shuffle: True
num_workers: 4
drop_last: True
collate_fn:
type: BatchImageCollateFunction
val_dataloader:
type: DataLoader
dataset:
type: CocoDetection
img_folder: DEIM-main/visdrone2019_coco/val2017
ann_file: DEIM-main/visdrone2019_coco/annotations/instances_val2017.json
return_masks: False
transforms:
type: Compose
ops: ~
shuffle: False
num_workers: 4
drop_last: False
collate_fn:
type: BatchImageCollateFunction
训练配置改动
DEIM 的配置是层层引用的,实际训练时要改的文件不止一个。默认 640 尺寸训练的话,关键就是两个点:数据集引用和 batch size。
训练轮数与保存路径
在 configs/deim_dfine/deim_hgnetv2_s_coco.yml 里调整 epoch、输出路径等参数,默认是 132 epoch。
挂载自定义数据集
在 configs/deim_dfine/dfine_hgnetv2_s_coco.yml 里,把数据集配置切到刚才准备好的 custom_xulvisdrone.yml。
训练尺寸
在 configs/base/deim.yml 里确认训练输入尺寸。这里默认用 640,并且 Mosaic 是按四块切分的策略。
batch size
在 configs/base/dataloader.yml 里把 total_batch_size 从 32 改成 8。640×640 下,4090 上大概会占到 20G 显存,这一步不改,训练很容易顶满显存。
模型训练
这次只训练 deim_dfine-s,输入尺寸 640×640,训练 132 轮,并加载官方 COCO 预训练权重做微调。
python train.py -c configs/deim_dfine/deim_hgnetv2_s_coco.yml --use-amp --seed=0 -t deim_dfine_hgnetv2_s_coco_120e.pth
训练过程中可以开 TensorBoard 看曲线:
tensorboard --logdir=outputs/deim_hgnetv2_s_coco/summary
如果页面没有内容,优先检查路径,十有八九是 logdir 指错了。
模型验证
验证时同样走 train.py,只是加上 --test-only。
python train.py -c configs/deim_dfine/deim_hgnetv2_s_coco.yml --test-only -r outputs/deim_hgnetv2_s_coco/best_stg2.pth
maxDets=100
在 maxDets=100 的设置下,VisDrone 验证集 map50 大约是 0.474,测试集约 0.396。
maxDets=300
VisDrone 这类密集目标场景里,maxDets=100 有时不够用。因为部分图片里的目标数量可能接近甚至超过 100,所以我又把 maxDets 调到 300 再跑了一次。
修改位置在 faster_coco_eval 的 cocoeval.py 里,对应环境路径按自己的实际安装位置调整即可。
调整后,验证集 map50 约 0.475,测试集约 0.397。提升不算特别大,但对密集场景的评估会更完整一些。
单张图片测试
测试命令如下:
python tools/inference/torch_inf.py -c configs/deim_dfine/deim_hgnetv2_s_coco.yml -r outputs/deim_hgnetv2_s_coco/best_stg2.pth --input visdrone2019_coco/images/test/0000006_00159_d_0000001.jpg --device cuda:0
需要注意的是,原始绘图逻辑里只有类别索引,没有类别名,如果想看得更直观,可以自己在可视化时把索引映射成实际类别。
ONNX 导出与推理
先补齐依赖:
pip install onnx==1.14.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install onnxruntime-gpu==1.18.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
导出 ONNX
python tools/deployment/export_onnx.py -c configs/deim_dfine/deim_hgnetv2_s_coco.yml -r outputs/deim_hgnetv2_s_coco/best_stg2.pth
导出后可以用 Netron 看一下网络结构,确认输出节点和后处理路径都正常。
官方 ONNX 推理脚本
python tools/inference/onnx_inf.py --onnx outputs/deim_hgnetv2_s_coco/best_stg2.onnx --input visdrone2019_coco/images/test/0000006_00159_d_0000001.jpg
实际观察下来,ONNX 和 pth 的结果会有一点偏差,通常和预处理流程有关,不一定是模型本身出了问题。
自定义 ONNX 推理脚本
如果只想做轻量部署,可以直接用不依赖 torch 的推理脚本,核心依赖只有 numpy、opencv 和 onnxruntime。速度上,大概在 9~10ms 这个量级,比 YOLOv8 的推理要慢一些。
与 YOLOv8 / YOLOv11 对比
这次实测的感受比较直接:
- mAP50 比 YOLOv8 高出接近 6 个点,能到 47% 左右;
- 训练显存占用比较高,batch size 8 时大约需要 20G;
- 训练速度比 YOLOv8 慢一倍左右,整套训练约 12 小时;
- 检出率不错,但误检和同一目标出现多个重叠框、甚至类别不一致的情况仍然比较明显。
如果你的场景更看重精度,DEIM 值得试;如果更追求训练和推理速度,YOLO 系列依然更省心。
常见报错
1. RuntimeError: CUDA error: device-side assert triggered
一般是数据集配置有问题,最常见的原因是类别 id 和 yaml 里的索引没对上。自定义数据集通常要求类别索引从 0 开始,比如 10 个类就应该对应 0 到 9。
2. Could not load library libcudnn... undefined symbol
这类报错通常是 calflops 相关依赖把 nvidia-cudnn-cu12 装进来了,而它和系统里的 cudnn 版本冲突。处理思路有两个:
- 删系统 cudnn,不太推荐,影响面太大;
- 删虚拟环境里的 cudnn,通常更稳妥,比如卸载
nvidia-cudnn-cu12。
3. ModuleNotFoundError: No module named 'calflops'
这是前面冲突的连锁反应之一。因为 calflops 主要用于计算 FLOPs,如果当前训练并不依赖它,可以直接把 engine/misc/profiler_utils.py 里相关调用注释掉,先把主流程跑通。
小结
DEIM 的思路很清楚:通过更密集的监督和更合理的匹配损失,解决 DETR 系列训练慢的问题。放到 VisDrone2019 这种无人机密集小目标场景里,它的优势主要体现在召回和精度上;代价则是显存占用、训练速度和后处理稳定性。整体来看,这是一套值得做精度基线、也值得继续调参挖潜的方案。

