
做道路交通场景下的目标检测绕不开两个痛点一是目标尺度变化剧烈同一帧画面里既有近景占屏的公交车也有远处只有几十个像素的行人二是类别天然不平衡车辆样本可能占八成行人、摩托车、非机动车只占零星几条。很多检测模型在这类场景下要么漏检严重要么精度和速度顾此失彼。这个项目选择基于 RetinaNet 构建道路交通多目标检测与识别系统核心就是解决上述两个问题——用特征金字塔覆盖多尺度目标用 Focal Loss 压制大量易分负样本的干扰在单阶段检测器里做到接近两阶段模型的精度同时保留实时推理的能力。整个项目从数据准备、模型训练到推理部署走通了一条可复用的完整链路。内容包括道路交通场景的类别划分与标注规范、RetinaNet 的核心原理通俗拆解、Anchor 与 FPN 的参数设计、Focal Loss 的调参逻辑、训练过程中的 loss 曲线分析、模型导出与推理加速以及实际落地时常见的漏检、误检问题排查。无论你是刚开始接触目标检测的学生还是要在园区、路口、高速等场景做车辆与行人识别工程的开发者这篇文章里记录的思路和踩坑经验都能直接拿过去参考。1. 项目场景与设计思路拆解1.1 为什么选 RetinaNet 而不是 Faster R-CNN 或 YOLO做模型选型时我先把候选模型按“两阶段”和“单阶段”分了两类。Faster R-CNN 这类两阶段检测器精度高因为它在第二阶段会对候选框做二次分类和回归相当于用两次筛选换精度但缺点是速度慢在一张普通工业显卡上跑到 10 FPS 以下很正常做成实时视频检测很吃力。SSD、YOLO 这类单阶段检测器速度快但早期版本在密集小目标场景下精度明显不如两阶段尤其是道路交通这种目标互相遮挡、尺度差异大的场景几乎必然出现漏检。RetinaNet 是 2017 年提出的一个关键折中方案。它本质上是单阶段检测器推理时只过一次网络但引入两个重要设计把精度拉了上来FPN 特征金字塔负责让不同大小的目标在不同分辨率的特征图上被检测Focal Loss 负责解决训练时正负样本比例极端失衡的问题。这两个设计补上了单阶段模型的短板让它能在保持高推理速度的同时检测精度逼近甚至超过两阶段模型。实际测试中同样的数据下 RetinaNet 相比当时同配置的 Faster R-CNN 速度能快一倍左右精度差距在可接受范围内。还有一个现实因素RetinaNet 结构上就是 backbone FPN 两个子网络逻辑清晰方便后续做剪枝、量化、TensorRT 加速这些工程化改造。这点在落地阶段非常重要。我见过不少项目模型精度不错但一到部署环节就发现结构太复杂、算子太偏导出 ONNX 后推理引擎不支持最后只能重写后处理代码效率奇低。RetinaNet 在这方面的兼容性实测很好。1.2 道路交通场景检测难在哪里道路交通检测属于典型的高复杂度场景难点集中在四个方面。一是尺度差异极大。一张 1920×1080 的路口画面中近处的卡车可能占据 300×300 像素而远处路口的行人只有 20×40 像素。检测器如果只在单一尺度特征图上做检测必然顾此失彼。FPN 通过多层级特征图输出从底层高分辨率特征捕捉小目标从高层语义特征捕捉大目标本质上就是用“多路分工”来对抗尺度问题。二是遮挡严重。行人与车辆重叠、车辆与车辆紧贴、树木和灯杆遮挡目标局部都会让检测框不稳定或直接漏检。RetinaNet 的 Anchor 机制对部分遮挡有一定容忍度因为遮挡目标通常还保留可辨认的局部特征只要 Anchor 与目标的重叠度足够高分类头仍能输出正确的类别。但遇到大面积遮挡时仅靠模型本身是不够的后处理阶段的 NMS 阈值调节也能缓解一部分问题实测把 NMS 的 IoU 阈值从默认的 0.5 调到 0.45可以减少高遮挡场景下的框被错误合并的情况。三是类间相似与类内差异。轿车和 SUV、行人和骑行者在外观上有大量相似特征需要通过训练数据把类间边界“压”得更清晰。这个阶段我一般会在数据增强里加入更强的色彩扰动避免模型只靠颜色来区分类别而是去学形状和纹理特征。四是光照与天气变化。白天强逆光、夜晚车灯过曝、雨天反光这些环境因素会让同一辆车的视觉特征产生巨大变化。因此数据准备阶段必须刻意包含不同时段、不同天气下的样本这个后面会细说。1.3 多目标检测的类别规划与细粒度权衡这个项目的检测类别最初设计了 10 类小轿车、SUV、公交车、卡车、摩托车、自行车、行人、交通信号灯、交通标志、锥桶。类别规划的原则是“能够用视觉特征稳定区分的就独立成类容易混淆的先合并再迭代拆分”。比如卡车和公交车二者轮廓相近但公交车通常有车窗连续结构卡车则更杂。如果你手里标注数据不多强行拆成两类会导致模型在两类之间反复横跳。我的做法是第一版先合并为“大型车辆”等数据量充足后再细拆。相反行人和骑行者虽然都属于“人”但行为模式、碰撞风险完全不同必须从一开始就分开否则后续做流量统计、安全预警时数据全部失效。工程上还有一个细节类别编号最好不要随意增减。一旦模型训练完成并部署新增类别意味着重新标注、重新训练、重新评测涉及整条链路。所以类别规划宁愿前期多想几天也不要后期返工。2. 环境配置与工具链准备2.1 深度学习框架与源码方案整个项目基于 PyTorch 实现原因有几个。一是生态环境成熟社区里 RetinaNet 的实现比较多不管是从头实现还是基于检测库修改都有大量可参考的资料。二是 PyTorch 的动态图特性在调试阶段极其顺手比如训练时想打印中间层特征图直接在 forward 里加一行就行不需要像静态图那样先构图再执行。三是部署阶段的 ONNX 导出、TensorRT 转换对 PyTorch 的支持都很好。关于 RetinaNet 本身的实现我不建议从头写除非你是为了学习原理。我更推荐在成熟的检测库基础上改造——这类库已经把数据加载、训练循环、评估流程、日志记录都封装好了你只需要关注模型结构和训练配置。我自己项目里用的是基于 mmdetection 二次改造的方案主要原因是你可以在不修改库源码的前提下通过配置文件完成数据路径、模型结构、训练策略的定制。如果你更习惯纯 PyTorch 风格也可以基于 torchvision 自带的 RetinaNet 实现来改代码量更小适合快速验证想法。提示无论选哪种基础库训练和评估必须用同一套代码和配置维护避免训练时用 A 增强、评估时用 B 增强这种低级错误。这种问题排查起来非常痛苦。2.2 硬件资源需求估算RetinaNet 的显存占用主要来自 backbone 和 FPN 的特征图训练时的占用远高于推理时。以 800×800 的输入分辨率为例ResNet50 backbone FPNbatch size 为 8 时单卡显存占用约 10~12GB。所以训练阶段至少需要一张 16GB 显存的显卡24GB 会更从容可以支撑更大的 batch 或者更大的输入分辨率。推理阶段的资源需求则小得多。在 Jetson 这类嵌入式平台上跑 FP16 量化后的模型1080P 视频流大约能到 10~20 FPS在桌面级显卡上使用 TensorRT FP16 加速后实测可以达到 40 FPS 以上。如果你要部署到纯 CPU 环境劝你早点打消念头RetinaNet 的 FPN 多分支结构在 CPU 上很难达到实时即使做了 INT8 量化也够呛。道路交通检测天然需要实时性算力不足的硬件上不如换用更轻量的模型。2.3 标注工具与数据格式规范训练数据格式我首选 COCO 格式。COCO 的 JSON 结构把图片信息、标注信息、类别信息分得很清楚配合各类检测库都是零成本接入。标注工具方面如果是从零开始标注推荐用支持自动保存和快捷键标注的工具效率会高很多。几百张图手工标注还能忍受上千张图如果工具不好用光标注就能耗掉两周时间。标注规范里有一条必须提前确定遮挡目标的框怎么画。我采用的通行做法是标注目标的“可见部分加可推断部分”即只要能从视觉上确定目标整体延伸范围即使部分被遮挡也标注完整框但如果目标超过一半被遮挡导致无法确定边界则不标注或标为“忽略区域”。忽略区域在 COCO 格式中对应 iscrowd1训练时这些区域不会被计入损失避免模型学到错误边界。3. RetinaNet 核心原理通俗解析3.1 Anchor 机制与 FPN 特征金字塔的分工逻辑Anchor 可以理解为一组预先定义好的候选框它们覆盖不同的大小和长宽比。RetinaNet 在每个特征图位置生成多个 AnchorAnchor 与真实目标框计算 IoUIoU 大于 0.5 的被当作正样本小于 0.4 的当作负样本介于两者之间的在训练中被忽略。FPN 做的事情则更像一个团队分工输入图像经过 backbone 后得到多个层级的特征图低层特征图分辨率高、保留更多细节适合检测小目标高层特征图分辨率低、语义信息强适合检测大目标。RetinaNet 使用了 P3 到 P7 共五层特征图P3 对应原图的 1/8 尺寸P7 对应 1/128 尺寸。每层特征图上的 Anchor 面积范围不同P3 上放小 AnchorP7 上放大 Anchor这样目标按尺寸被分配到最适合检测的特征层上。这里有一个工程注意点Anchor 的尺寸必须和你的数据集匹配。RetinaNet 默认的 Anchor 面积范围是 32×32 到 512×512如果你的场景里大量目标比这个范围小——比如远处行人只有 20×40 像素——默认参数就不够覆盖。我通常在训练前对数据集中所有真实框做聚类统计按统计结果调整 Anchor 的基础尺寸和比例。统计方法很简单用脚本把所有标注框的宽度和高度聚类成 3~5 个簇把簇中心作为 Anchor 的基准宽高效果比一路默认参数好很多。3.2 Focal Loss解决类别不平衡的关键设计Focal Loss 是这个模型的核心创新。在目标检测里一张图上 Anchor 可能有一万多个但真正的目标可能只有十几个大量 Anchor 是背景。训练时这些背景 Anchor 产生的简单负样本会主导损失模型学到的是“啥也不用干也能把 loss 压得很低”。Focal Loss 做的事情是给不同样本加权重对于已经能分类正确的样本降低它的损失权重对于分类困难、容易出错的样本放大它的损失权重。公式里有两个关键参数。γ 是聚焦参数控制对难易样本的注意力偏向默认值 2 实测效果最好当 γ0 时 Focal Loss 退化成普通交叉熵。α 是类别权重参数用来调整正负样本本身的数量不平衡默认 0.25 表示负样本的权重被压低到四分之一。这两个参数一般不需要大改但如果你发现训练出来的模型对某一类特别不敏感可以尝试调高该类在 α 中的权重。我在实际训练中最直观的感受是没用 Focal Loss 之前训练到后期 loss 已经很低了但验证集上的 mAP 就是上不去尤其行人和摩托车两类几乎检测不出来换成 Focal Loss 后虽然前期 loss 下降变慢但到了后期精度明显拉升。根本原因就是难分样本——比如远距离小行人——在普通交叉熵下被海量简单背景样本淹没了梯度根本轮不到它们。3.3 RetinaNet 整体结构速览模型整体可以拆成三段ResNet backbone 负责提取特征FPN 负责把多层特征融合成多尺度输出最后的分类子网络和回归子网络分别输出目标类别和框的位置。分类子网络和回归子网络是两条并行分支结构类似都是几个卷积层叠加互不共享参数。这样设计的好处是分类任务和定位任务可以各自学习适合的特征不像共享参数时容易互相干扰。因为只有一条前向路径RetinaNet 的推理速度远快于两阶段模型。实测在相同硬件上同样的输入分辨率RetinaNet 的推理时间大约是 Faster R-CNN 的一半而 mAP 差距能控制在 1~2 个百分点以内。对实时道路交通检测来说这个取舍非常划算。4. 数据集准备与增强策略4.1 数据来源规划与数量门槛道路交通检测的数据来源一般有两个渠道公开数据集和自采数据。公开数据集的好处是已经标注好可直接用于预训练或作为训练集的一部分但公开数据和实际应用场景往往存在分布差异比如公开数据集里多为晴朗天气、标准视角而你的实际场景可能是黄昏、逆光、高速视角。我建议的做法是用公开数据集做基础训练集建立模型的初始能力同时积累场景数据针对你的真实应用环境做补充。场景数据的采集成本不高——用监控摄像头或行车记录仪录制几段不同时段、不同天气的视频抽帧后人工筛选有效画面即可。表 1 是我的经验参考值。类别最少标注目标数建议标注目标数场景覆盖要求小轿车10005000不同颜色、角度、光照行人8004000站姿、行走、奔跑、遮挡摩托车5002000骑行、推行、载人交通标志3001500不同距离、角度、反光单类目标数量低于 300 的时候模型对该类别的学习基本靠预训练权重的“底子”实战效果非常不稳定。所以数量规划必须前置。4.2 标注质量控制的几个细节标注质量直接影响模型上限这个环节的坑我踩过很多。第一个坑是标注框过紧或过松。COCO 评估时 mAP 对 IoU 非常敏感过紧的框导致预测框即使位置不错但 IoU 不够高被算成误检过松的框则让模型学到不准确的边界。我的规范是框边缘紧贴目标可见轮廓对于车辆包含后视镜、保险杠等外延部件行人包含头部和脚部不裁剪掉任何可见肢体。第二个坑是标注人员之间标准不一致。如果多人标注必须提前做一致性校准。方法是让不同的人标同一批图片计算标注框之间的平均 IoU低于 0.7 就需要重新对齐标准。这个环节看起来费时间但能避免模型在学习过程中收到矛盾信号。第三个坑是小目标的漏标。低于 32×32 像素的行人、远处的小轿车人眼很容易遗漏。这类样本即使漏标了也不会直接让训练报错但会作为背景负样本参与训练等于教模型“这个位置没有目标”最终导致小目标漏检严重。我习惯在标注后用脚本检测数据集中的未标注小目标区域对疑似区域做人工复核。4.3 数据增强策略与参数配置数据增强是解决数据不足和过拟合的最直接手段。我这次用的增强策略分为三组每组的针对场景不同。第一组是几何变换随机翻转、随机缩放、随机裁剪。水平翻转对道路交通场景非常友好因为车辆和行人的左右结构对称随机缩放和裁剪则变相增加了尺度的多样性模拟不同距离下的观测。这组增强我默认全开翻转概率 0.5随机缩放范围设置在 0.5~1.5 倍之间。第二组是颜色与光照变换HSV 通道随机扰动、亮度对比度调整、高斯噪声。这一组专门应对不同时段和天气的光照变化。随机改变图像的饱和度和明度相当于模拟了清晨、黄昏、阴天的光照条件高斯噪声则提高模型对传感器噪声的鲁棒性。第三组是 Mosaic 拼接增强。Mosaic 把四张图拼成一张训练等于在一个 batch 里同时看到了四个不同场景能显著增强模型对复杂背景的适应性。尤其对于小目标检测Mosaic 让小目标在缩放过程中保持相对更多的像素信息。注意增强参数不宜过猛。我曾把随机缩放范围调到 0.3~2.0 倍结果模型在小目标上精度明显下降因为目标被缩得太小后关键特征丢失严重。增强的目的是模拟真实场景的多样性不是创造现实中不存在的极端情况。5. 模型训练与参数调优全过程5.1 训练前配置预训练权重与超参数初始化训练时我没有从零初始化整个网络而是在 ImageNet 预训练的 ResNet50 基础上做迁移学习。这里有个常见误区加载预训练权重时只加载 backbone 的权重FPN 和检测头因为结构不同无法直接复用。Faster R-CNN 和 Mask R-CNN 这类模型在检测库中通常提供完整的预训练权重可以直接加载省去单独加载 backbone 的步骤。超参数初始化时几个关键数值我的经验如下输入分辨率800×800这个尺寸在精度和速度之间比较平衡。单纯为了追求小目标精度调到 1000×1333 也可以但训练和推理速度会明显下降。Batch size取决于显存16GB 显存跑 batch size 8 比较稳。batch size 太小时 BN 层的统计量不稳定影响收敛。初始学习率0.01batch size 8 对应配合 warmup 策略使用。前 500 步学习率从 0.001 线性升到 0.01避免模型在训练初期因为学习率过大而震荡。优化器SGDmomentum 0.9weight decay 0.0001。虽然 Adam 系列优化器收敛更快但检测任务中 SGD 在同样的训练步数下最终精度的上限往往更高。训练总步数我一般设置在 12~20 个 epoch 之间具体看数据集大小。公开数据集预训练权重已经让模型有了不错的初始能力后面更多是在场景数据上做微调所以不需要训练太久。5.2 训练过程监控loss 曲线与 mAP 怎么看训练时盯住两条曲线就够了总 loss 曲线和验证集 mAP 曲线。总 loss 曲线在初始阶段会快速下降这是模型在学最基础的分类和定位能力。随着训练进行曲线下降会变缓这是正常现象。需要注意两个异常信号一是在 800~800 输入下总 loss 如果在第 10 个 epoch 后还没有降到初始值的 1/3 以下说明学习率设置偏高或训练数据有问题二是 loss 曲线出现明显反弹大概率是数据增强引入的噪声过大或者学习率安排不合理。验证集 mAP 比 loss 更能反映真实检测能力。我每隔 1 个 epoch 评估一次验证集记录 mAP0.5 和 mAP[0.5:0.95] 两个指标。两个指标关注点不同mAP0.5 只要求预测框和真实框的 IoU 达到 0.5更关注“能不能检测到”mAP[0.5:0.95] 平均多个 IoU 阈值更关注“检测得准不准”。对于道路交通场景我认为两者都要看漏检用 mAP0.5 评估框的精度用 mAP[0.5:0.95] 评估。5.3 NMS 后处理与阈值调优推理阶段的 NMS 后处理对最终结果影响巨大这个往往容易被忽略。NMS 的作用是在大量重叠的预测框中选出置信度最高的那个把重复框去掉。默认的 NMS IoU 阈值是 0.5意思是两个框的重叠度超过 50% 就被合并。道路交通场景下有两个特殊问题需要调整 NMS。一是密集人群场景多个行人挨得很近框之间重叠度高。NMS 阈值太高容易把不同行人的框合并成一个太低又会在同一个目标上保留多个框。我实测在行人密集场景下阈值降到 0.4 能够减少大部分合并错误。二是跨类别抑制也就是一个目标同时被预测为轿车和 SUV 的情况。RetinaNet 默认对每个类别独立做 NMS这会导致同一个目标输出两个类别不同的框。我后来在看板绘制阶段做了跨类别的 NMS对不同类别的重叠框也做一次合并只保留置信度更高的那个。6. 推理部署与工程化落地6.1 模型导出与接口封装训练好的 PyTorch 模型不能直接放到生产环境跑至少需要做两步导出和封装。我常用的导出方式是先转成 ONNX 格式再做推理框架的转换。ONNX 导出有一个关键细节要注意输入尺寸固定化。PyTorch 模型在训练时支持动态输入尺寸但导出 ONNX 时建议把输入尺寸固定为一个高和宽比如 800×800。原因是动态尺寸会显著增加算子复杂度很多推理框架对动态 shape 支持不完善可能导致导出失败。如果实在需要多尺寸输入可以用两个固定尺寸的模型分别部署效果比一个动态模型的兼容性更稳定。模型封装这一步我通常写成独立的推理类不把后处理逻辑散落在业务流程里。这个类接收一帧图像返回检测结果列表内部包含预处理resize、归一化、模型推理、NMS 后处理三个环节。封装的好处是后续如果要替换模型或加 TensorRT 加速只需改内部实现对外接口完全不变。6.2 TensorRT 加速与 FP16 量化实测部署在 GPU 上时TensorRT 加速效果非常明显。实测同一模型在 PyTorch 原始推理是 35ms/帧转成 TensorRT FP16 后降到 12ms/帧提速接近 3 倍。TensorRT 的加速主要来自三个层面算子融合把多个小算子合并成一个大算子减少内核启动开销、精度校准FP16 或 INT8 下用更少的位数存储权重和激活值、显存优化推理时更高效的显存复用策略。其中 FP16 量化在检测任务里精度损失通常很小mAP 下降不超过 1 个百分点工程收益却很明显。如果你要做 INT8 量化要注意逐层校准的过程。INT8 量化需要用代表性数据做校准校准数据要和实际场景一致否则量化误差会被放大。我试过用白天的数据校准模型夜间图片扑街重新用混合场景数据校准后就好了。6.3 摄像头流接入与实时视频检测框架部署阶段的经典场景是接摄像头实时视频流。这里最大的坑是处理速度跟不上视频帧率导致画面卡顿或检测结果延迟。解决方案不是优化模型推理速度而是改成异步处理架构。我采用的多线程模型是这样的采集线程负责从摄像头取帧放入一个固定长度的队列推理线程从队列中取帧做检测把结果放入输出队列显示线程从输出队列取结果并绘制。队列满时丢最旧的帧保证延迟可控。实际操作中有个参数需要根据摄像头帧率调整抽帧间隔。如果摄像头是 30 FPS但模型推理只能做到 15 FPS没必要每帧都推理。每 2 帧抽 1 帧做检测中间 1 帧用上一帧的结果补上视觉上完全没问题还能降低计算负载。这也是道路交通视频监控中常见的工程做法。7. 常见问题与排查实录7.1 大量漏检先查数据还是先调参漏检问题首先要定位在哪一个环节。判断方法是直接把测试集中的典型图片喂给模型查看输出结果。如果训练时 mAP 已经不错了但实际场景漏检多半是数据分布差异如果训练时 mAP 本身就低那就要排查训练环节。训练阶段漏检通常有两个原因类别不均衡或 Anchor 参数不匹配。类别不均衡的表现是少数类几乎全漏解决方法是调整 α 权重或补充该类别的训练数据。Anchor 不匹配的表现是特定尺寸范围的目标全漏比如远处行人解决方法是按数据集统计重新设置 Anchor 尺寸。实际场景漏检则大概率是数据覆盖不足。我遇到过夜间车辆漏检严重的问题原因是训练数据里夜间样本占比太低。补充夜间数据后模型表现明显改善。说到底模型能检测什么取决于训练数据里有什么。7.2 小目标检测效果差的针对性优化小目标检测差是道路交通场景的高频问题。提升效果的手段按收益排序提升输入分辨率、加大浅层特征图权重、调整 Anchor 尺寸、增加小目标样本的数据增强。这四招按顺序做一遍效果立竿见影。提升输入分辨率最直接。800×800 提升到 1280×1280 后小目标的特征信息更完整检测难度大幅降低但推理时间可能翻倍。所以在做这个调整前先确认硬件算力是否吃得住。另一个思路是修改 FPN 的输出层配置让 P2 层原图 1/4 分辨率也参与检测它的分辨率更高对小目标更友好。但这会增加计算量具体影响需要用实验数据说话。数据增强方面针对性做法是复制小目标并粘贴到其他位置。这个操作原理很简单小目标样本本来就少复制粘贴可以增加它出现的次数让模型有更多机会学习。我在项目中用过随机角度、随机位置的粘贴方式小目标的 mAP 提升了约 3 个百分点。7.3 训练 loss 不下降或早期震荡怎么办loss 不下降的排查顺序固定为数据是否正常、超参数是否合理、模型结构是否正确。先检查数据。用脚本可视化加载后的训练样本确认图片和标注框是否正确对齐有没有标签错位的文件。再检查 loss 统计方式如果跑了很多步但 loss 一直在一个较小范围内波动可能是类别权重 α 设置不当导致难例权重过低。如果是从头训练不加载预训练权重loss 下降极慢是正常的因为检测头要从零学特征建议尽量使用预训练权重。早期震荡最大概率是学习率和 warmup 设置问题。学习率直接从 0.01 开始通常会导致 loss 先涨后跌甚至直接发散。正确的做法是加 warmup前几百步用很小的学习率让模型先稳定下来再逐渐升到目标学习率。另一个原因是 batch size 过小BN 层统计不稳定这种情况下可以考虑增大 batch size 或者使用同步 BN。注意训练日志的保存密度也很重要。每 10 步记一次训练 loss每 500 步做一次小批量验证。日志太少会看不到损失曲线的细粒度变化日志太多则会拖慢训练速度。合理密度才能高效排查问题。7.4 套用一份可复用的排障速查表为了方便后续项目快速排障我把踩过的坑整理成了表 2 所示的速查表。现象可能原因优先解决动作每类都漏检Anchor 尺寸与数据集不匹配统计标注框尺寸重新设置 Anchor仅少数类漏检正负样本不平衡调 Focal Loss 的 α 权重补充该类样本小目标全部漏检输入分辨率过低或 P2 层未参与检测提高输入分辨率启用 P2 层预测框重叠严重NMS 阈值过高调低 NMS IoU 阈值至 0.4 左右同类目标多输出一个框跨类别 NMS 未开启增加跨类别 NMS 逻辑训练 loss 震荡学习率过大或 warmup 缺失降低初始学习率增加 warmup 步数实际场景表现差但训练 mAP 高训练数据和场景分布差异过大补充场景数据微调这套速查表帮我在三次不同的检测项目中快速定位了问题每次节省的排查时间都在一天以上。最后说点个人的实操体会RetinaNet 这个模型放在现在并不算“年轻”但如果你要找一个精度高、速度快、部署方便的检测基线方案它仍然非常能打。我之前也用更新的模型做过尝试但综合考虑训练成本、部署复杂度和社区成熟度最终跑通项目的还是 RetinaNet。这给我的一个启发是选模型不是追求最新而是匹配场景和工程链路的成熟度。数据标注这个环节再强调一次它直接决定模型上限。很多人把精力都花在调参上但数据质量差的模型再怎么调都上不去。我建议在项目早期把标规范则定清楚多花几天做质量校准比后续反复返工划算得多。实际部署中我还有一个体会检测框出来只是第一步如何筛选有效信息才是真正影响业务价值的地方。比如交通监控里对同一个目标连续多帧的检测结果做轨迹平滑能够明显减少误报和跳变。这个方向虽然不在本文的标题范围内但如果你的系统已经跑通了检测流程非常值得继续深入做下去。