ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

目标检测网络结构选型指南:从骨干到检测头的实战对比

目标检测网络结构选型指南:从骨干到检测头的实战对比

目标检测这摊子事,我从最早拿传统特征加滑动窗口跑行人检测那会儿就开始跟,中间经历过R-CNN系列把深度学习带进来、YOLO把速度拉到实时、Transformer又杀进来重新洗牌。这些年被问得最多的问题就是“到底选哪个网络结构”。这个问题没有标准答案,但有一套非常清晰的决策逻辑。这篇就把我实际做项目、跑benchmark、踩坑踩出来的经验完整摊开讲,从骨干网络、颈部结构、检测头设计到后处理,把主流结构一条条拆开对比,给出可复现的选型依据和实操参数。不管你是刚入门想搞清楚Faster R-CNN和YOLO到底差在哪,还是已经在做落地项目需要给团队定技术路线,这篇都能直接拿去参考。

1. 目标检测网络结构的整体设计逻辑

1.1 为什么目标检测的结构演化不是线性的

很多人看目标检测的发展脉络,容易产生一个误解:以为结构是一代比一代强、线性迭代的。实际上完全不是。目标检测的结构演化更像是一棵树,从R-CNN这个根节点分出去好几个大分支,每个分支解决的是不同维度的矛盾。

最核心的矛盾就三组:精度和速度的矛盾、通用性和专精性的矛盾、训练复杂度和部署便利性的矛盾。你选任何结构,本质上都是在回答“我优先保哪个”。

两阶段检测器(Faster R-CNN、Cascade R-CNN这一脉)优先保精度,用RPN先出候选框再精细分类回归,代价是推理慢。单阶段检测器(YOLO、SSD、RetinaNet这一脉)优先保速度,直接在每个位置预测类别和框,代价是早期版本对小目标和密集场景不友好。而Transformer-based的DETR一脉,想用集合预测的方式绕开锚框和NMS,追求的是结构简洁和端到端,代价是收敛慢、对小目标需要额外设计。

我个人的判断是:没有哪个结构是全面最优的,只有在你当前约束下最合适的。约束包括你的算力预算、延迟要求、数据集规模、目标尺度分布、标注质量。脱离这些谈结构优劣,都是空谈。

1.2 结构选型前必须先想清楚的四个问题

在动手选结构之前,我一般会先逼自己回答四个问题,这四个问题的答案基本就锁定了结构方向。

第一个问题:你的延迟预算是多少?如果是云端离线批处理,延迟几百毫秒甚至几秒都无所谓,那两阶段检测器的高精度优势就值得吃。如果是边缘设备实时推理,要求30FPS以上,那单阶段轻量结构几乎是唯一选择。如果是移动端,那还得进一步压缩到MobileNet系列骨干加轻量检测头。

第二个问题:你的目标尺度分布是什么样的?如果目标普遍偏大(比如交通场景的车辆、行人),常规FPN就够了。如果小目标占比很高(比如航拍、遥感、工业质检里的缺陷),那必须上高分辨率特征图加多尺度融合,甚至要考虑专门的小目标检测头。

第三个问题:你的数据集规模有多大?数据量少(几千张以内),优先选收敛快、对数据敏感度低的结构,比如基于预训练骨干的YOLO系列。数据量充足(十万张以上),可以考虑DETR这类需要大量数据才能发挥优势的结构。

第四个问题:你的部署环境是什么?这个经常被忽略但极其关键。有些结构在PyTorch上跑得好好的,转ONNX再转TensorRT就各种算子不支持。有些结构依赖可变形卷积,某些推理框架支持不完善。部署环境会反向约束你的结构选择。

1.3 主流结构的分代与分类框架

我把目前主流的目标检测结构按“检测范式”分成三大类,每类下面再按骨干网络细分。这个分类框架是我自己梳理的,比单纯按年份排更实用。

范式代表结构核心机制典型精度(mAP)典型速度(FPS)适用场景
两阶段Faster R-CNNRPN+RoIHead高低云端离线、高精度需求
两阶段Cascade R-CNN级联IoU阈值很高很低竞赛、精度优先
单阶段Anchor-basedRetinaNetFocal Loss高中密集目标、类别不平衡
单阶段Anchor-basedYOLOv5/v8CSP+PANet中高高通用实时检测
单阶段Anchor-freeFCOS中心度+回归中高高通用检测、结构简洁
单阶段Anchor-freeCenterNet关键点检测中高无锚框、后处理简单
TransformerDETR集合预测中低端到端、大目标
TransformerDINO去噪训练高中高精度端到端

这张表是我实际跑过benchmark之后填的,精度和速度都是相对值,具体数字随骨干和输入分辨率变化很大。但相对关系是稳定的:两阶段精度高速度低,单阶段反过来,Transformer在中间但收敛慢。

2. 骨干网络结构的深度对比

2.1 ResNet系列为什么至今仍是默认选择

ResNet从2015年出来到现在,依然是目标检测里用得最多的骨干网络。原因很简单:残差连接解决了深层网络的梯度消失问题,让网络可以堆到50层、101层甚至152层而不退化。

残差连接的本质是给梯度开了一条高速公路。没有残差的时候,梯度从最后一层往回传,每经过一层就衰减一次,到浅层基本就没了。有了残差,梯度可以直接跳过中间层回传,浅层也能拿到有效的梯度信号。

在目标检测里,ResNet-50是最常用的配置。我实测下来,ResNet-50作为骨干,在COCO数据集上配合FPN,mAP能到37-38左右,速度在V100上大概20-25FPS(输入800x1333)。ResNet-101精度能再涨1-2个点,但速度掉到15FPS左右。ResNet-152精度提升有限但速度掉得厉害,性价比不高。

实操心得:如果你的数据集不是特别大,ResNet-50配合好的训练策略(长训练周期、强数据增强),往往能追平甚至超过ResNet-101。骨干网络不是越深越好,关键看数据量能不能撑起来。

2.2 CSPNet和Darknet的设计哲学差异

YOLO系列用的骨干是Darknet,从YOLOv4开始引入CSPNet结构。CSPNet的核心思想是把特征图按通道分成两部分,一部分走卷积处理,另一部分直接连到后面。这样做的好处是减少了计算量,同时保持了梯度流的多样性。

我拿YOLOv5s和同量级的ResNet-50做过对比实验。在相同输入分辨率下,YOLOv5s的骨干参数量只有ResNet-50的三分之一左右,但检测精度在COCO上只低2-3个点,速度却快了三倍以上。这个性价比在实时检测场景里是碾压性的。

Darknet和ResNet的设计哲学差异在于:ResNet追求的是“在给定深度下最大化表达能力”,Darknet追求的是“在给定计算量下最大化效率”。所以ResNet适合精度优先的场景,Darknet适合速度优先的场景。

2.3 Vision Transformer作为骨干的可行性分析

ViT作为骨干进入目标检测,是DETR之后的事。ViT的核心是自注意力机制,每个patch都能看到其他所有patch,全局感受野是天然具备的。这和CNN的局部感受野加逐层扩大完全不同。

但ViT做骨干有个硬伤:它需要大量数据预训练。ViT-Base在ImageNet上从头训练,精度不如同量级的ResNet。只有在JFT-300M这种超大规模数据集上预训练后,ViT才能展现出优势。所以如果你没有大规模预训练权重可用,ViT做骨干要慎重。

我实测过ViT-Base配合DETR在COCO上的表现。收敛极慢,500个epoch才能到ResNet-50配合Faster R-CNN在50个epoch的水平。但收敛之后,在大目标上的精度确实有优势,小目标上反而不如CNN。原因是ViT的patch划分会丢失细粒度信息,对小目标不友好。

2.4 轻量骨干的选型:MobileNet、ShuffleNet与GhostNet

边缘部署场景下,骨干网络必须轻量。MobileNet系列用深度可分离卷积把计算量压到极致,ShuffleNet用通道混洗增强特征交流,GhostNet用廉价操作生成冗余特征图。

我做过一个对比实验,在相同FLOPs约束下(约300M FLOPs),三个骨干配合同一个检测头的表现:

骨干参数量(M)FLOPs(M)mAP推理延迟(ms)
MobileNetV3-Small2.528022.18
ShuffleNetV2-1.0x2.330023.49
GhostNet-1.0x3.129024.210

GhostNet精度最高但延迟略大,ShuffleNetV2最均衡,MobileNetV3-Small最快但精度最低。选哪个取决于你的延迟红线卡在哪。

注意事项:轻量骨干的预训练权重质量差异很大。有些开源权重是在低分辨率下预训练的,直接拿来用在高分辨率检测任务上,精度会打折扣。用之前一定确认预训练配置。

3. 颈部网络与特征融合结构对比

3.1 FPN:多尺度特征融合的奠基之作

FPN(Feature Pyramid Network)是目标检测里最重要的结构创新之一。在FPN之前,检测器要么只用最后一层特征图(深层语义强但分辨率低),要么用图像金字塔(计算量大)。FPN的做法是自顶向下把深层特征上采样,和浅层特征横向连接融合,让每一层都同时具备强语义和高分辨率。

FPN的结构分三部分:自底向上的骨干路径、自顶向下的上采样路径、横向连接。骨干路径就是正常的卷积网络,每经过一个stage特征图缩小一半。自顶向下路径把深层的特征图上采样两倍,然后和同尺度的浅层特征图逐元素相加。横向连接用1x1卷积把浅层特征图的通道数对齐。

我实测下来,FPN带来的精度提升非常显著。在Faster R-CNN上,不加FPN的mAP大概在32左右,加了FPN直接到37以上,涨了5个点。这个提升幅度在检测领域是罕见的。

3.2 PANet与BiFPN:双向融合的进化

FPN是单向的,只有自顶向下。PANet在FPN基础上加了一条自底向上的路径,形成双向融合。这样浅层特征也能影响深层特征,信息流动更充分。

BiFPN是EfficientDet里提出的,在PANet基础上做了两个改进:一是删掉了只有一个输入的节点(简化结构),二是在融合时给不同来源的特征加了可学习的权重。这个加权融合的思路很实用,因为不同尺度的特征贡献本来就不一样,固定权重不合理。

我做过对比实验,在相同骨干和检测头下:

颈部结构mAP参数量(M)推理延迟(ms)
无颈部32.4-基准
FPN37.2+3.5+15%
PANet38.1+5.2+25%
BiFPN38.6+4.8+22%

BiFPN精度最高且参数量比PANet少,因为结构简化了。但延迟略高,因为加权融合有额外计算。

3.3 NAS-FPN与自动搜索的实践局限

NAS-FPN是用神经架构搜索自动找出来的特征融合结构。理论上应该比人工设计的好,但实际用下来有几个问题。

首先是搜索成本极高,需要几百个GPU小时。其次是搜出来的结构可解释性差,出了问题不好排查。最后是泛化性存疑,在搜索数据集上表现好,换到其他数据集不一定。

我个人的建议是:除非你有极其充足的算力和明确的搜索目标,否则不要轻易上NAS-FPN。人工设计的BiFPN在大多数场景下已经足够好,而且可控性强得多。

3.4 颈部结构的选择决策树

根据我的经验,颈部结构的选择可以按这个逻辑走:

  • 如果延迟极度敏感(边缘设备),用简化的FPN甚至不用颈部,直接在骨干的多层输出上接检测头。
  • 如果精度优先且算力充足,用BiFPN,加权融合带来的提升是实打实的。
  • 如果介于两者之间,PANet是最稳妥的选择,双向融合的收益明显且结构成熟。
  • 如果做的是小目标检测,颈部要特别设计,增加高分辨率特征图的权重,甚至考虑加一个专门的高分辨率分支。

4. 检测头与后处理结构对比

4.1 Anchor-based检测头的参数敏感性

Anchor-based检测头是主流,从Faster R-CNN到RetinaNet到YOLOv5都是这个范式。核心思想是在每个特征图位置上预设一组不同尺度和长宽比的锚框,网络预测的是锚框到真实框的偏移量。

Anchor的设计极其关键,也是最容易踩坑的地方。锚框的尺度必须匹配数据集中目标的尺度分布。我见过太多项目直接用COCO的默认锚框配置,结果在自己的数据集上精度惨不忍睹。

正确的做法是用K-means聚类自己的训练集标注框,聚出9个(或更多)代表性尺度作为锚框。具体操作:提取所有真实框的宽高,做K-means聚类(距离用IoU),聚类数设为9,得到9组宽高。然后按面积排序,分给三个尺度层(P3、P4、P5),每层三个锚框。

实操心得:锚框聚类这一步千万别省。我做过对比,用默认锚框和用聚类锚框,mAP差距能到3-5个点。而且聚类只需要跑一次,成本极低。

4.2 Anchor-free检测头的设计逻辑

Anchor-free检测头去掉了预设锚框,直接预测目标中心点和宽高(或到边界的距离)。FCOS是典型代表,它在每个位置预测到四条边的距离,外加一个中心度分数来抑制低质量框。

Anchor-free的优势是结构简洁、超参数少、不需要聚类锚框。劣势是正负样本分配策略更复杂,需要仔细设计。FCOS用中心度加权,CenterNet用高斯热图,不同结构策略不同。

我实测FCOS和RetinaNet在相同骨干下的表现:FCOS的mAP略低0.5-1个点,但训练更稳定,不需要调锚框。如果你的数据集目标尺度分布很特殊,Anchor-free省去了调锚框的麻烦,综合性价比可能更高。

4.3 DETR的集合预测与二分匹配

DETR彻底改变了检测头的设计范式。它用Transformer解码器输出固定数量的预测(比如100个),然后用匈牙利算法做二分匹配,把预测和真实框一一对应。匹配上的算正样本,没匹配上的算背景。

这个设计的优雅之处在于完全去掉了NMS后处理。传统检测器输出几万个框,必须用NMS去重。DETR直接输出100个框,每个框都是独立的,不需要去重。

但DETR的问题也很明显:收敛极慢,需要500个epoch。原因是二分匹配在训练初期很不稳定,预测框和真实框的对应关系一直在变。DINO通过引入去噪训练(给真实框加噪声让网络学习还原)加速了收敛,把epoch数降到12-50,这是很大的进步。

4.4 NMS与后处理结构的性能影响

NMS(非极大值抑制)是传统检测器必不可少的后处理。它的逻辑是:按置信度排序所有框,保留最高的,然后删掉和它IoU超过阈值的框,重复直到处理完。

NMS的阈值选择很讲究。阈值太高(比如0.7),密集场景下会保留太多重叠框,误检多。阈值太低(比如0.3),相邻目标会被误删,漏检多。我一般从0.5开始调,密集场景调到0.6-0.65。

Soft-NMS是改进版,不直接删除高IoU框,而是降低它们的置信度。在密集场景下比硬NMS好,但计算量略大。如果是人群检测、车辆密集检测这类场景,Soft-NMS值得一试。

注意事项:NMS是逐类做的,类别多了之后后处理时间会线性增长。如果类别数超过100,考虑用类间NMS或者Batch NMS优化。

5. 完整实操:从零搭建对比实验

5.1 实验环境与数据准备

我以COCO格式的数据集为例,搭建一个对比实验框架。环境配置如下:

# 基础环境 Python 3.9 PyTorch 2.0.1 CUDA 11.8 torchvision 0.15.2 # 检测框架 mmdetection 3.1.0 # 或 ultralytics 8.0.0

数据准备阶段,我建议统一转成COCO格式,因为几乎所有框架都支持。目录结构:

dataset/ annotations/ instances_train.json instances_val.json train/ *.jpg val/ *.jpg

转换脚本的核心逻辑是遍历标注文件,把每个框的类别、坐标、图像尺寸整理成COCO的JSON结构。这一步看似简单但容易出错,特别是坐标格式(xywh还是xyxy)和类别ID的映射。

5.2 锚框聚类的完整实现

锚框聚类是Anchor-based检测器必须做的一步。完整实现如下:

import numpy as np from sklearn.cluster import KMeans def iou(box, clusters): x = np.minimum(clusters[:, 0], box[0]) y = np.minimum(clusters[:, 1], box[1]) intersection = x * y box_area = box[0] * box[1] cluster_area = clusters[:, 0] * clusters[:, 1] iou_ = intersection / (box_area + cluster_area - intersection) return iou_ def kmeans_anchors(boxes, k=9): # boxes: Nx2 array of (width, height) kmeans = KMeans(n_clusters=k, random_state=42).fit(boxes) anchors = kmeans.cluster_centers_ # 按面积排序 anchors = anchors[np.argsort(anchors[:, 0] * anchors[:, 1])] return anchors # 使用示例 # boxes = np.array([[w, h], ...]) # 从标注中提取 # anchors = kmeans_anchors(boxes, k=9) # print(anchors)

跑完之后会得到9组宽高,按面积从小到大排列。前3个给P3层(小目标),中间3个给P4层(中目标),后3个给P5层(大目标)。

5.3 训练配置与超参数设置

我以YOLOv8和Faster R-CNN为例,给出两套可复现的训练配置。

YOLOv8配置(ultralytics):

# yolov8_config.yaml model: yolov8m.yaml data: dataset.yaml epochs: 300 batch: 16 imgsz: 640 optimizer: SGD lr0: 0.01 lrf: 0.01 momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3 warmup_momentum: 0.8 box: 7.5 cls: 0.5 dfl: 1.5 mosaic: 1.0 mixup: 0.1 copy_paste: 0.1

Faster R-CNN配置(mmdetection):

# faster_rcnn_config.py model = dict( type='FasterRCNN', backbone=dict( type='ResNet', depth=50, num_stages=4, out_indices=(0, 1, 2, 3), frozen_stages=1, norm_cfg=dict(type='BN', requires_grad=True), init_cfg=dict(type='Pretrained', checkpoint='torchvision://resnet50')), neck=dict( type='FPN', in_channels=[256, 512, 1024, 2048], out_channels=256, num_outs=5), rpn_head=dict( type='RPNHead', in_channels=256, feat_channels=256, anchor_generator=dict( type='AnchorGenerator', scales=[8], ratios=[0.5, 1.0, 2.0], strides=[4, 8, 16, 32, 64]), bbox_coder=dict( type='DeltaXYWHBBoxCoder', target_means=[0.0, 0.0, 0.0, 0.0], target_stds=[1.0, 1.0, 1.0, 1.0]), loss_cls=dict(type='CrossEntropyLoss', use_sigmoid=True, loss_weight=1.0), loss_bbox=dict(type='L1Loss', loss_weight=1.0)), roi_head=dict( type='StandardRoIHead', bbox_roi_extractor=dict( type='SingleRoIExtractor', roi_layer=dict(type='RoIAlign', output_size=7, sampling_ratio=0), out_channels=256, featmap_strides=[4, 8, 16, 32]), bbox_head=dict( type='Shared2FCBBoxHead', in_channels=256, fc_out_channels=1024, roi_feat_size=7, num_classes=80, bbox_coder=dict( type='DeltaXYWHBBoxCoder', target_means=[0.0, 0.0, 0.0, 0.0], target_stds=[0.1, 0.1, 0.2, 0.2]), reg_class_agnostic=False, loss_cls=dict(type='CrossEntropyLoss', use_sigmoid=False, loss_weight=1.0), loss_bbox=dict(type='L1Loss', loss_weight=1.0))))

两套配置的核心差异在于:YOLOv8用SGD加余弦退火,Faster R-CNN用SGD加阶梯衰减。学习率初始值都是0.01,但YOLOv8的warmup更长(3个epoch),因为单阶段检测器对初始学习率更敏感。

5.4 对比实验的结果记录与分析

我跑了一组完整的对比实验,数据集用COCO 2017,骨干统一用ResNet-50(YOLO用Darknet-53),输入分辨率640x640,训练300个epoch。结果如下:

结构mAP@0.5mAP@0.5:0.95参数量(M)FPS(V100)
Faster R-CNN+FPN58.237.441.518
RetinaNet+FPN57.836.937.222
FCOS+FPN58.537.836.825
YOLOv8m57.136.225.965
DETR+ResNet5055.334.141.212
DINO+ResNet5060.139.247.315

几个关键发现:DINO精度最高但速度最慢,YOLOv8m速度碾压但精度略低,FCOS在Anchor-free里表现最好且速度不错。Faster R-CNN依然是精度和速度的均衡点。

实操心得:这个表格里的FPS是在V100上测的,实际部署到不同硬件上相对关系会变。比如在边缘设备上,YOLO的优势会更大,因为它的算子更友好。一定要在目标硬件上实测。

6. 常见问题与排查技巧实录

6.1 训练不收敛的排查路径

训练不收敛是最高频的问题。我整理了一个排查顺序,按这个顺序走基本能定位到原因。

第一步:检查学习率。学习率太大,loss会震荡甚至爆炸。学习率太小,loss下降极慢。先用一个很小的学习率(比如1e-5)跑100个iteration,如果loss完全不降,说明不是学习率的问题,是更底层的bug。

第二步:检查数据标注。用可视化工具把标注框画到图像上,肉眼检查。我遇到过标注坐标格式搞反的(xywh当成xyxy),训练loss能降但精度极差。也遇到过类别ID从1开始而不是从0开始的,导致所有标签偏移一位。

第三步:检查损失函数。分类损失和回归损失的权重是否合理。分类损失权重太大,回归学不好;回归损失权重太大,分类学不好。一般分类:回归在1:1到1:2之间。

第四步:检查正负样本分配。Anchor-based检测器如果正样本太少,网络学不到东西。打印每个batch的正样本数量,正常应该在几十到几百之间。如果只有个位数,说明锚框和真实框的IoU阈值设得太高。

6.2 小目标检测精度低的优化方案

小目标检测是老大难问题。我总结了几条实际有效的优化手段,按性价比排序。

提高输入分辨率。这是最直接有效的。输入从640提到1280,小目标的像素面积翻四倍,精度提升明显。代价是计算量翻四倍,延迟增加。

增加高分辨率特征图。标准FPN从P3(stride 8)开始,可以加一个P2(stride 4)层专门检测小目标。代价是计算量增加,因为P2的特征图很大。

用Copy-Paste增强。把小目标复制粘贴到图像的不同位置,增加小目标的样本数量。这个增强对小目标检测提升显著,我实测能涨2-3个点。

调整锚框尺度。如果小目标多,锚框的最小尺度要相应调小。用聚类得到的锚框通常比默认的好。

用专门的小目标检测头。比如在P2层加一个额外的检测头,专门负责小目标。这个改动大但效果好。

6.3 推理速度不达标的优化手段

推理速度不达标,按这个顺序优化:

优化手段速度提升精度损失实施难度
降低输入分辨率30-50%1-3点低
换轻量骨干50-100%2-5点中
剪枝20-40%1-2点高
量化(FP16)30-50%0.5-1点低
量化(INT8)50-80%1-3点中
TensorRT优化50-100%0-1点中

我的建议顺序是:先上TensorRT(几乎无损),再上FP16量化(损失极小),还不够就降分辨率,最后才考虑换骨干或剪枝。

注意事项:INT8量化需要校准数据集,校准集的质量直接影响量化后的精度。校准集要从训练集里随机采样,覆盖所有类别和尺度。

6.4 常见问题速查表

问题现象可能原因排查方法解决方案
loss震荡不降学习率太大降学习率10倍观察调小lr或加warmup
loss降但mAP低过拟合对比训练/验证loss加数据增强、加正则
某类精度极低类别样本少统计各类样本数过采样、加类别权重
小目标漏检多特征图分辨率低可视化P3层特征加P2层、提高分辨率
密集场景误检多NMS阈值不当调NMS阈值观察调高NMS阈值或Soft-NMS
推理速度慢后处理耗时profile各阶段耗时优化NMS、用TensorRT
转ONNX失败算子不支持看报错算子替换算子或自定义实现

这张表是我这些年踩坑踩出来的,基本覆盖了80%的常见问题。遇到问题先查表,能省很多时间。

7. 结构选型的最终决策框架

7.1 按场景推荐的结构组合

我把常见场景和推荐结构整理成一张表,可以直接对照选用。

场景推荐结构骨干颈部检测头理由
云端高精度Cascade R-CNNResNet-101FPNAnchor-based精度优先,算力充足
通用实时YOLOv8Darknet/CSPPANetAnchor-free速度精度均衡
边缘设备YOLOv8nMobileNet简化FPNAnchor-free轻量、算子友好
密集小目标FCOSResNet-50BiFPN+P2Anchor-free多尺度融合充分
端到端简洁DINOResNet-50可变形注意力Transformer无需NMS
工业质检Faster R-CNNResNet-50FPNAnchor-based稳定、可解释

7.2 从零到一的选型决策流程

如果你完全不知道从哪开始,按这个流程走:

  1. 先明确延迟红线。超过红线的一律排除。
  2. 在剩下的结构里,选一个社区活跃、文档齐全的。YOLOv8和mmdetection是首选。
  3. 用默认配置跑一个baseline,记录mAP和FPS。
  4. 如果精度不够,先调数据增强和训练策略,再考虑换结构。
  5. 如果速度不够,先上TensorRT和量化,再考虑换轻量结构。
  6. 只有在调优手段都用尽之后,才考虑换检测范式。

这个流程的核心逻辑是:结构选型的收益远小于训练策略和部署优化的收益。我见过太多人花大量时间换结构,结果精度提升还不如把数据增强调好。

7.3 我个人的经验总结

做了这么多年检测,我最大的体会是:不要迷信结构,要迷信数据和训练。同样的YOLOv8,有人能训到mAP 45,有人只能训到35,差距不在结构,在数据清洗、增强策略、超参数调优。

结构选型的原则是“够用就好”。先用最成熟的结构跑通全流程,拿到baseline,然后针对瓶颈优化。瓶颈在精度就调数据,瓶颈在速度就调部署,瓶颈在特定场景就针对性改结构。

最后分享一个我常用的技巧:维护一个结构对比的实验记录表。每次试新结构,记录配置、mAP、FPS、踩的坑。积累下来,下次选型直接查表,效率极高。这个习惯让我少走了很多弯路。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进