目录
训练自己的数据集分为4部分,先配置环境,再获取制作自己的数据集,然后修改配置训练,最后验证训练结果,附带可视化界面。YOLOv11为Ultralytics公司YOLO系列实时目标检测器的最新迭代版本,训练流程与YOLOv8基本一致,仅替换了新的网络结构与预训练权重,如果有其他目标检测的数据集可以直接拿来用,从第3训练模型开始看,新手小白0基础建议一步一步跟着来,哪里看不明白的或者遇到哪有问题可以发到评论区交流,我看到后都会及时回答~
1. 环境配置
在训练YOLOv11模型前环境必须配置完成,还不会配置环境的可以看我的这篇博客
环境配置完之后就可以使用自己的数据集训练,因此需要获取数据集。
点击下载训练源码 夸克网盘下载 ,建议先全部转存提前下载,若有需要下载的资源失效,可至公众号获取百度盘链接下载。
YOLOv11网络结构图,论文必备,无水印图可 微信公众号-笑脸惹桃花 回复“1111” 获取。
2. 数据集
数据集可以使用网上公开的跟自己研究相契合的数据集,或者是搜索/拍摄自己研究所需要的图片进行标注制作成数据集,这里两种方法都详细介绍一下,比如这里做一个安全帽检测的研究。
2.1 网上搜索公开数据集
使用网上公开的数据集,可供寻找的网站也有很多,这里仅介绍我使用过效果不错的网站
2.1.1 搜索引擎
最基础的搜索方式,需要做什么方面的研究就在上面搜索,
2.1.2 Kaggle
在搜索框输入安全帽的英文(因为是英文网站,都需要翻译成英文后搜索)Safety helmet (找不到结果可以多尝试不同的关键词)
搜索后就可以找到相关的内容,点击datasets筛选数据集,下载几个看一下数据集是否为目标检测的数据格式,一般文件夹为JPEGImages和Annotations包含这两个就可以使用
点进去查看相关数据是否符合要求,点击download即可下载。
2.1.3 Roboflow
该网站非常适合获取目标检测数据集,文件标注格式齐全,非常推荐使用,在搜索框输入安全帽的英文(因为是英文网站,都需要翻译成英文后搜索)Safety helmet (找不到结果可以多尝试不同的关键词),找到跟自己研究相关的
点进去后,可以看到关于数据集的介绍,我们点击左侧的Datasat,查看数据集。
点击右侧Download Dataset下载,该网站可自选下载格式,我们选择Pascal VOC格式的,格式转换起来也较为方便,下载的数据一般会划分好训练验证测试集,可以全部打乱重分也可以直接用划分好的。
若是下载到分割数据集,即json格式的标注可以看我的这篇文章转为txt
2.2 自制数据集
自制数据集需要先获取一定数量的目标图片,可以拍摄或者下载,图片足够之后使用标注工具Labelimg或者Labelme进行标注。
2.2.1 Labelimg安装
使用Labelimg建议使用python3.10以下的环境,这里创建一个python3.8的虚拟环境,不会创建的可以去看我这篇博客点击查看
conda create -n labelimg python=3.8
这里创建完之后进入labelimg环境
conda activate labelimg
进入labelimg环境之后通过pip下载labelimg(需要关闭加速软件)
pip install labelimg
安装完成之后就可以使用
2.2.2 Labelimg使用
在使用labelimg之前,需要准备好数据集存放位置,这里推荐创建一个大文件夹为data,里面有JPEGImages、Annotations和classes.txt,其中JPEGImages文件夹里面放所有的图片,Annotations文件夹是将会用来对标签文件存放,classes.txt里存放所有的类别,每种一行。
classes.txt里存放所有的类别,可以自己起名,需要是英文,如果有空格最好用下划线比如no_hat
上述工作准备好之后,在labelimg环境中cd到data目录下,如果不是在c盘需要先输入其他盘符+:
例如D: 回车之后再输入cd文件路径,接着输入以下命令打开labelimg
labelimg JPEGImages classes.txt
打开软件后可以看到左侧有很多按钮,open dir是选择图片文件夹,上面选过了
点击change save dir 切换到Annotations目录之中,点击save下面的图标切换到Pascal voc格式
切换好之后点击软件上边的view,将 Auto Save mode(切换到下一张图会自动保存标签)和Display Labels(显示标注框和标签) 保持打开状态。
常用快捷键:
A:切换到上一张图片
D:切换到下一张图片
W:调出标注十字架
del :删除标注框
例如,按下w调出标注十字架,标注完成之后选择对应的类别,这张图全部标注完后按d下一张
所有图像标注完成后数据集即制作完成,转换后的整体结构如下图。
2.3 数据集转换及划分
2.3.1 数据集VOC格式转yolo格式
如何查看自己数据集格式,打开Annotations文件夹,如果看到文件后缀为.xml,则为VOC格式,如果文件后缀为.txt则为yolo格式,后缀名看不到请搜索 如何显示文件后缀名。yolov11训练需要转为yolo格式训练,转换代码如下,一般txt放在labels文件夹中。
# 作者:CSDN-笑脸惹桃花 https://blog.csdn.net/qq_67105081?type=blog
# github:peng-xiaobai https://github.com/peng-xiaobai/Dataset-Conversion
import os
import xml.etree.ElementTree as ET
# 定义类别顺序
categories = ['hat','nohat']
category_to_index = {category: index for index, category in enumerate(categories)}
# 定义输入文件夹和输出文件夹
input_folder = r'f:\data\Annotations' # 替换为实际的XML文件夹路径
output_folder = r'f:\data\labels' # 替换为实际的输出TXT文件夹路径
# 确保输出文件夹存在
os.makedirs(output_folder, exist_ok=True)
# 遍历输入文件夹中的所有XML文件
for filename in os.listdir(input_folder):
if filename.endswith('.xml'):
xml_path = os.path.join(input_folder, filename)
# 解析XML文件
tree = ET.parse(xml_path)
root = tree.getroot()
# 提取图像的尺寸
size = root.find('size')
width = int(size.find('width').text)
height = int(size.find('height').text)
# 存储name和对应的归一化坐标
objects = []
# 遍历XML中的object标签
for obj in root.findall('object'):
name = obj.find('name').text
if name in category_to_index:
category_index = category_to_index[name]
else:
continue # 如果name不在指定类别中,跳过该object
bndbox = obj.find('bndbox')
xmin = int(bndbox.find('xmin').text)
ymin = int(bndbox.find('ymin').text)
xmax = int(bndbox.find('xmax').text)
ymax = int(bndbox.find('ymax').text)
# 转换为中心点坐标和宽高
x_center = (xmin + xmax) / 2.0
y_center = (ymin + ymax) / 2.0
w = xmax - xmin
h = ymax - ymin
# 归一化
x = x_center / width
y = y_center / height
w = w / width
h = h / height
objects.append(f"{category_index} {x} {y} {w} {h}")
# 输出结果到对应的TXT文件
txt_filename = os.path.splitext(filename)[0] + '.txt'
txt_path = os.path.join(output_folder, txt_filename)
with open(txt_path, 'w') as f:
for obj in objects:
f.write(obj + '\n')
需要自行将类别替换,这里顺序要记住,文件夹也对应替换
2.3.2 数据集划分
训练自己的yolov11检测模型,数据集需要划分为训练集、验证集和测试集,这里提供一个参考代码,划分比例为8:1:1,也可以按照自己的比例划分,获取的数据集划分过了则不用重复划分。
# 作者:CSDN-笑脸惹桃花 https://blog.csdn.net/qq_67105081?type=blog
# github:peng-xiaobai https://github.com/peng-xiaobai/Dataset-Conversion
import os
import shutil
import random
# random.seed(0) #随机种子,可自选开启
def split_data(file_path, label_path, new_file_path, train_rate, val_rate, test_rate):
images = os.listdir(file_path)
labels = os.listdir(label_path)
images_no_ext = {os.path.splitext(image)[0]: image for image in images}
labels_no_ext = {os.path.splitext(label)[0]: label for label in labels}
matched_data = [(img, images_no_ext[img], labels_no_ext[img]) for img in images_no_ext if img in labels_no_ext]
unmatched_images = [img for img in images_no_ext if img not in labels_no_ext]
unmatched_labels = [label for label in labels_no_ext if label not in images_no_ext]
if unmatched_images:
print("未匹配的图片文件:")
for img in unmatched_images:
print(images_no_ext[img])
if unmatched_labels:
print("未匹配的标签文件:")
for label in unmatched_labels:
print(labels_no_ext[label])
random.shuffle(matched_data)
total = len(matched_data)
train_data = matched_data[:int(train_rate * total)]
val_data = matched_data[int(train_rate * total):int((train_rate + val_rate) * total)]
test_data = matched_data[int((train_rate + val_rate) * total):]
# 处理训练集
for img_name, img_file, label_file in train_data:
old_img_path = os.path.join(file_path, img_file)
old_label_path = os.path.join(label_path, label_file)
new_img_dir = os.path.join(new_file_path, 'train', 'images')
new_label_dir = os.path.join(new_file_path, 'train', 'labels')
os.makedirs(new_img_dir, exist_ok=True)
os.makedirs(new_label_dir, exist_ok=True)
shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
# 处理验证集
for img_name, img_file, label_file in val_data:
old_img_path = os.path.join(file_path, img_file)
old_label_path = os.path.join(label_path, label_file)
new_img_dir = os.path.join(new_file_path, 'val', 'images')
new_label_dir = os.path.join(new_file_path, 'val', 'labels')
os.makedirs(new_img_dir, exist_ok=True)
os.makedirs(new_label_dir, exist_ok=True)
shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
# 处理测试集
for img_name, img_file, label_file in test_data:
old_img_path = os.path.join(file_path, img_file)
old_label_path = os.path.join(label_path, label_file)
new_img_dir = os.path.join(new_file_path, 'test', 'images')
new_label_dir = os.path.join(new_file_path, 'test', 'labels')
os.makedirs(new_img_dir, exist_ok=True)
os.makedirs(new_label_dir, exist_ok=True)
shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
print("数据集已划分完成")
if __name__ == '__main__':
file_path = r"f:\data\JPEGImages" # 图片文件夹
label_path = r'f:\data\labels' # 标签文件夹
new_file_path = r"f:\VOCdevkit" # 新数据存放位置
split_data(file_path, label_path, new_file_path, train_rate=0.8, val_rate=0.1, test_rate=0.1)
代码可以自动划分各种格式的图片及标签文件,且无论图片及标签数量是否对应,均会对应移动到相同的文件夹下,同时给出出现差异的图片或标签文件名,方便小白快速查找原因。划分完成之后数据集的准备工作就好了,具体的目录结构如下图,我们一般导入到images,labels会自动寻找。
3. 训练模型
需要下载源码,这里选择的是yolov11 v8.3.20版本的,本文演示所用的安全帽检测数据集点此下载,注意,此数据集的两个标签分别为 'person','hat' 。
不会下载源码的可以看我的这篇博客 查看源码文章 ,也可以点击下载代码 夸克网盘下载 ,我上传了多版本可以全部转存避免后续找不到,cat图片一并上传,下载8.3.0及以上版本,(压缩包内附带yolov11n.pt、yolov11s.pt和yolov11m.pt预训练权重,链接资源失效请评论区反馈,看到会补,或者至公众号下载)可以下载下图所示几个预训练权重文件,常规使用yolov11n.pt即可。
有了源码之后需要修改里面的参数,导入自己的数据集。
3.1 创建data.yaml
在yolov11根目录下(也就是本文所用的ultralytics-8.3.20目录下)创建一个新的data.yaml文件,也可以是其他名字的例如hat.yaml文件,文件名可以变但是后缀需要为.yaml,内容如下,文件夹路径分别修改为前边划分后数据集的路径。test可有可无
train: f:/VOCdevkit/train/images # train images (relative to 'path') 128 images
val: f:/VOCdevkit/val/images # val images (relative to 'path') 128 images
test: f:/VOCdevkit/test/images
nc: 2
# Classes
names: ['hat','nohat']
其他路径和类别自己替换,需要和上面数据集转换那里类别顺序一致。
3.2 训练模型
这是使用官方提供的预训练权重进行训练,使用yolov11n.pt,也可以使用yolov11s.pt,模型大小n<s<m<l<x,训练时长成倍增加,官方的命名为yolo11,本文yolov11与yolo11指代相同。
下载完成之后放入ultralytics-8.3.20根目录中,创建一个yolov11_train.py文件,内容如下,关闭amp训练。
import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO
if __name__ == '__main__':
model = YOLO('ultralytics/cfg/models/11/yolo11n.yaml')
model.load('yolo11n.pt') #注释则不加载
results = model.train(
data='data.yaml', #数据集配置文件的路径
epochs=200, #训练轮次总数
batch=16, #批量大小,即单次输入多少图片训练
imgsz=640, #训练图像尺寸
workers=8, #加载数据的工作线程数
device= 0, #指定训练的计算设备,无nvidia显卡则改为 'cpu'
optimizer='SGD', #训练使用优化器,可选 auto,SGD,Adam,AdamW 等
amp= True, #True 或者 False, 解释为:自动混合精度(AMP) 训练
cache=False # True 在内存中缓存数据集图像,服务器推荐开启
)
这里用哪个模型对应哪个yaml,如果使用yolov11s.pt则对应yolo11s.yaml
epochs是训练轮数,可以由少变多看训练效果,workers和batch根据电脑性能进行调整,如果运行吃力则相应降低,最好为2的n次方。没有显卡则把device=0修改为device='cpu' 。
也可以使用命令行执行训练
yolo task=detect mode=train model=yolo11n.yaml pretrained=yolo11n.pt data=data.yaml epochs=200 imgsz=640 device=0 optimizer='SGD' workers=8 batch=64 amp=False cache=False
训练过程如图,耐心等待训练完成即可,训练完成后会生成.pt权重文件,可以用来验证训练效果。
训练模型过程中有任何报错可以发在评论区交流~
4. 模型测试
找到之前训练的结果保存路径,创建一个yolov11_predict.py文件,内容如下
from ultralytics import YOLO
# 加载训练好的模型,改为自己的路径
model = YOLO('runs/detect/train/weights/best.pt') #修改为训练好的路径
source = 'test1.jpg' #修改为自己的图片路径及文件名
# 运行推理,并附加参数
model.predict(source, save=True)
运行后就会得到预测模型结果
或者使用命令行指令进行预测,权重和图片路径自己修改。
yolo predict model=runs/detect/train/weights/best.pt source='test1.jpg'
可以打开对应路径下查看预测的图片效果,模型就训练好啦~
测试集上推理模型精度代码如下,可新增v11_val.py,输入下方代码,更改模型路径及数据集路径即可。
import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO
if __name__ == '__main__':
model = YOLO('runs/detect/train/weights/best.pt') #修改为自己训练的模型路径
model.val(data='hat.yaml', #修改为自己的数据集yaml文件
split='test',
imgsz=640,
batch=16,
iou=0.6, #阈值可以改,mAP50为0.5的情况下
conf=0.001,
workers=8,
)
运行后即出现测试集上各类别的精度及总体精度。
5. 可视化界面
很多同学的需求是制作出一个可视化界面ui作为系统来展示预测的效果,这里我分享了两个简单的图片预测的界面,导入模型权重文件和图片就可以进行预测并展示,pyqt5写的可以参考这篇文章 点击这里 ,界面如下
免费的功能较为简单,只有图片检测显示。
写了一个进阶版的程序,可以对图片,视频和本地及云摄像头进行检测并展示,pyside6和pyqt5界面如下。感兴趣可以通过公众号获取,需要定制系统也可以联系我。
遇到报错可以打开评论区交流。 关注微信公众号 快速联系我~