YOLO v11的学习记录(八) 使用自定义数据从头训练一个目标检测的模型

1、准备数据

我已经有了标注好的数据文件,当然也可以用标注工具生成数据,比如下文中的方法:https://blog.csdn.net/xulibo5828/article/details/154707998

  • 我的原始数据目录结构:
python 复制代码
datasets
├── images/
│   ├── class1/
│   │   ├──cls1-00001.jpg
│   │   ├──cls1-00002.jpg
│   │   ├──。。。
│   │   ├──cls1-00nnn.jpg
│   ├── class2/
│   │   ├──cls2-00001.jpg
│   │   ├──cls2-00002.jpg
│   │   ├──。。。
│   │   ├──cls2-00nnn.jpg
│   │ 。。。
│   ├── classn/
│       ├──clsn-00001.jpg
│       ├──clsn-00002.jpg
│       ├──。。。
│       ├──clsn-00nnn.jpg
├── labels/
│   ├── class1/
│   │   ├──cls1-00001.txt
│   │   ├──cls1-00002.txt
│   │   ├──。。。
│   │   ├──cls1-00nnn.txt
│   ├── class2/
│   │   ├──cls2-00001.txt
│   │   ├──cls2-00002.txt
│   │   ├──。。。
│   │   ├──cls2-00nnn.txt
│   │ 。。。
│   ├── classn/
│       ├──clsn-00001.txt
│       ├──clsn-00002.txt
│       ├──。。。
│       ├──clsn-00nnn.txt
├── classes.txt
   

images和labels目录下分别保存有图片和标签,按照不同的分类存放在class1------classn目录下,classes.txt是所有分类的名称明细。


  • 标注文件的格式

YOLO对目标检测的标注文件格式要求如下:

https://blog.csdn.net/xulibo5828/article/details/145657008

python 复制代码
class x_center y_center width height

其中 class 是目标的类别索引(从 0 开始),x_center、y_center 是边界框中心点相对于图像宽度和高度的归一化坐标,width 和 height 是边界框宽度和高度相对于图像宽度和高度的归一化值。

我的原始数据中所有txt文件都是按照这个格式要求标注的。


  • 用于YOLO训练的目录结构

预期的YOLO项目下训练文件的目录结构是这样的:

python 复制代码
datasets
├── images/
│   ├── train/
│   ├── var/
│   ├── test/
├── labels/
│   ├── train/
│   ├── valr/
│   ├── test/
├── dataset.yaml

imags目录下保存图片,按照用途的不同又分为train(训练集)、var(验证集)和test(测试集),labels目录下保存与images目录下图片文件的同名txt文件,dataset.yaml是训练配置文件。

运行脚本,将原始数据划分数据集,并自动生成dataset.yaml文件:

python 复制代码
import os
import shutil
import random
from pathlib import Path

# 配置参数
RAW_DATA_DIR = "dataset/generated_dataset"  # 原始数据根目录
TARGET_DATA_DIR = "datasets_yolo"  # 转换后数据根目录
TRAIN_RATIO = 0.7  # 训练集比例
VAL_RATIO = 0.2  # 验证集比例
TEST_RATIO = 0.1  # 测试集比例


def create_dirs():
    """创建目标目录结构"""
    dirs = [
        f"{TARGET_DATA_DIR}/images/train",
        f"{TARGET_DATA_DIR}/images/val",
        f"{TARGET_DATA_DIR}/images/test",
        f"{TARGET_DATA_DIR}/labels/train",
        f"{TARGET_DATA_DIR}/labels/val",
        f"{TARGET_DATA_DIR}/labels/test"
    ]
    for dir in dirs:
        Path(dir).mkdir(parents=True, exist_ok=True)


def load_classes():
    """从classes.txt加载类别信息"""
    classes_path = os.path.join(RAW_DATA_DIR, "classes.txt")
    with open(classes_path, "r", encoding="utf-8") as f:
        classes = [line.strip() for line in f if line.strip()]
    return classes


def split_data_per_class(class_name):
    """按类别划分数据"""
    # 获取该类别的所有图片文件
    img_dir = os.path.join(RAW_DATA_DIR, "images", class_name)
    img_files = [f for f in os.listdir(img_dir) if f.endswith(('.jpg', '.jpeg', '.png'))]
    random.shuffle(img_files)

    # 划分数据
    total = len(img_files)
    train_split = int(total * TRAIN_RATIO)
    val_split = int(total * (TRAIN_RATIO + VAL_RATIO))

    train_files = img_files[:train_split]
    val_files = img_files[train_split:val_split]
    test_files = img_files[val_split:]

    return train_files, val_files, test_files


def copy_files(class_name, file_list, subset):
    """复制图片和标签文件到目标目录"""
    for img_file in file_list:
        # 复制图片
        src_img = os.path.join(RAW_DATA_DIR, "images", class_name, img_file)
        dst_img = os.path.join(TARGET_DATA_DIR, "images", subset, img_file)
        shutil.copy2(src_img, dst_img)

        # 复制标签
        label_file = os.path.splitext(img_file)[0] + ".txt"
        src_label = os.path.join(RAW_DATA_DIR, "labels", class_name, label_file)
        dst_label = os.path.join(TARGET_DATA_DIR, "labels", subset, label_file)
        if os.path.exists(src_label):
            shutil.copy2(src_label, dst_label)


def generate_dataset_yaml(classes):
    """生成dataset.yaml文件"""
    yaml_content = f"""# YOLOv11 Dataset Configuration
path: {os.path.abspath(TARGET_DATA_DIR)}  # 数据集根目录
train: images/train  # 训练集图片路径
val: images/val      # 验证集图片路径
test: images/test    # 测试集图片路径

# 类别信息
nc: {len(classes)}  # 类别数量
names: {classes}    # 类别名称列表
"""
    yaml_path = os.path.join(TARGET_DATA_DIR, "dataset.yaml")
    with open(yaml_path, "w", encoding="utf-8") as f:
        f.write(yaml_content)


def main():
    # 初始化
    random.seed(42)  # 设置随机种子确保结果可复现
    create_dirs()
    classes = load_classes()

    # 处理每个类别
    for class_name in classes:
        print(f"Processing class: {class_name}")
        train_files, val_files, test_files = split_data_per_class(class_name)

        # 复制文件
        copy_files(class_name, train_files, "train")
        copy_files(class_name, val_files, "val")
        copy_files(class_name, test_files, "test")

    # 生成配置文件
    generate_dataset_yaml(classes)
    print(f"数据转换完成!目标目录:{TARGET_DATA_DIR}")


if __name__ == "__main__":
    main()

2、训练

打开conda prompt,cd到datasets_yolo的上级目录下,激活创建好的YOLO虚拟环境,输入已下指令试运行:

python 复制代码
yolo task=detect \
    mode=train \
    model=yolo11n.yaml \
    data="datasets_yolo/dataset.yaml" \
    epochs=10 \
    imgsz=640 \
    batch=16 \
    device=0,1 \
    workers=2 \

命令解释:

task=detect:任务类型,实例分割 segment,目标检测 detect、分类 classify、姿态估计 pose

mode=train:模式,训练 train、推理 predict、验证 val、导出 export

model=yolo11n.yaml:使用的基础模型是 YOLOv11版本(yolo11n),但是不用它的预训练权重(从头训练),如果使用预训练权重,将该段指令改为:model=yolo11n.pt

model=yolo11n.pt:使用的基础模型是 YOLOv11 的(yolo11n)的预训练分割模型

data=dataset.yaml:指定数据集配置文件,包含训练集 / 验证集路径、类别信息等

epochs=10:训练总轮次为 10 轮(先小批次试运行)

imgsz=640:输入图像的尺寸统一调整为 640x640 像素

batch=16:每批处理 16 张图像

device=0,1:指定使用第 0 号 和第 1 号 GPU 进行训练(若为 cpu 则使用 CPU)

workers=2:使用2个并行进程训练,提高效率

第一次训练,会自动下载模型数据,需要连接科学网。当小批次运行成功后,修改和优化训练参数,进行正式训练。

相关推荐
篮球只打两年半1 小时前
普罗米修斯监控系统学习实践报告
学习
Rock_yzh1 小时前
LeetCode算法刷题——54. 螺旋矩阵
数据结构·c++·学习·算法·leetcode·职场和发展·矩阵
莫道桑榆晚丶1 小时前
Linux系统编程--------MP3项目实战
linux·学习
yoyo君~1 小时前
本地仓库推送到github
学习·github·无人机
crary,记忆1 小时前
React 之 useEffect
前端·javascript·学习·react.js
张较瘦_2 小时前
Spring Boot | 学习Spring Boot 3要有哪些Java基础?
java·spring boot·学习
懷淰メ2 小时前
【AI加持】基于PyQt5+YOLOv8+DeepSeek的结核杆菌检测系统(详细介绍)
yolo·目标检测·计算机视觉·pyqt·deepseek·ai分析·结核杆菌
阿宁又菜又爱玩2 小时前
Mybatis学习
java·学习·mybatis
走在路上的菜鸟2 小时前
Android学Dart学习笔记第十一节 错误处理
android·笔记·学习·flutter