先把丑话说在前面:YOLOv8这套流程,真正花时间的从来不是环境配置,而是数据准备和排查那些莫名其妙的报错。我自己第一次跑通,环境大概用了半小时,数据集前前后后折腾了两天。这篇就是把这条路重新走一遍,你会踩到的坑我尽量先替你踩一遍,你照着做就行。文章适合完全没配过深度学习环境的新手,也适合已经跑过YOLOv5、想快速切到YOLOv8的老手,内容覆盖从conda创建虚拟环境、安装PyTorch和ultralytics、准备并标注自己的数据集、写data.yaml、执行训练、看日志和结果,到导出模型的完整链路。我会把每个环节"为什么这么做"也讲清楚,毕竟环境配置这类事,只知道命令不知道怎么改,换个电脑照样抓瞎。
1. 动手前先盘清楚:环境依赖与版本匹配逻辑
1.1 conda、CUDA、PyTorch到底是什么关系
先别急着敲命令。很多人环境装到一半就崩,根本原因不是操作问题,而是没搞明白这几样东西是干什么的、谁依赖谁。
你的电脑里有一个硬件叫GPU,GPU干活需要一个"翻译官"叫显卡驱动,NVIDIA的显卡驱动装好之后,系统才能认到这张卡。但深度学习框架PyTorch不能直接和驱动对话,中间还隔着一个CUDA工具包。CUDA可以理解成GPU的"指令手册",PyTorch照着CUDA给的接口去调用GPU算力。cuDNN则是CUDA之上的深度神经网络加速库,跑卷积的时候尤其重要,纯CUDA能做但速度慢,cuDNN就是专门为神经网络优化的那部分。
所以这条链是:驱动→CUDA→cuDNN→PyTorch→ultralytics(YOLOv8封装库)。每一层都要兼容,但注意,不是CUDA版本越高越好,真正卡脖子的是PyTorch官方编译时支持哪个CUDA版本。比如PyTorch 2.x的官方安装命令会明确写cu118、cu121这种后缀,意思是这个版本的PyTorch是基于CUDA 11.8或12.1编译的。
你自己的显卡驱动只需满足一个条件:驱动版本不低于目标CUDA版本要求的最低驱动。NVIDIA驱动是向后兼容的,老驱动能跑新版CUDA的情况很少见,但新版驱动一定能跑老版本CUDA。所以最简单的策略是先把显卡驱动升到最新,CUDA工具包反而不一定非装不可——你用pip装PyTorch的时候,它会自动把配套的CUDA运行库一并拉下来,不需要系统里单独装一套CUDA。
1.2 用conda隔离环境,避免把本机Python搞乱
这一步是我最想让你认真对待的。很多人的Python环境最后变成一团乱麻,就是因为所有的包都直接怼进系统Python,今天装一个TensorFlow,明天装一个PyTorch,后年想跑YOLOv8发现版本冲突,又不敢乱删。
conda就是用来解决这个问题的。你可以把conda创建的虚拟环境理解成一个个独立的小房间,每个房间里有一套完整的Python解释器和各自的第三方库,互相看不见、互不干扰。YOLOv8要装PyTorch,PyTorch要求某个版本的numpy,而另一个项目要用老版本numpy,如果都在系统Python里,就会打架;分到两个虚拟环境里,各自安好。
建议安装Miniconda而不是完整版Anaconda,Miniconda体积小,按需安装包,更干净。装的时候注意勾选"Add to PATH"选项,或者装完手动把conda的Scripts目录加到环境变量里,不然命令行找不到conda命令。Windows上如果之前装过Python,可能还会遇到conda和系统Python抢占命令行的情况,解决办法就是在conda里激活环境后,确认当前用的是虚拟环境里的Python,而不是系统那个。
1.3 本机硬件到底够不够跑YOLOv8
这个话题最好放前面说。YOLOv8的目标检测训练,GPU最好要有,但也不是没GPU就不能跑。CPU训练完全可行,只是速度会让你怀疑人生。我自己在一颗8核CPU上跑过几十张图片的小数据集,一个epoch也就几十秒,但如果是几百上千张图的正常数据集,一个epoch可能要几分钟甚至更久,一个完整训练跑下来半天就没了。
像GTX 1660 Ti这种6GB显存的入门卡,跑YOLOv8n或者YOLOv8s完全够用,batch size调到16左右都不会爆显存。显存小就选小模型、调低batch size、调小输入尺寸。显存不够不是死路,后面我会专门讲OOM(Out of Memory)的调整策略。
建议训练前先用nvidia-smi看一眼驱动和显存。如果显示NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver,说明驱动没装好,先解决驱动问题再继续。
2. 完整安装流程:从建环境到跑起第一行YOLO命令
2.1 创建conda虚拟环境并安装PyTorch
打开终端(Windows建议用Anaconda Prompt,macOS/Linux直接用终端),依次执行:
conda create -n yolov8 python=3.9 -y conda activate yolov8Python版本选3.9是我个人比较稳的选择。YOLOv8官方要求Python >= 3.8,但3.10以上某些依赖容易出小毛病,3.9兼容性最好,PyTorch和各种依赖都能找到对应的编译包。
激活环境之后,安装PyTorch。在这之前先确认自己的显卡支持哪个CUDA版本,再看PyTorch官方提供的安装命令。到PyTorch官网的Get Started页面,选择你的操作系统、包管理器选pip、CUDA版本,它会直接生成安装命令。我以CUDA 11.8为例:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118电脑没有NVIDIA显卡或者准备用CPU跑,就装CPU版:
pip install torch torchvision torchaudio注意CPU版和GPU版的PyTorch体积都不小,下载时间取决于网络。如果下载速度极慢,可以用国内镜像源,比如清华源或阿里云源,但PyTorch官方源里的cu118版本在镜像源里不一定同步,遇到问题就老老实实等官方源下载完,别反复中断,容易把包下坏。
装完验证是不是GPU版,在Python里执行:
import torch print(torch.__version__) print(torch.cuda.is_available())torch.cuda.is_available()输出True才算真的能用GPU,输出False说明装的还是CPU版,或者驱动和CUDA版本不匹配,回头检查驱动。
2.2 安装ultralytics包并验证环境
PyTorch装好之后,YOLOv8本体就简单了:
pip install ultralytics这个包会一次性把YOLOv8训练、验证、导出需要的wheel依赖拉齐,包括opencv-python、matplotlib、pandas、pyyaml这些。
装完先跑一次推理验证全链路,把YOLOv8官方提供的最轻量权重yolov8n.pt下下来,随便拿一张图片测一下:
yolo predict model=yolov8n.pt source='https://ultralytics.com/images/bus.jpg'第一次跑这个命令,它会自动下载权重和测试图片,之后就在后台生成了检测结果。如果这一步能跑通,说明环境配置已经完成,可以进入数据集阶段了。
这里有个常见坑:yolo命令在终端里找不到。这通常是conda环境的Scripts目录没进PATH。Windows下检查一下conda环境里的python.exe和yolo.exe路径,手动把C:\Users\你的用户名\miniconda3\envs\yolov8\Scripts加进环境变量,或者干脆每次都用python -m ultralytics来调用命令,效果一样。
2.3 训练脚本能跑的最小验证
环境装好、推理通了,但还没完。我最推荐再做一步"最小化训练验证",直接用官方自带的coco8.yaml这个迷你数据集跑一个epoch:
yolo detect train data=coco8.yaml model=yolov8n.pt epochs=1 imgsz=640这一步的意义不是训练模型,而是验证你机器上所有跟训练相关的组件(数据加载、损失计算、日志记录、权重保存)都是通的。如果这个都能跑通,说明环境没有问题,后面数据集出问题就集中排查数据集。
3. 准备自己的数据集:标注、整理、划分一步都不能错
3.1 数据采集和文件命名规范
环境只是工具,数据集才是你项目的灵魂。很多初学者上来就蒐集一百张图开始标,训练完效果很差,然后怀疑模型有问题。其实90%的情况是数据有问题。
采集图片的时候注意三点:
- 数量:每个类别起步建议200张以上,如果类别多、背景复杂,500张起。当然不是绝对,但你要明白,YOLOv8的预训练权重是在COCO数据集上训的,它见过的场景非常多,你要检测的目标如果和COCO里的常见物体类似(车、人、猫狗),训练数据可以少一些,因为迁移学习帮你打了个好底子。如果目标很特殊,比如工厂里的瑕疵、农田里的病虫害,那就必须多采集,让模型学会你的数据分布。
- 多样性:同一个目标,要在不同光线、不同角度、不同距离、不同遮挡程度下各拍一些。模型学的是特征的分布,而不是记忆某几张图。宁可500张各种角度都有,都不要2000张千篇一律的正脸特写。
- 清晰度:分辨率太低的图,经过resize到640×640之后信息损失很大。如果原始图只有320×240,训练时再缩放到640,其实就是把模糊的像素做插值,特征不会变清晰。
图片的命名和路径一定要全英文,不要带空格,更不要带中文。Ultralytics的源码里依赖yaml读取路径,Windows上的中文路径有时候会触发编码问题,报错内容还不直观,排查起来特别浪费时间。我自己就吃过这个亏:数据集放在D:\数据集\图片下,训练到一半报FileNotFoundError,改成D:\datasets\images之后马上就好了。
3.2 标注工具选型与YOLO格式说明
准备数据集的第二步是标注。这里要先说清楚YOLOv8用的是哪种标注格式,因为这直接决定你选什么工具、导出什么格式。
YOLO格式的标注文件是txt,每一行对应图片里的一个目标,格式是:
class_id x_center y_center width height注意这五个数字的含义:
class_id是从0开始的类别编号,比如你有"猫"和"狗"两个类别,那"猫"是0,"狗"是1。x_centery_center是目标框中心点的坐标,widthheight是目标框的宽和高。- 这四个数值都是归一化的,即除以图片的宽度和高度,范围是0到1。
举个例子,一张1280×720的图片里有一只猫,猫框左上角在(320, 180),右下角在(960, 540)。那么中心点是(640, 360),宽是640,高是360,归一化后就是:
0 0.5 0.5 0.5 0.5所以同一个图片文件名对应两个文件:图片是cat_001.jpg,标注是cat_001.txt。两者必须在同名目录下,只是后缀不同。
标注工具有几个选择:
- LabelImg:老牌工具,支持PascalVOC和YOLO格式导出,界面简单,Windows上需要配置PyQt5环境,国内教程多。
- X-AnyLabeling:较新的工具,支持自动标注,可以加载YOLOv8模型辅助标注,效率高。
- Label Studio:功能强大,支持团队协作,适合大型项目。
- Roboflow:在线标注平台,内置很多标注增强工具,免费版有图片数量限制。
我个人推荐新手用X-AnyLabeling,因为它的YOLO格式导出流程最顺,界面也更现代化,自带模型推理自动标注,虽然自动标注的框要人工检查修正,但能省一半时间。LabelImg虽然经典,但它的文件存储格式有时会让你多一步转换。
不管用哪个工具,标注完成后一定抽查几份txt,对照图片看看坐标有没有明显越界、类别ID有没有写错。这一项体检只需要五分钟,但能省下训练完才发现模型学了一堆错误标注的几小时。
3.3 数据集目录结构和data.yaml怎么写
标注完,把图片和标注文件整理成Ultralytics标准目录结构。虽然支持各种自定义结构,但最省事的是这样:
datasets/ └── my_dataset/ ├── images/ │ ├── train/ │ │ ├── cat_001.jpg │ │ ├── cat_002.jpg │ │ └── ... │ └── val/ │ ├── cat_101.jpg │ └── ... └── labels/ ├── train/ │ ├── cat_001.txt │ └── ... └── val/ ├── cat_101.txt └── ...注意images和labels目录名不能改,这是Ultralytics默认约定。train和val子目录里,图片和对应的txt文件要严格一一对应。
然后在datasets/my_dataset/下创建一个data.yaml文件,内容如下:
train: D:/datasets/my_dataset/images/train val: D:/datasets/my_dataset/images/val nc: 2 names: ['cat', 'dog']train和val字段指向图片目录,而不是标注目录,Ultralytics会根据图片目录自动找对应的labels目录。nc是类别总数,names是类别名称列表,顺序必须和标注文件里的class_id一致。很多人在这一步把names顺序写反,训练的时候Loss降得很漂亮,但推理出来类别全是乱的,排查到吐血。
路径这里,Windows上强烈建议用正斜杠/,不要用反斜杠\。YAML解析的时候反斜杠是转义符,容易出问题,这是新手最容易踩的坑。
3.4 数据集划分:用脚本而不是手动拖文件
数据集划分看起来简单,但手动一个一个拖文件不仅累,还容易出现图片和标注文件不同步的情况。我建议写个小脚本一次性搞定:
import os import random import shutil random.seed(42) data_dir = "D:/datasets/raw" images = [f for f in os.listdir(data_dir) if f.endswith((".jpg", ".jpeg", ".png"))] print(f"共找到 {len(images)} 张图片") random.shuffle(images) val_count = int(len(images) * 0.2) val_images = images[:val_count] train_images = images[val_count:] os.makedirs("D:/datasets/my_dataset/images/train", exist_ok=True) os.makedirs("D:/datasets/my_dataset/images/val", exist_ok=True) os.makedirs("D:/datasets/my_dataset/labels/train", exist_ok=True) os.makedirs("D:/datasets/my_dataset/labels/val", exist_ok=True) def move_files(file_list, split_name): for img in file_list: basename = os.path.splitext(img)[0] txt_name = basename + ".txt" if not os.path.exists(os.path.join(data_dir, txt_name)): print(f"警告: {img} 缺少对应的标注文件 {txt_name}") continue shutil.move(os.path.join(data_dir, img), f"D:/datasets/my_dataset/images/{split_name}/{img}") shutil.move(os.path.join(data_dir, txt_name), f"D:/datasets/my_dataset/labels/{split_name}/{txt_name}") move_files(train_images, "train") move_files(val_images, "val") print("划分完成!")这个脚本的random.seed(42)很重要,固定随机种子之后,每次运行得到的划分结果都一样,方便复现。val比例取20%是经验值,数据集大可以适当降低到10%,数据集小可以提高到30%,但20%是比较平衡的起始点。
脚本里对缺失标注文件的检查是我后来加的。有一次我漏标了几张图,训练时Ultralytics报Image ... has no labels的警告,虽然不会崩,但会造成训练集图片和标签对不上,影响训练效果。
4. 训练配置的核心参数逐项解读
4.1 模型选型:n/s/m/l/x怎么选
YOLOv8按网络深度和宽度分为5个规格:yolov8n、yolov8s、yolov8m、yolov8l、yolov8x,从n到x模型越来越大、精度越高、速度越慢。很多人一上来就直接选最大的,理由是精度最高,但接着就发现显存不够、训练速度巨慢,最后放弃。
我的经验是:如果项目没有明确的速度要求,先用n跑通流程,再用s或者m做正式训练。n虽然精度最低,但训练速度快、显存占用小,非常适合验证你的数据集和代码有没有问题。等跑通之后,再用更深的模型提高上限。
官方模型权重文件名后有预训练标记,比如yolov8n.pt是已经在COCO数据集上预训练过的权重,yolov8n.yaml是纯网络结构定义。用yolov8n.pt来训练是迁移学习,模型初始化时继承了COCO上学习到的通用特征,收敛快、效果好。除非你的数据分布和自然图像差异极大,否则推荐用预训练权重做起点。
4.2 训练命令和关键参数说明
训练命令的标准格式:
yolo detect train data=data.yaml model=yolov8n.pt epochs=100 imgsz=640 batch=16 device=0逐项解读:
data=data.yaml:刚写好的数据集配置文件。model=yolov8n.pt:起始权重。epochs=100:训练轮数。新手可以先训50轮看Loss趋势,有下降空间再加大。100轮是起步,效果不够就200轮。imgsz=640:训练时输入图片的尺寸。YOLOv8默认640,如果你的目标较小,可以试试800或960,但显存占用会指数级上升。小目标检测的明显改善经常来自imgsz的提升,这点比换更大模型更有效。batch=16:每批图片数量。这是最影响显存占用的参数。显存6GB用16,8GB用32,我没法给死数值,最好用nvidia-smi边跑边看显存占用。device=0:指定GPU编号。多卡机器可以写成device=0,1,CPU训练写device=cpu。
这些参数不是设一次就完事的,需要根据训练过程动态调整。我的习惯是先跑20轮,观察Loss下降曲线和显存占用,再决定是加大batch还是加大imgsz。
4.3 不常被提到但很影响结果的高级参数
除了上面那些基础参数,还有几个官方默认值之外值得关注的点:
patience:早停轮数,默认50。就是验证集指标连续50轮不提升就停止训练。数据集小的时候建议改成20或30,不然白白浪费时间。cache:设为True可以把图片提前缓存在内存里,省去每轮都从磁盘读图的时间。数据集几百张图时见效明显,但会占用内存。workers:数据加载线程数,默认8。Windows上如果报DataLoader worker相关的错,把它降成2或者0。optimizer:默认是auto,自动选SGD或AdamW。新手不用改,但要知道这个参数存在。lr0:初始学习率,默认0.01。如果你的数据集很小,Loss发散的几率高,可以试着调低到0.001,代价是收敛速度变慢。cos_lr:学习率是否按余弦曲线衰减,默认False。对最后的收敛精度有帮助,但会延长训练时间。augment相关参数:YOLOv8默认开启了很多数据增强,比如随机翻转、色调抖动、缩放平移。数据量少的时候增强能帮你减少过拟合,但增强太强也可能让模型学不到稳定的特征。官方默认参数是经过大量实验调优的,新手不要轻易改。
我见过太多人拿到参数就狂调,实际上YOLOv8的默认参数已经在一个很大的超参数空间里往死里优化过了。你改了不一定更好,反而可能因为某个参数不匹配导致训练崩溃。默认参数跑通,再针对性调整一到两个参数,这是最稳的路径。
4.4 训练时如何监控资源
训练启动之后,至少前几分钟要多盯一眼资源情况。在另一个终端窗口运行:
nvidia-smi -l 1-l 1是每秒刷新一次。主要看三列:显存占用(Memory Usage)、GPU利用率(GPU-Util)和温度。
如果显存占用接近上限,大概率会在某个batch直接OOM。这时候不用慌,按优先级调整:先降batch,比如从32降到16再降到8;batch降完还不行就降imgsz,从640降到512;再不行就换成更小的模型,从s换到n。如果GPU利用率一直很低,比如低于50%,说明数据加载成了瓶颈,可能是workers太少,也可能是数据集放在机械硬盘上读图太慢,把图片放到SSD上会有明显改观。
5. 训练日志、损失曲线与评估指标怎么看
5.1 训练日志字段解读
训练启动后,终端会不断刷新类似这样的输出:
Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size 1/100 2.31G 1.158 1.595 1.172 5 640box_loss是边界框回归损失,衡量预测框和真实框的差距;cls_loss是分类损失,衡量类别预测的对错;dfl_loss是分布焦点损失,是YOLOv8新增的损失项,用于让框的回归更精确。这三个值总体趋势应该随着训练下降(会有波动),但如果出现某一项先降后升、而且Validation那边的对应指标明显恶化,就要警惕过拟合了。
这里最直观的指标其实是后面Validation的表格,包含Precision(精确率)、Recall(召回率)、mAP50、mAP50-95。
5.2 用results.csv画损失函数曲线图
训练结束后,Ultralytics会把所有指标记录在runs/detect/train/exp/results.csv里(也可能是train2、train3,每次训练递增)。这个CSV是最有价值的文件,因为它记录了每一个epoch的完整训练数据。画损失曲线就用它:
import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("runs/detect/train/exp/results.csv") df.columns = [col.strip() for col in df.columns] plt.figure(figsize=(12, 8)) plt.subplot(2, 2, 1) plt.plot(df["epoch"], df["train/box_loss"], label="train box loss") plt.plot(df["epoch"], df["val/box_loss"], label="val box loss") plt.legend() plt.title("Box Loss") plt.subplot(2, 2, 2) plt.plot(df["epoch"], df["train/cls_loss"], label="train cls loss") plt.plot(df["epoch"], df["val/cls_loss"], label="val cls loss") plt.legend() plt.title("Cls Loss") plt.subplot(2, 2, 3) plt.plot(df["epoch"], df["metrics/mAP50"], label="mAP50") plt.plot(df["epoch"], df["metrics/mAP50-95"], label="mAP50-95") plt.legend() plt.title("mAP") plt.subplot(2, 2, 4) plt.plot(df["epoch"], df["metrics/precision"], label="precision") plt.plot(df["epoch"], df["metrics/recall"], label="recall") plt.legend() plt.title("Precision & Recall") plt.tight_layout() plt.savefig("training_curves.png", dpi=300)这个代码会生成一张四宫格图:Loss曲线、mAP曲线、精确率召回率曲线。保存下来的PNG直接放进论文或者项目报告里完全够用。每次训练完都跑一遍这个脚本,比对不同实验的曲线,比记一堆数字直观多了。
5.3 一套判断训练状态的方法
画完曲线,怎么判断模型好不好?我有一套自己的判断逻辑:
首先看mAP50-95,它是综合指标,比mAP50更严格。mAP50指的是IoU阈值0.5时的平均精度,mAP50-95是0.5到0.95每隔0.05取一个阈值,共10个阈值下的平均。同样一张图,mAP50容易虚高,mAP50-95才是模型真实力的体现。如果你的目标是做工程落地,mAP50-95至少要0.5以上才算能用的模型。
其次看train loss和val loss的差距。训练结束时如果train loss很低、val loss还很高,说明过拟合。解决办法不是盲目加数据,而是先加早停(如果还没触发)、换轻量模型、增强数据增强、加dropout。反过来如果两个loss都停留在高位不降,说明模型欠拟合,考虑加大模型、增加训练轮数、调低学习率。
最后看precision和recall的平衡。精确率表示"模型说它是猫的结果里真的有多少是猫",召回率表示"所有猫里模型找回来了多少"。如果你的业务更关心漏检(比如质检,瑕疵不能漏),就偏向recall;更关心误检(比如安防,不想总报警),就偏向precision。在训练阶段调整conf_thres推理阈值可以在这个平衡上做微调,阈值设高一点,精确率上升、召回率下降;阈值设低一点,召回率上升、精确率下降。
6. 踩坑实录:训练中最常见的报错与排查链路
6.1 OOM显存不足:每个人的第一课
OOM几乎是每个人都逃不掉的坎。报错长得像这样:
torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to allocate 2.00 GiB (GPU 0; 6.00 GiB total capacity; 5.12 GiB already allocated; ...)这时候千万别第一反应去换显卡。正确的排查顺序是:
- 降batch,比如从16降到8,再降到4。这是最直接有效的方法。
- 降imgsz,从640降到512,显存占用会按面积比例下降,大概降到原来的64%。
- 换更小的模型,yolov8s换yolov8n,参数量差将近3倍。
- 检查是不是有别的进程占用显存。
nvidia-smi看一下,经常有人在后台跑着其他程序忘了关,GPU显存被占了一半。如果确实有僵尸进程,可以用taskkill /PID 进程号 /F(Windows)或kill -9 进程号(Linux)结束掉。
还有一个可能被我忽略的坑:多进程DataLoader会向GPU拷贝数据,如果workers太多也可能触发显存溢出,虽然概率不高,但排查到最后依然OOM的话,把workers从8降到2试试。
6.2 Windows下DataLoader worker报错
Windows用户大概率会遇到这样一个错:
An attempt has been made to start a new process before the current process has finished its bootstrapping phase.这个报错原因是Windows下多进程数据加载的启动方式和Linux不同,非常"经典"。网上有人说把workers=0,确实简单粗暴能解决,但每个epoch的数据加载会变慢很多。
更好的解决方案是在你的训练脚本入口处加一行:
if __name__ == "__main__": main()不过yolo命令是Ultralytics封装好的,你没法直接加。所以实际做法是:在项目里写一个Python脚本,内容如下:
from ultralytics import YOLO def main(): model = YOLO("yolov8n.pt") model.train(data="data.yaml", epochs=100, imgsz=640, batch=16, device=0) if __name__ == "__main__": main()用python train.py运行,这种写法在Windows上才能真正稳定使用多worker加载。如果你直接在命令行执行yolo detect train ...遇到workers报错,要么降workers,要么就改用脚本方式。
6.3 训练中断之后怎么办
训练过程不是总会一帆风顺。笔记本合盖休眠、断电、手动Ctrl+C中断都有可能。这时候如果从头再训,前面几十个epoch就白跑了。
Ultralytics的resume机制很简单:
yolo detect train resume model=runs/detect/train/exp/weights/last.pt它会读取last.pt里的epoch信息和optimizer状态,从断点继续训练。要注意一点:如果用的是命令行方式,把原来的命令参数复制过来,然后后面加resume=True,否则可能因为参数不一致导致问题。
我的习惯是:训练超过50个epoch之后,每隔一段时间就备份一次last.pt,尤其是数据集很大的时候。有一次我在第120个epoch中断了,靠resume从断点接着跑完,省了将近两个小时,这个习惯很值得养成。
6.4 训练结果很好但推理很差,先怀疑这三件事
训练时mAP很高,但拿自己的测试图去预测,效果却惨不忍睹。这是最伤士气的情况,但几乎每一个项目都会遇到。我的排查顺序是:
第一,检查标注的类别ID是否和names顺序一致。这是最容易出问题的,尤其类别多的时候。标注文件里class_id是0,但data.yaml里names第一个不是你要检测的那个类,模型学到的语义就完全乱了。
第二,检查推理图片和训练图片的分布差异。训练数据是白天的场景,推理的时候拿夜间的图,效果差是必然的。这种情况下不是模型有问题,是你的数据集分布覆盖不到位,补充同分布的数据才是正解。
第三,检查预处理差异。YOLOv8推理的时候会自动对输入图片做letterbox和归一化,正常情况下不需要你手动预处理。但如果你自己写了数据预处理管线,比如先resize再推理,或者做了灰度转换,模型看到的数据分布就和训练时不一样,结果当然会崩。最简单的验证方法:直接用Ultralytics的预测代码,不做任何预处理再试试。
6.5 中文路径和特殊字符路径的坑
这个坑我用亲身经历证明它值得单独说一次。数据集放在中文路径下,比如D:\项目\数据集\,训练时可能报各种奇怪的错,比如找不到文件、读取图片失败、或者yaml解析错误。YAML规范和Windows文件系统对非ASCII字符的支持都不太完整,两个问题叠加起来,报错信息还往往不是直接指向路径问题,排查成本极高。
方案就一个字:改。把数据集根目录改成纯英文路径,图片文件名也改成纯英文,任何项目都适用这条规则。这个建议朴素,但能帮你躲开一堆不可名状的报错。
7. 训练收官:模型评估、导出与部署前的最后一步
7.1 用验证集跑一次完整评估
训练完成后,Ultralytics会在runs/detect/train/exp/下生成两个权重文件:best.pt和last.pt。best.pt是根据验证集指标选出的最优权重,last.pt是最后一个epoch结束时的权重。常规操作是用best.pt。
跑评估命令:
yolo detect val model=runs/detect/train/exp/weights/best.pt data=data.yaml它会输出完整的指标报告,包括每个类别的precision、recall、mAP。这里我想提醒你:单看mAP不够,要看类别维度的表现。比如两个类别,一个mAP95%,一个mAP40%,平均下来可能还不错,但实际应用中低分的那类模型根本不能用。遇到这种情况,优先补充该类别的训练数据,而不是急着调模型参数。
7.2 模型导出:ONNX还是TensorRT
训练只完成了任务的一半,真正落地还要把PyTorch模型导出成部署格式。YOLOv8的导出命令特别简单:
yolo export model=runs/detect/train/exp/weights/best.pt format=onnxONNX是跨平台的标准格式,几乎所以推理框架都支持,导出之后可以用onnxruntime或者OpenVINO运行,CPU上的推理速度也会有所提升。如果目标平台是NVIDIA的GPU,可以进一步导出TensorRT引擎:
yolo export model=best.pt format=engine device=0TensorRT会在导出时针对你的具体显卡做算子融合和显存优化,推理速度比PyTorch原生快很多。但注意TensorRT引擎和显卡绑定,换一张显卡就要重新导出一次。
如果是RK3588这类边缘设备,流程一般是先导出ONNX,再在RKNN工具链中转成RKNN格式。这类边缘设备跑YOLOv8已经比较成熟了,但每一步都有各自的坑,导出时走官方工具链给的版本组合最稳。
7.3 推理测试时的两个实用套路
拿训练好的模型去测单张图片:
yolo predict model=runs/detect/train/exp/weights/best.pt source=test.jpg conf=0.25conf=0.25是置信度阈值,低于这个值的结果会被过滤掉。这个值的设定直接关联前面说的precision和recall平衡。正式部署前,建议在验证集上跑不同conf值画一条置信度曲线,选择一个对自己业务最合理的平衡点,而不是凭感觉拍一个数字。
写到最后,还是想分享一个我个人的体会。很多人看YOLOv8的教程,关注的总是"训练"这两个字的瞬间,但真正做下来你会发现,环境配置和训练代码只是一块敲门砖,数据集质量和排错能力才是决定你项目成败的关键。我自己现在做一个检测项目,标注和检查数据的时间占比往往超过60%,训练反而只占一小部分。这种时间分配在初看时觉得不合理,但做多了就明白,模型的上限从你准备好数据那一刻就已经确定了。至于环境配置,一次配好之后很少再动它,真正花时间是和那些莫名报错斗智斗勇的过程。这篇写下来的每个坑,都是我花真金白银的时间换来的,你照着避开了,就比当初的我已经快了一步。后续如果再遇到新问题,记住先看日志、再查版本、然后验证数据,这三板斧解决90%的问题。祝你的模型早日收敛。