4. YOLOv8 训练自己的数据集:数据标注格式、数据集划分、YAML 配置与参数调优

好,到了真正动手的环节了。前面我们聊了 YOLOv8 的架构和安装,但说实话,那些都是开胃菜。真正让模型为你工作的,是这一步——训练你自己的数据集。

我刚开始带项目的时候,总觉得训练模型是最高大上的部分。后来被现实狠狠教育了一顿——数据准备占了整个项目 70% 的时间。你想想看,模型再牛,喂进去的数据是垃圾,吐出来的只能是更精致的垃圾。所以这一章,咱们把数据标注、划分、配置、调参这几个硬骨头啃下来。

核心要点:一个高质量的数据集 + 合理的配置文件 = 训练成功的一半。另一半?嗯,是耐心。

4.1 数据标注格式:LabelImg vs Roboflow

YOLOv8 默认使用 YOLO 格式的标注文件。每个图片对应一个同名的 .txt 文件,内容长这样:

0 0.5 0.5 0.3 0.4
1 0.2 0.8 0.1 0.15

每行代表一个目标:类别索引 中心点x 中心点y 宽度 高度。注意,坐标都是归一化到 [0,1] 的。为什么要归一化?说白了,不管你的图片是 1920x1080 还是 640x480,模型看到的坐标范围都一样,训练更稳定。

那怎么生成这种标注文件?两个主流工具:LabelImg 和 Roboflow。

对比项 LabelImg Roboflow
运行方式 本地安装,Python 或 exe 在线网页,无需安装
标注格式 支持 YOLO、VOC、COCO 等 支持 30+ 格式导出
团队协作 单机,手动合并 云端多人协作
数据增强 无 内置旋转、翻转、马赛克等
适用场景 小规模、本地数据 中大规模、需要预处理

我个人习惯:如果数据量在几百张以内,用 LabelImg 就够了,简单直接。如果超过 1000 张,或者需要做数据增强,我会用 Roboflow。它那个在线标注界面确实比 LabelImg 顺手,而且导出 YOLO 格式一键搞定。

小技巧:LabelImg 默认保存的类别名是数字索引。记得在标注前先建一个 classes.txt,按顺序写好类别名,比如 person、car、dog。这样导出的标注文件索引才不会乱。

4.2 数据集划分:训练集、验证集、测试集

数据标完了,接下来要分家。YOLOv8 训练时默认需要两个目录:train 和 val。测试集不是必须的,但我建议你留一份,用来做最终评估。

常见的划分比例:

  • 训练集:70% - 80%
  • 验证集:10% - 15%
  • 测试集:10% - 15%

目录结构长这样:

dataset/
├── images/
│   ├── train/
│   ├── val/
│   └── test/
└── labels/
    ├── train/
    ├── val/
    └── test/

注意:图片和标注文件要一一对应,文件名必须相同(后缀不同)。

我写了一个简单的 Python 脚本来做划分,分享给你:

import os
import random
import shutil

def split_dataset(data_dir, train_ratio=0.8, val_ratio=0.1):
    images = [f for f in os.listdir(os.path.join(data_dir, 'images')) if f.endswith(('.jpg', '.png'))]
    random.shuffle(images)
    
    n = len(images)
    train_end = int(n * train_ratio)
    val_end = int(n * (train_ratio + val_ratio))
    
    splits = {
        'train': images[:train_end],
        'val': images[train_end:val_end],
        'test': images[val_end:]
    }
    
    for split_name, file_list in splits.items():
        os.makedirs(f'{data_dir}/images/{split_name}', exist_ok=True)
        os.makedirs(f'{data_dir}/labels/{split_name}', exist_ok=True)
        for f in file_list:
            shutil.move(f'{data_dir}/images/{f}', f'{data_dir}/images/{split_name}/{f}')
            label_file = f.replace('.jpg', '.txt').replace('.png', '.txt')
            if os.path.exists(f'{data_dir}/labels/{label_file}'):
                shutil.move(f'{data_dir}/labels/{label_file}', f'{data_dir}/labels/{split_name}/{label_file}')

split_dataset('dataset/')

避坑指南:我曾经犯过一个低级错误——划分前没有打乱数据。结果训练集全是白天的图片,验证集全是晚上的。模型在训练集上表现很好,一到验证集就崩。所以,一定要先随机打乱,再划分。

4.3 YAML 配置文件编写

YOLOv8 用 YAML 文件告诉模型:你的数据在哪、有哪些类别。这是训练前必须写好的文件。

一个标准的 dataset.yaml 长这样:

# 数据集路径
path: ./dataset  # 数据集根目录
train: images/train  # 训练集图片路径(相对 path)
val: images/val      # 验证集图片路径
test: images/test    # 测试集图片路径(可选)

# 类别信息
nc: 3  # 类别数量
names: ['person', 'car', 'dog']  # 类别名称列表

几个容易踩的坑:

  • path 建议用路径或相对于 YAML 文件的路径。我习惯把 YAML 文件放在数据集根目录下,这样 train 和 val 直接写相对路径就行。
  • nc 必须和 names 列表长度一致。多一个少一个都会报错。
  • 类别名称的顺序要和标注文件里的索引对应。比如 person 是 0,car 是 1,dog 是 2。

我的习惯:每次写完 YAML 文件,我都会用 yaml.safe_load() 验证一下格式。Python 的缩进问题在 YAML 里同样致命——一个空格错位,模型就找不到数据了。

4.4 训练参数调优

数据准备好了,YAML 写好了,终于可以开始训练了。但别急着跑,先看看几个关键参数。

YOLOv8 的训练命令:

yolo train model=yolov8n.pt data=dataset.yaml epochs=100 imgsz=640 batch=16

参数说明:

参数 默认值 说明 调优建议
model yolov8n.pt 预训练模型权重 小数据集用 nano,大数据集用 large
epochs 100 训练轮数 先跑 50 轮看 loss 曲线,再决定是否增加
imgsz 640 输入图片尺寸 显存不够就降到 416 或 320
batch 16 批次大小 显存允许的情况下尽量大,但别超过 64
lr0 0.01 初始学习率 如果 loss 震荡,降到 0.001
patience 50 早停耐心值 小数据集设 20,防止过拟合

我个人经验:刚开始调参时,别一上来就追求极致。先用默认参数跑一轮,看看 loss 曲线和 mAP 的变化。如果 loss 下降很慢,再考虑调学习率;如果 mAP 在验证集上停滞不前,可能是数据量不够或者标注质量有问题。

调参口诀:先跑通,再调优。loss 震荡降 lr,mAP 不涨查数据。

还有一个参数我特别想提——patience。这个参数控制早停机制:如果验证集上的 mAP 连续 patience 轮没有提升,训练就自动停止。我建议设成 20-30,既能节省时间,又不会错过最佳模型。

4.5 本章知识体系

下面这张图帮你理清整个流程:

YOLOv8 训练自己的数据集 - 完整流程 数据标注 数据集划分 YAML配置 训练调参 关键提醒: • 标注质量 > 标注数量:100张高质量标注远胜1000张粗标 • 先跑通再调优:第一次训练用默认参数,观察loss曲线 • 早停机制:patience设20-30,避免无效训练

从数据标注开始,到划分、配置、调参,每一步都环环相扣。别想着跳过任何一步——我见过太多人因为标注格式不对,训练到一半才发现,白白浪费十几个小时。