2. 9月11日 YOLO环境安装与数据准备
2. 9月11日 YOLO环境安装与数据准备
YOLO介绍
YOLO(You Only Look Once)是一种流行的目标检测算法,它的核心思想是将目标检测任务转换为一个单次推断问题。与传统的目标检测方法不同,YOLO算法通过一个统一的神经网络同时预测图像中的目标位置和类别。这种设计使得YOLO能够实现快速且高效的目标检测,特别适合于需要实时处理的场景,如视频监控、自动驾驶等。
YOLOv8作为该系列的最新版本,进一步优化了检测精度和速度,使其在多个应用场景中表现出色。本专栏将带领大家从0开始学习,有兴趣的小伙伴们可以点个关注~
YOLOv8性能评估
在COCO数据集上的评估结果显示,YOLOv8在检测精度和速度上均优于前几代模型。下表展示了YOLOv8与其他版本在COCO数据集上的性能对比:
| Model | mAP (mean Average Precision) | FPS (Frames Per Second) |
|---|---|---|
| YOLOv5 | 0.48 | 140 |
| YOLOv6 | 0.52 | 120 |
| YOLOv7 | 0.56 | 110 |
| YOLOv8 | 0.60 | 100 |
mAP(mean Average Precision)是一个在目标检测任务中常用的性能评估指标。它衡量的是模型在识别图像中的对象时的准确性和一致性。mAP计算了在不同召回率水平上的平均精度,通常用于比较不同模型的性能。具体来说,对于目标检测任务,mAP是所有类别的AP的平均值,其中AP(Average Precision)是指在某个特定召回率下,模型预测正确的正样本数与所有预测为正的样本数之比的平均值。在实际应用中,mAP越高,表示模型的检测性能越好。
FPS(Frames Per Second)则是用来衡量视频播放或游戏运行流畅度的一个指标,表示每秒钟能够渲染和显示的帧数。在视频和游戏领域,FPS越高,画面的流畅度越好。对于实时视频处理或游戏开发来说,高FPS是必要的,因为它能够提供更平滑和响应更快的用户体验。在目标检测模型中,FPS也是一个重要的性能指标,特别是在需要实时处理视频流的应用中,如视频监控、自动驾驶等。
一、环境准备
1. Anaconda
Anaconda 是一个开源的 Python 和 R 语言的发行版,致力于简化数据科学、机器学习、人工智能和大数据的包管理和部署。它包含了大量流行的数据科学包,并且通过 Conda 包管理器提供了便捷的包安装、更新和管理方式。
https://www.anaconda.com/download
2. 创建yolov8虚拟环境
在电脑左下角搜索Anaconda,点击打开Anaconda Prompt

创建新的虚拟环境yolov8
conda create -n yolov8 python=3.8
激活yolov8环境
conda activate yolov8
二、yolov8模型下载
Ultralytics 的 YOLOv8 是一款前沿的尖端模型,它在以前的 YOLO 版本基础上取得了成功,并引入了新特性与改进,以进一步提升性能和灵活性。YOLOv8 设计得既快速又精确,易于使用,适用于广泛的对象检测与跟踪、实例分割、图像分类及姿态估计任务。
pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple/
下载训练模型

三、准备数据集
之前标注做的不好,
本次用现成的
安全帽检测数据集 (Helmet Detection)_数据集-飞桨AI Studio星河社区 (baidu.com)

1. 将xml转成txt文件
将标注文件转换为YOLO格式。YOLO格式的标注文件内容如下:
<class_id> <x_center> <y_center> <width> <height>



import xml.etree.ElementTree as ET
import os
def convert(size, box):
x_center = (box[0] + box[1]) / 2.0
y_center = (box[2] + box[3]) / 2.0
#分别计算纵坐标和横坐标的中心点
x = x_center / size[0]
y = y_center / size[1]
w = (box[1] - box[0]) / size[0]
h = (box[3] - box[2]) / size[1]
# print(x, y, w, h)
return (x, y, w, h)
def convert_annotation(xml_files_path, save_txt_files_path, classes):
xml_files = os.listdir(xml_files_path)
print(xml_files)
for xml_name in xml_files:
print(xml_name)
xml_file = os.path.join(xml_files_path, xml_name)
out_txt_path = os.path.join(save_txt_files_path, xml_name.split('.')[0] + '.txt')
out_txt_f = open(out_txt_path, 'w')
tree = ET.parse(xml_file)
root = tree.getroot()
size = root.find('size')
w = int(size.find('width').text)
h = int(size.find('height').text)
for obj in root.iter('object'):
difficult = obj.find('difficult').text
cls = obj.find('name').text
if cls not in classes or int(difficult) == 1:
continue
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))
# b=(xmin, xmax, ymin, ymax)
print(w, h, b)
bb = convert((w, h), b)
out_txt_f.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')
if __name__ == "__main__":
# 1、指定yolo类别
classes1 = ["helmet","head"]
# 2、voc格式的xml标签文件路径
xml_files1 = r'D:\yolo_test\HelmetDetection\annotations'
# 3、转化为yolo格式的txt标签文件存储路径
save_txt_files1 = r'D:\yolo_test\HelmetDetection\labels'
convert_annotation(xml_files1, save_txt_files1, classes1)
with open(save_txt_files1 + '/classes.txt', 'w') as file:
for class_name in classes1:
file.write(class_name + '\n')
2. 划分数据集
在机器学习和计算机视觉领域,特别是在深度学习模型的训练过程中,通常会将数据集划分为几个部分,以确保模型的有效性和泛化能力。这四个部分:test、train、trainval、val,各自扮演不同的角色:
- train(训练集):
- 训练集是用于训练模型的数据集部分。
- 模型通过学习训练集中的样本来调整参数。
- 在深度学习中,训练集通常包含大量标注好的数据,用于网络的迭代训练。
- val(验证集):
- 验证集用于在训练过程中评估模型的性能,但不参与训练。
- 它帮助我们监控模型在看不见的数据上的表现,从而避免过拟合。
- 验证集独立于训练集,可以用来进行超参数调整和模型选择。
- test(测试集):
- 测试集用于在模型训练完成后最终评估模型的性能。
- 它应该完全独立于训练过程,只在最后评估时使用一次。
- 测试集可以看作是模型部署前的最后一道检验。
在实际应用中,数据的划分比例可以根据具体任务和数据量来决定。常见的划分比例有:
- 70% 训练集,15% 验证集,15% 测试集
- 80% 训练集,10% 验证集,10% 测试集
- 或者其他根据需要调整的比例
正确地划分数据集对于构建一个健壮、可靠的机器学习模型至关重要。
import os
import random
import shutil
import time
import yaml
class YOLOTrainDataSetGenerator:
def __init__(self, origin_dataset_dir, train_dataset_dir, train_ratio=0.7, val_ratio=0.15, test_ratio=0.15,
clear_train_dir=False):
# 设置随机数种子
random.seed(1233)
self.origin_dataset_dir = origin_dataset_dir
self.train_dataset_dir = train_dataset_dir
self.train_ratio = train_ratio
self.val_ratio = val_ratio
self.test_ratio = test_ratio
self.clear_train_dir = clear_train_dir
assert self.train_ratio > 0.5, 'train_ratio must larger than 0.5'
assert self.val_ratio > 0.01, 'train_ratio must larger than 0.01'
assert self.test_ratio > 0.01, 'test_ratio must larger than 0.01'
total_ratio = round(self.train_ratio + self.val_ratio + self.test_ratio)
assert total_ratio == 1.0, 'train_ratio + val_ratio + test_ratio must equal 1.0'
def generate(self):
time_start = time.time()
# 原始数据集的图像目录,标签目录,和类别文件路径
origin_image_dir = os.path.join(self.origin_dataset_dir, 'images')
origin_label_dir = os.path.join(self.origin_dataset_dir, 'labels')
origin_classes_file = os.path.join(self.origin_dataset_dir, 'classes.txt')
if not os.path.exists(origin_classes_file):
return
else:
origin_classes = {}
with open(origin_classes_file, mode='r') as f:
for cls_id, cls_name in enumerate(f.readlines()):
cls_name = cls_name.strip()
if cls_name != '':
origin_classes[cls_id] = cls_name
# 获取所有原始图像文件名(包括后缀名)
origin_image_filenames = os.listdir(origin_image_dir)
# 随机打乱文件名列表
random.shuffle(origin_image_filenames)
# 计算训练集、验证集和测试集的数量
total_count = len(origin_image_filenames)
train_count = int(total_count * self.train_ratio)
val_count = int(total_count * self.val_ratio)
test_count = total_count - train_count - val_count
# 定义训练集文件夹路径
if self.clear_train_dir and os.path.exists(self.train_dataset_dir):
shutil.rmtree(self.train_dataset_dir, ignore_errors=True)
train_dir = os.path.join(self.train_dataset_dir, 'train')
val_dir = os.path.join(self.train_dataset_dir, 'val')
test_dir = os.path.join(self.train_dataset_dir, 'test')
train_image_dir = os.path.join(train_dir, 'images')
train_label_dir = os.path.join(train_dir, 'labels')
val_image_dir = os.path.join(val_dir, 'images')
val_label_dir = os.path.join(val_dir, 'labels')
test_image_dir = os.path.join(test_dir, 'images')
test_label_dir = os.path.join(test_dir, 'labels')
# 创建训练集输出文件夹
os.makedirs(train_image_dir, exist_ok=True)
os.makedirs(train_label_dir, exist_ok=True)
os.makedirs(val_image_dir, exist_ok=True)
os.makedirs(val_label_dir, exist_ok=True)
os.makedirs(test_image_dir, exist_ok=True)
os.makedirs(test_label_dir, exist_ok=True)
# 将图像和标签文件按设定的ratio划分到训练集,验证集,测试集中
for i, filename in enumerate(origin_image_filenames):
if i < train_count:
output_image_dir = train_image_dir
output_label_dir = train_label_dir
elif i < train_count + val_count:
output_image_dir = val_image_dir
output_label_dir = val_label_dir
else:
output_image_dir = test_image_dir
output_label_dir = test_label_dir
src_img_name_no_ext = os.path.splitext(filename)[0]
src_image_path = os.path.join(origin_image_dir, filename)
src_label_path = os.path.join(origin_label_dir, src_img_name_no_ext + '.txt')
if os.path.exists(src_label_path):
# 复制图像文件
dst_image_path = os.path.join(output_image_dir, filename)
shutil.copy(src_image_path, dst_image_path)
# 复制标签文件
src_label_path = os.path.join(origin_label_dir, src_img_name_no_ext + '.txt')
dst_label_path = os.path.join(output_label_dir, src_img_name_no_ext + '.txt')
shutil.copy(src_label_path, dst_label_path)
else:
pass
train_dir = os.path.normpath(train_dir)
val_dir = os.path.normpath(val_dir)
test_dir = os.path.normpath(test_dir)
data_dict = {
'train': train_dir,
'val': val_dir,
'test': test_dir,
'nc': len(origin_classes),
'names': origin_classes
}
yaml_file_path = os.path.normpath(os.path.join(self.train_dataset_dir, 'data.yaml'))
with open(yaml_file_path, mode='w') as f:
yaml.safe_dump(data_dict, f, default_flow_style=False, allow_unicode=True)
if __name__ == '__main__':
g_origin_dataset_dir = r'D:\yolo_test\HelmetDetection'
g_train_dataset_dir = r'D:\yolo_test\test'
g_train_ratio = 0.7
g_val_ratio = 0.15
g_test_ratio = 0.15
yolo_generator = YOLOTrainDataSetGenerator(g_origin_dataset_dir, g_train_dataset_dir, g_train_ratio, g_val_ratio,
g_test_ratio, True)
yolo_generator.generate()
四、最终文件夹分布
