要说 YOLO,这几年的热度确实一直没下去。原因也很直白:它把目标检测的门槛压得足够低,低到哪怕你只懂一点 Python,手里也只有一台普通笔记本,也能在半天之内把训练和推理整套流程跑通。这篇文章不搞花活,直接把我自己在 YOLOv8 和 YOLO26 两条版本线上反复折腾出来的稳健流程写出来,从环境搭建、数据集准备、模型训练、导出,一直到本地推理落地,每一层都给你讲清楚为什么这么做,以及翻车的时候从哪里排查。全文复制粘贴就能跑,尽量做到零报错。
1. 先把版本差异这件事说透,避免你用错教程
1.1 YOLOv8 和 YOLO26 的关系不是“新老替代”,而是“同一套管道”
新手最容易卡住的第一个问题不是代码报错,而是“我该学 v8 还是学 26”。我先给个结论:如果你现在打开官方仓库,能看到 YOLOv8、YOLO11、YOLO26 这类不同代际的模型都在同一个项目里维护,它们的训练入口、数据格式、配置方式高度一致。
YOLOv8 胜在稳定,生态里的第三方面板、导出工具、教程量最大,很多公司线上跑的模型还是 v8。YOLO26 是 newer 架构的代表,在检测头设计、特征融合层做了改动,小目标表现更好,训练收敛速度也快一些。但对你来说,最先要建立的概念不是“哪个更强”,而是“一套流程能用到底”。
这里有个很重要的实操提示:不要混着看教程写代码。比如 v8 年代的训练脚本用yolo detect train,新的版本可能已经改成了yolo train,不同时期的文档截图会出现参数名不一致的情况。你跟着一篇文章走到底,优先级永远高于“东拼西凑查资料”。下面所有命令我均以当前版本通用写法为准,v8 和老版本用户需要小调整的地方我会单独标注。
1.2 我的统一工作流:为什么可以一套脚本横跨两个版本
我给团队内部做技术方案时,经常画这么个链路:
数据集标注 -> yaml配置 -> 训练 -> 评估 -> 导出 -> 推理脚本这套链路里真正会被版本影响到的只有两处:一次是模型权重加载时的参数名,一次是导出格式的选择。数据集格式、标注逻辑、训练超参、推理后处理这些核心逻辑,在 YOLO 体系里几乎是全版本通用的。所以我会先帮你把通用部分吃透,再在关键节点给出 v8 和 26 的差异化说明。
提示:最稳妥的做法是装完环境后固定版本号。不要频繁 upgrade 到最新版,否则今天能跑的代码,过两周再跑可能就被新版本 API 改了。后面我会给出锁版本的具体命令。
2. 环境搭建的“稳”,全靠这几条反直觉原则
2.1 别在系统 Python 里直接装,先建虚拟环境
很多新手一上来就是pip install ultralytics,装完确实也能用,但等到你项目增多、依赖冲突频繁报错时,就知道虚拟环境的好处了。我推荐用 Anaconda 或者 Miniconda,原因不只是隔离环境,而是后续装 CUDA 版 PyTorch 时,conda 对版本匹配的处理比裸 pip 省心。
具体命令,新建终端依次执行:
conda create -n yolo python=3.10 -y conda activate yolo选 Python 3.10 的原因:Ultralytics 官方对 3.8-3.12 都有支持,但 3.10 在兼容性和第三方库(比如 onnxruntime、openvino)之间最平衡。3.11、3.12 也能用,但个别老库编译容易踩坑,没必要冒险。
2.2 PyTorch 安装:先看显卡,再决定命令
有 NVIDIA 显卡的同学,去 PyTorch 官网选对应 CUDA 版本的安装命令,例如:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121这里的cu121表示 CUDA 12.1。如果你不知道自己的 CUDA 版本,终端里跑:
nvidia-smi看右上角CUDA Version是多少,只要它不低于 PyTorch 要求的版本就行。比如你看到 CUDA 11.8,那装 cu118 的 PyTorch 完全没问题;看到 12.x,装 cu121 或 cu124 都行。
没有独立显卡的 Windows 用户也别慌,直接装 CPU 版:
pip install torch torchvision torchaudio这句命令在没有 GPU 的机器上会默认装 CPU 版,推理小模型完全够用,只是训练会慢很多。建议新手期先拿 CPU 跑通流程,再决定要不要租卡。
安装完验证一下:
python -c "import torch; print(torch.__version__); print(torch.cuda.is_available())"输出True就说明 GPU 可用。这一步是零报错的关键前提,后面所有训练卡死问题,有一半可以在这里找到答案。
2.3 ultralytics 安装与权重文件说明
接下来安装目标检测的核心包:
pip install ultralytics建议顺手把版本锁住,方便复现:
pip install ultralytics==8.3.20安装完成后,你不需要手动去下载权重文件。第一次执行推理命令时,包会自动拉到yolov8n.pt或对应的模型文件。这个自动下载机制很方便,但也有个隐患:某些网络环境里连接官方下载源会超时。遇到超时不要反复重试,直接手动下载 .pt 文件扔到当前目录下就行。
验证一下是否装好:
yolo predict model=yolov8n.pt source=https://ultralytics.com/images/bus.jpg跑通后会生成一个runs/detect/predict目录,里面是带检测框的结果图。看到这张图,你的环境搭建就正式过关了。
3. 第一次推理跑通后,必须搞懂这几件事
3.1 输出结果里每个数字代表什么
用脚本方式做推理时,很多人拿到结果后一头雾水:
from ultralytics import YOLO model = YOLO("yolov8n.pt") results = model("bus.jpg")results是一个列表,每个元素对应一张图。里面的boxes对象包含:
boxes.xyxy:四个角坐标,分别是左上角 x、y 和右下角 x、yboxes.conf:置信度,模型有多确信这个框是目标boxes.cls:类别索引,对应 coco 类别列表里的序号
新手最容易犯的错是把坐标顺序搞错。xyxy 是像素坐标,直接可以画在图片上;如果你在后续做跟踪或者裁剪,高频用到的也是这个。千万别拿它和 yolo 训练标注时的格式(cx, cy, w, h 归一化)混淆,两者不是一回事。
3.2 用官方脚本批量推理,比一个个写循环更省事
跑单张图验证很简单,但实际项目里你大概会面对一个文件夹几百张图。官方 CLI 一句命令搞定:
yolo predict model=yolov8n.pt source=./images save=True如果不希望输出图片叠加框,而是需要原始的检测结果 json,可以加:
yolo predict model=yolov8n.pt source=./images save_txt=True save_json=True很多人不知道save_txt=True会生成 YOLO 格式的 txt 文件,每个框一行,内容是class x_center y_center width height,这个格式是归一化的,不能直接当像素坐标用。如果你要的是像素坐标,建议在 Python 脚本里解析,或者用save_txt=True的 txt 结合图像的宽高换算回来。
3.3 首跑常见的三个报错,对应的修复顺序
报错一:ModuleNotFoundError: No module named 'ultralytics'。这个是环境没激活或者装错环境。终端里执行conda activate yolo后再python进入解释器验证。
报错二:下载权重超时。手动下载对应 pt 文件放到项目目录,然后用model = YOLO("yolov8n.pt")指定本地路径,不再走自动下载。
报错三:CUDA out of memory。这是显卡显存不够,最常见于训练阶段。改小 batch size,或者把图片尺寸从默认 640 降到 512,命令里加imgsz=512即可。
这三个问题处理完,整个推理链路基本就通了。
4. 从零训练自己的数据集,关键操作点逐个拆
4.1 标注格式不用自定义,认准 YOLO txt 格式
很多新手一开始想用 VOC 或者 COCO 格式,再写代码转换成 YOLO 格式。我不建议这么做。直接用 LabelImg 或者开源标注工具(比如某跨平台标注工具),导出时选 YOLO 格式即可。
YOLO 格式的标注文件,每个 txt 对应一张同名图片,每行是:
class_id x_center y_center width height注意这四项坐标全部是归一化的,取值在 0 到 1 之间,除以图片宽高得到的比例。如果你手工标注了一个框的像素坐标,想转成 YOLO 格式,转换公式是:
x_center = (xmin + xmax) / 2 / image_width y_center = (ymin + ymax) / 2 / image_height width = (xmax - xmin) / image_width height = (ymax - ymin) / image_height4.2 数据集的目录组织:少一个文件都会报错
建议按照下面的结构组织:
datasets/ ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/注意 images 和 labels 必须在同一级目录下,且训练集和验证集的数量最好按 9:1 或 8:2 划分。标注工具导出的 txt 文件,命名必须和图片完全一致,比如IMG_001.jpg对应IMG_001.txt,一个都不能少。
4.3 写一个干净的 data.yaml,别踩路径坑
训练时你需要一个 yaml 配置文件,内容大致如下:
path: ./datasets train: images/train val: images/val names: 0: person 1: car这里最坑的是path字段。如果你用的是相对路径,它相对于你执行命令的当前目录;如果你用绝对路径,建议写正斜杠,Windows 下用反斜杠容易转义出错。很多人在这一步报AssertionError: train dataset not found,几乎都是 path 写错。
names 列表的顺序必须和标注时的 class_id 对应,顺序错一个,训练出来的模型就会把猫识别成狗,而且损失值看着还挺正常。
4.4 训练命令与参数:不要全默认,先看这五个
yolo train model=yolov8n.pt data=data.yaml epochs=50 imgsz=640 batch=8 device=0解释一下每个参数:
model=yolov8n.pt:加载预训练权重做迁移学习。n 是 nano 版本,适合显存小的机器。epochs=50:训练轮数。小数据集 50 轮基本够看效果。imgsz=640:输入图片尺寸。检测速度与精度都受这个影响。batch=8:一次喂入模型多少张图。8G 显存跑 nano 模型这个值基本安全。device=0:用第一张显卡训练。没有 GPU 则写device=cpu。
训练结束后,runs/detect/train/weights/里会有best.pt和last.pt,前者是验证集上效果最好的权重,后者是最后一轮的。以后做推理都用 best.pt。
4.5 训练中断、Loss 不降、类别不平衡,我惯用的处理思路
训练中断要先看有没有resume能力。YOLO 支持断点续训:
yolo train resume model=runs/detect/train/weights/last.ptLoss 完全不降,先检查数据集格式和标注是否正确。有个快速可视化方法:训练前用yolo check data.yaml或写个脚本把标注画到图片上看看框和对象是否对齐,这一步能排查掉 90% 的数据问题。
类别不平衡时,不要急着调 loss 函数,先检查各类别图片数量,少的类别用复制增强或者多收集数据,比任何参数调整都直接。
5. 从 pt 权重到实际部署,导出与推理落地的完整套路
5.1 ONNX 导出:跨平台跨端点的第一步
训练完的.pt权重只能在 PyTorch 环境里运行。你想在 C++、Android、或者不带 Python 的服务器上跑,就得先导出成中间格式。最常用的是 ONNX:
yolo export model=best.pt format=onnx opset=12 imgsz=640opset=12是为了兼容更多推理框架。导出后的.onnx文件可以直接用 ONNX Runtime 加载推理,也可以再转成 TensorRT 的 engine 格式跑在 NVIDIA GPU 上。
注意导出的时候不要二次修改 imgsz,保持 640 和训练时一致,否则输出层形状和训练时的后处理逻辑对不上。
5.2 用 ONNX Runtime 写一个不依赖 ultralytics 的推理脚本
这才是“落地”的真正含义:线上服务器或者设备端不需要装全套训练环境。脚本核心代码如下:
import cv2 import numpy as np import onnxruntime as ort session = ort.InferenceSession("best.onnx", providers=["CUDAExecutionProvider", "CPUExecutionProvider"]) input_name = session.get_inputs()[0].name input_shape = session.get_inputs()[0].shape # [1, 3, 640, 640] image = cv2.imread("test.jpg") img = cv2.resize(image, (640, 640)) img = img[:, :, ::-1].transpose(2, 0, 1) # BGR转RGB,HWC转CHW img = img.astype(np.float32) / 255.0 img = np.expand_dims(img, axis=0) outputs = session.run(None, {input_name: img})[0] # outputs shape: [1, 84, 8400],前4个为框坐标,后面为类别概率这段代码的细节是:必须做 BGR to RGB、归一化、HWC to CHW 三个操作。很多人在 PyTorch 里跑得好好的,换成 ONNX 后检测结果全乱,原因就是输入预处理没对齐。
5.3 后处理:从模型输出到检测框的必要工序
84 的含义是 4 个坐标信息 + 80 个类别概率(coco 数据集)。8400 是不同尺度下候选框的数量。你需要做三件事:
- 把 8400 个候选框中置信度低(比如低于 0.25)的过滤掉
- 找到每个框最大概率对应的类别
- 做非极大值抑制,把重叠的高分框合并
NMS 在 ONNX 模型里可能已经包含,也可能没有。format=onnx默认输出是没有 NMS 的原始输出,需要你额外实现或用 cv2 的 NMS 函数。如果不想自己写,导出时可以用yolo export model=best.pt format=onnx nms=True,让输出包含 NMS 后结果,但端到端结构会复杂一些。
对于 CPU 推理,另一个常用的优化是量化。使用 int8 量化的 ONNX 模型在 CPU 上推理速度能提升 2 到 3 倍,精度损失一般能控制在可接受范围。具体做法需要准备一批校准图,调用 onnxruntime 的 quantization 工具,新手先跑通流程,这个优化可以后面再做。
5.4 不同硬件下的部署路径选择:一张表看明白
| 目标环境 | 推荐格式 | 推理框架 | 备注 |
|---|---|---|---|
| Windows/Linux Python 服务 | ONNX | ONNX Runtime | 部署最简单,性能中等 |
| NVIDIA GPU 服务器 | TensorRT | TensorRT | 速度快,适合高并发 |
| 浏览器端 | WebAssembly | ONNX Runtime Web | 需要额外处理输入输出格式 |
| 手机端 | NCNN/TFLite | 各自框架 | 需要先转 ONNX 再转目标格式 |
我自己常用的部署套路是:模型重 n 或 s,图 ize 640,GPU 上跑 TensorRT FP16,CPU 上退到 ONNX Runtime。这个组合在实际项目里最省心。
6. 模型在本地跑通了,参数也训练完,为什么一部署就崩?排查顺序很重要
6.1 症状一:推理速度突然很慢,甚至比 CPU 还慢
出现这个情况先别骂代码。检查一下 ONNX Runtime 是不是真的在用 GPU provider:
print(ort.get_available_providers())如果只有CPUExecutionProvider,说明你没有安装 GPU 版 onnxruntime,或者 CUDA/cuDNN 版本不匹配。这时去装对应的onnxruntime-gpu,比如:
pip uninstall onnxruntime pip install onnxruntime-gpu装完再跑,速度一般会有几倍到几十倍的差距。
6.2 症状二:检测框偏移或者角度不对,但训练时画的很好
这个八成是预处理问题。我用过一个开源摄像头监控项目,图片是从视频流里截取的 BGR 帧,直接在脚本里缩放后送进模型,结果半小时没查出问题。后来发现是忘了做 BGR 转 RGB。还有一次是归一化乘了1/255,但模型的输入层自带归一化,结果数值被归一化了两次,检测精度直线下降。
建议把预处理封装成一个函数,任何部署脚本都调用它,不要每次重新写一遍。
6.3 症状三:损失函数正常下降,但验证集 mAP 低
这种情况我会先怀疑两处:数据划分是否过拟合了同一批图,以及标注中是否有大量漏检。用训练集中表现最好的 best.pt 去 val 集跑一遍,打印出每一类的 mAP。如果某个类别特别低,看看该类别样本数量和标注质量。如果所有类别都低,建议去检查验证集和训练集是否存在大量相似图片,这会让训练过程虚高但泛化能力差。
另外,anchor 参数我也提一嘴。YOLOv8 和 YOLO26 基本使用自适应 anchor,你不需要手动设置。如果换成老版本模型,再用自定义数据集时,注意训练脚本会自动做 anchor 聚类,不需要你在 yaml 里硬写。
7. 零报错体系化自检清单以及几条我一直沿用的经验
这部分是给已经跑通整个流程的人看的。我在多个项目里试过,这套自检清单能减少至少 70% 的无效调试时间。
7.1 终端里的自检顺序
1. conda 环境是否激活 2. torch.cuda.is_available() 是否为 True 3. ultralytics 版本是否是你安装的版本 4. data.yaml 的 path 是否与当前目录匹配 5. 图片和 txt 标注文件的数量是否一致 6. 第一次训练前,先跑几个 epoch,确认 loss 在下降 7. 导出前确认 imgsz 与训练时一致如果你按照这个顺序排查,几乎所有"莫名其妙"的报错都能定位。尤其第 6 条,很多人上来就跑 100 epoch,跑到 90 才发现数据有问题,浪费大量时间。先跑 5 轮,看 loss 和预测样例,再评估要不要继续。
7.2 切换 YOLOv8 和 YOLO26 时,我固定保留的三个习惯
第一个习惯是建立并固定模型权重文件目录。把 v8 和 26 的预训练权重分开存放,避免自动下载时文件名冲突。
第二个习惯是训练脚本里显式传入全部核心参数。不要依赖 yaml 里的默认值,所有影响训练的关键配置全部写到命令行或脚本里,这样日志可查,复现更容易。
第三个习惯是保留一份运行成功的完整日志。每次跑通一个重要节点,就把终端内容保存一份。出了新问题,回去翻日志比对参数差异,经常比对完就发现问题了。这比在网上搜答案更高效。
这些做法不涉及什么高深技巧,纯粹是经历过几次"明明昨天还能跑,今天却报错"之后沉淀下来的习惯。尤其是版本管理这一点,YOLO 项目迭代太快,依赖库更新也快,没有固定版本的意识,零报错就是一句空话。
7.3 最后说一条容易被忽略的推理优化
如果你打算在 CPU 机器上一次处理很多图片,记得把输入图片批量推理,而不是循环单张。ONNX Runtime 支持多输入:
batch_imgs = np.stack([preprocess(p) for p in [img1, img2, img3]]) session.run(None, {input_name: batch_imgs})同样的性能提升也适用于官方 YOLO 推理,source 换成文件夹路径时它本来就是批量处理的。实际项目里,图片预处理往往比模型推理更耗时间,顺手开个多线程读取图片,整体吞吐又能提一截。
把这些流程跑下来,你的 YOLO 就不再是一个"能跑 demo"的水平,而是真正能应对不同环境、不同数据集、不同部署目标的一条完整链路。后面想深挖的方向也很多,比如模型剪枝、蒸馏、TensorRT 的 FP16/INT8 优化、自定义后处理算子,都是从这里延伸出去的。先把地基打扎实,比追着新模型跑更有价值。