ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

YOLO目标检测从零到部署:环境安装、原理与项目实战

YOLO目标检测从零到部署:环境安装、原理与项目实战 第一次接触目标检测的人多半是从想让程序自己认出图里有什么这个朴素念头开始的。而 YOLO 这三个字母几乎是所有人绕不开的入口。它做的事情说起来很简单给一张图模型一次性把图里每个目标的位置框出来同时告诉你它是什么类别。跟早期的两阶段方案相比YOLO 把找框和分类塞进同一个网络里一次前向就出结果速度快到能跑实时视频流这也是它能在安防、工业质检、零售盘点、农业监测、自动驾驶感知里遍地开花的原因。这套教程的定位很明确环境安装、原理拆解、项目实战一路走完。它适合三类人——完全没碰过深度学习但会一点 Python 的同学、跑过分类模型但没做过检测的开发者、以及需要在业务里落地一个检测功能但不想从论文啃起的工程师。我自己带过不少从零起步的人最深的感受是YOLO 的坑不在算法本身而在环境、数据格式和参数选择这三块脏活上。所以下面这些内容我会把踩过的坑、参数背后的算术、以及能直接抄的配置全部摊开讲。1. 为什么 YOLO 值得花时间学从检测任务到系列演进1.1 目标检测到底在解决什么问题先用一句话把任务说清楚分类是回答这张图是什么检测是回答这张图里有哪些东西分别在哪个位置。后者的输出结构是一个列表列表里每一项包含四个坐标加一个类别标签外加一个置信度分数。这个看似简单的一步难度却上了不止一个台阶——因为图里目标的数量是不固定的位置是不规则的还可能出现遮挡、截断、密集重叠。传统的做法是把检测拆成两段先用各种方法在图上撒一堆候选区域再对每个区域做分类。这套流程准确率不低但每个候选区域都要过一次网络一秒钟几帧都算快的。YOLO 的破局点在于把整张图切成网格每个网格直接回归出中心落在它内部的那些框。一次前向一次出结果速度直接上了一个数量级。这个设计带来的副作用是早期版本对密集小目标的召回很差。因为每个网格只负责有限几个框两个目标中心落在同一个格子就容易漏。所以后来整个系列一直在解决这个问题——从多尺度特征金字塔到动态标签分配再到更细粒度的检测头主线都是围绕怎么让每个目标都能被分配到合适的预测单元展开的。理解这条主线你就理解了 YOLO 八成的演进逻辑。我们再落到实际场景上。工业场景里做零件缺陷检测你要的不只是有缺陷而是缺陷在左上角还是右下角占多大面积零售货架盘点你要的是每个 SKU 的框和数量统计养殖场里数猪、数鸡、判断异常行为也是检测加计数的组合。这类需求都有共同点目标数量多、要求实时、部署环境算力有限。这正是 YOLO 最舒服的战场。1.2 YOLO 系列演进的主线逻辑很多人一上来就纠结我该学第几代。与其记版本号不如记住每一代在解决什么问题。这条线捋清楚版本对你来说就只是一个名字。第一代的核心贡献是端到端的单阶段回归思路把检测当回归问题做速度快但精度和定位都偏粗糙。第二代引入了 BatchNorm、更高分辨率分类器预训练、以及基于聚类的锚框精度有了明显提升。第三代是很多人心里的经典版本多尺度预测加残差结构加上一批数据增强技巧在当时的工程可用性上做到了很好的平衡。第四代开始把大量训练技巧系统化地堆进来包括 Mosaic 增强、CIoU 损失、标签平滑工程味很浓。第五代是真正让 YOLO 变成产品的一代代码结构清晰、配置文件规范、训练推理导出全打通至今仍有大量项目在用它。再往后第六第七代属于思路相对激进的过渡版本工程落地不如前后两代普及。第八代是目前社区里最主流的一代它最大的变化是换成了 Anchor-Free 的检测头加解耦头训练时不再需要聚类锚框同时把分类和回归分支拆开配合动态标签分配小目标和重叠目标的表现在同一量级上更稳。第九第十代在不同技术点上做文章比如一些训练策略和结构微调。再往后的版本系列迭代速度很快命名也在变具体以官方仓库的 release 记录为准不建议死记硬背版本号。对初学者来说我的建议是直接从第八代或更新的主流版本入手理由很实在文档全、社区活跃、出问题搜得到答案、一行命令就能完成训练到导出。同时把第五代当成读代码教材因为它的模块划分最清楚读懂了再去读新版本会轻松很多。1.3 学习路线怎么排才不走弯路我见过太多人卡在错误的顺序上。有人先把损失函数公式抄了三页纸结果连数据怎么标注都不知道有人第一天就去调超参数模型跑都没跑通。按照经验比较顺的顺序是这样先把环境跑通能用官方预训练权重在一张图上画出框这一步的成就感很重要能撑住后面枯燥的部分。然后自己标几十张图走一遍标注→转换格式→配置 yaml→训练→推理的完整闭环。数据集小一点没关系关键是流程完整。接着再回头补原理损失函数怎么算的、标签分配是怎么回事、为什么小目标难。这时候看公式脑子里有画面理解速度快很多。最后做部署和优化导出 ONNX、剪枝量化、换推理后端、处理实际的视频流和业务逻辑。顺序反了会很痛苦。我有个朋友一开始啃损失函数啃了一周放弃后来改成先跑通再回头读三天就把 DFL 那部分看明白了。原因不复杂——代码跑过一遍之后抽象概念会挂在你见过的具体数据上。2. 环境安装从零把工具链搭起来2.1 硬件与显卡选择先认清自己手上有什么环境安装前的第一件事不是敲命令而是确认你的硬件路线。这个决定会影响后面所有安装步骤。NVIDIA 独立显卡是最省心的路线CUDA 生态完整几乎所有训练流程都基于它写的。显存 8G 是能舒服跑通 yolov8n/s 在 640 分辨率训练的起步线12G 以上可以玩更大的模型和更高的分辨率。如果显存紧张可以用小模型加低分辨率先跑通流程等流程没问题了再租云端算力做正式训练。AMD 显卡在 Windows 上坑比较多常见的可行路线是在 Linux 下走 ROCm或者在 Windows 下借助 DirectML 这类兼容层但性能和生态支持都比不上 CUDA很多算子需要额外适配。我的态度是除非你已经有 AMD 卡且不想换否则训练阶段优先用 NVIDIA 或者云端。Apple Silicon 的 Mac 可以用 MPS 后端跑推理和小规模训练日常做验证和演示够用但训练大模型会比较吃力。它最实用的场景是把导出的轻量模型跑在本地做应用开发。纯 CPU 也不是完全不能玩。CPU 训练一个几百张图的小数据集几百轮下来可能要几小时到一天验证流程是可以的但别指望做正经实验。CPU 推理倒是完全可用一个量化后几 MB 的检测模型在普通电脑上跑几十帧每秒没问题。提示如果你打算买卡别只看显存数字还要看显存带宽和 FP16 算力这两项对训练吞吐的影响比单纯的显存容量更直接。2.2 用 Conda 隔离环境把 PyTorch 装对深度学习环境最大的问题是依赖冲突。不同项目要的 PyTorch、CUDA、NumPy 版本互相打架装到系统 Python 里迟早出事。所以第一步永远是建独立环境。conda create -n yolo python3.10 -y conda activate yoloPython 版本我一般选 3.10。太新比如 3.13有些包还没跟上太旧3.7、3.8新版本框架不支持。3.10 是目前兼容性最好的甜点区。接下来装 PyTorch。这里有个关键点不要直接pip install torch。默认源装的往往是 CPU 版本或者 CUDA 版本和你的驱动不匹配。正确的做法是指定官方 wheel 源并根据你的 CUDA 版本选对应索引。比如 CUDA 11.8pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118CUDA 12.1 就把cu118换成cu121。装完一定要验证python -c import torch; print(torch.__version__, torch.cuda.is_available(), torch.cuda.device_count())输出里True才算成功。如果打印False常见原因是驱动版本太老、装的包是 CPU 版、或者虚拟环境里装了两份 torch。这时候别硬调代码先解决环境——pip list | grep torch看一眼装的到底是什么版本有cpu后缀就是装错了。框架本体就一行pip install ultralytics它会把依赖一起带上。装完跑yolo checks会输出一张环境体检表Python 版本、PyTorch 版本、CUDA 可用性、依赖包状态一目了然。这个命令我在排障时用得最多能省掉一半的猜测时间。Mac 用户走 MPS 的话装完 torch 后加一句检查python -c import torch; print(torch.backends.mps.is_available())返回True就可以在训练时把设备参数设成mps。注意 MPS 后端在部分算子上会有兼容问题报错了就退回 CPU 跑别耗在上面。2.3 数据标注工具怎么选、怎么用环境跑通后下一个必需工具是标注软件。目标检测的数据格式是图片 同名 txttxt 里每行是一个目标格式为class_id x_center y_center width height其中后四个值是归一化到 0 到 1 之间的相对坐标。这个格式需要标注工具帮你生成。传统选择是 labelImg安装简单pip install labelImg labelImg打开后左侧选PascalVOC或YOLO格式切换到 YOLO 格式后框完目标直接生成 txt。用 labelImg 有几个细节要注意快捷键W画框、D下一张、A上一张、CtrlS保存标注顺序最好固定下来比如从上到下、从左到右这样复查时不容易漏。另外在较新的 Python 环境下labelImg 偶尔会因为 Qt 版本问题启动失败遇到这种情况可以尝试指定 PyQt5 版本重装或者直接换成更新的替代工具。近两年我用得更多的是 X-AnyLabeling 这类带辅助标注能力的工具它可以先加载一个模型做预标注你只需要修正框的位置标注效率能提高好几倍。做几百张图的小项目这个差距不明显做几千张图的正式项目辅助标注就是刚需。标注阶段的几个经验都是踩过坑才明白的类别定义要提前想清楚别标到一半加类别。改类别名会导致前面的标注全废或者要写脚本批量改。框要贴紧目标边缘别为了保险画大一圈。多出来的背景会稀释特征模型学到的是模糊的边界。遮挡目标也要标能看清一半就标标注时凭经验补全被挡住的边界。完全不标会让模型认为被遮挡的目标不存在。截断目标的框可以超出图片边界归一化后坐标允许小于 0 或大于 1训练时会正确处理不要硬裁到边缘。同一张图的目标数量分布要尽量自然别刻意只挑单目标的图否则模型学不会处理密集场景。2.4 环境报错速查表环境阶段遇到的报错八成是下面这几类。整理成表方便对照。报错现象常见原因处理方式torch.cuda.is_available()返回 False装了 CPU 版 torch / 驱动过旧用官方 CUDA 索引重装更新显卡驱动CUDA out of memorybatch 或 imgsz 偏大减小 batch、降低 imgsz、开启 AMPImportError: libGL.so.1系统缺少图形库Linux 下安装系统级图形依赖No labels found路径配置错误或标签缺失检查 yaml 中 train/val 路径和 txt 是否同名DataLoader 卡死Windows多进程加载冲突训练时设置workers0中文路径报错部分库不支持非 ASCII 路径项目目录全部改成英文不带空格OpenCV 版本冲突多个包依赖不同版本固定一个版本统一在隔离环境中管理这张表我自己用了很久。绝大多数时候报错信息里已经写明了原因只是被一堆堆栈淹没了。建议养成一个习惯报错先看最后几行再看最前面几行中间的层层调用可以忽略。3. 核心原理损失函数、标签分配与小目标难题3.1 损失函数到底在算什么训练一个检测模型本质是在让预测结果逼近标注结果。损失函数就是衡量差距有多大的尺子。现代 YOLO 的损失一般由三块组成理解这三块你就理解了训练在优化什么。分类损失衡量的是这个框的类别对不对。常用二元交叉熵对每个类别独立判断。用交叉熵而不是 Softmax是因为一个框理论上只能属于一个类别单标签但用多个独立的二分类可以更灵活地处理一些边界情况实现上也更简单。回归损失衡量的是框的位置准不准。早期用的是简单的坐标差平方和后来发现它和实际评价指标 IoU 不一致——坐标差很小但 IoU 很低的情况很常见。于是演进到了 IoU 系列损失先算预测框和真实框的交并比再在此基础上加入中心点距离、长宽比一致性等约束。目前主流用的是 CIoU 这一类它同时考虑重叠面积、中心距离和形状相似度收敛更稳。**分布式焦点损失DFL**是较新版本引入的一项设计。传统做法是直接回归一个数比如框的左边界距离是 37.4 像素。DFL 换了个思路把这个连续值离散成若干区间通常是 16 个 bin让网络预测它落在各个区间的概率分布最后取期望作为结果。这相当于把一个回归问题变成了分类问题来做好处是梯度更稳定边界定位更精细。代价是检测头多了一些通道数。还有一个容易被忽略的部分是标签分配。一张图里可能标了 20 个目标但网络输出了成千上万个预测框哪些框该对哪个目标负责早期靠 IoU 阈值硬匹配效果一般。新版本用动态分配策略综合分类置信度和定位质量来选择正样本让学得好的框承担更多的监督信号。这一改动对小目标和重叠目标的提升很明显。注意看损失曲线时别只盯着总损失。分类损失和回归损失是分开的有时总损失在降但回归损失卡住不动说明定位学不动这时候该查的是标注质量和学习率不是数据量。3.2 Anchor 与 Anchor-Free 的取舍锚框这个概念值得单独说因为它是理解新旧版本差异的关键。锚框的思路是预先在特征图每个位置放若干个不同尺寸和长宽比的参考框网络不直接预测框的绝对位置而是预测相对参考框的偏移量。这样做的好处是网络学起来简单因为偏移量一般落在小范围内数值稳定。锚框的尺寸通常用 k-means 在训练集上聚类得到目的就是让参考框和数据里的真实框分布匹配。问题是锚框带来了一堆新麻烦。首先你得为每个数据集重新聚类锚框尺寸换数据集就得重调。其次锚框数量和尺寸是超参数设少了召回不够设多了计算量大。最后是正负样本极不均衡需要靠复杂的采样策略去平衡。Anchor-Free 就是把这层中间商去掉了网络直接预测目标中心点和宽高或者预测中心点到四条边的距离。这让模型和数据集解耦了——换数据集时不需要重聚类超参数少了一大半。目前主流版本基本都走这条路。代价也不是没有。Anchor-Free 对标签分配的依赖更强需要更精细的分配策略来保证每个目标都能拿到足够的正样本。所以你会看到去掉了锚框的同时动态标签分配被引了进来这两者是配套的。对新手的实际影响是什么很简单如果你用第五代训练前记得在自家数据上跑一遍锚框聚类否则精度会白白损失一截。如果你用第八代及之后这一步可以省了但要注意标签分配的默认参数在极端场景比如全是极小目标下可能要调。3.3 小目标检测为什么这么难小目标是检测任务里的老大难值得专门拎出来讲。问题的根源在特征图的分辨率。输入 640×640 的图主干网络下采样 32 倍后得到 20×20 的特征图下采样 16 倍得 40×40下采样 8 倍得 80×80。一个 16 像素见方的目标在 80×80 的特征图上只占 2 个格子在 20×20 上连一个格子都占不满。而深层的特征图虽然语义信息强但空间细节已经被池化和卷积磨掉了小目标的特征基本消失。所以解决小目标核心思路就是用更浅、分辨率更高的特征图来检测。最直接的做法是增加一个下采样 4 倍、分辨率 160×160 的检测头专门负责小目标。这能显著提升召回代价是计算量上升因为高分辨率特征图的计算开销是平方级增长的。另一条路是从输入侧想办法。把推理分辨率从 640 提到 1280特征图整体放大一倍小目标占的格子数变成四倍效果立竿见影。但显存占用和推理时间都会明显上升实际项目里要权衡。我一般在离线质检场景下用高分辨率在实时视频流里用 640 加轻量模型。还有一条工程上非常实用的路子切片推理。把大图切成若干有重叠的小块逐块推理后再把结果合并回去。这样每个小目标在它所在的那块图里就变成了正常尺寸的目标检测效果提升很明显。代价是推理次数变多速度会降而且块与块之间的重叠区域需要做去重处理。数据层面也有可做的。Mosaic 增强把四张图拼成一张等效于让模型见到更多的小目标和更复杂的场景。Copy-Paste 增强把小目标复制粘贴到不同位置直接增加小目标的样本密度。这两项在配置里都是可以调权重的小目标任务里我会把 Mosaic 保持开启但要注意close_mosaic参数——在训练最后若干轮关闭 Mosaic让模型在真实分布上收敛这个细节对最终精度影响不小很多人忽略了。4. 项目实战从数据集到部署走完整流程4.1 数据集组织与配置文件写法先说目录结构。我习惯这样排datasets/bird/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── bird.yaml图片和标签分开放但同名images/train/001.jpg对应labels/train/001.txt。框架靠文件名去找标签所以命名不能对不上也不能有重复。txt 缺失会被当成负样本背景图处理这个行为有时候有用但如果是误删就会静默地拉低精度很隐蔽。然后是 yaml 配置文件path: /data/datasets/bird train: images/train val: images/val names: 0: sparrow 1: swallow 2: crane几个容易错的地方path写成绝对路径最稳相对路径容易因为工作目录变化而失效train和val是相对于path的路径类别编号必须从 0 开始连续中间断了会导致索引错位模型学出来的类别和你想的完全不是一回事。关于验证集怎么划不要随机抽 10% 了事。如果数据集里同一个视频/同一次采集的图很多随机划分会让训练集和验证集出现高度相似的图验证指标虚高。正确做法是按采集批次、按场景、按时间段划分让验证集真正代表没见过的新数据。我见过指标 0.95 上线后掉到 0.6 的案例九成是划分方式的问题。4.2 训练参数怎么定把每个数字的来由说清楚训练命令长这样yolo detect train \ modelyolov8n.pt \ databird.yaml \ epochs200 \ imgsz640 \ batch16 \ device0 \ optimizerAdamW \ lr00.001 \ patience50 \ projectruns/bird \ nameexp01一个个参数说。model决定网络大小和预训练权重。后缀 n/s/m/l/x 依次变大。选择依据是算力和精度要求n 和 s 适合边缘部署和快速验证m 是精度和速度的平衡点l 和 x 适合离线高精度场景。我的习惯是先拿 n 跑一轮确认流程没问题和指标量级合理再换大模型跑正式实验。epochs是训练轮数。数据集小几百张可以设大一些200 到 300 轮数据集大几万张100 到 150 轮就够。配合patience早停指标长时间不涨就自动停下不用死等。imgsz是输入分辨率。默认 640。目标普遍偏小就提到 960 或 1280目标很大就降到 416 甚至 320 提速。注意它必须是 32 的倍数因为主干网络下采样 5 次。batch是批大小直接影响显存占用。怎么估算拿 yolov8n 在 640 分辨率、FP16 混合精度下举例batch 16 大概吃 4 到 5G 显存batch 32 大概 8 到 9G。所以 8G 卡上 batch 16 比较稳12G 卡可以试试 24 或 32。懒得算就设batch-1框架会按当前显存的 60% 自动定一个值这个功能在换机器时特别好用。lr0是初始学习率。用 SGD 时 0.01 是常见起点用 AdamW 时要降到 0.001 左右因为 AdamW 的自适应特性让它对学习率更敏感。学习率配错是训练失败的头号原因之一表现为损失震荡或者直接发散成 NaN。optimizer的选择上我对新手的建议是 AdamW 起步。它收敛快、对学习率不敏感虽然最终精度可能比调好的 SGD 略低一点点但省下的调参时间完全值得。追求极致精度时再换回 SGD 慢慢磨。数据增强相关参数里mosaic开启四图拼接mixup做图像混合copy_paste做目标复制粘贴主要针对分割任务但也有检测收益close_mosaic设为 10 表示最后 10 轮关掉 Mosaic。这几个参数的调整思路是数据量少就加强增强数据量大就减弱增强。freeze参数用于冻结主干网络的层数。如果你只有几百张图冻结前 10 层做迁移学习效果通常比全量微调好因为小数据全量微调很容易过拟合。实操心得正式训练前先用epochs3跑一遍确认损失在降、验证能跑通、显存没爆。这 3 轮可能只要几分钟但能省掉跑一整夜发现数据配错了的崩溃。4.3 训练过程怎么看指标与曲线解读训练开始后控制台会滚动输出一堆指标。搞清每个指标的含义才能判断训练状态。box_loss是回归损失衡量框位置。它应该稳步下降最后趋于平缓。如果它一直高高在上不降优先怀疑标注坐标有问题。cls_loss是分类损失。它下降通常比 box_loss 快因为分类问题相对简单。如果它降不下去可能是类别定义混乱或者某几类样本太少。precision精确率是预测为某类的框里有多少是对的。它高说明误检少。recall召回率是真实存在的目标里有多少被检出来了。它高说明漏检少。mAP50是 IoU 阈值 0.5 时的平均精度这个指标比较宽松通常用来判断模型有没有学会。mAP50-95是在 0.5 到 0.95 多个阈值上取平均对定位精度要求更严。实际项目里更该关注这个。经验上mAP50 到 0.9 以上但 mAP50-95 只有 0.5 左右说明模型能找对目标但框不够准这时候要去看标注质量。训练完会在输出目录生成曲线图。重点看几张损失曲线看是否过拟合训练损失继续降但验证损失回升、PR 曲线看各类别的表现是否均衡、混淆矩阵看哪两类总被混淆。混淆矩阵特别有用——如果哈士奇和狼互相混淆严重那多半不是模型的问题而是这两类的样本特征确实相近需要靠增加区分性样本或者加入上下文信息来解决。4.4 部署把模型变成能跑的服务训练出 best.pt 只是第一步真正上线要经过格式转换。不同部署目标对应不同格式选错了会白折腾。部署目标推荐格式说明服务器 GPUTensorRT engine延迟最低需与显卡和环境匹配服务器 CPUOpenVINO 或 ONNX通用性好CPU 上优化明显移动端 Android/iOSTFLite / NCNN / CoreML体积小量化后几 MB通用跨平台ONNX兼容性最好作为中间格式国产边缘芯片各家自有格式需用厂商工具链转换导出命令很简单yolo export modelruns/bird/exp01/weights/best.pt formatonnx opset12 simplifyTrue imgsz640opset12是比较通用的算子集版本simplifyTrue会做一次图优化去掉冗余节点通常能提速几个百分点。注意导出后一定要验证精度有没有掉——量化过程可能引入误差尤其是 INT8 量化需要准备一批校准数据来减小损失。ONNX 推理的最小示例import cv2 import numpy as np import onnxruntime as ort session ort.InferenceSession( best.onnx, providers[CUDAExecutionProvider, CPUExecutionProvider], ) img cv2.imread(test.jpg) h, w img.shape[:2] resized cv2.resize(img, (640, 640)) blob resized[:, :, ::-1].transpose(2, 0, 1)[None].astype(np.float32) / 255.0 outputs session.run(None, {session.get_inputs()[0].name: blob}) # outputs[0] 形状通常是 (1, 4 num_classes, 8400) # 这里只演示输入输出坐标还原和 NMS 需要自己实现 print(outputs[0].shape)这段代码只到拿到原始输出为止。后处理包括三步把归一化坐标还原回原图尺寸、按置信度阈值过滤、做非极大值抑制去掉重叠框。这三步网上有大量现成实现但建议自己手写一遍因为不同版本的输出排布不一样有的是(1, 84, 8400)有的是(1, 8400, 84)照抄代码很容易踩坑。如果部署在视频流上还有几个工程细节要注意帧间缓存和跳帧策略、推理和绘制的解耦别让绘制阻塞推理、以及多路视频的批处理调度。这些不是算法问题但直接决定系统能不能跑稳。5. 常见问题与排查技巧实录5.1 训练不收敛或者指标异常的排查路径训练出问题是最高频的求助场景我按经验整理了一条排查顺序从概率最高的地方开始查。第一件事可视化检查标注。写个小脚本把标注框画到原图上随机抽二三十张看一眼。我遇到过太多次这种情况别人说模型学不会结果一看标注框全画反了左上角和右下角顺序搞混或者坐标没归一化或者类别 ID 全错位。这类错误模型再强也学不会而且损失曲线看起来会很诡异——不降也不发散就是卡住。第二步用预训练模型直接推理几张图。如果官方权重在你数据上也能检出目标说明环境和数据加载没问题问题在训练配置。如果连官方权重都检不出东西那是环境或者数据格式的问题。第三步检查学习率。损失出现 NaN 或者剧烈震荡先把学习率降一个数量级试试。用 AdamW 却设了 0.01 的初始学习率是最常见的配置错误。第四步看类别分布。如果某一类样本量是其他类的十分之一模型会倾向忽略它。这时候要么补数据要么在损失里给少样本类别加权。第五步判断是否过拟合。训练损失持续下降但验证指标在某个点后开始变差就是过拟合。对策是加数据、加增强、加正则或者减少模型规模。一条经验模型完全没学到和学到一半卡住是两种不同的病。前者通常是数据或配置的硬错误后者通常是容量和数据的匹配问题。先分清是哪一种能省很多时间。5.2 显存和性能相关的坑显存不够是第二高频问题。除了减小 batch 和 imgsz 这两个直接手段还有几个不那么直观的办法。开启混合精度训练AMP能省下大约 30% 到 40% 的显存几乎无损精度基本属于必须开。梯度累积可以在小 batch 下模拟大 batch 的效果——比如你想用 batch 32 但显存只够 8就设累积步数为 4每次反向 4 次再更新一次参数效果接近但速度会慢一些。另一个坑是显存碎片。长时间训练或者频繁切换模型时显存可能出现碎片化明明总量够但分配不出来。这时候设一下 PyTorch 的显存分配策略或者干脆重启进程往往能解决。推理阶段的性能优化则是另一套思路。主要瓶颈通常不在网络本身而在前后处理图像解码、缩放、归一化、NMS。这几个环节如果都用 Python 循环写能吃掉一半以上的时间。实践中的优化顺序是先把后处理从纯 Python 改成 NumPy 向量化再把图像预处理用 OpenCV 或硬件加速最后才考虑换推理后端和量化。很多人一上来就折腾 TensorRT结果前后处理还是瓶颈提升非常有限。5.3 部署上线后的典型问题模型在本地测试好好的上线就出问题这种情况太常见了。归归类主要是三种。域偏移。训练数据是白天拍的线上跑的是夜里的监控画面训练用的是手机拍的图线上是固定机位的高清图。分布不一样模型表现就会掉。解决办法是在部署环境里采一批真实数据标注后做微调哪怕只标几百张提升也很明显。这一步我建议当成上线流程的固定环节而不是出问题后的补救。阈值设置不当。demo 里conf0.25看着挺好实际业务里可能误检一堆。这时候要做的不是瞎调阈值而是先看 PR 曲线找到满足业务要求的平衡点。如果是宁可错杀不可放过的场景比如危险品检测就降阈值提召回如果是报出来必须准的场景比如自动计费就提阈值保精度。类别索引对不上。训练时的类别顺序和部署代码里写死的顺序不一致导致输出的类别名全错。这个 bug 很低级但很常见因为标注文件里的顺序和 yaml 里的顺序、和部署代码里的列表是三处独立维护的东西很容易不同步。我的做法是只维护一份配置其他两处都从它读取杜绝手写重复。6. 把手上的流程往更多场景延展6.1 从检测扩展到分割、姿态与旋转框检测跑通之后同一套工具链能做的事情还有不少改动成本比想象中低。实例分割在检测框的基础上多输出一个像素级掩码用的是同一套主干和训练流程只是换个模型权重和数据集标签格式多了一行多边形坐标。如果你需要算目标面积、做精细抠图直接上分割版本就行。姿态估计输出的是人体关键点适合做行为分析、动作识别、健身指导这类应用。它的数据标注比检测麻烦需要标关键点位置但对人的标注任务来说相对直观。旋转框检测解决的是目标不是水平放置的问题比如航拍图里的车辆、遥感图里的船只、工业场景里斜放的零件。普通水平框会把大量背景包进来旋转框能给出带角度的框定位更准。如果你的场景里目标方向多变这一步升级很值得。选型的时候就一个判断标准问自己我最终要用检测结果做什么。如果只是计数和定位检测够用如果要算面积或抠图上分割如果要判断姿态上关键点如果目标是倾斜的上旋转框。别为了技术先进而过度设计。6.2 三维目标检测和边缘部署的入门方向三维目标检测是另一个层次的题目。它处理的是点云或者深度图输出的是带三维尺寸和朝向的框主要用在自动驾驶、机器人抓取、仓储体积测量这些场景。入门门槛比二维高因为数据处理管线完全不同点云的稀疏性、无序性需要专门的网络结构来处理。如果你想往这个方向走建议先熟悉一个公开数据集的结构再跑通一个基础模型不要一上来就啃最新的论文。边缘部署方向则更偏工程。核心是在算力受限的设备上把模型跑起来并跑稳。关键手段是模型量化FP16 和 INT8、算子融合、以及针对特定硬件的图优化。这里有个容易被忽视的点量化不是无损的尤其是 INT8对检测这类回归密集的任务影响比分类任务大。做量化的时候一定要准备一批有代表性的校准数据并且量化后拿真实场景数据验证不要只看文件大小变小了就以为成功。从我自己的经验看检测这个方向的学习曲线是前期陡、后期缓。前两周你会觉得什么都难环境、数据、参数全是坑跑通两三个完整项目之后你会发现新任务基本就是换数据、微调参数、改部署代码这三件事的排列组合。真正拉开差距的地方其实是数据处理和问题定位能力而不是背下多少个模型结构。最后一个建议也是最实在的一条每做完一个项目把当时的配置文件、训练日志和踩坑记录留档。检测任务的参数敏感度很高同一个数据集换一批参数结果可能差好几个点。下次遇到类似问题时这些记录比任何教程都有用因为它们是在你的数据、你的环境下验证过的。
返回列表