yolo_v8 从如坑到入土(一)

20次阅读
没有评论

共计 5199 个字符,预计需要花费 13 分钟才能阅读完成。

目录

  1. 先定义“好标签”:标注规范与口径
  2. 工具三选一:Label Studio / CVAT / Roboflow
  3. 目录结构与命名约定
  4. 标注 → 导出为 YOLO(检测 / 分割 / 关键点)
  5. data.yaml 编写模板(多数据集 / 多任务)
  6. 数据集 体检脚本(合法性 / 分布 / 可视化)
  7. 划分 train/val/test(分层与去泄漏)
  8. 数据增强策略(上线友好 vs 竞赛风格)
  9. 最小训练 / 验证一把过
  10. 常见坑与排错清单
  11. 课后练习(含参考答案要点)

1) 先定义“好标签”:标注规范与口径

检测(Bounding Box)

  • 紧致贴合:矩形尽量贴合可见区域,不要留大边。
  • 遮挡 / 截断:只框可见部分;>50% 可见仍标注;完全遮挡不标。
  • 重叠实例:分开各自标注,不合并。
  • 旋转物体:仍用轴对齐框(YOLO 检测头假定 axis-aligned)。
  • 模糊 / 远小目标:若最短边 < 4 像素,建议不标(训练难、噪声大)。

分割(Instance Segmentation)

  • 多边形 勾勒外轮廓;孔洞按工具规范(内环)处理;
  • 重叠实例分别标,避免“粘连”。

关键点(Pose/Keypoints)

  • 定义关键点顺序与可见性规则(如:不可见记 0/1),务必写成 README。

类目清单(示例)

0 person
1 bicycle
2 car
3 dog

一旦开工,类目名称与顺序不可随意改动。改动 = 全量重映射(见 §10)。


2) 工具三选一:Label Studio / CVAT / Roboflow

三者都能导出 YOLO 格式,取悦即可:

  • Label Studio:易上手,开源;装插件可导 YOLO。适合小团队。
  • CVAT:专业、多人协作强,支持检测 / 分割 / 关键点;导出 YOLO 系列格式。
  • Roboflow:托管式,导出 / 转换方便;免费配额适合入门练习。

通用流程

  1. 创建项目 → 录入 类目清单 并给每类配色;
  2. 导入图片(注意版权与尺寸多样性);
  3. 配置协作:任务划分、质检人(QA)与抽检比例(≥ 10%);
  4. 标注快捷键训练(框 = 拖拽;分割 = 笔刷 / 多边形;复制 =Ctrl+D 等);
  5. 质检:对齐“边界策略”“遮挡策略”;
  6. 导出:选择 YOLO(检测 / 分割 / 关键点)格式包。

3) 目录结构与命名约定

YOLOv8 推荐:

my-dataset/
  images/
    train/  xxx.jpg
    val/    xxx.jpg
    test/   xxx.jpg  # 可选
  labels/
    train/  xxx.txt
    val/    xxx.txt
    test/   xxx.txt  # 可选
  • 标签文件与图片 同名,内容为 YOLO 行(详见下节)。
  • 建议文件名只用 [a-z0-9_-],避免空格与中文路径。

4) 标注 → 导出为 YOLO

4.1 YOLO 检测标签(*.txt)

每行一个框:

<class_id> <x_center> <y_center> <width> <height>
  • 坐标都是 相对比例(0~1),相对图像宽高;
  • 例:2 0.512 0.433 0.210 0.180 表示类 2 的框。

4.2 YOLO 分割标签

  • 与检测类似,但在该行后追加 归一化多边形点序列x1 y1 x2 y2 ...
  • 一个实例可含多个轮廓,工具会生成多行(按导出器规范)。

4.3 YOLO 关键点(pose)

  • 行内含 num_keypoints(x, y, v)v 是可见性标志;
  • 你需要在 data.yaml 中提供 kpt_shape: [num_kpts, dim]flip_idx(见官方示例)。

4.4 从工具导出到目录

  • CVATExport → YOLO 1.x/YOLOv5-7/YOLOv8,选 train/val 分包或一次性导出后自己拆分。
  • Label Studio:安装 YOLO 导出插件(或先导 COCO 再转换脚本)。
  • RoboflowExport → YOLOv8 直接得到标准结构包。

5) data.yaml 模板

最小示例(检测 / 分割通用):

# data.yaml
path: /abs/path/to/my-dataset  # 或相对路径
train: images/train
val: images/val
# test: images/test
nc: 4
names: [person, bicycle, car, dog]

关键点任务需补:

kpt_shape: [17, 3]    # 关键点数量与维度
flip_idx: [0,2,1,4,3,...]  # 左右翻转映射(示例,按你的定义填写)

多数据源(合并多个子集):

train:
  - /data/ds1/images/train
  - /data/ds2/images/train
val:
  - /data/ds1/images/val
  - /data/ds2/images/val

6) 数据集 体检脚本(强烈建议)

用 Python 快速扫一遍标签合法性与分布。

# check_yolo_dataset.py
import os, glob, math
from collections import Counter, defaultdict

def read_sizes(txt_path):
    bad, classes = [], Counter()
    for p in glob.glob(os.path.join(txt_path, '**', '*.txt'), recursive=True):
        with open(p, 'r', encoding='utf-8') as f:
            for ln, line in enumerate(f, 1):
                arr = line.strip().split()
                if len(arr) < 5: bad.append((p, ln, 'len<5')); continue
                try:
                    cid = int(arr[0]); vals = list(map(float, arr[1:5]))
                except: bad.append((p, ln, 'parse')); continue
                x,y,w,h = vals
                if not (0<=x<=1 and 0<=y<=1 and 0<w<=1 and 0<h<=1):
                    bad.append((p, ln, 'range'))
                if w*h < 1e-5: bad.append((p, ln, 'tiny'))
                classes[cid]+=1
    return bad, classes

for split in ['train','val','test']:
    lbl = f'my-dataset/labels/{split}'
    if os.path.isdir(lbl):
        bad, cls = read_sizes(lbl)
        print(f'[{split}] classes:', dict(cls))
        if bad:
            print(f'[{split}] BAD {len(bad)} lines (path, line, why):')
            for b in bad[:20]: print(' ', b)
            print('...')

看三件事:① 非法坐标 / 极小框;② 类别分布是否 长尾过度 ;③ 是否存在 大量空标签(没对象也不是错,但要有意识)。


7) 划分 train/val/test(分层与去泄漏)

  • 分层 :按 类目出现 做近似分层(防止某类只落在 train);
  • 去泄漏
    • 同一视频 /Burst 连拍 → 只放一个 split;
    • 同一 ID 的同场景重复图 → 去重或固定到 train;
    • 生成式增强出的图片 不要 混入验证集。

快速划分脚本(按文件名哈希 80/10/10)

import os, shutil, hashlib, glob
SRC='images_all'  # 原始图像目录
DST='my-dataset'
for sp in ['train','val','test']:
    os.makedirs(f'{DST}/images/{sp}', exist_ok=True)
    os.makedirs(f'{DST}/labels/{sp}', exist_ok=True)

def bucket(p):
    h=int(hashlib.md5(p.encode()).hexdigest(),16)%100
    return 'train' if h<80 else ('val' if h<90 else 'test')

for img in glob.glob(f'{SRC}/**/*.jpg', recursive=True):
    sp=bucket(os.path.basename(img))
    base=os.path.splitext(os.path.basename(img))[0]
    lbl=img.replace('/images_all/','/labels_all/').replace('.jpg','.txt')
    shutil.copy2(img, f'{DST}/images/{sp}/{base}.jpg')
    if os.path.exists(lbl):
        shutil.copy2(lbl, f'{DST}/labels/{sp}/{base}.txt')

更严格的“按视频 /ID 分桶”可在文件名或清单里编码,再按桶分配。


8) 数据增强策略

上线友好型(稳健泛化)

  • 颜色扰动(HSV/ 亮度对比度)、水平翻转、轻微缩放与裁剪;
  • 关闭极端 mosaic/mixup(可能引入不自然分布)。

竞赛 / 极限型(追分)

  • 开启 mosaic/mixup、大尺度多尺度训练;
  • 结合强随机裁剪与旋转(注意不要剪掉太多目标)。

命令示例(参数以你本地 ultralytics 版本为准)

yolo train model=yolov8n.pt data=data.yaml epochs=100 imgsz=640 \
  hsv_h=0.015 hsv_s=0.7 hsv_v=0.4 fliplr=0.5 degrees=0.0 translate=0.1 scale=0.5 shear=0.0 \
  mosaic=0.0 mixup=0.0  # 上线友好:先关掉

注意不同版本默认增强略有差异,建议显式写出关键增强参数,确保可复现。


9) 最小训练 / 验证一把过

# 1) 训练
yolo train model=yolov8n.pt data=data.yaml epochs=50 imgsz=640 batch=auto
# 2) 验证(可单独跑,也会在训练结束自动评估)yolo val model=runs/detect/train*/weights/best.pt data=data.yaml
# 3) 推理查看效果
yolo predict model=runs/detect/train*/weights/best.pt source=images/val --save

关注指标:mAP50mAP50-95Precision/Recall 与推理速度。类目极不均衡时观察 每类 mAP


10) 常见坑与排错清单

  • 类目错位 names 顺序变了 → 训练 / 预测类别全乱。办法:统一 names,如需改动,用脚本 重映射 class_id 后再训。
  • 坐标越界 / 空行:导出后跑 §6 的体检脚本;有问题回工具修或用脚本过滤。
  • 图片有,标签无:表示“负样本”(OK);但要控制比例,避免网络学到“背景即一切”。
  • 过小框:面积极小的框会扰乱训练;考虑阈值过滤(如 w*h<1e-4)。
  • 分割多边形自交:某些导出会产生自交 polygon,训练时报错;回到工具里修形或简化点数。
  • 路径 / 编码:Windows 反斜杠与中文路径可能导致脚本失效;路径用相对 / 英文。

11) 课后练习(建议 60–90 分钟)

练习 A(两类玩具集)

  1. 任选 120 张图片,定义两类(如 apple, banana),各 ≥ 50 个框;
  2. 标注并导出 YOLO;
  3. 用体检脚本列出类分布与小框比例;
  4. epochs=50 训练,报告 mAP50 与每类 AP

练习 B(数据增强对比)

  • 同一数据,跑两组:mosaic=0.0mosaic=0.5 mixup=0.2,比较 mAP 与错检 / 漏检案例。

练习 C(重映射与合并)

  • [car, van, bus] 合并为 vehicle,写脚本把旧标签重映射后重训;
  • 加入一批“全背景图”,观察 Precision/Recall 变化。

参考答案要点:A) 类别均衡度、标注一致性对 mAP 的影响;B) 强增强可能提升 Recall 但也会增加假阳性;C) 合并类能提升样本规模,前提是语义一致。


附录:类别重映射脚本(示例)

# remap_classes.py
import os, glob
mapping = {0:0, 1:0, 2:0}  # car/van/bus -> vehicle(0)
for p in glob.glob('my-dataset/labels/**/*/*.txt', recursive=True):
    lines=[]
    with open(p,'r') as f:
        for line in f:
            arr=line.strip().split()
            if not arr: continue
            cid=int(arr[0])
            if cid in mapping:
                arr[0]=str(mapping[cid])
                lines.append(' '.join(arr))
    with open(p,'w') as f: f.write('\n'.join(lines)+'\n')

小结

数据是模型的镜子。先把 口径 规范 写清楚,再让工具替你稳稳地执行。体检脚本是你最好的“班主任”——天天查、每次训前查。

正文完
 0
一诺
版权声明:本站原创文章,由 一诺 于2025-09-08发表,共计5199字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码