YOLOv5目标检测:环境搭建与自定义数据集训练
简介:一份面向具备Python与计算机视觉基础的入门级研究人员和工程技术人员的YOLOv5实践指导文档,聚焦本地环境搭建与目标检测入门,帮助初次接触该框架的读者完成从系统要求确认、依赖库安装到首个检测实例跑通的全过程。包内仅含1个docx文件,压缩包约19KB,以图文步骤与命令示例组织内容,便于按章节查阅和对照操作。文档围绕Windows、macOS或Linux环境展开,说明Python 3.6以上及GPU场景下CUDA 10.2、cuDNN 7.6以上的版本匹配,并覆盖Anaconda虚拟环境创建、PyTorch安装、官方仓库克隆、requirements依赖安装、预训练模型下载与detect.py参数解释、检测结果目录查看等环节;末尾还简要引介基于自定义数据集的模型训练与配置文件调整思路。已有239人学习下载,适合用作课堂教学材料或工程项目参考,读者可据此建立可复现的实验环境,理解关键参数与排错方向,并为后续定制化目标检测任务打下基础。
1. 从一张抓拍图开始:YOLOv5目标检测到底解决什么
把一张车间抓拍图丢进检测脚本,十几秒后控制台打出“person”“helmet”和对应置信度,这种即时反馈是YOLOv5目标检测最直观的价值。这份资源是一套从零搭建本地YOLOv5环境、跑通预训练检测,再走到自定义数据集训练的实操教程,主线依赖Python与PyTorch,GPU链路绕不开CUDA、cuDNN的版本匹配。它适合已经有Python基础、能看懂目录和命令,但还没完整跑过一次检测项目的人,也适合要把检测能力嵌进小工具、课程设计或内部验证脚本的工程人员。照着走完,能完成环境搭建、首轮检测、数据准备与训练参数设置,并知道出错时先查环境层、数据层还是参数层。
2. 环境栈先对齐:Python 3.8、PyTorch与CUDA/cuDNN的匹配检查
环境搭建最怕“先装再说”。YOLOv5本身不复杂,复杂的是PyTorch、CUDA、cuDNN三层版本错位后,报错经常指向一行看起来无关的代码。我的习惯是先把Python版本、虚拟环境、GPU可用性三件事确认掉,再碰依赖文件。项目正文给出的最低要求是:主流桌面系统、Python 3.6或更高、CUDA 10.2或更高、cuDNN 7.6或更高;实际落地时我更倾向把Python锁在3.8,因为这一档和PyTorch、各类视觉依赖的兼容面更稳,遇到旧包的概率低。
2.1 为什么先锁Python 3.8和虚拟环境,而不是直接在系统Python里装
系统Python里往往已经堆了各种包,直接装PyTorch和检测依赖,轻则版本冲突,重则把原本能跑的其他脚本弄坏。虚拟环境的价值不是“看起来专业”,而是把YOLOv5这套依赖封在一个盒子里,后面删环境、换版本、复现实验都不影响主机。项目正文里用conda创建yolov5_env,这个做法适合新手,因为conda对Python版本和二进制包的处理更省心;如果本机没有conda,用venv也能完成同样的隔离,只是后面装PyTorch时要更注意安装源。
先创建环境并确认Python版本:
# 创建独立环境,Python 锁在 3.8 conda create --name yolov5_env python=3.8 -y # 激活环境 conda activate yolov5_env # 确认当前 shell 用的是环境里的 Python python -V这段命令的逻辑很直接:conda create负责建环境,--name指定环境名,python=3.8把解释器版本钉住,-y跳过交互确认。激活后必须用python -V确认版本,因为终端里常见的翻车是“环境建了但没激活”,后面pip install全装到系统Python里。出现CommandNotFoundError时,先看终端是否重新打开过,或者按本机conda安装方式执行初始化;不要在这个状态继续装包。环境名不是必须叫yolov5_env,但建议固定一个,后面排错时能快速判断当前终端在哪个环境。
2.2 GPU链路检查:CUDA/cuDNN、PyTorch与torch.cuda的验证顺序
GPU链路要按“驱动可用 → PyTorch能识别CUDA → cuDNN能返回版本”的顺序看,不要一上来就改代码。项目正文要求CUDA 10.2以上、cuDNN 7.6以上,这是最低门槛;实际安装时,PyTorch安装包会带对应的CUDA运行时,但显卡驱动必须满足它的最低要求。换句话说,torch.version.cuda显示的是PyTorch编译时对应的CUDA版本,torch.cuda.is_available()回答的是当前机器能不能真正调用GPU,torch.backends.cudnn.version()则用来看cuDNN是否可用。三者不是一回事,混在一起看很容易误判。
| 检查项 | 常见命令 | 通过标准 | 不匹配时的典型表现 |
|---|---|---|---|
| Python版本 | python -V | 3.8且来自虚拟环境 | 包装到了系统环境,后续命令找不到 |
| PyTorch版本 | python -c "import torch; print(torch.__version__)" | 能正常导入 | 导入报DLL、符号或版本冲突 |
| CUDA可用性 | python -c "import torch; print(torch.cuda.is_available())" | 返回True | 返回False,检测脚本只能跑CPU |
| CUDA编译版本 | python -c "import torch; print(torch.version.cuda)" | 有版本号且与安装选择一致 | 显示None,说明装的是CPU包 |
| cuDNN版本 | python -c "import torch; print(torch.backends.cudnn.version())" | 有版本号 | 返回None或运行时报cuDNN错误 |
把检查写成一个小脚本更省事:
import torch print("torch:", torch.__version__) print("cuda_available:", torch.cuda.is_available()) print("cuda_version:", torch.version.cuda) print("cudnn_version:", torch.backends.cudnn.version()) # 只有 cuda_available 为 True 时才继续取设备信息 if torch.cuda.is_available(): print("device_count:", torch.cuda.device_count()) print("device_name:", torch.cuda.get_device_name(0)) print("capability:", torch.cuda.get_device_capability(0))这段脚本先打印PyTorch版本,再看CUDA是否可用,最后才取设备名和算力。device_count是可见GPU数量,get_device_name(0)是第0块卡的名字,get_device_capability(0)返回主次版本号,后面判断某些算子是否支持时会用到。若cuda_available为False,先不要改detect.py,也不要在训练命令里硬写--device 0;此时要么装错了CPU版PyTorch,要么驱动不满足,要么当前终端不在正确环境里。我的血泪经验是:先把CPU链路跑通,再回来修GPU,能少掉很多“以为是模型问题”的误判。
2.3 安装PyTorch与依赖的落地命令
PyTorch安装命令要按硬件分叉。项目正文给出的是GPU环境用pip install torch torchvision,CPU环境用pip install torch torchvision cpuonly。不同安装源对CPU版的写法不完全一样,cpuonly不一定是通用参数,落地时以项目页给出的安装源为准;如果命令报“找不到满足条件的版本”,先检查pip源和Python版本,不要反复重试同一条命令。装完PyTorch后,再进仓库装requirements.txt,顺序不要反,否则依赖解析容易把PyTorch版本顶掉。
# 先升级 pip,减少旧解析器带来的版本冲突 python -m pip install --upgrade pip # GPU 环境:安装 PyTorch 与 torchvision pip install torch torchvision # CPU 环境:按项目页给出的 CPU 安装命令执行 # 示例写法可能是 pip install torch torchvision cpuonly # 若当前源不支持该写法,改用项目页提供的 CPU 专用命令python -m pip比直接pip更稳,因为它明确走当前Python解释器,能减少“pip装到另一个环境”的问题。GPU分支装完必须回到2.2的检查脚本确认cuda_available;CPU分支则接受cuda_available=False,后面检测和训练命令统一加--device cpu。如果GPU分支装完仍返回False,先卸载当前PyTorch再按匹配版本重装,不要在同一环境里反复覆盖安装。依赖装完后,用pip list看PyTorch和torchvision是否成对出现,版本差距过大时,后面导入检测模块可能直接报错。
3. 把仓库跑起来:依赖安装、权重获取与detect.py首轮检测
环境层确认完,下一步是把YOLOv5仓库拉下来、装依赖、拿到权重、跑通一张图。这个阶段的目标不是调出最佳精度,而是让整条链路从输入图片走到输出目录,形成可重复的最小闭环。很多新手在这里翻车,不是因为YOLOv5难,而是仓库目录、权重文件、输入路径三者没有对齐:命令在仓库根目录执行,权重文件名写错,--source指向一个不存在的相对路径,最后报错看起来像模型坏了。
3.1 仓库目录与requirements.txt:先看哪些依赖会碰CUDA
克隆仓库时建议把目录名固定成yolov5,后面所有命令都在这个目录下执行。项目正文里的做法是克隆后cd yolov5,再装requirements.txt。仓库地址以项目页给出的为准,命令里用占位符替换,避免把地址写死。进入目录后先看requirements.txt,重点看torch、torchvision、numpy、opencv-python这几类包;如果前面已经装好PyTorch,pip install -r requirements.txt通常不会重装大包,但不同源仍可能触发版本调整,装完要再跑一次CUDA检查。
# 克隆仓库,目录名固定为 yolov5,便于后续命令统一 git clone <YOLOv5仓库地址> yolov5 # 进入仓库根目录 cd yolov5 # 安装检测与训练依赖 python -m pip install -r requirements.txt # 装完复查 PyTorch 是否还在、CUDA 是否仍可用 python -c "import torch; print(torch.__version__, torch.cuda.is_available())"git clone的第二个参数是本地目录名,写成yolov5后,后面cd yolov5不会因为仓库默认名不同而失败。python -m pip install -r requirements.txt会读取依赖清单,常见的坑是网络中断导致某个包只装了一半,或者pip缓存里留下旧版本;出现“Requirement already satisfied”但导入仍报错时,先pip show 包名看版本和位置,再决定是否单独重装。装完复查PyTorch不是多余动作,因为依赖清单里的版本约束有可能把已装好的PyTorch替换掉,尤其是跨大版本时。
3.2 权重文件获取与完整性检查
预训练权重是首轮检测的关键。项目正文用yolov5s.pt,这个模型体积相对小,适合先跑通链路。权重下载失败最常见的原因不是地址错,而是下载中断后留下一个0字节或半截文件,脚本加载时报“unpickling error”或“invalid load key”,看起来像代码问题。我的做法是下载后先看文件是否存在、大小是否明显异常,再用PyTorch尝试加载一次;不要只看浏览器显示“下载完成”。
# 从项目页给出的权重地址下载,文件名保持 yolov5s.pt wget -O yolov5s.pt <yolov5s.pt下载地址> # 检查文件是否存在以及大小是否合理 python -c "from pathlib import Path; p=Path('yolov5s.pt'); print(p.exists(), p.stat().st_size if p.exists() else 0)"wget -O把下载内容固定写到yolov5s.pt,避免服务端文件名带额外后缀导致后面--weights找不到。检查脚本只做两件事:文件是否存在、字节数是否大于0;更严格一点可以尝试torch.load,但不同版本对加载参数有差异,新手阶段先用文件大小排除半截文件就够了。Windows没有wget时,用浏览器下载后把文件放到仓库根目录,文件名保持一致;不要放到weights/子目录却在命令里写根目录路径。若文件大小明显偏小,直接删掉重下,不要试图用旧文件继续跑。
3.3 detect.py首轮运行:五个参数的作用与推荐起点
首轮检测建议先用项目正文给出的参数跑一张图:--weights yolov5s.pt --source test.jpg --img 416 --conf 0.4 --iou 0.5。这组参数不是唯一答案,但能让你看到完整输出。--weights指定模型文件,--source指定输入,可以是单张图、目录、视频或摄像头编号;--img是推理输入尺寸,必须是32的倍数,416比640快,但小目标更容易漏;--conf是置信度阈值,调高会减少框,调低会增加框;--iou是非极大值抑制阈值,调高会保留更多重叠框,调低会压掉更多重复框。
# 单张图首轮检测,GPU 可用时 device 写 0 python detect.py --weights yolov5s.pt --source test.jpg --img 416 --conf 0.4 --iou 0.5 --device 0 # 如果当前只有 CPU,显式指定 cpu,避免脚本反复尝试 GPU python detect.py --weights yolov5s.pt --source test.jpg --img 416 --conf 0.4 --iou 0.5 --device cpu--device 0表示使用第0块GPU,--device cpu强制走CPU。首轮不要同时改多个参数,先固定img=416、conf=0.4、iou=0.5看结果,再单独调一个。图片里目标很小、框明显偏少时,先把--img提到640,再把--conf降到0.25;框重复严重时,先把--iou降到0.45。--source写相对路径时,命令必须在仓库根目录执行;路径里有空格或中文时,加引号并尽量改成纯英文短路径,能避开一批文件读取问题。
3.4 结果目录与一次检测的日志阅读
检测跑完后,结果默认落在runs/detect/exp,再跑一次会变成exp2、exp3。这个自动递增机制容易让人看错目录,所以我一般显式加--project和--name,把每次实验分开。日志里重点看三件事:检测到了多少目标、预处理/推理/NMS各花了多少时间、输出图片保存在哪。日志中的速度数字受图片尺寸和硬件影响,不要拿单张图的时间和别人比;首轮只关心链路是否通、框是否画在合理位置。
# 用固定项目名和实验名,避免结果目录自动递增后找不到 python detect.py --weights yolov5s.pt --source ./samples --img 640 --conf 0.25 --iou 0.45 --project runs/detect --name demo_01 --device cpu # 需要把框坐标保存成 txt 时追加 --save-txt python detect.py --weights yolov5s.pt --source ./samples --img 640 --conf 0.25 --iou 0.45 --project runs/detect --name demo_txt --save-txt --device cpu--source ./samples会批量处理目录下的图片,适合一次看多张;--project指定结果根目录,--name指定本次实验子目录,固定命名后排查时不用猜exp序号。--save-txt会把检测框保存成标签文件,后面做结果统计或二次筛选时有用。批量检测时如果某张图报错,先单独拿那张图跑一次,确认是图片损坏、路径问题还是尺寸异常;不要在一堆图里猜。结果图里框的位置明显偏移时,先确认原图没有被旋转或裁剪过,标注和推理的坐标系不一致时,画出来的框会整体错位。
4. 自定义数据集训练:YOLO标注格式、data.yaml与train.py参数
预训练模型能识别通用类别,但真实项目往往只关心几个特定目标。训练自定义数据集的核心不是把epochs调大,而是把数据格式、类别数量、配置文件三件事对齐。YOLOv5要求的标注格式很克制:每张图片对应一个同名txt,每行五个数,分别是类别id、归一化后的中心点x、中心点y、宽度、高度。只要有一行坐标没归一化、类别id越界,训练就可能报维度错误,或者loss看着在降但模型学不到东西。
4.1 YOLO标注格式:一行五个数,错一个就白训
标准目录通常长这样:images/train放训练图,images/val放验证图,labels/train和labels/val放同名txt。图片和标签的文件名主干必须一致,比如frame_001.jpg对应frame_001.txt。每行格式为class x_center y_center width height,其中x_center、y_center、width、height都除以图片宽高,落在0到1之间。常见错误是把像素坐标直接写进去,或者把左上角坐标当成中心点坐标,训练时不会立刻报错,但框会学偏。
| 目录/文件 | 作用 | 常见错误 |
|---|---|---|
images/train | 训练图片 | 图片名和标签名主干不一致 |
images/val | 验证图片 | 验证集为空或和训练集重复 |
labels/train | 训练标签 | 一行不是5列,坐标未归一化 |
labels/val | 验证标签 | 类别id超过nc-1 |
data.yaml | 数据与类别配置 | nc和names长度不一致 |
先跑一个标签检查脚本,比训练报错后再回头查省时间:
from pathlib import Path img_dir = Path("dataset/images/train") label_dir = Path("dataset/labels/train") bad = [] for txt in label_dir.glob("*.txt"): for line_no, line in enumerate(txt.read_text().splitlines(), 1): parts = line.split() if len(parts) != 5: bad.append((txt.name, line_no, "列数不是5")) continue cls, x, y, w, h = parts if not (0 <= int(cls) < 3): bad.append((txt.name, line_no, "类别越界")) vals = [float(v) for v in (x, y, w, h)] if any(v < 0 or v > 1 for v in vals): bad.append((txt.name, line_no, "坐标未归一化")) print("bad_count=", len(bad)) print(bad[:10])这段脚本检查三件事:每行是否正好5列、类别id是否在0到2之间、四个坐标是否都在0到1之间。nc=3时类别id只能是0、1、2,出现3就是越界;坐标出现大于1的数,基本可以判定用了像素值。检查结果里bad_count为0再继续,不为0就先改标签。图片和标签数量不一致也要查,缺标签的图片在训练时会被跳过或当成负样本,具体行为取决于配置,最稳的做法是训练前让两边数量对齐。
4.2 data.yaml与模型yaml:nc、names和预训练权重的对齐
data.yaml是数据入口,至少要有path、train、val、nc、names。path是数据集根目录,train和val相对path写;nc是类别数,必须等于names列表长度;names的顺序就是标注里类别id的顺序。模型yaml里的nc也要同步改,项目正文提到编辑models/yolov5s.yaml中的类别数量。使用预训练权重时,骨干和检测头会按新类别数重建,类别不匹配的权重部分会被跳过或覆盖;不要因为看到“加载成功”就以为类别数自动对齐了。
# data.yaml 示例:三类目标 path: ./dataset train: images/train val: images/val nc: 3 names: ['person', 'helmet', 'vest']path写相对路径时,训练命令要在仓库根目录执行,或者直接写绝对路径;train和val不要重复写path前缀,否则会拼成dataset/dataset/images/train。nc: 3对应names里三个类别,顺序不能乱:标注里的0对应person,1对应helmet,2对应vest。改完data.yaml,再把models/yolov5s.yaml里的nc改成3;如果只改一处,训练可能在构建检测头时报通道数不匹配。预训练权重的类别数通常是通用类别,和自定义类别不一致是正常现象,训练脚本会按新配置重建输出层,关键是data.yaml和模型yaml两处保持一致。
4.3 train.py参数:batch、epochs、img、cache怎么定
训练命令可以直接沿用项目正文的结构:--img 416 --batch 16 --epochs 300 --data data.yaml --cfg models/yolov5s.yaml --weights yolov5s.pt --cache。这组参数适合中等规模数据和一般显存,但不是死数。--batch受显存限制,报显存不足就降到8或4;--epochs300是常见起点,数据少时可以降,数据多或指标还在涨时可以加;--img和检测阶段保持一致更省心,416快,640对小目标更友好;--cache把图片缓存到内存,速度快但吃内存,数据量大或内存小时不要开。
# 自定义数据训练:先按这组参数跑通,再逐项调 python train.py --img 416 --batch 16 --epochs 300 --data data.yaml --cfg models/yolov5s.yaml --weights yolov5s.pt --cache --device 0 --workers 4--data指向刚写的data.yaml,--cfg指定模型结构,--weights加载预训练权重,--device 0用第0块GPU,--workers 4是数据加载进程数。Windows上--workers设太大容易卡在启动阶段,可以先设0或2;--cache在内存不足时会拖慢甚至中断训练,数据量超过内存时去掉。训练输出在runs/train/exp,权重在weights/best.pt和weights/last.pt;best.pt按验证指标选,last.pt是最后一轮,中断后恢复用--resume runs/train/exp/weights/last.pt。恢复训练时不要同时改数据配置,否则断点状态和新配置可能对不上。
4.4 训练过程看什么:loss、mAP、显存与中断恢复
训练日志里先看三个loss:box_loss、obj_loss、cls_loss。box_loss反映框位置,obj_loss反映目标存在与否,cls_loss反映分类;三者整体应往下走,短期抖动正常,长期不降才要查数据。再看mAP@0.5和mAP@0.5:0.95,前者宽松,后者严格;验证集指标不涨但训练loss一直降,可能是过拟合或验证集分布不同。显存方面,训练一开始就OOM,优先降--batch或--img,不要先改模型结构;训练中途OOM,看是否有异常大图或数据加载进程堆积。
| 观察项 | 正常表现 | 异常时先查 |
|---|---|---|
| box_loss | 逐步下降并趋稳 | 标签坐标是否归一化、框是否画错 |
| obj_loss | 逐步下降 | 背景图是否太多、标签是否缺失 |
| cls_loss | 逐步下降 | 类别id是否越界、names顺序是否一致 |
| mAP@0.5 | 总体上升 | 验证集是否太少、是否过拟合 |
| 显存占用 | 训练中基本稳定 | batch、img、workers、cache |
中断恢复用last.pt,不要用best.pt,因为best.pt只保留验证指标最好的那一轮,优化器状态不完整。恢复命令里--resume指向last.pt,其他参数尽量保持不变。训练结束后,用best.pt跑一次detect.py做肉眼复核,别只看mAP数字;指标高但框错位,往往是标注格式或数据增强配置的问题。
5. 避坑排查:五类高频翻车现场与定位路径
YOLOv5的报错有个特点:表面看是模型问题,实际根因经常在环境、路径或标签。排查时按“环境层 → 数据层 → 参数层”走,比盯着最后一行报错有效。下面五类现象是首轮搭建和自定义训练里最容易遇到的,每条按现象、原因、解决写清楚,方便直接对照。
5.1 环境与依赖类:先排除“装错了”和“没装全”
现象一:torch.cuda.is_available()返回False,检测脚本只能跑CPU。
原因通常有三种:装成了CPU版PyTorch、当前终端不在虚拟环境里、显卡驱动不满足PyTorch包的要求。解决顺序是先python -V确认解释器,再pip show torch看安装位置,最后跑2.2的检查脚本看torch.version.cuda是否为None。为None基本就是CPU包,卸载后按GPU安装命令重装;有版本号但仍False,检查驱动是否正常。不要在这个状态硬写--device 0,脚本会反复尝试并报设备不可用。
现象二:pip install -r requirements.txt卡住或报版本冲突。
原因多是Python版本过高、pip解析器太旧、依赖源里某个包没有当前平台版本。解决时先确认Python是3.8,再升级pip,然后单独装报错的那个包看完整错误。依赖文件里的大包如果已经装好,不要反复全量重装;用pip show 包名确认版本和路径,缺哪个补哪个。装完必须复查PyTorch是否被替换,尤其是跨大版本依赖。
现象三:权重文件加载报invalid load key或unpickling error。
原因通常是下载中断留下半截文件,或者文件名对但内容不是权重。解决时先看文件大小是否明显偏小,再重新下载;不要用文本编辑器打开.pt文件试图“修复”。下载后放到仓库根目录,--weights写相对路径;放在子目录时路径要跟着改。文件大小正常但仍加载失败,换一个权重文件试,排除文件本身问题。
5.2 检测与训练类:参数和标签最容易埋雷
现象四:检测结果没有框,或者框明显偏多。
没有框时先看--conf是否过高,0.4在某些小目标图上会过滤掉弱响应,降到0.25再试;再看--img是否太小,416对远距离小目标不友好,提到640。框偏多时先看--iou是否过高,0.5会保留更多重叠框,降到0.45;再确认输入图是否被重复检测或目录里混入了相似图片。不要同时改三个参数,否则无法判断是哪个起作用。预训练模型的类别表不包含自定义目标时,检测不到是正常现象,这时应该走训练流程,而不是继续调阈值。
现象五:训练报维度不匹配,或loss不降、mAP长期为0。
维度不匹配先查data.yaml的nc和names长度是否一致,再查models/yolov5s.yaml里的nc是否同步改过;两处不一致时,检测头输出通道和标签类别数对不上。loss不降时查标签:每行是否5列、坐标是否归一化、类别id是否越界、图片和标签文件名主干是否一致。mAP长期为0还要看验证集是否为空、val路径是否写错。先用几十张图做小规模过拟合测试,能在训练集上把loss压下去,再扩到全量数据;一上来就跑300轮,出了问题很难定位。
| 排查层级 | 先看什么 | 通过标准 |
|---|---|---|
| 环境层 | Python版本、PyTorch位置、CUDA可用性 | 解释器在虚拟环境,cuda_available符合预期 |
| 依赖层 | requirements.txt是否装完、PyTorch是否被替换 | 导入检测模块不报错 |
| 数据层 | 图片/标签数量、txt五列、坐标范围、类别id | 检查脚本bad_count=0 |
| 配置层 | data.yaml的nc/names、模型yaml的nc | 两处类别数一致 |
| 参数层 | img、batch、conf、iou、workers | 显存不爆,结果可复现 |
6. 从能跑到可信:结果复核、阈值扫描与工程化小技巧
首轮检测跑通后,最容易犯的错是拿一张图的结果当结论。置信度阈值和IOU阈值对框的数量影响很大,单张图看着合适,换一批图就可能漏检或重复。我的做法是先固定--img和--iou,只扫--conf,用几十张代表性图片看框数变化,找一个拐点再全量跑。下面这个小脚本把不同conf下的检测结果分别存目录,并统计保存的标签行数,能快速看出阈值从0.25到0.55时框数掉了多少。
import subprocess from pathlib import Path for conf in [0.25, 0.35, 0.45, 0.55]: name = f"scan_conf_{int(conf * 100)}" subprocess.run([ "python", "detect.py", "--weights", "yolov5s.pt", "--source", "samples", "--img", "640", "--conf", str(conf), "--iou", "0.45", "--project", "runs/detect", "--name", name, "--save-txt", "--device", "cpu", ], check=True) label_dir = Path("runs/detect", name, "labels") txts = list(label_dir.glob("*.txt")) if label_dir.exists() else [] boxes = sum(len(p.read_text().splitlines()) for p in txts if p.exists()) print(f"conf={conf}, images={len(txts)}, boxes={boxes}")脚本里--img和--iou固定,只改变--conf,这样框数变化才能归因到置信度阈值。--save-txt让检测结果落成标签文件,统计labels目录下的行数就是框数;不同版本的结果目录结构可能略有差异,如果labels不在预期位置,按实际输出调整label_dir。--device cpu是为了让脚本在没GPU的机器上也能跑,有GPU时改成0会快很多。扫完后不要只看总框数,抽几张图对比:conf提高后先消失的是低置信度小目标,如果这些目标必须保留,就不能把阈值调得太高。阈值扫描不是玄学,它只是把“凭感觉调参”变成可对比的记录。从那以后我每次跑新数据都先用几十张图扫一遍conf,再决定是否全量跑,省下的返工时间比调模型多。希望帮到你。
本文还有配套的精品资源,点击获取