
目标检测这块RCNN、DETR、YOLO 是绕不开的三座大山。我最早接触的是 YOLO那会儿还在用 v3 跑一些简单的车辆检测后来因为项目需要做高精度的小目标识别被迫回头啃了 Faster R-CNN 的两阶段逻辑再后来 DETR 出来Transformer 直接端到端出框确实把检测流程简化了一大截。这三条技术路线各有各的脾气选错了轻则精度上不去重则训练直接崩掉。下面我按自己的实际使用经验把这三类算法的核心机制、训练部署要点、以及踩过的坑逐一拆开讲适合刚入门目标检测的开发者也适合正在做模型选型的技术负责人参考。1. 三条技术路线的本质差异1.1 RCNN 家族从选择性搜索到区域建议网络RCNN 系列的核心思路是“先找候选区域再对每个区域做分类和回归”。最早的 RCNN 用选择性搜索Selective Search生成约 2000 个候选框然后逐个送入 CNN 提取特征最后用 SVM 分类。这个流程慢得离谱一张图推理要几十秒根本没法落地。Fast R-CNN 做了改进把整张图先过一遍 CNN 得到特征图再通过 RoI Pooling 从特征图上抠出每个候选区域的特征分类和回归共用同一个网络速度提升了一个量级。但候选框的生成仍然依赖外部算法瓶颈还在。Faster R-CNN 真正把检测变成了端到端可训练的结构关键就是 RPNRegion Proposal Network。RPN 在特征图上用滑动窗口生成锚框Anchor每个锚框输出前景/背景二分类和四个偏移量筛选出约 300 个高质量候选框送给后面的 RoI Head 做精细分类和坐标回归。整个网络可以联合训练推理速度在 GPU 上能到 5-10 FPS取决于骨干网络。我实测过 ResNet-50 骨干的 Faster R-CNN 在 1080p 图像上单卡 T4 大概 7 FPS 左右精度确实比同期的 YOLO 高尤其是小目标和密集场景。RCNN 家族还有一个变体叫 Mask R-CNN在 Faster R-CNN 基础上加了一个分割分支可以同时输出检测框和像素级掩码。这个在需要实例分割的场景里非常实用比如工业质检中要精确测量缺陷面积Mask R-CNN 就是首选。但它的计算量也更大训练时显存占用比 Faster R-CNN 高出约 30%。1.2 DETRTransformer 带来的端到端革命DETRDEtection TRansformer是 Facebook 在 2020 年提出的它彻底抛弃了锚框和非极大值抑制NMS把检测变成了一个集合预测问题。整体结构很简洁CNN 骨干提取特征Transformer 编码器增强特征解码器用一组可学习的对象查询Object Queries去“询问”图像里有什么物体最后每个查询输出一个框和类别。训练时用匈牙利算法做二分图匹配把预测框和真实框一一对应再计算损失。DETR 最大的优势是流程干净没有锚框、没有 NMS超参数少端到端训练。但它的缺点也很明显收敛极慢原始 DETR 需要 500 个 epoch 才能收敛而 YOLO 通常 100-300 个 epoch 就够了。另外 DETR 对小目标的检测效果一般因为 Transformer 编码器对高分辨率特征图的计算复杂度是平方级的通常只能下采样到 1/32 分辨率小目标信息丢失严重。后来 Deformable DETR 通过可变形注意力机制把收敛速度提升了 10 倍小目标精度也上来了算是目前比较实用的 DETR 变体。DETR 训练自己的数据时有一个坑特别容易踩类别不平衡。因为匈牙利匹配是一对一的每个真实框只能匹配一个预测框如果某个类别样本很少模型很容易忽略它。我的做法是在损失里给稀有类别加权或者用 Focal Loss 的思路调整分类损失。另外 DETR 的学习率需要 warmup前 10 个 epoch 从 1e-6 线性升到 1e-4否则训练很容易发散。1.3 YOLO回归问题的极致工程化YOLO 把检测直接建模为回归问题一张图送入网络输出就是每个网格的类别概率和边界框坐标。从 v1 到 v8再到现在的 v11、v12YOLO 的演进方向一直是“更快更准更易部署”。YOLOv1 的精度一般但速度极快YOLOv3 引入 FPN 和多尺度预测精度大幅提升YOLOv5 工程化做得最好代码结构清晰训练脚本开箱即用YOLOv8 换成了 Anchor-Free 结构损失函数用 Task-Aligned Assigner 做正负样本匹配精度和速度都达到了很好的平衡。YOLO 的损失函数是核心不同版本差异很大。YOLOv3 用 MSE 做坐标回归交叉熵做分类二值交叉熵做置信度。YOLOv5 改用 CIoU Loss 做坐标回归分类和置信度用 BCEWithLogits。YOLOv8 进一步用 DFLDistribution Focal Loss做框回归把坐标预测变成分布预测精度更高。我实测下来YOLOv8 在 COCO 上比 YOLOv5 的 mAP 高了约 2-3 个点推理速度基本持平。YOLO 的部署生态也是最成熟的。TensorRT 加速后T4 上跑 YOLOv8n 在 640 分辨率下可以到 1000 FPS1080p 输入大概 200-300 FPS。如果是多路视频流检测比如 1080p25 帧的视频用 TensorRT 加速的 YOLOv8s 在 T4 上大概能支持 8-12 路同时检测具体取决于模型大小和后处理优化程度。这里有个经验多路场景下预处理和后处理往往是瓶颈用 CUDA 核函数做 letterbox 和 NMS 能显著提升吞吐。2. 训练自己的数据从数据准备到模型收敛2.1 数据标注的格式选择与转换训练自己的数据第一步是标注。常用的标注工具是 LabelImg矩形框和 LabelMe多边形分割。标注格式有 VOC XML、COCO JSON、YOLO TXT 三种。VOC 格式最通用COCO 格式适合实例分割和多人协作YOLO 格式最简洁每行是class_id x_center y_center width height坐标都归一化到 0-1。我一般先用 LabelImg 标 VOC 格式然后用脚本转成 YOLO 或 COCO。转换时最容易出错的是坐标归一化尤其是图像尺寸不一致时。我的做法是写一个统一的转换脚本读取每张图的宽高再计算归一化坐标。另外类别 ID 的映射要固定不能训练时用一套推理时用另一套否则结果全乱。对于实例分割任务YOLOv8-seg 需要多边形标注格式是class_id x1 y1 x2 y2 ... xn yn坐标同样归一化。标注时要注意多边形必须闭合且不能自交否则训练时会报错。我踩过一次坑标注的多边形有重叠训练时 loss 一直震荡排查了半天才发现是标注问题。2.2 数据增强的策略与陷阱数据增强是提升模型泛化能力的关键。YOLO 默认开启 Mosaic 增强把四张图拼成一张增加小目标和上下文多样性。但 Mosaic 有一个副作用如果数据集本身标注质量不高Mosaic 会把错误标注也拼进去导致模型学到错误特征。我的经验是前 10 个 epoch 先关掉 Mosaic让模型先学好基础特征再开启 Mosaic 做精细调优。另外 HSV 增强色调、饱和度、亮度对颜色敏感的类别要慎用。比如检测交通信号灯色调变化太大会让红灯变绿灯模型直接学废。我的做法是对这类类别单独设置增强参数或者干脆关掉 HSV 增强。随机翻转也要注意水平翻转对大多数类别没问题但垂直翻转对“上下”有语义的类别比如天空、地面会引入错误标签。2.3 训练中的 BN 崩溃与学习率调优YOLO 训练中 BNBatch Normalization崩溃是个常见问题表现为 loss 突然变成 NaN或者 mAP 骤降到 0。根本原因通常是 batch size 太小BN 的统计量估计不准。YOLOv8 默认 batch size 是 16如果显存不够只能降到 8 或 4这时 BN 就容易出问题。解决方案有两个一是改用 SyncBN多卡同步统计量二是冻结 BN 层用预训练模型的统计量。我一般优先用 SyncBN如果只有单卡就冻结 BN 并降低学习率。学习率方面YOLO 用余弦退火调度初始学习率 0.01warmup 3 个 epoch。如果训练时 loss 震荡厉害先把学习率降到 0.001 试试。DETR 的学习率要小得多初始 1e-4骨干网络用 1e-5因为 Transformer 对学习率非常敏感。Faster R-CNN 的学习率通常是 0.02SGD或 1e-4Adam具体看优化器选择。3. 部署与推理优化从 PyTorch 到 TensorRT3.1 模型导出与格式转换训练完的 PyTorch 模型要部署第一步是导出成 ONNX。YOLOv8 用model.export(formatonnx)一行搞定但要注意 opset 版本建议用 12 或 13太低不支持某些算子太高 TensorRT 可能不认。导出后可以用 Netron 可视化检查结构确认输入输出节点名称。ONNX 转 TensorRT 用trtexec工具命令大概是trtexec --onnxyolov8s.onnx --saveEngineyolov8s.engine --fp16 --workspace4096--fp16开启半精度速度能提升 1.5-2 倍精度损失通常小于 1 个点。--workspace是显存上限单位 MB设太小会转换失败。我一般设 4096 或 8192看模型大小。DETR 导出 ONNX 稍微麻烦一点因为 Transformer 的动态形状支持不好。我的做法是固定输入尺寸比如 800x1333导出静态图。Faster R-CNN 的 ONNX 导出更复杂RPN 和 RoI Align 算子在不同 opset 下行为不一致建议用 mmdeploy 或 torchvision 自带的导出脚本。3.2 多路视频流检测的吞吐优化多路视频流检测是实际项目中最常见的需求比如监控场景要同时处理 8 路 1080p 摄像头。瓶颈通常在三个地方解码、预处理、后处理。解码用 NVDEC 硬件加速预处理用 CUDA 核函数做 letterbox 和归一化后处理用 GPU 版的 NMS。TensorRT 只负责推理前后处理如果还在 CPU 上跑整体吞吐会被拖垮。我实测过 T4 上跑 YOLOv8s640 分辨率FP16 精度纯推理能到 800 FPS 左右。但加上解码和前后处理单路 1080p25 帧的视频大概占用 80-100 FPS 的推理能力所以理论上能支持 8 路左右。如果换成 YOLOv8n能支持 15 路以上。这里的关键是批处理Batch Inference把多路视频的帧拼成一个 batch 一起推理能显著提升 GPU 利用率。但 batch size 太大会增加延迟需要根据实际场景权衡。3.3 一键部署脚本的编写要点一键部署脚本能省很多事但写的时候要注意环境隔离。我一般用 Docker 封装基础镜像选nvidia/cuda:11.8-cudnn8-runtime-ubuntu22.04然后装 TensorRT、OpenCV、PyTorch。Dockerfile 里要固定版本号不能写latest否则下次构建可能就挂了。脚本的核心步骤是检查 GPU 驱动、安装依赖、下载模型权重、导出 ONNX、转换 TensorRT 引擎、启动推理服务。每一步都要有错误处理和日志输出方便排查。我习惯在脚本里加一个--dry-run参数只打印步骤不实际执行方便调试。4. 模型选型的决策框架与实战建议4.1 精度优先还是速度优先选模型之前先问自己三个问题精度要求多高速度要求多快部署环境是什么如果精度优先比如医疗影像或工业质检Faster R-CNN 或 Mask R-CNN 是稳妥选择mAP 通常比 YOLO 高 3-5 个点。如果速度优先比如实时监控或自动驾驶YOLOv8 是首选TensorRT 加速后轻松过百帧。如果两者都要兼顾可以考虑 Deformable DETR 或 YOLOv8x但需要更强的 GPU。我做过一个对比测试在自建的电力红外数据集上约 5000 张图5 个类别Faster R-CNN ResNet-50 的 mAP0.5 是 0.82YOLOv8s 是 0.79DETR 是 0.76。但推理速度上YOLOv8s 是 200 FPSFaster R-CNN 是 8 FPSDETR 是 15 FPS。所以如果场景允许 10 FPS 左右的推理速度Faster R-CNN 的精度优势值得考虑如果要实时YOLO 是唯一选择。4.2 小目标检测的针对性优化小目标检测是三大算法的共同难点。YOLO 的解决方案是多尺度预测在 P3、P4、P5 三个尺度上分别检测小、中、大目标。但 P3 特征图的分辨率是 80x80640 输入每个格子对应 8x8 像素如果目标小于 8 像素基本检测不到。我的做法是增加 P2 层160x160或者用切片推理SAHI把大图切成小图分别检测再合并。Faster R-CNN 对小目标的处理更好因为 RPN 生成的锚框可以设置很小的尺寸比如 16x16。但锚框太小会导致正样本太少训练困难。我的经验是锚框尺寸要根据数据集统计来设用 K-means 聚类真实框的宽高选 9 个聚类中心作为锚框尺寸。DETR 的小目标检测最弱因为编码器下采样到 1/32小目标特征几乎丢失。Deformable DETR 通过多尺度可变形注意力缓解了这个问题但计算量也上去了。如果小目标很多建议直接用 YOLO 或 Faster R-CNN别跟 DETR 死磕。4.3 模型蒸馏与剪枝的实用技巧模型太大跑不动蒸馏和剪枝是两个常用手段。蒸馏是用大模型教师指导小模型学生训练让学生模型逼近教师模型的输出分布。YOLO 蒸馏我试过用 YOLOv8x 教 YOLOv8nmAP 提升了约 2 个点推理速度不变。关键是损失函数的设计除了硬标签损失还要加软标签损失KL 散度温度参数 T 一般设 3-5。剪枝是去掉冗余的通道或层减少计算量。结构化剪枝对 YOLO 比较友好因为卷积层通道数多剪掉 30% 的通道速度能提升 20-30%精度损失控制在 1 个点以内。但剪枝后要微调否则精度掉得厉害。我一般用 L1 范数排序通道重要性剪掉最小的 20-30%然后微调 50 个 epoch。5. 常见训练故障的排查链路5.1 混淆矩阵不唯一标注与匹配的隐藏问题YOLO 训练完看混淆矩阵有时候会发现同一个类别在不同运行中结果不一致或者矩阵总和跟验证集样本数对不上。这个问题我排查了很久最后定位到两个原因一是数据加载器的 shuffle 和随机增强导致每次验证的样本顺序不同如果验证集有重复图片或标注错误结果就会波动二是 NMS 的 IoU 阈值设置不当导致某些框被错误抑制或保留。解决方案是固定验证集的随机种子关掉验证时的数据增强然后检查标注文件是否有重复或漏标。另外混淆矩阵的总和应该等于验证集的真实框总数如果对不上说明有框被漏检或误检到其他类别。我一般会导出所有预测框和真实框用脚本逐张对比找出差异最大的图片重点检查。5.2 训练中 loss 突然飙升的应急处理训练到一半 loss 突然飙升甚至变成 NaN这是最让人头疼的问题。常见原因有学习率太大、梯度爆炸、数据中有脏样本、BN 统计量崩溃。我的排查顺序是先看 loss 曲线如果是缓慢上升大概率是学习率问题降学习率重启训练如果是突然飙升检查最近加入的数据是否有标注错误如果 loss 直接 NaN检查梯度范数加梯度裁剪gradient clipping。梯度裁剪在 YOLO 和 DETR 训练中都很重要我一般设 max_norm10.0。另外混合精度训练AMP有时会导致 NaN可以先用 FP32 跑几个 epoch 确认模型没问题再开 AMP。如果 AMP 下 NaN试试把 loss scale 调小或者用动态 loss scaling。5.3 推理结果与训练指标不一致的排查训练时 mAP 很高推理时结果却很差这种问题通常是预处理或后处理不一致导致的。训练时的图像归一化参数均值、标准差必须和推理时完全一致否则输入分布变了模型输出全乱。YOLO 默认用 0-1 归一化不减去 ImageNet 均值但有些自定义模型会减这个要仔细核对。另一个常见问题是 NMS 阈值。训练时验证用的 NMS 阈值和推理时不一致会导致框的数量和位置不同。我一般固定 NMS IoU 阈值为 0.45YOLO 默认置信度阈值 0.25。如果推理时框太多先调高置信度阈值如果框太少调低置信度阈值或 NMS 阈值。6. 从工程落地反推技术选型6.1 数据量少的时候怎么选数据量少于 1000 张时Faster R-CNN 和 DETR 都容易过拟合YOLO 相对好一些因为它的数据增强更激进。但更好的做法是用预训练模型微调冻结骨干网络只训练检测头。YOLOv8 支持freeze参数可以冻结前 N 层。我一般冻结前 10 层学习率设 0.001训练 50-100 个 epoch。如果数据量极少少于 200 张可以考虑少样本检测方法比如用 CLIP 做零样本检测或者用 DETR 的变体如 Conditional DETR做微调。但说实话数据太少什么模型都难最好的办法还是多标数据。6.2 边缘设备部署的模型选择边缘设备如 Jetson Nano、树莓派算力有限模型必须又小又快。YOLOv8n 是最优选参数量只有 3.2MTensorRT 加速后在 Jetson Xavier NX 上能跑 30 FPS 左右。Faster R-CNN 和 DETR 在边缘设备上基本跑不动除非用 MobileNet 骨干但精度会掉很多。如果边缘设备支持 NPU如瑞芯微 RK3588可以用 RKNN 工具链转换 YOLO 模型INT8 量化后速度能提升 2-3 倍。但量化会掉精度需要做量化感知训练QAT来补偿。我实测 RK3588 上 YOLOv8n INT8 量化后mAP 掉了约 2 个点但速度从 15 FPS 提升到 40 FPS性价比很高。6.3 持续迭代与版本管理模型上线不是终点持续迭代才是。我一般用 MLflow 或 WandB 做实验管理记录每次训练的超参数、数据集版本、评估指标。模型权重用 DVC 或 Git LFS 管理确保每次部署的模型可追溯。数据集的版本也要管新增标注后要重新划分训练集和验证集避免数据泄露。迭代节奏上我一般每两周做一次全量训练每周做一次增量训练。增量训练只在新标注的数据上微调学习率设小一点0.0001训练 20-30 个 epoch。如果新数据分布和旧数据差异大就做全量训练避免灾难性遗忘。踩了这么多坑我最大的体会是没有最好的模型只有最合适的模型。RCNN 精度高但慢DETR 流程干净但难训YOLO 快且工程化好但精度上限有限。选型时先明确场景的精度和速度底线再根据数据量、部署环境、团队熟悉度做权衡。另外训练前的数据清洗和标注检查比调参重要十倍我见过太多项目因为标注错误导致模型学废回头返工的成本极高。