YOLOv8及其改进(二) 本文(4.5万字) | 训练自建目标检测与图像分割数据集 |

142 篇文章

已下架不支持订阅

本文详细介绍了如何使用YOLOv8及其改进进行目标检测和图像分割,包括数据集的收集、标注、划分,训练环境的配置,模型的训练、验证和推理。此外,还讲解了数据增强、模型优化和性能指标的评估,以及YOLOv8的改进方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


点击进入专栏:
《人工智能专栏》 Python与Python | 机器学习 | 深度学习 | 目标检测 | YOLOv5及其改进 | YOLOv8及其改进 | 关键知识点 | 各种工具教程



基础入门篇 |训练 验证 推理 直接打印 FPS,mAP50,75,95

在这里插入图片描述


训练 --train.py

在这里插入图片描述

大家可以在 ultralyticsultralytics 文件夹下新建一个train.py,然后直接复制我的代码,

所有训练有关的超参数都可以在这个文件中调节,基本和 YOLOv5 使用方式相同,

这里我说一下比较重要的几个参数:

  • YOLO( ):这个参数里面可以写你模型 yaml 文件的路径,也可以直接写 .pt 文件
  • YOLO( ).load( ):如果你不加 .load( ),那就是不使用权重从头训练,加了就是使用权重迁移学习
  • data:数据集 yaml 文件的路径
  • epochs:训练轮数
  • batchbatch size 大小
  • cache:设置成 True 可以加速训练
  • patience:早停轮数,不想设置早停的话,可以把这个值设置成一个非常大的数
  • optimizer:优化器,最新版应该是提供了 7 7 7 种,注释有写包含哪几种,还可以设置成 auto
  • close_mosaic:最后多少轮关闭马赛克数据增强,这是一种训练技巧,很有效,一般设置 10 10 10- 30 30 30
  • resume:断点续训,一个最实用的参数,直接在这里写你断了的那轮的 last.pt 的路径就接上了
  • single_cls:数据集是单个类别的时候记得开启,不开其实也没事
  • cos_lr:是否开启余弦学习率
  • label_smoothing:数据集标注质量很差的时候可以考虑给这个参数设置个 0.1 0.1 0.1- 0.5 0.5 0.5
  • device:多 GPU 训练时这里直接写一个列表,比如 [0, 1]
from ultralytics import YOLO

if __name__ == '__main__':
    # 加载模型
    model = YOLO(r'yolov8.yaml')  # 不使用预训练权重训练
    # model = YOLO(r'yolov8.yaml').load("yolov8n.pt")  # 使用预训练权重训练
    # 训练参数 ----------------------------------------------------------------------------------------------
    model.train(
        data=r'coco128.yaml',
        epochs=300,  # (int) 训练的周期数
        patience=50,  # (int) 等待无明显改善以进行早期停止的周期数
        batch=32,  # (int) 每批次的图像数量(-1 为自动批处理)
        imgsz=640,  # (int) 输入图像的大小,整数或w,h
        save=True,  # (bool) 保存训练检查点和预测结果
        save_period=-1,  # (int) 每x周期保存检查点(如果小于1则禁用)
        cache=False,  # (bool) True/ram、磁盘或False。使用缓存加载数据
        device='',  # (int | str | list, optional) 运行的设备,例如 cuda device=0 或 device=0,1,2,3 或 device=cpu
        workers=8,  # (int) 数据加载的工作线程数(每个DDP进程)
        project='runs/train',  # (str, optional) 项目名称
        name='exp',  # (str, optional) 实验名称,结果保存在'project/name'目录下
        exist_ok=False,  # (bool) 是否覆盖现有实验
        pretrained=True,  # (bool | str) 是否使用预训练模型(bool),或从中加载权重的模型(str)
        optimizer='SGD',  # (str) 要使用的优化器,选择=[SGD,Adam,Adamax,AdamW,NAdam,RAdam,RMSProp,auto]
        verbose=True,  # (bool) 是否打印详细输出
        seed=0,  # (int) 用于可重复性的随机种子
        deterministic=True,  # (bool) 是否启用确定性模式
        single_cls=False,  # (bool) 将多类数据训练为单类
        rect=False,  # (bool) 如果mode='train',则进行矩形训练,如果mode='val',则进行矩形验证
        cos_lr=False,  # (bool) 使用余弦学习率调度器
        close_mosaic=0,  # (int) 在最后几个周期禁用马赛克增强
        resume=False,  # (bool) 从上一个检查点恢复训练
        amp=True,  # (bool) 自动混合精度(AMP)训练,选择=[True, False],True运行AMP检查
        fraction=1.0,  # (float) 要训练的数据集分数(默认为1.0,训练集中的所有图像)
        profile=False,  # (bool) 在训练期间为记录器启用ONNX和TensorRT速度
        freeze=None,  # (int | list, 可选) 在训练期间冻结前 n 层,或冻结层索引列表。
        # 分割
        overlap_mask=True,  # (bool) 训练期间是否应重叠掩码(仅适用于分割训练)
        mask_ratio=4,  # (int) 掩码降采样比例(仅适用于分割训练)
        # 分类
        dropout=0.0,  # (float) 使用丢弃正则化(仅适用于分类训练)
        # 超参数 ----------------------------------------------------------------------------------------------
        lr0=0.01,  # (float) 初始学习率(例如,SGD=1E-2,Adam=1E-3)
        lrf=0.01,  # (float) 最终学习率(lr0 * lrf)
        momentum=0.937,  # (float) SGD动量/Adam beta1
        weight_decay=0.0005,  # (float) 优化器权重衰减 5e-4
        warmup_epochs=3.0,  # (float) 预热周期(分数可用)
        warmup_momentum=0.8,  # (float) 预热初始动量
        warmup_bias_lr=0.1,  # (float) 预热初始偏置学习率
        box=7.5,  # (float) 盒损失增益
        cls=0.5,  # (float) 类别损失增益(与像素比例)
        dfl=1.5,  # (float) dfl损失增益
        pose=12.0,  # (float) 姿势损失增益
        kobj=1.0,  # (float) 关键点对象损失增益
        label_smoothing=0.0,  # (float) 标签平滑(分数)
        nbs=64,  # (int) 名义批量大小
        hsv_h=0.015,  # (float) 图像HSV-Hue增强(分数)
        hsv_s=0.7,  # (float) 图像HSV-Saturation增强(分数)
        hsv_v=0.4,  # (float) 图像HSV-Value增强(分数)
        degrees=0.0,  # (float) 图像旋转(+/- deg)
        translate=0.1,  # (float) 图像平移(+/- 分数)
        scale=0.5,  # (float) 图像缩放(+/- 增益)
        shear=0.0,  # (float) 图像剪切(+/- deg)
        perspective=0.0,  # (float) 图像透视(+/- 分数),范围为0-0.001
        flipud=0.0,  # (float) 图像上下翻转(概率)
        fliplr=0.5,  # (float) 图像左右翻转(概率)
        mosaic=1.0,  # (float) 图像马赛克(概率)
        mixup=0.0,  # (float) 图像混合(概率)
        copy_paste=0.0,  # (float) 分割复制-粘贴(概率)
    )

推理 --detect.py

在这里插入图片描述

同样的,推理功能也只需要一个 detect.py 就可以实现,代码大家依然可以复制我的代码

  • YOLO( ):这里写你推理使用的 .pt 文件的路径
  • source:这里写你想推理的资源的路径
  • save:表示是否保存检测结果
  • conf: 置信度阈值
  • iouNMS 时的 IoU 阈值
  • line_thickness:检测框线条的粗细
  • visualize:是否将特征图可视化出来
from ultralytics import YOLO

if __name__ == '__main__':
    # 加载模型
    model = YOLO(r'yolov8n.pt')  # YOLOv8n模型
    model.predict(
        source=r'ultralytics/assets/bus.jpg',
        save=True,  # 保存预测结果
        imgsz=640,  # 输入图像的大小,可以是整数或w,h
        conf=0.25,  # 用于检测的目标置信度阈值(默认为0.25,用于预测,0.001用于验证)
        iou=0.45,  # 非极大值抑制 (NMS) 的交并比 (IoU) 阈值
        show=False,  # 如果可能的话,显示结果
        project='runs/predict',  # 项目名称(可选)
        name='exp',  # 实验名称,结果保存在'project/name'目录下(可选)
        save_txt=False,  # 保存结果为 .txt 文件
        save_conf=True,  # 保存结果和置信度分数
        save_crop=False,  # 保存裁剪后的图像和结果
        show_labels=True,  # 在图中显示目标标签
        show_conf=True,  # 在图中显示目标置信度分数
        vid_stride=1,  # 视频帧率步长
        line_width=3,  # 边界框线条粗细(像素)
        visualize=False,  # 可视化模型特征
        augment=False,  # 对预测源应用图像增强
        agnostic_nms=False,  # 类别无关的NMS
        retina_masks=False,  # 使用高分辨率的分割掩码
        boxes=True,  # 在分割预测中显示边界框
    )

验证 --val.py

在这里插入图片描述

验证依然可以用一个 val.py 搞定,代码如下,

  • YOLO( ):这里写你想要验证的权重的路径
  • data:这里写你数据集 yaml 文件的路径
  • split:写 val 就是看验证集的指标,写 test 就是看测试集的指标(前提是你划分了测试集)
  • batch:测试速度时一般都设置成 1 1 1,设置越大,速度越快
from ultralytics import YOLO

if __name__ == '__main__':
    # 加载模型
    model = YOLO(r'yolov8n.pt')  
    # 验证模型
    metrics=model.val(
        val=True,  # (bool) 在训练期间进行验证/测试
        data=r'coco128.yaml',
        split='val',  # (str) 用于验证的数据集拆分,例如'val'、'test'或'train'
        batch=1,  # (int) 每批的图像数量(-1 为自动批处理)
        imgsz=640,  # 输入图像的大小,可以是整数或w,h
        device='',  # 运行的设备,例如 cuda device=0 或 device=0,1,2,3 或 device=cpu
        workers=8,  # 数据加载的工作线程数(每个DDP进程)
        save_json=False,  # 保存结果到JSON文件
        save_hybrid=False,  # 保存标签的混合版本(标签 + 额外的预测)
        conf=0.001,  # 检测的目标置信度阈值(默认为0.25用于预测,0.001用于验证)
        iou=0.6,  # 非极大值抑制 (NMS) 的交并比 (IoU) 阈值
        project='runs/val',  # 项目名称(可选)
        name='exp',  # 实验名称,结果保存在'project/name'目录下(可选)
        max_det=300,  # 每张图像的最大检测数
        half=False,  # 使用半精度 (FP16)
        dnn=False,  # 使用OpenCV DNN进行ONNX推断
        plots=True,  # 在训练/验证期间保存图像
    )

    print(f"mAP50-95: {metrics.box.map}") # map50-95
    print(f"mAP50: {metrics.box.map50}")  # map50
    print(f"mAP75: {metrics.box.map75}")  # map75
    speed_metrics = metrics.speed
    total_time = sum(speed_metrics.values())
    fps = 1000 / total_time
    print(f"FPS: {fps}") # FPS

不训练,只查看模型结构/参数量/计算量 --test.py

  • YOLO( ):写你想要查看结构的 yaml 文件路径即可
from ultralytics import YOLO

if __name__ == '__main__':
    # Load a model
    model = YOLO(r'path/to/xxx.yaml')  # build a new model from YAML
    model.info()


目标检测数据集

1. 收集数据集

随着深度学习技术在计算机视觉领域的广泛应用,行人检测和车辆检测等任务已成为热门研究领域。然而,实际应用中,可用的预训练模型可能并不适用于所有应用场景。

例如,虽然预先训练的模型可以检测出行人,但它无法区分“好人”和“坏人”,因为它没有接受相关的训练。因此,我们需要为自定义检测模型提供足够数量的带有标注信息的图像数据,来训练模型以区分“好人”和“坏人”。

本文将介绍几种收集数据集的常见方法,帮助大家更好地解决实际问题。


1.1 使用开源已标记数据集

使用开源数据集是收集数据的最简便方式之一。例如,ImageNet是一个大型图像数据库,包含超过1400万张图像,可用于深度学习模型的训练。此外,像COCOPASCAL VOC这样的数据集也经常用于目标检测模型的训练和评估。但是这些数据库中的图像通常来自不同的领域和应用场景,因此可能无法完全满足特定研究的需求。

在这里插入图片描述


1.2 爬取网络图像

另一种选择是通过网络搜索图像,并手动选择要下载的图像。然而,由于需要收集大量数据,因此此方法的效率较低。需要注意的是,网络上的图像可能受到版权保护。在使用这些图像之前,务必检查图像的版权信息。

或者,您可以编写一个程序来爬取网络并下载所需的图像,但是这需要对数据进行清洗,以确保数据质量。同样需要注意检查每个图像的版权信息。

在这里插入图片描述


1.3 自己拍摄数据集

对于一些特定的应用场景,如自动驾驶和安防监控等,需要收集特定场景下的数据,这时候就需要进行自主拍摄。可以在实际场景中拍摄图像或视频,并对其进行标注,以获得适用于特定场景的高质量数据集。

在这里插入图片描述


1.4 使用数据增强生成数据集

我们知道深度学习模型需要大量的数据。当我们只有一个小数据集时,可能不足以训练一个好的模型。在这种情况下,我们可以使用数据增强来生成更多训练数据。

常见的增强方式就是几何变换,类似翻转、裁剪、旋转和平移这些。

在这里插入图片描述

左边是狗的原始图像,右边是水平翻转的图像

在这里插入图片描述

猫的原始和随机裁剪图像


1.5 使用算法合成图像

最后一种获取目标检测数据集的方法是使用合成图像。合成图像是通过使用图像处理软件(例如Photoshop)在图像中添加对象、更改背景或合成多个图像以创建新的图像。这种方法可以提供一些特殊情况或无法通过其他方式获得的图像,但是合成图像通常无法完全代替真实场景的数据,可能会对模型的准确性产生一定的影响。

或者我们可以使用生成对抗网络 (GAN) 来生成数据集。
在这里插入图片描述

值得注意的是,收集训练数据集只是我们训练自定义检测模型的第一步。。。接下来我们要介绍如何标注数据集,当然这一步是假设你的图片已经准备完成。

本次案例依然使用我个人的月饼数据集

下载地址:https://download.csdn.net/download/weixin_43694096/87094367

在这里插入图片描述


2. 标注数据集

为什么要标注数据集?标注好的数据集有什么作用呢?
答:为了让计算机学会正确地识别物体,我们需要提供大量的标注数据集,这些数据集包含了图像或视频中物体的位置和类别信息。
标注数据集的作用在于,它可以帮助计算机学习到如何识别不同种类的物体,并且能够正确地定位它们的位置。通过标注数据集,我们可以让计算机逐渐学会如何识别和分类不同种类的物体,例如人、车、动物等等。这些数据集可以被用来训练深度学习模型,让模型学会如何识别新的图像或视频中的物体。

举个简单例子:比如说,我们想要让计算机自动识别图像中的猫和狗。为了让计算机学会如何识别这两个物体,我们需要提供一些图像样本,并在这些样本上标注猫和狗的位置。
如果我们没有标注数据集,计算机就无法学习到如何识别猫和狗。即使我们给计算机提供了大量的图像,它也无法准确地区分这两个物体。但是,如果我们有了标注数据集,计算机就可以通过学习这些数据来理解猫和狗之间的差异,并且可以在新的图像中准确地识别它们。
(当然这个例子指的是监督学习)


2.1 确认标注格式

YOLOv8 所用数据集格式与 YOLOv5 YOLOv7 相同,采用格式如下:

<object-class-id> <x> <y> <width> <height>

常用的标注工具有很多,比如LabelImgLabelMeVIA等,但是这些工具都需要安装使用,我这里给大家介绍一款在线标注数据集的工具Make Sense,打开即用,非常的便捷,在标注之前,我们来看一下一般情况下遵循的标注规则

  1. 目标框必须框住整个目标物体,不能有遗漏和重叠。
  2. 目标框应该与目标物体尽可能接近,但不能与目标物体重合。
  3. 目标框的宽度和高度应该为正数,不能为零或负数。
  4. 如果一张图片中有多个目标物体,每个目标物体应该用一个独立的目标框进行标注,不允许多个目标共用一个框。
  5. 如果目标物体的形状不规则,可以使用多个框进行标注,但必须框住整个目标物体。
  6. 目标框的坐标必须在数据集中统一。

2.2 开始标注

确认好标注格式后我们就可以开始标注了,进入网页后点击 Get Started 开始使用。

在这里插入图片描述

首先点击 Drop images 然后 Ctrl+A 选中整个数据集里面的图片。

在这里插入图片描述

随后添加标签信息,有几类就添加几个,因为我这里只检测月饼一类,所以只添加一个标签 Moon Cake

在这里插入图片描述

随后就进入了漫长的标注环节,这里大家一定要认真标注,不然对最终模型的影响还是很大的。

在这里插入图片描述
在这里插入图片描述

大约 3 3 3 个小时以后就标注完毕了。。。。

我们点击Action -> Export Annotation 导出 yolo 格式的标签文件。

在这里插入图片描述

导出之后的标签文件就是这个样子的,我们可以随机抽查几个看看有没有问题。

在这里插入图片描述


3. 划分数据集

也就是说,我们现在导出后的图片和标签是这个样子的:

Moon_Cake
	├─images
	   └─all
	└─labels
	   └─all

但是 YOLOv8 所需要的数据集路径的格式是下面这样子的(YOLOv8支持不止这一种格式),我们接下来要通过脚本来来划分一下数据集:

├── yolov8_dataset
	└── train
		└── images (folder including all training images)
		└── labels (folder including all training labels)
	└── test
		└── images (folder including all testing images)
		└── labels (folder including all testing labels)
	└── valid
		└── images (folder including all testing images)
		└── labels (folder including all testing labels)

具体其实只要修改路径就行了,代码我都做了注释。

# by CSDN 迪菲赫尔曼
import os
import random
import shutil

def copy_files(src_dir, dst_dir, filenames, extension):
    os.makedirs(dst_dir, exist_ok=True)
    missing_files = 0
    for filename in filenames:
        src_path = os.path.join(src_dir, filename + extension)
        dst_path = os.path.join(dst_dir, filename + extension)
        
        # Check if the file exists before copying
        if os.path.exists(src_path):
            shutil.copy(src_path, dst_path)
        else:
            print(f"Warning: File not found for {filename}")
            missing_files += 1

    return missing_files

def split_and_copy_dataset(image_dir, label_dir, output_dir, train_ratio=0.7, valid_ratio=0.15, test_ratio=0.15):
    # 获取所有图像文件的文件名(不包括文件扩展名)
    image_filenames = [os.path.splitext(f)[0] for f in os.listdir(image_dir)]

    # 随机打乱文件名列表
    random.shuffle(image_filenames)

    # 计算训练集、验证集和测试集的数量
    total_count = len(image_filenames)
    train_count = int(total_count * train_ratio)
    valid_count = int(total_count * valid_ratio)
    test_count = total_count - train_count - valid_count

    # 定义输出文件夹路径
    train_image_dir = os.path.join(output_dir, 'train', 'images')
    train_label_dir = os.path.join(output_dir, 'train', 'labels')
    valid_image_dir = os.path.join(output_dir, 'valid', 'images')
    valid_label_dir = os.path.join(output_dir, 'valid', 'labels')
    test_image_dir = os.path.join(output_dir, 'test', 'images')
    test_label_dir = os.path.join(output_dir, 'test', 'labels')

    # 复制图像和标签文件到对应的文件夹
    train_missing_files = copy_files(image_dir, train_image_dir, image_filenames[:train_count], '.jpg')
    train_missing_files += copy_files(label_dir, train_label_dir, image_filenames[:train_count], '.txt')

    valid_missing_files = copy_files(image_dir, valid_image_dir, image_filenames[train_count:train_count + valid_count], '.jpg')
    valid_missing_files += copy_files(label_dir, valid_label_dir, image_filenames[train_count:train_count + valid_count], '.txt')

    test_missing_files = copy_files(image_dir, test_image_dir, image_filenames[train_count + valid_count:], '.jpg')
    test_missing_files += copy_files(label_dir, test_label_dir, image_filenames[train_count + valid_count:], '.txt')

    # Print the count of each dataset
    print(f"Train dataset count: {train_count}, Missing files: {train_missing_files}")
    print(f"Validation dataset count: {valid_count}, Missing files: {valid_missing_files}")
    print(f"Test dataset count: {test_count}, Missing files: {test_missing_files}")

# 使用例子
image_dir = 'datasets/coco128/images/train2017'
label_dir = 'datasets/coco128/labels/train2017'
output_dir = './my_dataset'

split_and_copy_dataset(image_dir, label_dir, output_dir)

运行完脚本后我们的数据集就会划分成这个格式了,现在数据准备工作就彻底完成了,接下来我们开始着手训练模型。

在这里插入图片描述


4. 配置训练环境

4.1 获取代码
git clone https://github.com/ultralytics/ultralytics

针对网络不好的同学,我这里上传了一份:点击下载

4.2 安装环境
cd ultralytics
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

如果你不想使用 4.1 的获取源码指令,直接用CLI指令推理,那你可以使用如下的指令直接安装ultralytics包,这两种方式在更改项目代码时的操作是不同的。我推荐 pip install -r requirements.txt 这种方式,如果在改进代码时遇到了问题,请看我这篇博文

pip install ultralytics

5. 训练模型

5.1 新建一个数据集yaml文件

这个是我新建的,里面写绝对路径(主要是怕出错):

# moncake
train: D:\Pycharm_Projects\ultralytics\ultralytics\datasets\mooncake\train  # train images (relative to 'path') 128 images
val: D:\Pycharm_Projects\ultralytics\ultralytics\datasets\mooncake\valid # val images (relative to 'path') 128 images
test: D:\Pycharm_Projects\ultralytics\ultralytics\datasets\mooncake\test # test images (optional)

# Classes
names:
  0: MoonCake

这个是自带的,里面写相对路径,和我们的写法不同,但是都可以使用,据我所只还有很多种数据集读取方式:

# coco128
path: ../datasets/coco128  # dataset root dir
train: images/train2017  # train images (relative to 'path') 128 images
val: images/train2017  # val images (relative to 'path') 128 images
test:  # test images (optional)

# Classes
names:
  0: person
  1: bicycle
  2: car
  '''
  '''
  79: toothbrush

在这里插入图片描述

相应的数据集位置就在这里,我们可以和coco128对比一下,这两种划分格式都可以的,这里一定要注意路径问题!


YOLOv8提供CLIpython两种训练方式,
CLI就是直接在终端运行指令
python需要你新建一个python文件,然后运行代码


5.2 预测模型

这是官方提供的一些命令行方式,下面我们分开来介绍一下:

CLI 指令推理方式:

yolo task=detect    mode=train    model=yolov8n.pt        args...
          classify       predict        yolov8n-cls.yaml  args...
          segment        val            yolov8n-seg.yaml  args...
                         export         yolov8n.pt        format=onnx  args...

python 指令推理方式:

from ultralytics import YOLO

# Load a model
model = YOLO('yolov8n.pt')  # load an official model
model = YOLO('path/to/best.pt')  # load a custom model

# Predict with the model
results = model('https://ultralytics.com/images/bus.jpg')  # predict on an image

终端中直接键入以下指令就可以实现对图进行推理了,推理后如果不指定文件夹,就会默认保存到runs/detect/predict下。

yolo task=detect mode=predict model=yolov8n.pt source=data/images device=0 save=True

在这里插入图片描述

在这里插入图片描述
就这张图来说,v8确实比v5牛🍺,左上角的标志都检测出来了,但是阳台上的自行车还是没检测出来。


YOLOv8 关于模型的各种参数其实都写到了一起,在ultralytics/yolo/cfg/default.yaml,这是与先前版本最大的不同,通过使用这些指令我们就可以实现各种我们所需的操作。

在这里插入图片描述

参数名默认值说明
source图像或视频所在的目录
showFalse如果可能,显示结果
save_txtFalse将结果保存为.txt文件
save_confFalse保存带置信度得分的结果
save_cropFalse保存裁剪后带结果的图像
show_labelsTrue在绘图中显示对象标签
show_confTrue在绘图中显示对象置信度得分
vid_stride1视频帧率跨度
line_thickness3边界框的厚度(像素)
visualizeFalse可视化模型特征
augmentFalse对预测源应用图像增强
agnostic_nmsFalse类无关NMS
classes空列表按类别筛选结果,例如:class = 0或class = [0,2,3]
retina_masksFalse使用高分辨率分割掩模
boxesTrue在分割预测中显示边界框

5.3 训练模型

模型训练阶段的原理和预测步骤一致,都可以直接通过命令行搞定,关于这部分参数依然在ultralytics/yolo/cfg/default.yaml中,但我们要训练自己的数据集时记得在 data 参数后指定我们自己的数据集yaml文件路径哦。

以下提供三种指令,分别对应了不同的需求。(这里有一点值得注意, 我直接写data=MoonCake.yaml是报错的!这个涉及到一个坑的问题,没遇到的同学暂且忽略)


CLI 指令训练方式:

# 从YAML构建一个新模型,从头开始训练
yolo detect train data=coco128.yaml model=yolov8n.yaml epochs=100 imgsz=640
yolo detect train data=ultralytics/datasets/MoonCake.yaml model=yolov8n.yaml epochs=100 imgsz=640

# 从预训练的*.pt模型开始训练
yolo detect train data=coco128.yaml model=yolov8n.pt epochs=100 imgsz=640
yolo detect train data=ultralytics/datasets/MoonCake.yaml model=yolov8n.pt epochs=100 imgsz=640

# 从YAML中构建一个新模型,将预训练的权重转移到它并开始训练
yolo detect train data=coco128.yaml model=yolov8n.yaml pretrained=yolov8n.pt epochs=100 imgsz=640
yolo detect train data=ultralytics/datasets/MoonCake.yaml model=yolov8n.yaml pretrained=yolov8n.pt epochs=100 imgsz=640

Python 指令训练方式:

from ultralytics import YOLO

# Load a model
model = YOLO('yolov8n.yaml')  # build a new model from YAML
model = YOLO('yolov8n.pt')  # load a pretrained model (recommended for training)
model = YOLO('yolov8n.yaml').load('yolov8n.pt')  # build from YAML and transfer weights

# Train the model
model.train(data='coco128.yaml', epochs=100, imgsz=640)

在这里插入图片描述

参数默认值描述
model模型文件路径,如yolov8n.pt,yolov8n.yaml
data数据文件路径,如coco128.yaml
epochs100训练的轮数
patience50等待没有观察到改进的轮数,以便提前停止训练
batch16每个批次的图像数量(-1表示自动批处理)
imgsz640输入图像的大小,可以是整数或w,h
saveTrue保存训练检查点和预测结果
save_period-1每x个轮数保存检查点(如果<1,则禁用)
cacheFalseTrue / ram,磁盘或False。使用缓存加载数据
device运行的设备,如cuda device=0或device=0,1,2,3或device=cpu
workers8加载数据的工作线程数(每个RANK如果DDP)
project项目名称
name实验名称,结果保存到“project / name”目录中
exist_okFalse是否覆盖现有实验
pretrainedFalse是否使用预训练模型
optimizerSGD要使用的优化器,choices=[‘SGD’, ‘Adam’, ‘AdamW’, ‘RMSProp’]
verboseTrue是否打印详细输出
seed0用于可重复性的随机种子
deterministicTrue是否启用确定性模式
single_clsFalse将多类数据训练为单类
image_weightsFalse使用加权图像选择进行训练
rectFalse如果mode ='train’则进行矩形训练,如果mode ='val’则进行矩形验证
cos_lrFalse使用余弦学习率调度程序
close_mosaic10对于最后10个轮数禁用马赛克增强
resumeFalse从上一个检查点恢复训练
ampTrue自动混合精度(AMP)训练,choices=[True, False],True运行AMP检查

在训练过程中(训练结束后也可以看)我们可以通过Tensorboard实时查看模型的训练进度, 只需要在终端中键入如下的指令,这个在我们每次训练时候都会有提示:

tensorboard --logdir runs\detect\train2

在这里插入图片描述

训练结束后我们可以查看得到的一些指标数据:

在这里插入图片描述

在这里插入图片描述
我这里展示一张PR曲线图。


5.4 验证模型

验证模型同样是简单命令行即可实现,如果没有修改中的 ultralytics/yolo/cfg/default.yaml 默认值,同样别忘了指定自己数据集的yaml,即data=ultralytics/datasets/MoonCake.yaml


CLI 指令验证方式:

yolo task=detect mode=val model=yolov8n.pt
# mode=val 就是看验证集
yolo task=detect mode=val split=val model=runs/detect/train2/weights/best.pt  data=ultralytics/datasets/MoonCake.yaml
# mode=test 就是看测试集
yolo task=detect mode=val split=test model=runs/detect/train2/weights/best.pt  data=ultralytics/datasets/MoonCake.yaml

python 指令验证方式:

from ultralytics import YOLO

# Load a model
model = YOLO('yolov8n.pt')  # load an official model
model = YOLO('path/to/best.pt')  # load a custom model

# Validate the model
metrics = model.val()  # no arguments needed, dataset and settings remembered
metrics.box.map    # map50-95
metrics.box.map50  # map50
metrics.box.map75  # map75
metrics.box.maps   # a list contains map50-95 of each category

在这里插入图片描述
同样的,我们验证完后依然可以得到一个文件夹:
在这里插入图片描述
我们可以看一下检测效果:

在这里插入图片描述

嗯~ 古德古德~

参数名默认值描述
valTrue在训练过程中进行验证/测试
splitval用于验证的数据集划分,可选项有’val’、‘test’或’train’
save_jsonFalse是否将结果保存为JSON文件
save_hybridFalse是否保存标签的混合版本(标签+额外的预测结果)
conf0.25(predict),0.001(val)检测的物体置信度阈值(默认值),在训练和验证过程中使用不同的阈值
iou0.7非极大值抑制(NMS)的交并比(IoU)阈值
max_det300每个图像最多检测出的目标数量
halfFalse是否使用半精度(FP16)
dnnFalse是否使用OpenCV DNN进行ONNX推理
plotsTrue在训练/验证过程中是否保存图表

5.5 导出模型

只需使用如下命令,就可完成模型的导出。


CLI 指令导出方式:

yolo task=detect mode=export model=runs/detect/train/weights/best.pt

python 指令导出方式:

from ultralytics import YOLO

# Load a model
model = YOLO('yolov8n.pt')  # load an official model
model = YOLO('path/to/best.pt')  # load a custom trained

# Export the model
model.export(format='onnx')

导出有关的具体参数如下:
在这里插入图片描述

参数名默认值描述
formattorchscript导出的模型格式
kerasFalse是否使用Keras
optimizeFalseTorchScript: 是否针对移动设备进行优化
int8FalseCoreML/TF的INT8量化
dynamicFalseONNX/TF/TensorRT: 是否动态轴
simplifyFalseONNX: 是否简化模型
opsetONNX: 操作版本(可选)
workspace4TensorRT: 工作空间大小(GB)
nmsFalseCoreML: 是否添加NMS

注:TorchScript是PyTorch的模型导出工具。INT8(8位整数量化)是一种量化方法,可将神经网络参数表示为8位整数,以降低存储和计算成本。ONNX(Open Neural Network Exchange)是一种跨平台、开放式的机器学习框架。TensorRT是一种用于加速深度学习推理的高性能引擎。CoreML是苹果公司推出的机器学习框架。Keras是一种流行的深度学习框架。


分割数据集


1. 数据格式

我们先看下官方给我们提供的分割数据集示例,下载地址在这里:https://ultralytics.com/assets/coco8-seg.zip

打开后是这样子的

在这里插入图片描述

我们先读下 README.md

Ultralytics COCO8-seg 数据集

Ultralytics COCO8-seg 是一个小型但多才多艺的实例分割数据集,由 COCO train 2017 集的前 8 张图像组成,其中 4 张用于训练,4 张用于验证。
该数据集非常适用于测试和调试分割模型,或者尝试新的检测方法。

有了 8 张图像,它足够小,易于管理,同时又足够多样,可以用于测试训练流程是否存在错误,并在训练更大数据集之前作为健全性检查。

此数据集旨在与 Ultralytics YOLOv8 一起使用。

数据集的结构就是下面这样的,图片没有什么可说的,主要说下标签文件,

coco8-seg
	├─images
	│  ├─train
	│  └─val
	└─labels
	    ├─train
	    └─val

随便点开一个我们就会发现,相较于规范的检测任务,分割任务的标签显得比较的复杂,

在这里插入图片描述

我这里给大家写了一个小脚本,可以将对应的标签和图片输入进去,得到可视化结果,

请添加图片描述
看到这里大家可能也猜出来标签的含义了,每行的第一个数字表示类别的标识符,后续的数字表示一个由 x x x 和 y y y 坐标组成的序列,代表一个分割的多边形或轮廓,这个多边形由这些坐标点依次连接而成。

22 0.00746875 0.0539294 0.117891 0.0921412 0.231297 0.110118 ......

第一个数字 22 22 22 是类别标识符。
后续的数字是 x x x 和 y y y 坐标的交替序列,表示分割多边形的各个顶点。


可视化代码:

# by https://blog.csdn.net/weixin_43694096
import cv2
import numpy as np

def restore_masks_to_image(mask_data, image_path, output_path):
    # 读取图像
    img = cv2.imread(image_path)
    
    # 将掩码数据还原到图像上
    for mask in mask_data:
        values = list(map(float, mask.split()))
        class_id = int(values[0])
        mask_values = values[1:]

        # 将掩码数据转换为NumPy数组
        mask_array = np.array(mask_values, dtype=np.float32).reshape((int(len(mask_values) / 2), 2))

        # 将相对于图像大小的百分比转换为具体坐标值
        mask_array[:, 0] *= img.shape[1]  # 宽度
        mask_array[:, 1] *= img.shape[0]  # 高度

        # 将坐标值转换为整数
        mask_array = mask_array.astype(np.int32)

        # 在图像上绘制掩码
        cv2.polylines(img, [mask_array], isClosed=True, color=(0, 255, 0), thickness=2)

        # 在图像上绘制每个坐标点
        for point in mask_array:
            cv2.circle(img, tuple(point), 3, (255, 0, 0), -1)  # -1 表示填充圆

    # 保存带有掩码和坐标点的图像
    cv2.imwrite(output_path, img)


if __name__ == "__main__":
    mask_data = [
        "22 0.00746875 0.0539294 0.117891 0.0921412 0.231297 0.110118 0.2895 0.0674118 0.331281 0.0472 0.3865 0.0696706 0.423813 0.0943765 0.446188 0.105624 0.467078 0.1528 0.517813 0.182024 0.577516 0.253929 0.658094 0.379765 0.690922 0.532588 0.687937 0.6 0.650625 0.555059 0.658094 0.644941 0.668547 0.755059 0.676 0.838212 0.658094 0.894376 0.613328 0.925835 0.589453 0.914612 0.590938 0.856188 0.552141 0.791012 0.523781 0.725835 0.528266 0.633718 0.498422 0.577529 0.444703 0.505624 0.407391 0.505624 0.395453 0.541576 0.417844 0.591012 0.450672 0.642706 0.456641 0.642706 0.461109 0.725835 0.458125 0.786518 0.450672 0.853929 0.444703 0.898871 0.401422 0.869671 0.411875 0.815741 0.423813 0.734824 0.425297 0.694376 0.361125 0.608988 0.316359 0.588753 0.280547 0.703365 0.271594 0.757294 0.261141 0.829224 0.268609 0.869671 0.277562 0.901129 0.250703 0.937082 0.222344 0.939318 0.231297 0.901129 0.222344 0.844941 0.238766 0.7236 0.246219 0.642706 0.271594 0.510118 0.182062 0.507859 0.0999844 0.525835 0.0208906 0.494376 0.0015 0.0516941"
    ]

    image_path = "000000000034.jpg"
    output_path = "000000000034_out.jpg"

    restore_masks_to_image(mask_data, image_path, output_path)

2. 配置环境

代码地址:https://github.com/ultralytics/ultralytics

首先我们要下载源码,如果你会使用 git 工具,请直接拉取最新的代码。

git clone https://github.com/ultralytics/ultralytics.git

基础不好的同学,请使用我上传的文件,或手动下载代码。

这里我想强调下环境的配置,如果你是新手,请使用如下的指令安装,切记不要使用 pip install ultralytics 这条指令!

这样可以避免你遇到我教程外的错误。

cd ultralytics
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

3. 训练模型

下载好后,我们到这个路径下,ultralytics/ultralytics/cfg/datasets ,在这里我们可以看到 coco8-seg.yaml ,这个文件就是我们导入数据集的关键文件,

我这里使用官方提供的文件,所以不需要太多的更改,如果大家使用自己的数据集,那需要对应的改下里面的内容,

在这里插入图片描述

在这里插入图片描述

这个文件重要的地方有几处,

  • path 代表的根目录的路径
  • train 代表的是训练集图片位置
  • val 代表验证集图片位置
  • test 代表测试集图片位置
  • names 代表数据类别
  • download 代表下载地址,这个我们可以忽略掉

这部分要说的就是这么多,和检测任务没有区别。


训练过程和检测差别也不大,就是模型和数据集yaml的区别,接下来我们要新建一个 train-seg.py 文件,内容直接复制我的,所有的参数我写到下面了,大家对应的看就好了,

最重要的就是 yolov8-seg.yaml 路径和 coco8-seg.yaml 的路径,这里推荐大家写绝对路径,避免出错,

改好了这两个位置直接运行这个文件就开始训练了。

from ultralytics import YOLO

if __name__ == '__main__':
    # 加载模型
    model = YOLO(r'yolov8-seg.yaml')  # 不使用预训练权重训练
    # model = YOLO(r'yolov8-seg.yaml').load("yolov8n-seg.pt")  # 使用预训练权重训练
    # 训练参数 ----------------------------------------------------------------------------------------------
    model.train(
        data=r'coco8-seg.yaml',
        epochs=300,  # (int) 训练的周期数
        patience=50,  # (int) 等待无明显改善以进行早期停止的周期数
        batch=32,  # (int) 每批次的图像数量(-1 为自动批处理)
        imgsz=640,  # (int) 输入图像的大小,整数或w,h
        save=True,  # (bool) 保存训练检查点和预测结果
        save_period=-1,  # (int) 每x周期保存检查点(如果小于1则禁用)
        cache=False,  # (bool) True/ram、磁盘或False。使用缓存加载数据
        device='',  # (int | str | list, optional) 运行的设备,例如 cuda device=0 或 device=0,1,2,3 或 device=cpu
        workers=8,  # (int) 数据加载的工作线程数(每个DDP进程)
        project='runs/train',  # (str, optional) 项目名称
        name='exp',  # (str, optional) 实验名称,结果保存在'project/name'目录下
        exist_ok=False,  # (bool) 是否覆盖现有实验
        pretrained=True,  # (bool | str) 是否使用预训练模型(bool),或从中加载权重的模型(str)
        optimizer='SGD',  # (str) 要使用的优化器,选择=[SGD,Adam,Adamax,AdamW,NAdam,RAdam,RMSProp,auto]
        verbose=True,  # (bool) 是否打印详细输出
        seed=0,  # (int) 用于可重复性的随机种子
        deterministic=True,  # (bool) 是否启用确定性模式
        single_cls=False,  # (bool) 将多类数据训练为单类
        rect=False,  # (bool) 如果mode='train',则进行矩形训练,如果mode='val',则进行矩形验证
        cos_lr=False,  # (bool) 使用余弦学习率调度器
        close_mosaic=0,  # (int) 在最后几个周期禁用马赛克增强
        resume=False,  # (bool) 从上一个检查点恢复训练
        amp=True,  # (bool) 自动混合精度(AMP)训练,选择=[True, False],True运行AMP检查
        fraction=1.0,  # (float) 要训练的数据集分数(默认为1.0,训练集中的所有图像)
        profile=False,  # (bool) 在训练期间为记录器启用ONNX和TensorRT速度
        freeze= None,  # (int | list, 可选) 在训练期间冻结前 n 层,或冻结层索引列表。
        # 分割
        overlap_mask=True,  # (bool) 训练期间是否应重叠掩码(仅适用于分割训练)
        mask_ratio=4,  # (int) 掩码降采样比例(仅适用于分割训练)
        # 分类
        dropout=0.0,  # (float) 使用丢弃正则化(仅适用于分类训练)
        # 超参数 ----------------------------------------------------------------------------------------------
        lr0=0.01,  # (float) 初始学习率(例如,SGD=1E-2,Adam=1E-3)
        lrf=0.01,  # (float) 最终学习率(lr0 * lrf)
        momentum=0.937,  # (float) SGD动量/Adam beta1
        weight_decay=0.0005,  # (float) 优化器权重衰减 5e-4
        warmup_epochs=3.0,  # (float) 预热周期(分数可用)
        warmup_momentum=0.8,  # (float) 预热初始动量
        warmup_bias_lr=0.1,  # (float) 预热初始偏置学习率
        box=7.5,  # (float) 盒损失增益
        cls=0.5,  # (float) 类别损失增益(与像素比例)
        dfl=1.5,  # (float) dfl损失增益
        pose=12.0,  # (float) 姿势损失增益
        kobj=1.0,  # (float) 关键点对象损失增益
        label_smoothing=0.0,  # (float) 标签平滑(分数)
        nbs=64,  # (int) 名义批量大小
        hsv_h=0.015,  # (float) 图像HSV-Hue增强(分数)
        hsv_s=0.7,  # (float) 图像HSV-Saturation增强(分数)
        hsv_v=0.4,  # (float) 图像HSV-Value增强(分数)
        degrees=0.0,  # (float) 图像旋转(+/- deg)
        translate=0.1,  # (float) 图像平移(+/- 分数)
        scale=0.5,  # (float) 图像缩放(+/- 增益)
        shear=0.0,  # (float) 图像剪切(+/- deg)
        perspective=0.0,  # (float) 图像透视(+/- 分数),范围为0-0.001
        flipud=0.0,  # (float) 图像上下翻转(概率)
        fliplr=0.5,  # (float) 图像左右翻转(概率)
        mosaic=1.0,  # (float) 图像马赛克(概率)
        mixup=0.0,  # (float) 图像混合(概率)
        copy_paste=0.0,  # (float) 分割复制-粘贴(概率)
    )

开始训练时会打印出模型的参数量,计算量,结构信息。

在这里插入图片描述

训练结束后会打印出各种指标,包括 PRmAPSpeed等。

在这里插入图片描述


4. 评估模型

评估模型时有个同学问的最多的问题就是测试集的精度怎么看,

这里因为我们没有划分测试集,所以没法看测试集的指标,但是如果你划分了测试集,

直接使用我给的脚本,将 split 设置为 test ,这样就会打印出测试集的指标。

from ultralytics import YOLO

if __name__ == '__main__':
    # 加载模型
    model = YOLO(r'yolov8n.pt')  
    # 验证模型
    model.val(
        val=True,  # (bool) 在训练期间进行验证/测试
        data=r'coco128.yaml',
        split='val',  # (str) 用于验证的数据集拆分,例如'val'、'test'或'train'
        batch=1,  # (int) 每批的图像数量(-1 为自动批处理)
        imgsz=640,  # 输入图像的大小,可以是整数或w,h
        device='',  # 运行的设备,例如 cuda device=0 或 device=0,1,2,3 或 device=cpu
        workers=8,  # 数据加载的工作线程数(每个DDP进程)
        save_json=False,  # 保存结果到JSON文件
        save_hybrid=False,  # 保存标签的混合版本(标签 + 额外的预测)
        conf=0.001,  # 检测的目标置信度阈值(默认为0.25用于预测,0.001用于验证)
        iou=0.6,  # 非极大值抑制 (NMS) 的交并比 (IoU) 阈值
        project='runs/val',  # 项目名称(可选)
        name='exp',  # 实验名称,结果保存在'project/name'目录下(可选)
        max_det=300,  # 每张图像的最大检测数
        half=False,  # 使用半精度 (FP16)
        dnn=False,  # 使用OpenCV DNN进行ONNX推断
        plots=True,  # 在训练/验证期间保存图像
    )

5. 推理模型

推理使用我给的如下脚本就可以实现了。

import sys
sys.path.append("/root/ultralytics")
from ultralytics import YOLO

if __name__ == '__main__':
    # 加载模型
    model = YOLO(r'/root/ultralytics/ultralytics/yolov8n-seg.pt')  # YOLOv8n模型
    model.predict(
        source=r'/root/ultralytics/ultralytics/assets',
        save=True,  # 保存预测结果
        imgsz=640,  # 输入图像的大小,可以是整数或w,h
        conf=0.25,  # 用于检测的目标置信度阈值(默认为0.25,用于预测,0.001用于验证)
        iou=0.45,  # 非极大值抑制 (NMS) 的交并比 (IoU) 阈值
        show=False,  # 如果可能的话,显示结果
        project='runs/predict',  # 项目名称(可选)
        name='exp',  # 实验名称,结果保存在'project/name'目录下(可选)
        save_txt=False,  # 保存结果为 .txt 文件
        save_conf=True,  # 保存结果和置信度分数
        save_crop=False,  # 保存裁剪后的图像和结果
        show_labels=True,  # 在图中显示目标标签
        show_conf=True,  # 在图中显示目标置信度分数
        vid_stride=1,  # 视频帧率步长
        line_width=3,  # 边界框线条粗细(像素)
        visualize=False,  # 可视化模型特征
        augment=False,  # 对预测源应用图像增强
        agnostic_nms=False,  # 类别无关的NMS
        retina_masks=False,  # 使用高分辨率的分割掩码
        boxes=True,  # 在分割预测中显示边界框
    )

在这里插入图片描述
在这里插入图片描述


6. 分割怎么改进

有同学问分割怎么改进,其实和检测任务一样的,唯一区别就是下面红框中的区别,

是用我给的改进和脚本很容易上手改进分割任务~

在这里插入图片描述


推荐阅读:

各部分详情:(持续更新中…)

专栏实时更新目录连接_可点击查看

1. 机器学习



2. 深度学习与目标检测


3. YOLOv5


4. YOLOv5改进


5. YOLOv8及其改进


6. Python与PyTorch


7. 工具


8. 小知识点


9. 杂记


已下架不支持订阅

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值