YOLOv8 实战:环境、数据、训练与部署


这篇是操作手册:目标是让一个空环境走到一个能检测自己定义类别的模型,并导出成可部署的格式。每一步给命令、预期输出和常见报错的解释;原理不展开,需要解释”为什么”的地方一句话点到为止。

一、开工前的三件事

硬件路线。三条路,代价和能力差别很大:本机有 NVIDIA 显卡,训练推理都在本地;没有显卡或显存太小,租按时长计费的云 GPU(Colab 的免费额度、AutoDL 一类国内平台,几块钱一小时),流程与本地完全一致;纯 CPU 只够跑推理和极小的训练任务,正式训练不现实。

示例任务。为了可复现,全文分两段走:先用 ultralytics 包内置的 coco8(8 张图的小数据集,首次使用自动下载)把”训练、验证、导出”全流程几分钟跑通;再换成自己的数据集,重复同样的命令。这样不必先花几天找数据、做标注,管线问题和个人数据问题不会搅在一起。

版本。写作时 ultralytics 包的版本是 8.4.x,v8、v11、v12 都由这一个包提供,用法一致。文中命令以官方文档为准,参数名隔几个版本偶尔会变。

二、环境搭建

建独立环境。不要装在 base 或系统 Python 里——torch 的 CUDA 版本会被其他项目锁死。二选一:

# conda
conda create -n yolo python=3.11 -y
conda activate yolo
# 或 venv
python -m venv .venv && source .venv/bin/activate

装 PyTorch。新手最大的坑在这一步:直接 pip install torch 装到的是 CPU 版,训练慢一个数量级,而且不报任何错。正确顺序是先查显卡驱动支持的 CUDA 版本:

nvidia-smi   # 右上角显示驱动支持的 CUDA 上限

然后去 PyTorch 官网选对应的安装命令(CUDA 11.8、12.x 各有对应的一行),装完验证:

python -c "import torch; print(torch.cuda.is_available())"   # 必须输出 True

输出 False 就不要往下走——后面所有”训练慢”的问题都会溯源到这里。

装 ultralytics 并验证环境:

pip install ultralytics
yolo predict model=yolov8n.pt source='https://ultralytics.com/images/bus.jpg'

第一次运行会自动下载 yolov8n 权重(约 6 MB)。下载慢或失败时,到 GitHub 的 ultralytics 仓库 releases 页手动下载对应权重的 pt 文件,放到命令的执行目录即可。成功后终端会打印检测到的目标,结果图存在 runs/detect/predict/ 下——能看到输出,环境就通了。

pip 下载慢时换国内镜像源(-i https://pypi.tuna.tsinghua.edu.cn/simple);Windows 用户注意两点:路径分隔符用正斜杠或双反斜杠,数据集路径避免中文。

工作目录建议分三块:datasets/ 放数据集、weights/ 放手动下载的权重、脚本单独一个目录。ultralytics 的运行产物固定写进发起命令时所在目录的 runs/ 下,所以从哪里执行命令要固定下来,否则产物会散落在各处。

三、先跑一次推理

环境验证和正式使用是同一条命令,值得把参数说清:

yolo predict model=yolov8n.pt source='bus.jpg' conf=0.25 iou=0.7 save=True
参数 作用 默认
model 权重路径或名称 —
source 图片、目录、视频、摄像头编号 —
conf 置信度阈值,低于它的框直接丢弃 0.25
iou NMS 的重叠阈值 0.7
classes 只保留指定类别,如 classes=0 全部
save 是否保存结果图 True

终端每次推理会打印一段汇总,大致长这样:

image 1/1 /path/bus.jpg 640x480 4 persons, 1 bus, 38.2ms
Speed: 5.0ms preprocess, 38.2ms inference, 120.0ms postprocess per image
Results saved to runs/detect/predict

一行一张图:检测到的目标按类别计数,后面是三个阶段的耗时——预处理、推理、后处理。读耗时分布对后面的调优很重要:推理耗时才是模型本身的成本,预处理和后处理慢属于工程问题,换思路解决而不是换模型。

结果存在 runs/detect/predict/,每次运行目录自动递增(predict2、predict3),不会覆盖。

这一步的意义不止是”看到效果”:训练自己的模型之后,唯一的区别是把 model 换成自己训练出的权重路径,其余命令一字不变。先把输出长什么样记熟,后面验收自己的模型时才不会陌生。

四、构建自己的数据集

目录约定。ultralytics 按固定结构组织数据,有一个必须知道的细节:它会自动把路径中的 images 替换成 labels 来找标注文件。所以图片放 images/train、标注放 labels/train,两边文件同名(仅扩展名不同):

datasets/mydata/
├── images/
│   ├── train/   # 训练图片
│   └── val/     # 验证图片
└── labels/
    ├── train/   # 每张图一个同名 txt
    └── val/

标注格式每行一个目标:class_id cx cy w h,四个坐标按图片宽高归一化到 0 到 1,类别 id 从 0 开始。标错类别 id(从 1 开始数)是最常见的翻车点,症状是训练能跑、loss 正常、但某些类永远检不出来。

标注工具。个人项目用 labelimg 足够:pip install labelimg 装好启动,先把左侧的标注格式切成 YOLO(默认是 VOC 的 XML),再打开图片目录、指定标注保存目录;常用快捷键 w 画框、d 下一张、a 上一张、del 删框。它导出的 txt 与图片同名,直接放进 labels 目录即可。标注量上千或多人协作时换 CVAT,支持任务分发与进度管理。

训练数据的一个便捷来源是业务场景的视频:用 ffmpeg 每秒抽一帧(ffmpeg -i video.mp4 -vf fps=1 frames/%05d.jpg),比逐张截图高效得多——注意同一视频抽出的帧要划进同一个子集,否则相邻帧分跨训练与验证集,指标会虚高。

标注前先写三条规范,多人标注时尤其重要:遮挡目标框到可见部分还是整体轮廓;被画面边缘截断的目标怎么处理;框要贴多紧(贴着目标轮廓外一两像素,而不是留出大片背景)。框的口径不统一,模型学到的就是一套混合标准,指标怎么调都上不去。

改了标注要删缓存:首次训练时会在数据集目录生成 labels.cache 缓存文件,之后修改标注并不会自动刷新——症状是明明改了标注、训练却毫无变化。删掉各标注目录下的 .cache 文件再训练。

data.yaml 是数据集的说明书:

path: /absolute/path/to/datasets/mydata   # 建议绝对路径,少一层解析歧义
train: images/train
val: images/val
nc: 2            # 类别数
names: ['helmet', 'head']   # 类别名,顺序与标注的 id 一一对应

划分数据集按 8:1:1 或 7:2:1,原则是同一场景的连拍不要跨训练集和验证集。划分本身是个十几行的脚本:收集全部图片路径,打乱,按比例切三份,把图片与同名标注复制到对应目录:

import random, shutil, pathlib
random.seed(0)
imgs = sorted(pathlib.Path('raw_images').glob('*.jpg'))
random.shuffle(imgs)
n = len(imgs)
splits = {'train': imgs[:int(n*0.8)],
          'val': imgs[int(n*0.8):int(n*0.9)],
          'test': imgs[int(n*0.9):]}
for name, files in splits.items():
    (pathlib.Path(f'datasets/mydata/images/{name}')).mkdir(parents=True, exist_ok=True)
    (pathlib.Path(f'datasets/mydata/labels/{name}')).mkdir(parents=True, exist_ok=True)
    for f in files:
        shutil.copy(f, f'datasets/mydata/images/{name}/{f.name}')
        shutil.copy(f.with_suffix('.txt'), f'datasets/mydata/labels/{name}/{f.stem}.txt')

负样本:图里没有目标的图片照常放进 images、在 labels 里放一个空 txt 文件,对压误检有直接帮助,不要省。

五、训练

先跑通管线。用内置的 coco8 把全流程在几分钟内走一遍,确认环境和命令没有问题:

yolo train model=yolov8n.pt data=coco8.yaml epochs=10 imgsz=640

数据集会自动下载。这条命令跑通之后,训练自己的数据只是换一个 data 参数。

选模型档位。n、s、m、l、x 五档结构相同、宽深不同:n 最快最省显存,x 精度最高、最慢最吃显存。经验是边缘设备从 n 起步,单卡 8 GB 显存 s 或 m,效果不够再往上调——先小后大,每次只动一档。

正式训练自己的数据:

yolo train model=yolov8n.pt data=/absolute/path/to/data.yaml epochs=150 imgsz=640 batch=16

关键参数逐个说:

参数 作用 建议
epochs 总轮数 100 到 300 起步,配合早停
batch 每批图片数 显存不够可设 -1(自动探测)
imgsz 输入尺寸 默认 640;小目标多就调大,代价是显存
device 用哪块卡 0;多卡写 0,1
workers 数据加载进程 Windows 报多进程错误时设 0
patience 早停耐心值 默认 100,验证指标多少轮不涨就停
close_mosaic 最后几轮关闭 Mosaic 增强 默认 10,让收尾见到真实分布
cache 数据缓存进内存 数据集不大且内存充足时开

训练产物在 runs/detect/train/(重复运行递增):

  • weights/best.pt:验证集上最优的一版,部署用它
  • weights/last.pt:最后一轮的权重,断点续训用它
  • results.png:损失与指标曲线
  • confusion_matrix.png、PR_curve.png、F1_curve.png、labels.jpg:评估图
  • args.yaml:本次训练的全部参数,复现实验就靠它

训练曲线的三个信号:验证损失已经平台化就该早停;验证损失掉头向上是过拟合;训练损失还在降而验证指标不动,说明增强过度或数据不足。

习惯写代码的话,CLI 的每个参数在 Python API 里一一对应:

from ultralytics import YOLO

model = YOLO('yolov8n.pt')
model.train(data='/absolute/path/to/data.yaml', epochs=150, imgsz=640, batch=16)

需要循环做多组实验时,API 比反复敲命令顺手。多卡训练把 device 写成 ‘0,1’,batch 会自动均分到各卡。

训练时终端每个 epoch 打一行:三个损失(框回归、分类、DFL)、本批目标数与验证指标。最初若干轮指标乱跳是正常的——模型正从 COCO 预训练状态向新类别迁移,看趋势不看单点。

显存不足的三招按顺序试:batch 降(16 → 8 → 4)、imgsz 降(640 → 512)、模型换 n 档。中断后续训:

yolo train resume model=runs/detect/train/weights/last.pt

训练时长的估法很朴素:先设 epochs=10 跑一次,用这 10 轮的耗时乘以目标轮数外推。数据量、imgsz、batch、硬件四个变量都在影响它,别人的数字没有参考价值,自己的外推才有。

六、验证与读结果

yolo val model=runs/detect/train/weights/best.pt

输出的末尾长这样:

 Class     Images  Instances      Box(P      R    mAP50  mAP50-95)
 all        128        929      0.867    0.804     0.888      0.642
 helmet     128        214      0.912    0.876     0.921      0.703
 head       128        715      0.831    0.742     0.859      0.592

两组数:mAP@0.5 与 mAP@[0.5:0.95],后者才是严格口径;还有一张按类别拆开的表——这张表往往比总分有用,哪一类低、是精度低还是召回低,一眼可见。

训练目录里的评估图各有用途:results.png 看损失与指标曲线(平台化早停、反弹过拟合);混淆矩阵看类别互混和 background 行列(误检与漏检的分布);F1 曲线的峰值横坐标是部署时置信度阈值的推荐值;PR 曲线看哪一类在高召回区塌得快。

错误归因按固定三类走:漏检(有目标没框出来)查场景覆盖与标注、误检(框了不存在的东西)查负样本与置信度阈值、定位不准(类别对但 IoU 不够)查小目标占比与输入尺寸。一次只改一件事,改完用同一份验证集重评。

一个自检信号值得单独说:验证指标高得离谱时,先检查数据划分——同一场景的图如果同时出现在训练集和验证集,指标会好看但毫无意义。

七、部署导出

导出 ONNX:

yolo export model=runs/detect/train/weights/best.pt format=onnx

得到 best.onnx 后,最省事的推理方式是继续用 ultralytics 的命令行(装上 onnxruntime 包即可),前后处理与后处理框架都已内置:

pip install onnxruntime
yolo predict model=best.onnx source='test.jpg'

需要集成到自己的程序里时,用 onnxruntime 的会话接口:输入是 letterbox 缩放并归一化后的 640×640 张量,输出需要自己做解码与 NMS——前后处理的坐标换算细节要照着官方 predict 流程实现,这是自研集成的主要工作量。

其他目标:NVIDIA GPU 上要极限性能时导出 TensorRT(format=engine,需本机安装 TensorRT);Jetson 一类边缘盒子同样走 TensorRT 路线;Intel CPU 用 OpenVINO。导出后务必用同一批验证图对比精度——量化(int8)有损失,fp16 几乎没有。

部署时的阈值不要沿用训练评估的默认值:按业务对漏检和误报的代价重新定。F1 曲线的峰值是个起点,业务偏防漏检就往下调、偏防误报就往上调。

部署形态按场景三选一:本地程序直接加载模型文件;服务端做成接口(模型常驻内存,注意并发与批处理);边缘设备走对应硬件的推理框架。共同的要点是:训练框架与部署环境分离后,每一次模型更新都要重跑一遍验证集,确认精度没有在转换中损失。

八、常见问题速查

类别 症状 原因与处理
环境 torch.cuda.is_available() 为 False 装成了 CPU 版 torch,按官网 CUDA 命令重装
环境 权重下载失败或极慢 到 GitHub releases 手动下载放到当前目录
环境 pip 安装超时 换国内镜像源
数据 某些类永远检不出 类别 id 未从 0 开始,或 names 顺序与 id 不符
数据 报错找不到标注文件 目录结构不合规:images 必须与 labels 对应
数据 中文路径报错 数据集路径避免中文,或统一用正斜杠
训练 显存溢出(CUDA out of memory) batch 降、imgsz 降、换 n 档
训练 Windows 多进程报错 workers=0
训练 训练很慢但没报错 torch 是 CPU 版;或 workers 设太小
训练 中断后想继续 yolo train resume model=…last.pt
评估 验证指标高得离谱 数据划分泄漏,按场景重新划分
评估 mAP@0.5 高而 @0.5:0.95 低 定位是短板,查小目标占比与输入尺寸
数据 改了标注训练没变化 labels.cache 缓存陈旧,删除数据集里的 .cache 文件
使用 摄像头输入没反应 source=0 传整数是设备号,字符串才是文件路径
训练 想多卡并行 device 写 ‘0,1’,batch 自动均分
部署 导出后精度下降 fp16 可忽略,int8 需重新验证
部署 onnxruntime 推理结果异常 前处理的 letterbox 与坐标还原没对齐

九、跑通之后

这套命令行对检测之外的任务完全同构:实例分割用 yolov8n-seg.pt 这类权重,姿态估计用 -pose,旋转框(OBB)用 -obb,分类用 -cls,data.yaml 与训练、验证、导出的流程一致。多目标跟踪用 yolo track。全部参数用 yolo help 或官方文档查。

流程走通只是起点,接下来真正拉开效果的是三件事:按第六节的错误分析持续修数据、按业务重新标定置信度阈值、以及建立线上数据的回流机制。检测模型的上限从来不是训练参数决定的,是数据决定的。

参考


文章作者: Halensea
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Halensea !
 本篇
YOLOv8 实战:环境、数据、训练与部署 YOLOv8 实战:环境、数据、训练与部署
从一个空环境开始:装依赖、跑通第一次推理、标注自己的数据、训练、读懂训练产物、导出部署——每一步给命令、预期输出和踩坑提示,全程不需要先懂检测原理
2026-10-24
下一篇 
YOLO 是怎么工作的:目标检测的原理与流程 YOLO 是怎么工作的:目标检测的原理与流程
目标检测要同时回答"有什么"和"在哪里",而且答案的数量不固定。YOLO 把这两个问题压成一次前向传播的回归,十年间从七乘七网格走到免 NMS 的端到端,变化的是手段,不变的是实时这个约束
2026-10-20
  目录