此次使用的训练集来自:https://www.kaggle.com/datasets/ 口罩训练集
一共三个标签[‘without_mask’,‘with_mask’,‘mask_weared_incorrect’]

前提条件:已安装python环境,conda,显卡驱动
开发工具:Pycharm64
系统:windows11

1.下载官方代码

下载地址:yolov10
进入网址后,先点击code按钮,再点击Download ZIP,下载的文件是一个压缩包:yolov10-main.zip
在这里插入图片描述

2. 下载权重文件

YOLOV10N:https://github.com/THU-MIG/yolov10/releases/download/v1.1/yolov10n.pt
YOLOV10S:https://github.com/THU-MIG/yolov10/releases/download/v1.1/yolov10s.pt
YOLOV10M:https://github.com/THU-MIG/yolov10/releases/download/v1.1/yolov10m.pt
YOLOV10B:https://github.com/THU-MIG/yolov10/releases/download/v1.1/yolov10b.pt
YOLOV10L:https://github.com/THU-MIG/yolov10/releases/download/v1.1/yolov10l.pt
YOLOV10X:https://github.com/THU-MIG/yolov10/releases/download/v1.1/yolov10x.pt

2.1 yolov10解读

在这里插入图片描述
快速的看一下相关的文档,发现YOLOv10 相比YOLOv8有两个最大的改变分别是 添加了PSA层跟CIB层
在这里插入图片描述
在这里插入图片描述
去掉了NMS
在这里插入图片描述
废话不多说上干货

3.下载数据集

https://www.kaggle.com/datasets/
数据集使用的是VOC格式需要转换成YOLO格式

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

4.数据集处理

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

xml 转 txt

import xml.etree.ElementTree as ET
import os, cv2
import numpy as np
from os import listdir
from os.path import join

classes = []


def convert(size, box):
    dw = 1. / (size[0])
    dh = 1. / (size[1])
    x = (box[0] + box[1]) / 2.0 - 1
    y = (box[2] + box[3]) / 2.0 - 1
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x * dw
    w = w * dw
    y = y * dh
    h = h * dh
    return (x, y, w, h)


def convert_annotation(xmlpath, xmlname):
    with open(xmlpath, "r", encoding='utf-8') as in_file:
        txtname = xmlname[:-4] + '.txt'
        txtfile = os.path.join(txtpath, txtname)
        tree = ET.parse(in_file)
        root = tree.getroot()
        filename = root.find('filename')
        img = cv2.imdecode(np.fromfile('{}/{}.{}'.format(imgpath, xmlname[:-4], postfix), np.uint8), cv2.IMREAD_COLOR)
        h, w = img.shape[:2]
        res = []
        for obj in root.iter('object'):
            cls = obj.find('name').text
            if cls not in classes:
                classes.append(cls)
            cls_id = classes.index(cls)
            xmlbox = obj.find('bndbox')
            b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text),
                 float(xmlbox.find('ymax').text))
            bb = convert((w, h), b)
            res.append(str(cls_id) + " " + " ".join([str(a) for a in bb]))
        if len(res) != 0:
            with open(txtfile, 'w+') as f:
                f.write('\n'.join(res))


if __name__ == "__main__":
    postfix = 'png'  # 图像后缀
    imgpath = r'D:\YOLO_DATASETS\MASK\images'  # 图像文件路径
    xmlpath = r'D:\YOLO_DATASETS\MASK\annotations'  # xml文件文件路径
    txtpath = r'D:\YOLO_DATASETS\MASK\test\labels'  # 生成的txt文件路径

    if not os.path.exists(txtpath):
        os.makedirs(txtpath, exist_ok=True)

    list = os.listdir(xmlpath)
    error_file_list = []
    for i in range(0, len(list)):
        try:
            path = os.path.join(xmlpath, list[i])
            if ('.xml' in path) or ('.XML' in path):
                convert_annotation(path, list[i])
                print(f'file {list[i]} convert success.')
            else:
                print(f'file {list[i]} is not xml format.')
        except Exception as e:
            print(f'file {list[i]} convert error.')
            print(f'error message:\n{e}')
            error_file_list.append(list[i])
    print(f'this file convert failure\n{error_file_list}')
    print(f'Dataset Classes:{classes}')

在这里插入图片描述

5.数据集制作

把数据集根据比例拆分出:训练集,验证集,测试集
在这里插入图片描述

# 将图片和标注数据按比例切分为 训练集和测试集
import shutil
import random
import os

# 原始路径 D:\YOLO_DATASETS\MASK\images
image_original_path = "D:/YOLO_DATASETS/MASK/images/"
label_original_path = "D:/YOLO_DATASETS/MASK/labels/"

cur_path = os.getcwd()
# 训练集路径
train_image_path = os.path.join(cur_path, "D:/YOLO_DATASETS/MASK/datasets/images/train/")
train_label_path = os.path.join(cur_path, "D:/YOLO_DATASETS/MASK/datasets/labels/train/")

# 验证集路径
val_image_path = os.path.join(cur_path, "D:/YOLO_DATASETS/MASK/datasets/images/val/")
val_label_path = os.path.join(cur_path, "D:/YOLO_DATASETS/MASK/datasets/labels/val/")

# 测试集路径
test_image_path = os.path.join(cur_path, "D:/YOLO_DATASETS/MASK/datasets/images/test/")
test_label_path = os.path.join(cur_path, "D:/YOLO_DATASETS/MASK/datasets/labels/test/")

# 训练集目录
list_train = os.path.join(cur_path, "D:/YOLO_DATASETS/MASK/datasets/train.txt")
list_val = os.path.join(cur_path, "D:/YOLO_DATASETS/MASK/datasets/val.txt")
list_test = os.path.join(cur_path, "D:/YOLO_DATASETS/MASK/datasets/test.txt")

train_percent = 0.8
val_percent = 0.1
test_percent = 0.1


def del_file(path):
    for i in os.listdir(path):
        file_data = path + "\\" + i
        os.remove(file_data)


def mkdir():
    if not os.path.exists(train_image_path):
        os.makedirs(train_image_path)
    else:
        del_file(train_image_path)
    if not os.path.exists(train_label_path):
        os.makedirs(train_label_path)
    else:
        del_file(train_label_path)

    if not os.path.exists(val_image_path):
        os.makedirs(val_image_path)
    else:
        del_file(val_image_path)
    if not os.path.exists(val_label_path):
        os.makedirs(val_label_path)
    else:
        del_file(val_label_path)

    if not os.path.exists(test_image_path):
        os.makedirs(test_image_path)
    else:
        del_file(test_image_path)
    if not os.path.exists(test_label_path):
        os.makedirs(test_label_path)
    else:
        del_file(test_label_path)


def clearfile():
    if os.path.exists(list_train):
        os.remove(list_train)
    if os.path.exists(list_val):
        os.remove(list_val)
    if os.path.exists(list_test):
        os.remove(list_test)


def main():
    mkdir()
    clearfile()

    file_train = open(list_train, 'w')
    file_val = open(list_val, 'w')
    file_test = open(list_test, 'w')

    total_txt = os.listdir(label_original_path)
    num_txt = len(total_txt)
    list_all_txt = range(num_txt)

    num_train = int(num_txt * train_percent)
    num_val = int(num_txt * val_percent)
    num_test = num_txt - num_train - num_val

    train = random.sample(list_all_txt, num_train)
    # train从list_all_txt取出num_train个元素
    # 所以list_all_txt列表只剩下了这些元素
    val_test = [i for i in list_all_txt if not i in train]
    # 再从val_test取出num_val个元素,val_test剩下的元素就是test
    val = random.sample(val_test, num_val)

    print("训练集数目:{}, 验证集数目:{}, 测试集数目:{}".format(len(train), len(val), len(val_test) - len(val)))
    for i in list_all_txt:
        name = total_txt[i][:-4]

        srcImage = image_original_path + name + '.png'
        srcLabel = label_original_path + name + ".txt"

        if i in train:
            dst_train_Image = train_image_path + name + '.png'
            dst_train_Label = train_label_path + name + '.txt'
            shutil.copyfile(srcImage, dst_train_Image)
            shutil.copyfile(srcLabel, dst_train_Label)
            file_train.write(dst_train_Image + '\n')
        elif i in val:
            dst_val_Image = val_image_path + name + '.png'
            dst_val_Label = val_label_path + name + '.txt'
            shutil.copyfile(srcImage, dst_val_Image)
            shutil.copyfile(srcLabel, dst_val_Label)
            file_val.write(dst_val_Image + '\n')
        else:
            dst_test_Image = test_image_path + name + '.png'
            dst_test_Label = test_label_path + name + '.txt'
            shutil.copyfile(srcImage, dst_test_Image)
            shutil.copyfile(srcLabel, dst_test_Label)
            file_test.write(dst_test_Image + '\n')

    file_train.close()
    file_val.close()
    file_test.close()


if __name__ == "__main__":
    main()

6. 导入代码并安装所需驱动并启动

如果环境启动不了请参考官方文档

创建环境:conda create --name yolov10 python=3.8
激活环境:conda activate yolov10
安装依赖:pip install -r requirements.txt
在这里插入图片描述

6.1 创建mask.yaml

train: D:\YOLO_DATASETS\MASK\datasets\images\train  # train images (relative to 'path') 4 images
val: D:\YOLO_DATASETS\MASK\datasets\images\val  # val images (relative to 'path') 4 images

nc: 3

# class names
names: ['without_mask','with_mask','mask_weared_incorrect']

6.2 创建训练代码

# -*- coding: utf-8 -*-
"""
@Auth : dupo
@File :trian.py
@IDE :PyCharm
"""
from ultralytics import YOLOv10

import warnings
warnings.filterwarnings('ignore')


if __name__ == '__main__':
    model = YOLOv10('yolov10n.pt') # 加载预训练权重,改进或者做对比实验时候不建议打开,因为用预训练模型整体精度没有很明显的提升
    model.train(data=r'mask.yaml',
                imgsz=640,
                epochs=50,
                batch=4,
                workers=0,
                device='',
                optimizer='SGD',
                close_mosaic=10,
                resume=False,
                project='runs/detect',
                name='exp',
                single_cls=False,
                cache=False,
                )

6.3 安装TensorBoard查看训练情况

安装:pip install tensorboard
启动:tensorboard --logdir=E:\local_code\yolov10-main\runs\detect\exp

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

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

7. 模型检验

# -*- coding: utf-8 -*-

from ultralytics import YOLOv10

# wget https://github.com/THU-MIG/yolov10/releases/download/v1.1/yolov10{n/s/m/b/l/x}.pt


model = YOLOv10(r'E:\local_code\yolov10-main\runs\detect\exp\weights\best.pt')



model.predict(source=r'D:\YOLO_DATASETS\MASK\images\maksssksksss148.png', save=True)

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

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐