yolo笔记2:从标注到 YOLOv8 训练

简介

当你完成了 Label Studio 的标注工作,点击“导出”时,你会发现导出的文件结构并不能直接用于 YOLOv8 训练。
YOLO 模型对数据集有严格的要求:训练/验证集必须物理隔离,且必须包含 data.yaml 配置文件。

手动整理几千张图片不仅耗时,还容易出错(比如把猫的标签对应到了狗的图上)。本文将提供一个 Python 脚本,一键解决数据清洗、划分和配置生成的问题。


第一步:从 Label Studio 导出

  1. 进入项目,点击右上角 Export
  2. 格式选择 YOLO
  3. 下载并解压 ZIP 包。

解压后的目录结构(假设文件夹名为 ls_export):

ls_export/
├── classes.txt       # 类别表
├── notes.json
├── images/           # 图片(如果是本地挂载模式,这里可能为空)
└── labels/           # 标注文件
🔴 关键检查:图片都在吗?
如果你使用了 Docker 挂载本地存储(Local Storage),导出的压缩包里可能只有 labels 而没有图片。
解决方法:请将你原始的图片复制到这个 ls_export/images 文件夹中。确保文件名与 labels 里的 txt 文件名一一对应。

第二步:自动化清洗与划分(核心步骤)

为了替代繁琐的手工移动文件,我编写了一个脚本。它会帮你做三件事:

  1. 按 8:2 比例随机划分训练集和验证集。
  2. 自动补全负样本:如果某张图没有标注(背景图),自动生成空的 txt 文件(YOLO 训练必需,否则会报错)。
  3. 自动生成 data.yaml:读取 classes.txt 并生成配置。

1. 创建脚本文件

ls_export 同级目录下,新建文件 split_data.py,粘贴以下代码:

import os
import shutil
import random
import yaml
import argparse
from pathlib import Path

# 支持的图片格式
IMG_FORMATS = {'.bmp', '.jpg', '.jpeg', '.png', '.tif', '.dng', '.webp'}

def split_dataset(source_dir, output_dir, train_ratio=0.8):
    source_path = Path(source_dir)
    output_path = Path(output_dir)
    
    # 检查源文件
    src_images = source_path / 'images'
    src_labels = source_path / 'labels'
    classes_file = source_path / 'classes.txt'
    
    if not src_images.exists():
        print(f"❌ 错误: 找不到 images 文件夹: {src_images}")
        return

    # 创建目标目录
    for split in ['train', 'val']:
        (output_path / 'images' / split).mkdir(parents=True, exist_ok=True)
        (output_path / 'labels' / split).mkdir(parents=True, exist_ok=True)

    # 获取图片列表
    images = [f for f in src_images.iterdir() if f.suffix.lower() in IMG_FORMATS]
    random.shuffle(images)
    
    # 计算划分数量
    num_train = int(len(images) * train_ratio)
    split_map = {'train': images[:num_train], 'val': images[num_train:]}

    print(f"📊 数据集总数: {len(images)} | 训练集: {len(split_map['train'])} | 验证集: {len(split_map['val'])}")

    # 开始处理
    for split, imgs in split_map.items():
        print(f"🚀 处理 {split} 数据中...")
        for img in imgs:
            # 1. 复制/移动图片
            shutil.copy(str(img), str(output_path / 'images' / split / img.name))
            
            # 2. 处理标签
            label_name = img.stem + '.txt'
            src_label = src_labels / label_name
            dst_label = output_path / 'labels' / split / label_name
            
            if src_label.exists():
                shutil.copy(str(src_label), str(dst_label))
            else:
                # 关键:创建空标签文件(处理负样本)
                with open(dst_label, 'w') as f: pass

    # 生成 data.yaml
    names = {i: n.strip() for i, n in enumerate(open(classes_file).readlines())} if classes_file.exists() else {0: "unknown"}
    
    yaml_data = {
        'path': str(output_path.absolute()), # 绝对路径,防止报错
        'train': 'images/train',
        'val': 'images/val',
        'nc': len(names),
        'names': names
    }
    
    with open(output_path / 'data.yaml', 'w') as f:
        yaml.dump(yaml_data, f, sort_keys=False)
    
    print(f"✅ 处理完成!配置文件路径: {output_path / 'data.yaml'}")

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--source', type=str, required=True, help='Label Studio 导出目录')
    parser.add_argument('--output', type=str, required=True, help='输出的 YOLO 数据集目录')
    parser.add_argument('--ratio', type=float, default=0.8, help='训练集比例')
    args = parser.parse_args()
    split_dataset(args.source, args.output, args.ratio)

2. 运行脚本

打开终端,运行:

# 用法: python split_data.py --source <源目录> --output <新目录>
python split_data.py --source ./ls_export --output ./yolo_dataset

运行结束后,你会在 yolo_dataset 文件夹下看到完美的 YOLO 格式结构,且包含生成的 data.yaml


第三步:开始训练 (YOLOv8)

数据准备好了,现在开始训练。我们将使用 Ultralytics 官方库。

1. 安装环境

pip install ultralytics

2. 启动训练

脚本已经帮你生成了绝对路径的配置文件,所以你只需要一行命令:

yolo detect train \
    data=./yolo_dataset/data.yaml \
    model=yolov8n.pt \
    epochs=100 \
    imgsz=640 \
    batch=16

参数解释:

  • model: yolov8n.pt (Nano) 速度最快,适合 CPU 或入门显卡;yolov8m.pt 精度更高。
  • epochs: 训练轮数。100 轮通常能看到不错的效果。
  • imgsz: 输入图片大小,必须是 32 的倍数,常用 640。

常见问题与排查

Q1: 训练报错 file not foundno labels found

  • 检查 data.yaml 内容。脚本默认生成的是绝对路径 (path: /User/xxx/yolo_dataset),这是最稳妥的方式。如果你移动了数据集文件夹,需要手动修改 yaml 里的路径。

Q2: 为什么我的准确率 (mAP) 是 0?

  • 检查 Label Studio 的导出。YOLO 格式的 txt 内容必须是归一化的(0-1之间)。
  • 打开一个 txt 文件,如果看到类似 0 0.5 0.5 0.2 0.3 的数据是正常的;如果看到 0 500 300 100 200(像素值),说明导出格式选错了(选成了 CSV 或其他)。

Q3: 多边形标注 (Polygon) 怎么办?

  • 上述流程仅适用于目标检测 (Detect)。如果你在 Label Studio 画的是多边形,想做实例分割 (Segment),YOLOv8 需要的格式不同。
  • 你需要将 Label Studio 导出为 JSON 格式,然后编写转换脚本将 JSON 转为 YOLO Segmentation TXT 格式。

总结

通过引入自动化脚本,我们消除了从 Label Studio 到 YOLO 之间的人工操作壁垒。现在,你只需要专注于最核心的工作——高质量的标注,剩下的数据清洗和训练配置,交给代码自动完成即可。