大家好,这里是 YOLO 理论与改进实战系列 第 6 篇。前 5 篇我们已经彻底讲透了 YOLO 的核心思想、进化史、网络结构、标签分配机制和损失函数 —— 从 “理论层面” 帮大家从 “会用 YOLO” 进阶到 “懂 YOLO”。今天,我们正式进入实战落地环节,也是大家最关心的内容:如何用 YOLOv8 从零开始训练自己的数据集,实现自定义目标检测(比如检测自己标注的猫、狗、车辆、工业缺陷等)。

这一篇,我会做到 **「极致详细、保姆级拆解」,全程手把手教学,每一个步骤都配具体操作、命令代码、参数说明、常见问题 **,甚至包含 “鼠标点击哪里、输入什么命令、遇到报错怎么解决”,无论你是新手还是有一定基础,都能跟着步骤完成训练。

重点覆盖:数据集准备(标注、划分、格式转换)、环境配置(从 0 搭建 PyTorch 环境)、训练全流程(配置文件修改、参数设置、训练监控)、常见坑排查(训练中断、损失不收敛、精度上不去、推理报错)、模型导出与部署(ONNX/TensorRT 快速推理),全程贴合 ultralytics YOLOv8 官方最新版本,避免出现 “命令失效、版本不兼容” 等问题。

同时,衔接上一篇的损失函数内容 —— 训练过程中会讲解如何结合损失函数调整权重,让模型精度达到最佳,做到 “理论 + 实战” 无缝衔接 。建议大家收藏本文,训练时直接对照操作,避开所有新手坑。


0. 前言:实战前必看(明确目标、准备工具)

在开始实战前,我们先明确 2 个核心前提,避免后续操作走弯路:

0.1 实战目标

本次实战将以 「自定义目标检测(猫、狗、汽车三类检测)」 为目标,从零完成:标注数据集 → 配置环境 → 训练模型 → 模型评估 → 推理测试 → 模型部署最终实现:输入一张图片,模型自动框选出猫 / 狗 / 汽车,输出坐标、类别和置信度

0.2 准备工具与环境要求

提前备好,避免训练中途缺工具、报兼容错:

  • 硬件:建议 NVIDIA 独显(显存≥6G),CPU 无强制要求,内存≥8G,硬盘≥10G;
  • 标注工具:LabelImg(最简单,新手首选);
  • 编程工具:PyCharm / VS Code;
  • 系统终端:Windows 用 CMD/PowerShell,Linux/Mac 用终端;
  • Python 版本:3.8~3.11(推荐 3.9,最稳定);
  • 框架:PyTorch 1.13~2.1 + ultralytics 8.0+。

1. 第一步:数据集准备(核心!决定模型上限)

数据集是训练的根基,数据质量 = 模型上限。流程:收集图片 → 标注 → 划分训练 / 验证 / 测试集 → VOC 转 YOLO 格式

1.1 收集图片(数量 + 质量标准)

  • 数量:每类目标至少 50 张,推荐 100~200 张 / 类,总数 300~600 张最佳;
  • 质量:清晰、目标完整、姿态多样、背景多样;
  • 格式:统一 .jpg / .png,不要用中文文件名;
  • 存放:新建文件夹 yolov8_custom_dataset → 里面建 images,所有图片放这里。

1.2 LabelImg 标注(零难度)

YOLOv8 用 YOLO 格式训练,LabelImg 默认输出 VOC(XML),后面我们代码一键转换。

  1. 安装(CMD 执行):
pip install labelImg -i https://pypi.tuna.tsinghua.edu.cn/simple
  1. 打开:CMD 输入 labelImg
  2. 关键设置:
    • File → Open Dir:选你的 images 文件夹
    • Change Save Dir:在 yolov8_custom_dataset 里新建 labels,选它
    • 勾选 View → Auto Save
  3. 开始标注:
    • 快捷键 W:画框
    • 输入英文类别catdogcar
    • D 下一张,A 上一张
  4. 标注要求:
    • 框要贴紧目标,不紧不松
    • 类别绝对不能标错
    • 不要漏标、多标

标注完:images 里是图片,labels 里是对应 XML 标注。


1.3 自动划分数据集(train:val:test = 7:2:1)

手动挪文件容易乱,直接用代码一键划分

yolov8_custom_dataset 下新建 split_dataset.py

import os
import shutil
import random

# 你的数据集根目录
dataset_root = "yolov8_custom_dataset"

train_ratio = 0.7
val_ratio = 0.2
test_ratio = 0.1

# 创建文件夹
folders = [
    f"{dataset_root}/images/train",
    f"{dataset_root}/images/val",
    f"{dataset_root}/images/test",
    f"{dataset_root}/labels/train",
    f"{dataset_root}/labels/val",
    f"{dataset_root}/labels/test"
]
for f in folders:
    os.makedirs(f, exist_ok=True)

# 读取图片
img_files = [f for f in os.listdir(f"{dataset_root}/images") if f.endswith(('.jpg','.png'))]
random.seed(42)
random.shuffle(img_files)

# 划分数量
total = len(img_files)
train_num = int(total*train_ratio)
val_num = int(total*val_ratio)
test_num = total - train_num - val_num

train_files = img_files[:train_num]
val_files = img_files[train_num:train_num+val_num]
test_files = img_files[train_num+val_num:]

def move_files(files, split):
    for f in files:
        # 移动图片
        shutil.copy(f"{dataset_root}/images/{f}", f"{dataset_root}/images/{split}/{f}")
        # 移动标注
        xml = f.replace(".jpg",".xml").replace(".png",".xml")
        if os.path.exists(f"{dataset_root}/labels/{xml}"):
            shutil.copy(f"{dataset_root}/labels/{xml}", f"{dataset_root}/labels/{split}/{xml}")

move_files(train_files, "train")
move_files(val_files, "val")
move_files(test_files, "test")

print(f"划分完成!总:{total} 训练:{train_num} 验证:{val_num} 测试:{test_num}")

运行后,自动生成 train/val/test 结构。


1.4 VOC (XML) → YOLO (TXT) 格式转换

YOLOv8 只认 TXT 格式(归一化坐标),XML 不能直接训练。

yolov8_custom_dataset 下新建 voc2yolo.py

import os
import xml.etree.ElementTree as ET

# ===================== 只改这里 =====================
classes = ["cat", "dog", "car"]  # 你的类别,顺序必须和标注一致
# ====================================================

dataset_root = "yolov8_custom_dataset"
splits = ["train","val","test"]

def convert(xml_path):
    tree = ET.parse(xml_path)
    root = tree.getroot()
    size = root.find("size")
    w = int(size.find("width").text)
    h = int(size.find("height").text)

    lines = []
    for obj in root.findall("object"):
        cls = obj.find("name").text
        if cls not in classes: continue
        cls_id = classes.index(cls)
        xmlbox = obj.find("bndbox")
        x1 = float(xmlbox.find("xmin").text)
        y1 = float(xmlbox.find("ymin").text)
        x2 = float(xmlbox.find("xmax").text)
        y2 = float(xmlbox.find("ymax").text)

        # YOLO 归一化
        cx = (x1 + x2) / 2 / w
        cy = (y1 + y2) / 2 / h
        bw = (x2 - x1) / w
        bh = (y2 - y1) / h
        lines.append(f"{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}\n")
    return lines

for split in splits:
    xml_dir = f"{dataset_root}/labels/{split}"
    for xml in os.listdir(xml_dir):
        if not xml.endswith(".xml"): continue
        lines = convert(f"{xml_dir}/{xml}")
        with open(f"{xml_dir}/{xml.replace('.xml','.txt')}", "w") as f:
            f.writelines(lines)

print("✅ VOC → YOLO 转换完成!")

运行后,labels/train/val/test 里全是 TXT 文件,数据集准备完成!


2. 第二步:环境配置(从 0 搭建,不报错版)

2.1 安装 Python 3.9

  • 官网下载:Python 3.9.13
  • 必须勾选 Add Python to PATH
  • 验证:CMD 输入 python --version

2.2 安装 CUDA(GPU 必须)

  • 查看支持版本:NVIDIA 控制面板 → 帮助 → 系统信息 → 组件
  • 推荐安装 CUDA 11.8(最兼容)
  • 验证:nvcc -V

2.3 安装 PyTorch

GPU(CUDA 11.8):

pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

CPU:

pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu

验证:

import torch
print(torch.cuda.is_available())  # True=成功

2.4 安装 ultralytics(YOLOv8 官方库)

pip install ultralytics opencv-python pillow -i https://pypi.tuna.tsinghua.edu.cn/simple

验证:yolo version


3. 第三步:YOLOv8 训练(全程复制命令)

3.1 新建模型配置

在项目里新建 config 文件夹 → 新建 yolov8_custom.yaml

yaml

nc: 3          # 类别数量
names: ["cat","dog","car"]  # 类别名称
depth_multiple: 0.33
width_multiple: 0.25
anchors:
  - [10,13, 16,30, 33,23]
  - [30,61, 62,45, 59,119]
  - [116,90, 156,198, 373,326]

3.2 新建数据集配置 data.yaml

yolov8_custom_dataset 里新建:

yaml

train: yolov8_custom_dataset/images/train
val: yolov8_custom_dataset/images/val
test: yolov8_custom_dataset/images/test

nc: 3
names: ["cat","dog","car"]

3.3 启动训练(复制即用)

yolo train model=config/yolov8_custom.yaml data=yolov8_custom_dataset/data.yaml epochs=100 batch=8 imgsz=640 device=0 pretrained=True

参数说明

  • epochs=100:训练轮数,小数据集 50~100 足够
  • batch=8:显存小就改 4/2
  • imgsz=640:输入尺寸
  • device=0:用第一张 GPU
  • pretrained=True:迁移学习,必须开,精度暴涨

3.4 训练正常标志

  • 损失 loss 持续下降
  • mAP@0.5 逐步上升
  • 模型保存在 runs/detect/train/weights/best.pt

4. 第四步:模型评估 + 推理测试

4.1 模型评估(看精度)

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

看指标:

  • mAP@0.5 ≥ 0.7 合格
  • ≥ 0.8 优秀

4.2 推理测试(看实际效果)

测试文件夹:

yolo predict model=best.pt source=yolov8_custom_dataset/images/test save=True

测试单张图片:

yolo predict model=best.pt source=test.jpg save=True

结果保存在 runs/detect/predict


5. 第五步:模型导出与部署(落地可用)

5.1 导出 ONNX(通用部署格式)

yolo export model=best.pt format=onnx imgsz=640

5.2 ONNX 推理代码(可直接部署)

import onnxruntime as ort
import cv2
import numpy as np

model_path = "best.onnx"
img_path = "test.jpg"
classes = ["cat","dog","car"]
imgsz = 640
conf_thres = 0.5

session = ort.InferenceSession(model_path)
input_name = session.get_inputs()[0].name
output_name = session.get_outputs()[0].name

img = cv2.imread(img_path)
h, w = img.shape[:2]
scale = min(imgsz/w, imgsz/h)
new_w, new_h = int(w*scale), int(h*scale)
resized = cv2.resize(img, (new_w, new_h))
padded = np.zeros((imgsz, imgsz, 3), dtype=np.uint8)
padded[:new_h, :new_w] = resized

input = padded.transpose(2,0,1)/255.0
input = input[None].astype(np.float32)

pred = session.run([output_name], {input_name:input})[0]

for box in pred[0]:
    conf = box[4]
    if conf < conf_thres: continue
    cx, cy, bw, bh = box[0], box[1], box[2], box[3]
    x1 = int((cx - bw/2)*imgsz/scale)
    y1 = int((cy - bh/2)*imgsz/scale)
    x2 = int((cx + bw/2)*imgsz/scale)
    y2 = int((cy + bh/2)*imgsz/scale)
    cls = np.argmax(box[5:])
    cv2.rectangle(img, (x1,y1), (x2,y2), (0,255,0), 2)
    cv2.putText(img, f"{classes[cls]} {conf:.2f}", (x1,y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 2)

cv2.imwrite("result.jpg", img)
cv2.imshow("out", img)
cv2.waitKey(0)

6. 新手高频坑排查(完整版)

坑 1:找不到 data.yaml

  • 原因:路径错 / 没创建
  • 解决:用绝对路径,不要中文路径

坑 2:CUDA out of memory 显存爆炸

  • 解决顺序:
    1. batch=8 → 4 → 2
    2. imgsz=640 → 480 → 320
    3. yolov8n 最轻量模型
    4. 关闭占用 GPU 的软件

坑 3:loss 不下降,模型不收敛

  • 标注错误 / 图片太糊 / 类别写错
  • 没开 pretrained=True
  • 解决:清洗数据集 + 开启预训练

坑 4:推理漏检、误检超多

  1. 数据集场景太单一 → 补充不同背景、角度、光照
  2. 目标太小 → 调高分辨率 imgsz=640
  3. 置信度太高 → 推理加 conf=0.25
  4. 数据量太少 → 每类至少补到 100 张
  5. 训练轮数不够 → epochs 改 100~150
  6. 标注不精准 → 重新检查框和类别
  7. 开启数据增强:训练命令加 augment=True

坑 5:类别全错

  • 原因:classes 顺序和标注不一致
  • 解决:voc2yolo.pyyaml 三处类别完全一致

坑 6:训练中断,如何继续训练

yolo train model=runs/detect/train/weights/last.pt data=data.yaml epochs=100 resume=True

坑 7:TXT 文件为空

  • 图片里没目标,直接删除空 TXT 即可

坑 8:mAP 突然掉到 0

  • 标注混乱 / 数据集路径变动
  • 解决:重新检查划分与格式

坑 9:GPU 不调用,一直用 CPU

  • PyTorch 没装 GPU 版本
  • 重装对应 CUDA 版本的 torch

坑 10:预测框漂移、不准

  • 标注框不贴合目标
  • 图片分辨率太低
  • 解决:精准标注 + 高分辨率训练

7. 训练精度提升最终方案(直接照做)

  1. 每类目标 ≥ 100 张
  2. 标注精准、无错标、无漏标
  3. 开启 pretrained=True
  4. 训练轮数 100
  5. 开启增强 augment=True
  6. 分辨率 640
  7. 清洗脏数据(模糊、重复、过小)
  8. best.pt 推理

按这套流程,自定义数据集 mAP@0.5 稳定 0.7~0.9


总结

这篇是全网最完整的 YOLOv8 自定义数据集训练保姆级教程,从图片收集→标注→划分→格式转换→环境→训练→推理→部署→排错全覆盖。你只需要替换类别和图片,就能训练出自己的目标检测模型。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐