公司动态
YOLO目标检测入门:从环境搭建到自定义数据集训练全流程
刚接触 YOLO 目标检测的人往往喜欢搜“最新版教程”找一篇看上去最全的文章从环境安装、推理到自定义数据集训练一口气照着敲完。这个愿望是好的但实际情况通常是预训练模型能识别 bus可一换成自己的数据集就崩标签报错、训练 loss 不降、验证指标看不懂最后只能在收藏夹里吃灰。如果只能给一个判断我会说YOLO 入门真正要解决的不是看懂网络结构也不是背熟算法公式而是建立起一条从“图片输入”到“检测框输出”的最小闭环。只要这条闭环走通环境、数据、训练、评估这些概念就会自动串起来。这篇文章就按照这条闭环来写先让一个最小环境跑起来再做一次推理然后准备一个小型自定义数据集完成训练最后教你如何评估结果、排查问题以及下一步该往哪个方向走。1. 先放下“最新版”的执念想清楚 YOLO 到底让你学会什么说到目标检测YOLO 几乎是绕不开的名字。它全称是 You Only Look Once直译是“只看一次”。这个说法的背后是一个非常重要的设计思路把目标检测当成一个端到端的回归问题模型一次前向推理就能同时输出图中多个目标的类别和位置。很多新手上来就纠结“我应该学 YOLOv5、YOLOv8还是 YOLOv11最新版是不是一定更好”这是一个常见的误区。YOLO 发展到现在已经不仅仅是一个模型而是一整套方法、工程库和生态工具的集合。不同版本由不同团队维护接口、命令甚至标签格式都可能存在差异。今天网上很火的教程到了明天可能就会因为依赖版本变化而失效。1.1 目标检测任务到底在回答什么问题目标检测是图像任务里很重要的一类。它比图像分类多一个要求分类只告诉你图片里有什么类别检测还要告诉你目标在哪里。一个完整的检测输出通常包含两部分一是目标的类别比如“人、车、猫”二是目标在图像中的位置一般用边界框表示也就是我们常说的检测框。边界框通常由四个数值描述。不同算法使用的坐标系不一样有的是左上角坐标加上宽高有的是中心点坐标加上宽高还有的是旋转框。后面训练自定义数据集时你会看到 YOLO 标签格式用的是“归一化中心点 宽高”推理时拿到的又是“像素坐标框”。这两者如果不区分清楚非常容易踩坑。1.2 YOLO 的“只看一次”为什么能成为主流在 YOLO 出现之前比较有代表性的检测思路是两阶段方法第一阶段先生成许多可能包含目标的候选区域第二阶段再对每个候选区域做分类和坐标回归。这种思路精度不错但速度偏慢很难在实时视频场景里使用。YOLO 的设计则走了一条更直接的路把整张图片放进网络一次性输出所有目标的类别概率和边界框。整个过程不需要单独走候选区域生成因此速度很快。它牺牲了一部分对极小目标和密集重叠目标的精度换来了速度和端到端训练的便利。后来的 YOLO 系列版本虽然加入了多尺度预测、注意力机制、更复杂的增强策略但核心思想仍然延续了这个方向。1.3 小白真正要建立的是“训练-推理”闭环我记得很多刚开始学目标检测的朋友上来就去啃论文里的网络结构图结果越看越糊涂。实际开发中你是先在工具层面跑通流程再带着问题回头理解原理的。一个完整的学习路径应该是这样用预训练模型做一次推理感受“输入图片、输出检测框”这件事。准备几十张自己的图片标注成 YOLO 格式。在预训练权重基础上做小规模训练。用训练出的权重去跑测试图片观察结果和指标。遇到明显问题时再回到数据质量、参数设置、模型结构等层面去分析。这套流程不必追求多大数据量先把闭环走通就好。很多人训练失败不是因为算法理解不够而是因为数据目录不对、标签格式错了、环境依赖版本冲突或者是把 val 和 test 混为一谈。2. 环境安装不要追求一条命令装完先让最小环境能跑起来环境安装往往是劝退新手的第一道关卡。很多教程会甩给你一个很长的 pip install 命令复制进去跑了十几分钟结果 import 时报错或者训练时提示 CUDA 不可用。这种问题通常不是命令错了而是安装时的环境上下文不一样。我更建议把环境安装当成一个小项目来管理。不要直接在系统 Python 里装一堆包而是基于虚拟环境隔离。这样即使某个项目把依赖搞乱了也不会影响其他项目的使用。2.1 一个比较稳妥的安装顺序以常见的 YOLO 集成库 Ultralytics 为例安装路径大致是这样的# 创建一个独立的虚拟环境 conda create -n yolostudy python3.10 -y conda activate yolostudy # 先更新 pip pip install -U pip接下来安装 PyTorch。这里有一个非常重要的原则不要照抄别人命令里的 PyTorch 版本而是打开 PyTorch 官网根据你的操作系统和 CUDA 版本生成对应的安装命令。不同历史时间点官网推荐的命令会不断变化网上教程里的命令很容易过期。如果你的电脑没有 NVIDIA 显卡可以先安装 CPU 版本的 PyTorch。CPU 版本也能跑通 YOLO 的推理和小规模训练只是速度慢一些适合先验证流程。# 这是一个常见写法不代表当前所有环境都适用 pip install ultralytics安装完成后可以用下面的命令检查环境是否正常python -c import torch; print(torch.__version__, torch.cuda.is_available())如果输出中torch.cuda.is_available()是True说明 PyTorch 能正常使用 GPU。如果没有独立显卡或者驱动版本不匹配这行会输出False但推理流程依然可以继续。2.2 第一次推理用预训练权重验证环境环境装好之后不要急着训练。先跑一次推理确认整条链路是通的。下面的代码是集成库中常见的推理写法from ultralytics import YOLO # 加载预训练权重如果本地没有某些版本会自动下载 model YOLO(yolov8n.pt) # 对一张本地图片做预测并保存结果 results model.predict(sourcetest.jpg, saveTrue) print(results[0].names)如果你的网络环境导致模型下载失败可以先手动下载权重文件到当前目录再执行上面的代码。下载前要确认权重文件对应的模型名称与代码一致否则会出现形状不匹配之类的报错。2.3 环境安装中最常见的四类问题环境问题看起来五花八门实际上大多集中在几个方面。第一个是 PyTorch 和 CUDA 版本不匹配。有些人电脑里的显卡驱动已经很新但安装的 PyTorch 版本不支持对应的 CUDA 版本也可能反过来显卡驱动太老新版的 CUDA 依赖跑不起来。遇到这个问题建议先到 PyTorch 官网生成安装命令再检查驱动版本。第二个是包装到了错误的虚拟环境。很多人明明执行了 pip install但运行 import 时还是提示 ModuleNotFoundError。原因往往是当前终端没有激活目标虚拟环境或者同时存在多个 Python 环境。这种问题不是代码问题而是环境切换问题。第三个是训练或推理时显存不足。如果只是做推理验证可以调低imgsz比如从 640 改成 416如果是训练时显存不足则要调小batch或降低输入分辨率。第四个是文件路径问题。图片路径不要包含中文或特殊空格。YOLO 相关工具在处理中文路径时虽然有些版本已经兼容但为了少踩坑建议所有数据集和工作目录都使用纯英文路径。判断环境问题的时候先不要重装。先看报错发生的位置再看当前终端所在的环境最后看版本兼容性。重装往往是最后手段。3. 第一次推理看清楚图片、视频和模型返回的结构推理是 YOLO 环节里最能给你正反馈的一步。一张测试图片几行代码就能看到画好框的结果。但要真正用好模型不只是“看到有框”就够了还要理解模型返回的数据结构。很多人跑通一次推理后只保存了一张结果图后面要做批量处理或二次开发时就不知道怎么拿到坐标和类别了。因此第一次推理之后我建议你做一次“结果拆包”。3.1 从图片推理开始再尝试文件夹和视频单张图片推理的代码最简单from ultralytics import YOLO model YOLO(yolov8n.pt) results model.predict(sourcetest.jpg, saveTrue)如果你现在有一整个文件夹的图片不需要自己写循环results model.predict(sourcetest_images/, saveTrue)要处理视频文件时source 直接指向视频路径即可results model.predict(sourcetest_video.mp4, saveTrue)第一次尝试时我更建议用一张内容清晰、目标数量适中的真实照片而不是直接用摄像头。摄像头会带来实时性要求还要处理画面闪烁和卡顿这些都会干扰你对模型本身的理解。3.2 关键推理参数conf 与 iouconf是置信度阈值表示只保留置信度高于该值的检测框。默认值通常是 0.25。如果你发现结果里漏检了很多目标可以尝试降低成 0.1如果误检很多可以调高到 0.5 或更高。iou是用于非极大值抑制的 IoU 阈值。简单说当多个检测框重叠时用它来决定哪些框应该被合并或删除。对于稠密小目标场景这个参数可能需要调整。不过对第一次使用的人保持默认即可。不要把所有参数都改一遍。最好的做法是每次只改一个变量对比结果差异这样你才能知道每个参数到底影响什么。3.3 拿到结果后先学会“拆包”results是一个列表每个元素对应一张输入图片的推理结果。常用属性包括这些result.boxes.xyxy检测框坐标格式是像素坐标[x1, y1, x2, y2]。result.boxes.conf每个检测框的置信度。result.boxes.cls每个检测框的类别索引。result.names类别索引对应的类别名称。下面这段代码可以帮你逐张打印for r in results: for box in r.boxes: x1, y1, x2, y2 box.xyxy[0].tolist() confidence box.conf[0].item() class_id int(box.cls[0].item()) class_name r.names[class_id] print(class_name, round(confidence, 4), (round(x1), round(y1), round(x2), round(y2)))注意这里输出的坐标是像素级坐标不是训练标签中的归一化中心点坐标。很多新手训练完模型后会用训练标签的格式去理解推理输出结果发现自己画出来的框完全不对。3.4 保存检测结果的几种形态如果你需要保存检测框到文本文件而不是只保存画框后的图片可以在 predict 时加一个参数results model.predict(sourcetest_images/, save_txtTrue)这样每一张图片对应的检测结果会生成一个 txt 文件。文件的内容格式通常就是 YOLO 标签那一类格式也能让你快速看到检测到的所有目标。在真实项目中经常还需要把结果转成 JSON 或 CSV 供其他系统使用。这个集成库本身不一定有现成参数需要你用上一节里“结果拆包”的方式自行封装。也就是自己遍历boxes把所有检测框写到规定格式里。4. 自定义数据集不要急着造一万张图先让数据格式规范起来进入自定义数据集训练是绝大多数新手从“照着教程敲”到“真正开始做项目”的分水岭。问题是很多人的第一个自定义数据集不是输在标注数量不够而是输在目录结构、标签格式和数据划分这些看起来不起眼的细节上。我看过不少同学把图片放到一个文件夹把标注文件放到另一个文件夹然后在训练命令里写了一个非常复杂的路径拼接结果训练时提示找不到标签。其实 YOLO 这一类训练库对数据格式的要求非常清楚图片和标签文件同名标签内每行代表一个目标坐标全部归一化。4.1 先搞懂 YOLO 标签格式YOLO 标签文件是 txt 文件文件名必须与图片名一致只是后缀不同。比如图片叫cat_001.jpg标签就叫cat_001.txt。每一行格式是class_id x_center y_center width height所有坐标都做了归一化处理也就是用真实像素坐标除以图片的宽度或高度得到 0 到 1 之间的小数。这里需要注意x_center 和 y_center 是目标框的中心点不是左上角坐标。举个例子。一张宽 1000、高 800 的图片中某个猫框左上角坐标是 (400, 300)右下角坐标是 (600, 450)。那么这个框真实宽高是 200 和 150中心点坐标是 (500, 375)。归一化后标签内容就是0 0.5 0.46875 0.2 0.1875如果你的数据集里有多类目标类别索引从 0 开始计数而不是从 1 开始。上面这行中的 0 表示第一类目标不是“无效”的意思。4.2 一个规范的目录结构在训练时尽量把图片和标签分开管理但在文件名上严格一一对应。常见目录结构是这样的datasets/ └── mydataset/ ├── images/ │ ├── train/ │ │ ├── cat_001.jpg │ │ └── dog_001.jpg │ └── val/ │ └── test_001.jpg ├── labels/ │ ├── train/ │ │ ├── cat_001.txt │ │ └── dog_001.txt │ └── val/ │ └── test_001.txt └── dataset.yamlimages和labels下的子目录名称要保持一致。很多训练框架会自动寻找与图片同路径的标签文件将images替换为labels。如果你路径结构不匹配就会报 “found no labels” 或类似错误。dataset.yaml长这样path: /absolute/path/to/mydataset train: images/train val: images/val nc: 2 names: [cat, dog]path字段尽量使用绝对路径或相对稳定的路径不要使用带空格的目录。train和val指定的是相对于path的图片目录库会自动去找对应的 labels 目录。有时候只改 names 里的名称但忘了调整 nc 的数量就会在训练开始时报错。4.3 标注工具与训练前检查标注工具很多常见的有 LabelImg、Label Studio、CVAT、X-AnyLabeling 等。功能上差异不大关键是导出格式一定要选 YOLO 格式。如果标注工具导出的是 COCO 或 Pascal VOC也不是不能用但需要先做一遍格式转换增加了不必要的复杂度。标注完以后不要立刻训练。我建议先做两步检查。第一步是抽查标签是否对应图片内容。你可以写一个小脚本读取 txt 中的归一化坐标乘回图片宽高再用 OpenCV 画出框最后逐张查看。第二步是检查有没有空标签文件。如果某张图中没有任何目标它的标签 txt 可以保留为空文件也可以不创建。具体以你使用的训练框架为准。但大多数情况下如果目录里有损坏图片或者图片和标签名大小写不一致最终都会在训练日志里以奇怪的方式暴露出来。4.4 数据量学习用 20 张可以真实项目按需增加很多教学视频为了演示效果会使用一个公开数据集里面有几千张图片。这容易让人产生一种错觉只有数据量足够大模型才能训练出来。对于学习流程来说每个类别 20 到 50 张图片就足够走通训练链路了。模型效果不一定好但你能看到 loss 下降、指标上升、训练生成权重文件这套过程比效果更重要。如果一开始就想收集一万张图很可能半个月还没开始训练。当你要做一个真实场景的项目时训练数据应该覆盖目标出现的环境变化。至少要包含不同角度、不同光照、不同距离、不同遮挡情况。如果目标是特定设备上的零件就要尽量采集真实流水线中的画面而不是随便找一些网图。数据量不是唯一指标数据分布和标签质量通常更影响落地效果。我见过很多训练不收敛或者验证指标虚高的案例最后查下来都是 train 和 val 数据出现重叠。验证集的作用是模拟模型没有见过的数据如果它和训练集来自同一批图片再高的 mAP 也不能说明模型真有泛化能力。5. 用自己的数据集训练理解参数比执行命令更重要数据集准备好以后训练本身并不难。难的是当你发现训练出来的模型表现不好时你能不能判断出问题到底出在数据、参数还是模型选择上。5.1 最小训练命令先给一个最常见的最小训练示例from ultralytics import YOLO # 在预训练权重基础上继续训练 model YOLO(yolov8n.pt) model.train(datadataset.yaml, epochs50, imgsz640, batch16)这里使用yolov8n.pt表示加载预训练权重。如果你的库支持可以改成自己当前环境支持的模型权重名称。如果希望从头开始训练可以传入对应的 yaml 模型结构文件例如yolov8n.yaml不过标准实操中很少在小数据集上从头训练。使用命令行也是常见方式yolo detect train datadataset.yaml modelyolov8n.pt epochs50 imgsz640 batch16训练开始后如果一切正常日志里会显示每个 epoch 的 loss、验证集上的精度指标并定期保存权重。5.2 关键训练参数到底在控制什么训练时你会看到很多超参数第一次不必全懂但要理解最重要的几个。epochs表示训练轮次也就是整个数据集被模型完整看几遍。学习验证时设置 30 到 50 就够了。如果数据量很小轮次太多也可能导致过拟合。batch是每批进入网络的图片数量。它越大单位时间内处理的图片越多但不代表效果一定更好。显存不足时先把 batch 调小到 8 或 4。现在很多库也支持batch-1自动寻找显存能支持的最大批次但自动判断不一定最稳可能出现刚开始没事后面显存爆掉的情况。imgsz是训练输入的图片分辨率。常见默认值是 640。目标很小的时候提高分辨率能保留更多细节但显存占用和训练时间会明显增加。如果只是学习流程先固定在 640不要随意改动。patience是早停等待轮数。如果验证集指标连续该轮数没有提升训练就会自动停止。这个参数对长时间训练很有用避免浪费算力。device指定使用 CPU 还是 GPU。在集成库中通常device0表示第一块 GPUdevicecpu表示 CPU。如果你有多个 GPU可以传入device0,1。不过这是进阶操作入门阶段不需要折腾多卡训练。5.3 训练完成后生成哪些文件训练结束后默认会在runs/detect/train/目录下生成结果。不同版本路径可能稍有差异但通常会看到这些内容weights/best.pt在验证集上表现最好的权重。weights/last.pt最后一个 epoch 保存的权重。args.yaml本次训练的所有参数记录。results.png训练过程的指标曲线。confusion_matrix.png混淆矩阵。best.pt是你用来做推理和后续导出的首选权重。它在验证集上表现最好但要注意验证集是用来选择模型的依据不代表最终测试一定可靠。last.pt更多用于继续训练或异常中断后恢复。5.4 训练指标从 mAP 到过拟合判断目标检测训练过程中最常用的评价标准是 mAP全称是 Mean Average Precision。它结合了精确率和召回率用来衡量模型在不同置信度阈值下的综合性能。在训练日志里你会看到几个关键指标Precision预测出的框中真正正确的比例。Recall真实目标中模型能找到的比例。mAP50当预测框和真实框的 IoU 大于 0.5 时认为检测正确然后计算平均精度。mAP50-95在 0.5 到 0.95 多个 IoU 阈值下分别计算 mAP再取平均评价要求更严格。IoU 是预测框和真实框的重叠程度数值越接近 1表示位置越准。mAP50 对位置精度要求较松mAP50-95 更能反映定位质量。判断训练是否正常可以看三条信息loss 是否随训练下降。Precision 和 Recall 是否在合理范围内。train 和 val 的表现差异是否过大。如果训练集指标一直涨验证集指标反而下降说明模型已经开始过拟合了。如果训练集和验证集的 loss 都不降则要检查数据标签是否有问题、学习率是否设置不当、模型容量是否不足。5.5 增量训练是什么意思“增量训练”也是 YOLO 实战中经常遇到的概念。它指的是在已训练好的权重上继续用新数据训练而不是每次从零开始。如果新增的数据类别和原来完全一致你可以直接加载旧的 best.pt再设置较小的 epochs 继续训练。这样既保留了已学到的特征又能让模型适应新的数据分布。但如果要增加一个全新的类别就不能只拿新类别的数据训练而要把以前的旧类别数据一起加入。否则模型可能会把新类别误认成旧类别出现“灾难性遗忘”。这也是很多真实项目中模型越增量越退步的原因。6. 训练结束只是开始用测试集评估和保存结果训练跑完看到终端输出一堆指标很多人以为这项工作已经结束了。实际上训练只是帮你产出了一个候选模型真正决定模型能不能用的是你还没走过的一个环节用一个完全独立的数据集做测试。如果在训练阶段只划分了 train 和 val那么验证集已经被用来挑选 best model 了。你再用 val 去报告效果多少有一点“自己考自己”的味道。比较可靠的做法是额外留出一批测试集这部分图片从不出现在训练阶段只在模型选完之后用来评估。6.1 用 best.pt 批量预测测试集加载训练好的权重进行推理很简单from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict(sourcetest_images/, saveTrue, projecttest_output, conf0.25)如果你想同时保存标签文件可以再加上save_txtTrue。不过要小心生成的对象是测试图片的检测预测框不是原始的人工标注标签。你需要通过类别和坐标将模型输出与真实标注做对比才能计算 Precision 和 Recall。6.2 不要只看单张图要看误差分布很多人在评估时只挑几张效果最好的图片发出来这会让模型看起来比实际更可靠。正确做法是随机抽取一批测试图片包括模型容易出错的情况。如果训练时 mAP 很高测试集上明显下降大概率是数据分布不一致或者训练数据量太少模型记住了训练集里的背景和颜色而不是目标本身的特征。如果某个类别 AP 特别低优先检查该类别的样本数量是否太少标注是否有漏标。误检问题则要结合混淆矩阵看是模型把 A 类误认为 B 类还是把背景当成目标输出。6.3 从 PyTorch 模型到可部署产物当项目需要部署到线上服务或边缘设备时不能直接拿原生的 PyTorch 模型到处跑。常见的一步是导出为 ONNX 等中间格式。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) model.export(formatonnx, imgsz640)ONNX 导出之后推理时可以不用原始 PyTorch 环境而是采用 ONNX Runtime 这类轻量推理引擎。不同推理框架对模型输入的预处理要求可能不同。有很多做 C 推理或者嵌入式开发的朋友会在这一步遇到问题原因往往不是模型本身而是没有处理好图片缩放、归一化参数和输出后处理。因此我建议导出模型后先用同一个测试图片对比原始 PyTorch 模型的输出和导出模型的输出。如果检测框坐标有偏差优先检查输入分辨率、均值方差是否一致。7. 训练和推理出问题不要盲改参数按这个链路排查YOLO 项目里的 bug 很多。但多数问题并不是算法缺陷而是输入数据、环境依赖、参数设置和文件路径之间的错位。遇到报错时不要着急调参数也不要立刻重装环境。先按顺序排查会省下很多时间。7.1 问题排查顺序我把排查过程梳理为七层第一层现象。先确认你看到的是什么是训练直接报错还是训练正常但指标很差或是推理时一个框都没有。现象不同排查方向完全不同。第二层输入。检查图片路径是否存在、图片是否损坏、格式是否被框架支持、文件名是否包含中文或空格。很多“找不到图片”问题其实只是路径写错了。第三层数据格式。检查 labels 目录是否存在、txt 内容是否规范、类别索引是否越界、坐标是否归一化、train 和 val 是否有交叉。第四层环境。确认当前终端是否激活了正确的虚拟环境PyTorch、CUDA、集成库版本是否兼容。训练卡在 dataloader 时也要检查线程数是否设置过高。第五层参数。检查 epochs、batch、imgsz、learning rate 等是否合理。尤其是 batch 和 imgsz这两个参数会直接影响显存占用。第六层日志和产物。训练没有报错不代表一切正常。看 loss 曲线、看验证指标、看保存的预测图都能帮你判断模型状态。第七层算法和模型边界。考虑当前任务是否真的适合当前模型数据的复杂度是否超过模型容量训练类别和测试类别是否一致。7.2 常见异常速查现象优先排查点训练时报 found no labelsdata.yaml 的 path / train / val 路径是否正确labels 目录是否存在图片与txt 文件名是否一致训练时 CUDA out of memory调小 batch或调小 imgsz先跑通再逐步增加loss 一直不下降检查标签是否为空或坐标错误确认图片真实加载进训练集查看学习率是否异常推理时完全没有检测框检查 conf 阈值是否过高检查加载的权重是否对应训练