计算机视觉这两年火得不行,但很多人一上来就掉进“调包训练”的坑里,玩了一个月连目标检测到底在解决什么问题都说不清楚。目标检测是计算机视觉最核心的方向之一,既要“找到目标在哪”,又要“判断目标是什么”,比图像分类难了一个维度。这篇文章是把目标检测的底子给你捋清楚,从问题定义、经典流派到核心组件、训练实操,适合刚入门深度学习但被各种术语绕晕的开发者,也适合做了几年工程但一直没系统梳理过检测技术演进的从业者。读完你会明白R-CNN、YOLO这些名字背后的设计逻辑,以及为什么检测模型训练起来比分类模型麻烦那么多。
1. 目标检测到底在解决什么问题
1.1 检测任务的数学表达与物理意义
目标检测的一句话定义是:给定一张图像,找出其中所有属于预定类别集合的目标实例,并为每个实例输出一个边界框(Bounding Box)和对应的类别标签。
数学上,一张输入图像可以表示为 (I \in \mathbb{R}^{H \times W \times 3}),检测模型要输出一个集合:
[ D = {(b_i, c_i, s_i)}_{i=1}^{N} ]
其中 (b_i = (x_{min}, y_{min}, x_{max}, y_{max})) 是目标的边界框坐标,(c_i) 是类别编号,(s_i) 是置信度分数。
听起来很简单,但真正做起来麻烦得很。这里面有两个核心难点:
第一个难点是“尺度问题”。同一类目标在图像里可能大得占满整个画面,也可能小到只有十几个像素。比如行人检测,站在镜头前的人和远处的人,尺寸可能差几十倍。模型要同时对这两种极端尺度保持敏感,这本身就是个很大的挑战。
第二个难点是“密度问题”。目标可能密集排列、互相遮挡,比如拥挤的地铁车厢里的人群,每个目标只有头部一小块露出来。模型不仅要找到每个目标,还要把它们区分开,不能把两个人框到一起。
还有第三个麻烦的地方:一张图像里目标的“个数”是不固定的。这就是检测和分类的另一个本质区别——分类的输出维度是固定的(就那几个类别),检测输出的是不定长集合。你想想,全连接层往那一放,输出向量的长度是固定的,但目标数量是变化的,这中间的矛盾就需要特殊设计来解决。也正因为这个不定长输出的特性,检测模型的结构设计远比分类网络复杂,跑通一个训练实验的时间和算力成本也高得多。
1.2 困难的根源:坐标回归与不确定输出长度
既然检测难,那到底难在什么地方?我拆开说。
坐标回归的本质是输出四个连续数值,把目标的真实位置用浮点数框出来。这比分类里的离散标签要麻烦得多。分类输出的是一个概率分布,比如“是猫的概率0.9,是狗的概率0.1”,梯度更新方向是明确的。但回归输出的四个坐标,每一个都需要和真实坐标做距离计算,这个距离函数怎么定义、量纲怎么统一、不同尺度的目标怎么归一化,全是坑。
再说输出长度不定。训练时你标注了一张图,里面有5个目标,另一张图里有10个目标,模型输出该是5×5张量还是10×5张量?这个问题从R-CNN时代就开始用各种间接方式规避,先框出一堆候选区域,再逐个判断是不是目标,最后再做坐标修正,绕了一大圈。直到后来的DETR这种基于Transformer的方法,才算是从架构层面上正面解决了“集合预测”这个问题。
还有一个细节容易被忽略:边界框的真实坐标是绝对像素值,还是归一化后的相对值?用得最多的是除以图像宽高做归一化。为什么?为了对不同分辨率的输入具有一致性。要是图像是1280×720,一个目标在x方向占200个像素,换算成归一化坐标就是200/1280≈0.156。模型直接去回归这个0到1之间的小数,数值范围稳定,损失函数也好设计。
1.3 评价指标体系的核心逻辑
搞检测的人见面第一句话就是问“你mAP多少”。mAP(mean Average Precision)是检测领域最核心的评价指标,但很多人只知道这个名字,不清楚它背后的统计意义。
先拆解一步:AP是某个类别上的平均精度。简单来说,模型输出了一堆带置信度分数的框,从高到低排序,逐个判断这个框和某个真实框的IoU(Intersection over Union)是否大于某个阈值(通常是0.5),是就是TP(True Positive),不是就是FP(False Positive)。把Precision和Recall的关系画成一条曲线,曲线下的面积就是AP。
mAP就是把所有类别的AP取平均。
关键点在于:mAP是“排序”敏感的指标。它默认你会按置信度从高到低输出检测结果,而且希望置信度高的框确实更准。这也是为什么模型最后一层输出的分数非常关键——它不只是“判断对不对”,还要“排得出先后”。很多人训练时发现loss已经很低了,但是mAP提不上去,就是因为置信度排序质量差,高分框反而落在错误位置上。
顺便说一下,mAP一般会标“0.5”或“0.5:0.95”之类的后缀。mAP@0.5表示IoU阈值取0.5,mAP@0.5:0.95表示把IoU阈值从0.5到0.95,每隔0.05取一个,共10个阈值算平均。后者是更严格的指标,对框的定位精度要求高得多。做工程落地时,mAP@0.5足够用了,但写论文、刷榜单,基本都是mAP@0.5:0.95的天下。
2. 传统方法与深度学习之前的日子
2.1 滑动窗口与手工特征时代
目标检测不是深度学习火了以后才有的,20年前就有大量的研究和工程实践。只是那个时代受限于算力和特征表达,检测算法的思路非常“朴素”。
传统方法的经典套路是这样的:用固定尺寸的窗口,从头到尾扫过整张图像,每个位置都提取一个特征向量,然后丢进分类器判断窗口里有没有目标,如果有,输出目标类别和框位置。这招叫滑动窗口检测,听起来简单粗暴,实际上也确实是暴力枚举。
特征方面,最出名的是HOG(Histogram of Oriented Gradients,方向梯度直方图)特征。它的核心思想是把图像分成小格子,统计每个格子里梯度的方向分布,形成直方图。这个特征对局部形状和纹理信息有较强的表达能力,尤其是对行人这种竖直状态的目标非常有效,所以当年在行人检测上表现优秀。
紧接着,有人把块状特征进一步扩展,搞出了DPM(Deformable Part Model,可变部件模型)。DPM的思路很有意思:一个目标由若干个部件组成,比如人由头、躯干、四肢组成,每个部件单独检测,再把部件之间相对位置的约束关系也建模出来,综合判断整个目标是不是存在。这个思路本质上就是后来的Attention机制的雏形,或者说像极了把整体问题拆分成子任务再综合决策的过程。
但滑动窗口的致命弱点显而易见:计算量巨大。一张图里有成千上万个窗口位置,每个位置都要提取一次特征,再跑一次分类器。而且固定尺寸的窗口天然处理不了多尺度问题,你只能跑金字塔多尺度变换,也就是把图像缩放成多个分辨率,每个分辨率都滑一遍窗口,计算量再翻好几倍。那时候我的个人体会是:训练一个模型要跑一整夜,推理一张图也要秒级,离实时差得远。
2.2 selective search 与创新思路
滑动窗口不行,就有人想:为什么非要穷举所有窗口?能不能先选出“可能含目标的区域”,再只对这些区域跑检测?这个想法催生了Region Proposal(区域提议)这个概念,其中最火的算法是selective search。
selective search的思路是用图像分割的办法先把像素聚类成小的超像素块,再逐步融合相似的相邻块,形成一系列由小到大的候选区域。通过这种方式,候选框的数量从滑动窗口的上万个缩减到两三千个,计算压力减轻不少。而且这些候选框往往符合目标的真实轮廓,比固定网格的滑动窗口更贴近语义边界。
我记得那时候业内讨论最多的问题不是“特征怎么设计”,而是“怎么减少候选区的数量,同时不丢召回”。selective search给出的答案是用颜色、纹理、大小、形状五种相似度指标融合来做层次化分组,相关信息保留得比较完整,但速度依然很慢——一张图提取候选区域往往要一两秒。今天回看这一段历史,可以说没有selective search的铺垫,就没有后来的R-CNN系列。但传统方法终究是走到头了,瓶颈卡在“特征表达能力”上——不管怎么设计特征提取器,都很难覆盖各种光照、遮挡、姿态变化。深度学习的出现,直接把特征编码交给了卷积网络来自动学习,这才真正掀翻了整个检测领域的玩法。
3. 两阶段流派:从R-CNN到Faster R-CNN
3.1 R-CNN的开创性思路与笨重代价
2014年,R-CNN的出现给检测领域扔下了一颗炸弹。它做的事情,现在看很简单:先跑selective search提取约2000个候选区域,然后把每个候选区域裁剪出来,缩放到固定尺寸,扔进预训练好的卷积网络(比如AlexNet,再然后VGG)提取特征,最后用SVM分类器判断类别。就这么一套组合拳,在Pascal VOC数据集上把mAP提升到了前所未有的高度,跟传统方法拉开了巨大的差距。
但R-CNN的缺陷也非常明显:2000个候选区域要分别过一遍卷积网络,推理一张图像要几十秒。训练还要多阶段分开做,先训特征提取网络,再训SVM分类器,最后训回归器,每个环节还要保存中间特征,磁盘占用大得吓人。当时有人吐槽它“像一台笨重的机器,虽然功率大,但跑起来浑身发抖”。
3.2 Fast R-CNN与Faster R-CNN的效率革命
R-CNN系列真正走上正轨,是Fast R-CNN用了一个非常巧妙的架构调整:不再把每个候选区域单独送进卷积网络,而是先把整张图过一遍卷积主干,得到一个共享的特征图,再对特征图上的候选区域做ROI Pooling,把不同尺寸的区域池化到固定尺寸的特征输出,最后统一接全连接分类和回归。这样一来,卷积计算只做一次,共享计算,推理速度大幅提升。
再往后,Faster R-CNN甚至把候选区域提取也放进了网络结构里,引入RPN(Region Proposal Network,区域提议网络)这样一个轻量级子网络,直接在卷积特征图上生成候选区域。这次改动不仅是速度提升,更重要的是整个训练流程从多阶段变成了端到端,真正意义上完成了“检测=基础网络+候选区域提取+分类回归”的架构统一。
两阶段流派的优势在哪里?精度高。候选区域筛选相当于给模型一个“先粗筛后精细”的机会,分类和回归都在高质量的候选区域上进行,类别不平衡问题天然缓解。缺点是速度上不去,即使到了Faster R-CNN时代,在GPU上推理一张1080P图像也需要100毫秒以上,离视频实时检测还有不小的距离。
3.3 锚点机制的原理与影响
讲到Faster R-CNN就绕不开锚点(anchor)这个概念,它也是整个深度学习检测体系中最核心的设计之一。
锚点是什么?简单来说,就是预先设定的一组不同大小、不同长宽比的参考框。比如在特征图的每个位置放9个锚点框,长宽比有1:1、1:2、2:1三种,面积有128²、256²、512²三种。检测模型的任务不是直接回归目标的绝对坐标,而是预测目标相对于这些锚点框的偏移量。这个把“绝对预测”转成“相对预测”的设计高明在哪里?目标尺寸分布太广、绝对坐标范围太大,直接回归难度高;锚点相当于把搜索空间缩小到了“在这附近微调”的程度,回归起来容易得多。
锚点数量怎么定?这个说实话很多时候是经验值加调参。锚点数太多,正负样本不平衡会更严重,训练速度也被拖慢;锚点数太少,召回率容易掉下来。我在实际项目里通常这样取值:先统计标注数据里所有目标的宽高分布,然后做一次聚类分析,看看目标尺寸集中在哪几档,再根据聚类中心去定制锚点框。比如某个项目里目标普遍偏小,我就把面积档位调低,把128改为64,效果立刻好了不少。这招在很多检测框架里都支持手动配置锚点,值得每个做检测的人熟练掌握。
4. 单阶段流派:YOLO的进化与关键设计
4.1 YOLO把检测变成单次回归问题
两阶段流派虽然精度高,但速度一直被诟病。YOLO(You Only Look Once)的诞生就是要彻底解决这个问题:把检测当成一个单次回归问题,输入图像,输出边界框坐标和类别概率,一气呵成。
第一版YOLO的做法是把图像划分成S×S的网格,每个网格负责预测固定数量的边界框,以及这些框的置信度和类别概率。整个模型就是一个卷积网络,从输入到输出直接映射,没有任何候选区域筛选的中间步骤。速度真的能跑到实时,一张图像几毫秒到几十毫秒搞定。
但初代YOLO的问题也是明摆着的:每个网格只能预测两个框(S通常是7),对密集小目标效果很差;网格划分是固定的,目标恰好横跨网格边界时就找不到语义中心;加上没有多尺度机制,小目标召回率低得可怜。我当时拿YOLOv1跑VOC数据集,看到漏检率和小目标错检率,真的有点尴尬。
4.2 YOLOv3的架构分水岭
YOLOv3是个特别重要的节点,很多人就是从这里开始接触YOLO系列的。为什么说它是分水岭?因为v3从底层架构上做了三件大事。
第一,引入了多尺度预测。v3在三个不同尺度的特征图上分别做检测,大的特征图对应小目标,小的特征图对应大目标。这个设计解决了单尺度对尺度变化敏感的固有问题,也是后面几乎所有检测框架的标准配置。
第二,用了FPN(Feature Pyramid Network,特征金字塔网络)那种自顶向下的路径融合方式,把深层语义信息逐层回传到浅层特征上,让浅层特征图不仅“看得细”还“懂得多”。小目标的检测能力大幅提升。
第三,在主干网络上选择了Darknet-53,去掉了很多池化层,改用步长为2的卷积来做下采样。这样做的好处是特征信息保留更好,梯度传播路径更通畅,训练更稳。
YOLOv3的损失函数也值得一提,它把损失分成三块:坐标回归损失、置信度损失、类别损失。置信度损失用的是二分类交叉熵,判断“这个格子里面到底有没有目标”;类别损失用多标签交叉熵(有的框架用softmax,但v3是sigmoid),因为一个框可能同时属于多个类别语义(比如“人”和“行人”)。
YOLOv3的论文里有一个细节我特别喜欢,就是它指出边框坐标的回归目标应该用sigmoid函数压缩到0到1之间,直接预测网格内的相对位置,而不是预测任意浮点数。原始YOLO直接回归坐标导致前期预测值可能跑到离网格很远的地方,训练不稳定,v3用sigmoid套了一层,相当于给回归加了边界约束,实操中确实发现训练更稳。
4.3 Anchor-Free潮流与后续演进
YOLOv3之后,检测领域出现了一个很重要的思想转向:anchor-free。之前所有人都默认锚点是必需品,但一批工作开始质疑:能不能不定义锚点,直接让模型输出目标中心点和尺寸?
比较有代表性的方向是角点检测和中心点检测。比如有些方法把目标框拆成左上角和右下角的角点,用两个分支去预测角点热力图,再配对成框。CSPDarknet之后的YOLOv4、YOLOv5其实是把锚点机制的细节打磨到了极致——包括用聚类方式自动设计锚点尺寸、在损失函数里加CIoU Loss来优化边框的几何相似度等。到了YOLOX时代干脆转向anchor-free,把解耦头拿去,只保留回归中心和尺寸两个分支,推理速度又提了一档。
之后的YOLOv6、v7、v8等版本,更多是围绕训练策略改进:比如引入更优的标签分配策略、强化的数据增强(Mosaic、MixUp等),以及更高效的主干网络设计。从工程落地来看,YOLO系列仍然是性价比最高的选择,因为它只需一个模型文件,不经任何后处理优化,在GPU上就能轻松实时跑1080P视频。
5. 训练自己的检测模型,先过这几道坎
5.1 数据标注与格式转换
说到训练检测模型,第一步永远是数据。检测任务比分类任务对数据的要求高好几个量级,因为你不仅要知道“有什么”,还要标注“在哪”。
数据标注的格式五花八门:Pascal VOC用XML文件,COCO用JSON,YOLO系列用txt文件,每行是“类别 中心x 中心y 宽 高”的格式,坐标相对图像的宽高做了归一化。刚开始做检测项目的人最常见的坑:在标注工具里标的是像素坐标,转换成YOLO格式时忘了归一化,结果训练出来的模型输出框全跑偏。另外标注的时候,目标边缘要不要紧贴轮廓?我的经验是,紧贴轮廓更利于模型学习到目标的真实几何信息,但也不建议贴得太紧——稍微留出1%到2%的余量,让框的边界处包含一点点背景上下文,模型对边界位置的回归会更平稳。
还有一个数据层面的问题,类别不平衡。在目标检测里,有的类别特别多,有的类别只出现几次。训练时模型很容易偏向样本量大的类别,小类别的召回率极低。处理方式有几个:对图像做重复采样增强、对少数类做针对性数据增强(例如多裁剪、多旋转)、或者调整损失函数里不同类别的权重。不要指望靠一堆技巧一步到位,先观察模型在验证集上的每类AP(其实就是看每一类的mAP),哪个类别低就优先处理哪个。
5.2 anchors的选择与学习率、batch size的规律
检测模型训练里最容易被忽视但影响极大的两块:锚点设置和超参数选择。
锚点这块,前面提过可以聚类得到。具体说下怎么操作:把训练标注里所有真实框的宽高取出来,做k-means聚类,k通常是9,聚类中心就是9组锚点尺寸。值得注意的是,聚类用的距离函数不能是欧氏距离,而要用IoU的补数,即希望锚点框与真实框的IoU尽可能大。手工指定的锚点框和聚类得到的锚点框相比,在mAP上的差异可以达到两三个点。
学习率这一块也比分类任务更敏感。检测模型一般训练迭代轮数多,当batch size取16、输入尺寸640×640时,初始学习率设定在0.01到0.02之间比较安全。但关键是预热(warm-up)阶段:前几百步把学习率从很小的值逐步拉升到目标值,避免前期因为学习率太高导致模型震荡甚至发散。这个技巧我在实际使用中觉得比什么都重要,尤其是用大规模预训练权重起步的时候。
梯度裁剪也是一道安全网。检测头部分损失函数数值可能忽大忽小,特别是早期阶段锚点和特征匹配不稳定时,clip_norm设个10(按梯度全局范数裁剪)能避免偶发的loss突爆。很多教程不讲这个,但我在跑第一个检测模型时确实被loss突然变成nan坑过一次,开了梯度裁剪就再没出现过。
5.3 标签分配与损失函数:训练中的隐藏战场
检测模型训练的另一大核心是标签分配(label assignment)——也就是每个预测框到底“负责”哪个真实框。如果分配错了,损失函数再先进也白搭。
早期的方法是IoU阈值匹配:预测框和某个真实框的IoU > 0.5,就认为这个预测框负责该真实框。双阶段模型配合RPN可以这样玩,因为候选框质量高。单阶段模型如果没有锚点筛选,这样分配会导致大量难例,因为大量预测框根本落不到真实框附近。
后来YOLOv5时代开始流行一种动态分配策略:对于一个真实框,不再只看单个IoU阈值,而是把与其IoU较高的前k个预测框都分配给它,再通过模型自身的置信度来加权计算损失。这种“先粗筛,再精调”的动态分配机制,让正样本数量在训练过程中自动调整,对不同尺度和形状的目标适应能力更强。
损失函数选得好不好,影响也很明显。我自己常用的组合是CIoU Loss(边界框回归)+ BCE(二分类置信度)+ BCE(多标签分类)。CIoU Loss相比老旧的Smooth L1 Loss,考虑了重叠面积、中心点距离、宽高比例三个维度,回归精度提升不少。但使用CIoU时要注意:如果训练数据里目标宽高比特别极端(比如宽高比超过10的条状目标),CIoU的反向传播容易不稳定,这时可以退回IoU Loss或GIoU Loss,多试几个版本再定型。
5.4 过拟合与欠拟合的现实表现
检测模型过拟合和分类模型不一样,它通常不会显示“训练loss一直降、验证loss先降后升”那么干净的信号——验证集的mAP可能前期上升、后期甚至停滞或微降,但看起来loss表现还挺好。
我遇到过的最典型情况是:训练集mAP已经到80了,验证集mAP才55,而且验证集上的框要么多检了(预测了很多背景框),要么漏检(某些目标完全没预测出来)。这些基本就是过拟合的信号了。
此时先别慌,优先级依次是:
- 加大数据增强,特别是随机翻转、随机尺度缩放、色彩抖动这类能增加样本多样性的操作;
- 降低模型复杂度,比如把主干网络从最大规模换成轻量版;
- 加早停机制,在验证mAP连续10轮不涨时触发。
欠拟合的表现往往是验证集和训练集mAP都低,此时说明模型容量不足或训练时间不够。优先加训练周期,其次增大模型容量,而不是盲目调学习率。
6. 常用工具选型与实战路径选择
6.1 主流框架速览与选型建议
现在做目标检测,常用的框架基本是这几类:Ultralytics的YOLO系列、MMDetection、Detectron2,以及用来做自定义实验的PaddleDetection。
Ultralytics YOLO走得最远,官方仓库开箱即用,命令行几行代码就能训练、验证、导出模型,老本行也延续得好。如果目标是快速验证一个点子或者做工程项目落地,我会优先选这个,因为它的默认配置在大多数情况下都足够好:自动锚点聚类、自动数据增强策略、自适应灰度处理、多尺度训练都有内置。
MMDetection的特点是模块化做得极致,可以方便地把不同主干、不同检测头、不同标签分配策略组合在一起。论文复现重度用户会喜欢它,但它配置复杂,依赖版本众多,新手配置环境时很容易卡住。我的建议是:如果你想深入研究检测算法、对比不同模块的优劣,MMDetection再合适不过;如果只想快速解决一个实际业务问题,别在MMDetection上浪费时间。
Detectron2是另一个面向研究的框架,用起来也重,但我发现它的可视化工具做得很好——可以把预测框、特征图、热力图一步到位画出来,做算法调试非常方便。
PaddleDetection在国内生态里做得最完备,针对国产硬件和国产深度学习框架做了大量适配,部署到CPU、移动端都很顺手。如果生产环境是国产化栈,这个框架是最平滑的选择。
6.2 端到端的实践路径建议
如果你是第一次做目标检测项目,我给你一条最稳妥的路径:
第一步,用Ultralytics YOLO跑通一个最小样例。选COCO128这个小子集,跑5到10轮训练,目标只有一个:把环境搭建、数据加载、训练循环、模型导出这整条链路彻底跑通。
第二步,对标自己的业务数据。准备好标注数据后,用YOLO自带的自动聚类设置锚点,关闭预训练权重直接把模型训练到收敛,得到第一版性能基线。不要上来就用预训练模型加冻层训练,这样能帮助你判断数据量和任务复杂度。
第三步,优化性能。检查各类AP,如果小目标AP偏低,就加Mosaic增强、增大输入分辨率;如果定位精度差,就换CIoU或引入辅助训练分支。
最后一步,部署。打包成ONNX格式,或者转成TensorRT,测一下推理延迟和内存占用。工业生产一定要关注这一环,模型在离线评测里的mAP再高,上不了线都是白搭。
我的经验是:整个流程走完,一个中等规模数据(几千张图)的项目大概需要一到两周。其中数据清洗和标注占掉六成时间,训练调参反而比较快。别一上来就想搞创新模型结构,先把基线跑通,后面再慢慢迭代才有参照系。
7. 常见问题与排查技巧实录
7.1 训练不收敛的排查清单
训练过程中loss一直不降或者直接变成nan,是检测项目最高频且最磨人的问题。我把常见原因和排查顺序整理成了一张表,你按顺序检查基本能定位:
| 现象 | 可能原因 | 排查优先级 |
|---|---|---|
| loss前几步就nan | 学习率过高、梯度爆炸 | 先设小lr(0.0001)复训一次 |
| loss卡住完全不降 | 标签分配有误、类别编号错乱 | 可视化验证loss,看类别标签是否正确 |
| 训练loss和验证loss同时很高 | 数据预处理与标注格式不匹配 | 检查是否做了归一化、坐标是否越界 |
| 过拟合早期出现(训练好验证差) | 数据量不足、增强不够 | 加大Mosaic、随机翻转等增强强度 |
| 收敛了但单类AP特别低 | 样本数量太少、目标框太小 | 针对性补充数据或做裁剪增强 |
关于nan还有一个隐蔽原因:锚点框宽高出现0或负值。训练数据里如果有标注错误的框,比如宽高为0或坐标端点反了,回归目标就会异常,梯度自然出问题。标注清洗这步真的不能省。
7.2 推理阶段的典型问题
模型训练好了,推理阶段也会遇到新问题。
第一个问题:一张图输出几百个框,重叠严重。这是NMS(非极大值抑制)阈值设置不合理导致。NMS的核心逻辑是:按置信度排序,选中最高分框,把所有与它IoU大于阈值的框抑制掉,再继续从剩下框里选最高分的。阈值取0.4到0.6之间比较常见。阈值取太小(0.2),同类的不同目标挨得近时容易被一起抑制掉,导致漏检;取太大(0.8),重叠框太多,视觉上新检出很多重复框。调NMS阈值是最快的“收益手段”之一。
第二个问题:小目标完全检测不到,但大目标正常。这种情况大概率不是模型问题,而是输入尺寸太小。YOLOv5默认输入640×640,小目标在这么小的分辨率里可能只占十几个像素,特征都丢了。加大输入尺寸(比如1280×1280)+开启Mosaic增强,往往立竿见影。
第三个问题:模型在一张图上能跑通,但输入视频流时偶尔卡顿或内存涨。这还是推理管线问题,一般是没启用批处理、没做预处理缓存。视频检测最好用流式处理,把每帧预处理做成队列,别在检测循环里做大量numpy运算。
说实话,这些排查经验都是在项目里被喷出来的坑攒出来的。测下来的感受是:80%的训练问题出在数据上,15%出在超参数,只有5%是模型结构本身的问题。数据没搞干净,再好的网络也白搭。
关于目标检测的“概览上篇”,我最后再分享一点个人心得:做检测项目最忌讳的是“只见树木不见森林”。一上来就扎进某个框架的调参细节里,被各种API牵着鼻子走,结果连模型为什么这样设计都没搞懂。你如果能理解这个领域的演进逻辑——从滑动窗口到R-CNN再到YOLO——可能比多调出几个点mAP更有价值,因为后者换个数据集就失效,前者却能让你在面对新任务时做出正确的方案选择。下一篇再聊检测模型的部署优化与实战数据调优,到时候把端侧加速、剪枝量化和失败案例分析一并展开。