[卷积神经网络]使用YOLOv11训练自己的模型

时间:2024-11-09 13:28:51

YoloV11的源码:YOLOv11

一、数据集准备

        首先,准备好自己的数据集,包含图像文件和标注文件,因为我的数据集上Voc格式,所以需要先转为yolo格式,可以使用下面的脚本进行转换。

import os
import shutil
import xml.etree.ElementTree as ET


# 类别映射 (需要记住这个顺序,后续YOLO的配置文件中也要与这个顺序一致)
class_mapping = {
    'cls1':0,
    'cls2':1,
    # ...
}

def convert_voc_to_yolo(voc_annotation_file, yolo_label_file):
    tree = ET.parse(voc_annotation_file)
    root = tree.getroot()

    size = root.find('size')
    width = float(size.find('width').text)
    height = float(size.find('height').text)

    with open(yolo_label_file, 'w') as f:
        for obj in root.findall('object'):
            cls = obj.find('name').text
            if cls not in class_mapping:
                continue
            cls_id = class_mapping[cls]
            xmlbox = obj.find('bndbox')
            xmin = float(xmlbox.find('xmin').text)
            ymin = float(xmlbox.find('ymin').text)
            xmax = float(xmlbox.find('xmax').text)
            ymax = float(xmlbox.find('ymax').text)

            x_center = (xmin + xmax) / 2.0 / width
            y_center = (ymin + ymax) / 2.0 / height
            w = (xmax - xmin) / width
            h = (ymax - ymin) / height

            f.write(f"{cls_id} {x_center} {y_center} {w} {h}\n")

if __name__ == '__main__':
    
    # VOC格式数据集路径
    voc_data_path = 'VocData'    #请修改为自己的Voc数据集路径
    voc_annotations_path = os.path.join(voc_data_path, 'Annotations')
    voc_images_path = os.path.join(voc_data_path, 'JPEGImages')

    # YOLO格式数据集保存路径
    yolo_data_path = 'datasets/VOC'    #请修改为自己的输出路径
    yolo_images_path = os.path.join(yolo_data_path, 'images')
    yolo_labels_path = os.path.join(yolo_data_path, 'labels')

    # 创建YOLO格式数据集目录
    os.makedirs(yolo_images_path, exist_ok=True)
    os.makedirs(yolo_labels_path, exist_ok=True)
    
    print('开始转换')
    i = 0

    # 遍历VOC数据集的Annotations目录,进行转换
    for voc_annotation in os.listdir(voc_annotations_path):
        if voc_annotation.endswith('.xml'):
            voc_annotation_file = os.path.join(voc_annotations_path, voc_annotation)
            image_id = os.path.splitext(voc_annotation)[0]
            voc_image_file = os.path.join(voc_images_path, f"{image_id}.jpg")
            yolo_label_file = os.path.join(yolo_labels_path, f"{image_id}.txt")
            yolo_image_file = os.path.join(yolo_images_path, f"{image_id}.jpg")

            convert_voc_to_yolo(voc_annotation_file, yolo_label_file)
            if os.path.exists(voc_image_file):
                shutil.copy(voc_image_file, yolo_image_file)
            i+=1
            print('{}/{}'.format(i,len(os.listdir(voc_annotations_path))))

    print("转换完成!")

        在完成数据集格式的转换后还要对其进行划分,使用下面的代码将数据集划分为train,val,test

import os, shutil
from sklearn.model_selection import train_test_split


val_test_size = 0.2    #验证集占比
test_size = 0.5
postfix = 'jpg'
imgpath = 'datasets/VOC/images'    #数据集图像文件夹
txtpath =  'datasets/VOC/labels'   #数据集标签文件夹

output_folder = 'datasets\TestA'    #输出文件夹

output_train_img_folder = output_folder +'/images/train'
output_val_img_folder =  output_folder +'/images/val'
output_test_img_folder =  output_folder +'/images/test'
output_train_txt_folder =  output_folder +'/labels/train'
output_val_txt_folder =  output_folder +'/labels/val'
output_test_txt_folder =  output_folder +'/labels/test'

os.makedirs(output_train_img_folder, exist_ok=True)
os.makedirs(output_val_img_folder, exist_ok=True)
os.makedirs(output_test_img_folder, exist_ok=True)
os.makedirs(output_train_txt_folder, exist_ok=True)
os.makedirs(output_val_txt_folder, exist_ok=True)
os.makedirs(output_test_txt_folder, exist_ok=True)

listdir = [i for i in os.listdir(txtpath) if 'txt' in i]
train, val_test = train_test_split(listdir, test_size=val_test_size, shuffle=True, random_state=0)

test, val = train_test_split(val_test, test_size=test_size, shuffle=True, random_state=0)

idx = 0

for i in train:
    img_source_path = os.path.join(imgpath, '{}.{}'.format(i[:-4], postfix))
    txt_source_path = os.path.join(txtpath, i)

    img_destination_path = os.path.join(output_train_img_folder, '{}.{}'.format(i[:-4], postfix))
    txt_destination_path = os.path.join(output_train_txt_folder, i)

    shutil.copy(img_source_path, img_destination_path)
    shutil.copy(txt_source_path, txt_destination_path)
    idx += 1
    print('{}/{}'.format(idx,len(train)+len(val)+len(test)))

for i in val:
    img_source_path = os.path.join(imgpath, '{}.{}'.format(i[:-4], postfix))
    txt_source_path = os.path.join(txtpath, i)

    img_destination_path = os.path.join(output_val_img_folder, '{}.{}'.format(i[:-4], postfix))
    txt_destination_path = os.path.join(output_val_txt_folder, i)

    shutil.copy(img_source_path, img_destination_path)
    shutil.copy(txt_source_path, txt_destination_path)
    idx+=1
    print('{}/{}'.format(idx,len(train)+len(val)+len(test)))


for i in test:
    img_source_path = os.path.join(imgpath, '{}.{}'.format(i[:-4], postfix))
    txt_source_path = os.path.join(txtpath, i)

    img_destination_path = os.path.join(output_test_img_folder, '{}.{}'.format(i[:-4], postfix))
    txt_destination_path = os.path.join(output_test_txt_folder, i)

    shutil.copy(img_source_path, img_destination_path)
    shutil.copy(txt_source_path, txt_destination_path)
    idx+=1
    print('{}/{}'.format(idx,len(train)+len(val)+len(test)))
    
print('结束分割')

 二、配置文件

        接下来,需要为YOLO配置如下文件,以确保其能正常工作。

1.配置数据集

        数据集的映射关系如下图:

         为其配置一个yaml文件,包含数据集的路径,类别信息。

# 数据集的配置yaml文件

# 这里请写绝对路径,分别填入三个数据集中图像所在的位置
train: \yolov11\datasets\VOC\images\train  
val: \yolov11\datasets\VOC\images\val  
test: \yolov11\datasets\VOC\images\test  

# 类别数
nc: 6

# 类别名,请与之前转换时的序列保持一致
names: ['Boerner','Leconte','acuminatus','armandi','coleoptera','Linnaeus']

        2.配置模型

        新建一个yaml文件,你可以放在任何地方,这里为了方便管理放在了datasets目录下。且这个文件是官方提供的,不需要做过多更改:

# Ultralytics YOLO ????, AGPL-3.0 license
# YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 6 # 类别数,与之前保持一致
scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
  # [depth, width, max_channels]
#重点修改此位置,将你想要的那个模型配置放在第一位
  n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
  x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs
  s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
  m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
  l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs

# YOLO11n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
  - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
  - [-1, 2, C3k2, [256, False, 0.25]]
  - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
  - [-1, 2, C3k2, [512, False, 0.25]]
  - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
  - [-1, 2, C3k2, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
  - [-1, 2, C3k2, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]] # 9
  - [-1, 2, C2PSA, [1024]] # 10

# YOLO11n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  - [-1, 2, C3k2, [512, False]] # 13

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  - [-1, 2, C3k2, [256, False]] # 16 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 13], 1, Concat, [1]] # cat head P4
  - [-1, 2, C3k2, [512, False]] # 19 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 10], 1, Concat, [1]] # cat head P5
  - [-1, 2, C3k2, [1024, True]] # 22 (P5/32-large)

  - [[16, 19, 22], 1, Detect, [nc]] # Detect(P3, P4, P5)

三、开始训练

        编写一个训练脚本,然后直接运行它。

from ultralytics import YOLO

if __name__ == '__main__':
    # 加载模型
    #model = YOLO('datasets/yolo11s.pt')    #预训练权重
    model = YOLO(model='datasets/yolo11.yaml')
    # 训练模型
    train_results = model.train(
        data = 'datasets/VOC/VOC.yaml',   #数据集路径
        epochs = 100,        #训练轮次
        imgsz = 640,         #图片尺寸
        device = '0',        #使用设备
        batch = 16,
        name = 'Result',    #项目保存路径
    )
    

        训练完成后,训练结果将被放在yolov11\runs\detect目录下。