Datawhale AI夏令营第五期魔搭-CV竞赛方向Task1笔记–初识yolo模型
作者: 福州大学 我是一个温柔的刀客
2024/8/22
1. 赛题简介
本赛题最终目标是开发一套智能识别系统,能够自动检测和分类城市管理中的违规行为。该系统应利用先进的图像处理和计算机视觉技术,通过对摄像头捕获的视频进行分析,自动准确识别违规行为,并及时向管理部门发出告警,以实现更高效的城市管理。
本质上是属于CV中的目标检测题型.
下面是深度学习的两个主流的应用方向分流:
2. 初识YOLO模型
2.1 概念
YOLO,全称为“You Only Look Once”(你只看一眼),是一种流行的实时目标检测系统,由Joseph Redmon等人在2015年提出。YOLO模型的核心思想是将目标检测任务视为一个单一的回归问题,通过一个卷积神经网络(CNN)直接从图像像素到边界框坐标和类别概率的映射。YOLO模型经过了多次迭代,包括YOLOv2(YOLO9000)、YOLOv3和YOLOv4等版本,每个版本都在性能和速度上有所提升,同时也引入了一些新的技术,如更深的网络结构、更好的锚框机制、多尺度特征融合等。
2.2 YOLO模型所需要的训练格式
YOLO (You Only Look Once) 模型的训练通常需要特定的数据格式和组织结构。为了训练YOLO模型,需要准备数据集,并按照特定的格式进行标注,通常需要三个组成部分: 图像文件,标注文件,配置文件.
2.2.1 图像文件
包含了物体的视觉信息,比如颜色、形状、纹理、大小等。这些视觉信息对于训练一个能够识别和区分不同物体的模型至关重要。模型通过学习这些特征来识别物体并进行分类。
2.2.2 标注文件
包含了每个物体在图像中的位置信息,通常是以边界框的形式给出。边界框由四个坐标值组成,即左上角的(x, y)坐标和右下角的(x, y)坐标。此外,标注文件还会包含每个物体的类别标签。
标注文件与图像文件一一对应,用于指示图像中目标物体的位置和类别。标注文件通常使用 .txt
格式,每行代表一个物体的标签信息,格式如下:
<object_class> <x_center> <y_center> <width> <height>
其中:
<object_class>
:目标物体所属的类别编号。
<x_center>
、<y_center>
:目标物体边界框中心相对于图像尺寸的比例坐标。
<width>
、<height>
:目标物体边界框宽度和高度相对于图像尺寸的比例。
举个例子:
假设你有一张名为 image1.jpg
的图像文件,其中包含一只猫和一只狗,图像尺寸为640x480像素。对应的标注文件 image1.txt
可能如下所示:
0 0.3 0.4 0.2 0.3 # 猫,类别编号为0
1 0.7 0.6 0.15 0.2 # 狗,类别编号为1
这里的数字表示:
-
类别编号:0 表示猫,1 表示狗。
-
<x_center>
、<y_center>
:中心点的坐标相对于图像尺寸的比例,例如0.3和0.4表示猫的中心点在图像中的相对位置。 -
<width>
、<height>
:边界框的宽度和高度相对于图像尺寸的比例。
2.2.3 配置文件
配置文件通常分为两种:数据配置文件和模型配置文件.
数据配置文件:
数据配置文件通常使用 .data
扩展名,用于指定类别列表、训练和验证数据集路径等信息。
.data
文件扩展名通常用于表示数据文件,这类文件用于存储数据集的信息、模型训练所需的数据配置以及其他与数据相关的元数据。在不同的上下文中,.data
文件的具体内容和格式可能会有所不同。
示例:
classes= 20 # 类别数量
train = data/train.txt # 训练集图像列表文件路径
valid = data/valid.txt # 验证集图像列表文件路径
names = data/names.txt # 类别名称列表文件路径
backup = backup/ # 模型权重保存路径
模型配置文件:
模型配置文件通常使用 .cfg
扩展名,包含了模型架构的细节,如卷积层的数量、过滤器的数量、步长等。
.cfg
是文件扩展名的一种,通常用于表示配置文件(configuration file)。
示例:
[net] # net部分定义了整个网络的基本设置
batch=64 # 批次大小
subdivisions=16 # 每个批次被分成的子批次次数
width=416 # 输入图像的宽度
height=416 # 输入图像的高度
channels=3 # 彩色图像的通道数
momentum=0.9 # 动量
decay=0.0005 # 权重衰减
angle=0 # 角度数据增强
saturation = 1.5 # 饱和度数据增强
exposure = 1.5 # 曝光度数据增强
hue=.1 # 色调数据增强
[convolutional] # [convolutional] 卷积层
batch_normalize=1 # 是否使用批量归一化
filters=32 # 卷积层中的过滤器数量
size=3 # 卷积核大小
stride=1 # 步长
pad=1 # 是否使用填充(1为True,0为False)
activation=leaky # 激活函数类型
2.3 数据集
在机器学习项目中,通常会把数据集划分为三个主要的部分:训练集(Training Set)、验证集(Validation Set)和测试集(Test Set)。这些数据集的不同划分有助于确保模型能够很好地泛化到未见过的新数据上。下面是这三个部分的主要区别:
-
训练集 (Training Set)
- 目的:用于训练模型,即让模型学习如何从输入数据中提取特征,并据此做出预测。
- 使用方式:直接用于调整模型的权重和偏差等参数,以便模型能够学会数据中的模式。
- 特点:通常是数据集中最大的一部分。
-
验证集 (Validation Set)
- 目的:用于调整模型的超参数(如学习率、正则化参数等),并选择最佳模型版本。
- 使用方式:在训练过程中,周期性地使用验证集评估模型性能,以防止过拟合。这有助于找到最优的模型配置。
- 特点:一般较小,但足够大以便能给出模型性能的可靠估计。
-
测试集 (Test Set)
- 目的:用于最终评估模型的泛化能力,即模型在从未见过的新数据上的表现。
- 使用方式:在模型训练完成之后,使用测试集来评估模型的最终性能。理想情况下,在这个阶段之前测试集的数据不应该被用来做任何训练或调整。
- 特点:通常较小,但需要保持足够的代表性,以准确反映模型的真实性能。
如何划分数据集
- 比例:常见的划分比例包括 60% 训练 / 20% 验证 / 20% 测试 或者 70% 训练 / 15% 验证 / 15% 测试。这些比例可以根据具体项目的需求进行调整。
- 随机抽取:数据集通常会被随机打乱,然后按照上述比例划分,以确保每个子集都具有代表性和多样性。
- 保持一致性:如果数据集包含类别标签,则在划分时要确保各个子集中的类别分布一致,避免偏差。
注意事项
- 交叉验证:为了更充分地利用数据并减少对单个验证集划分的依赖,可以采用交叉验证(Cross-Validation)的方法。例如,k-折交叉验证(K-Fold Cross-Validation)将数据分成k个相等的部分,每次使用其中一个作为验证集,其余作为训练集,重复k次后平均结果。
通过这种方式划分数据集,可以有效地评估模型的学习能力和泛化能力,从而帮助构建更可靠的机器学习系统。
3.数据集代码
# 读取训练集视频.
for anno_path, video_path in zip(train_annos[:5], train_videos[:5]):
print(video_path)
anno_df = pd.read_json(anno_path)
cap = cv2.VideoCapture(video_path)
frame_idx = 0
# 读取视频所有画面变成一帧帧画面.
while True:
ret, frame = cap.read()
if not ret:
break
img_height, img_width = frame.shape[:2]
# 将一帧帧的画面写为数据集的一幅幅图.
frame_anno = anno_df[anno_df['frame_id'] == frame_idx]
cv2.imwrite('./yolo-dataset/train/' + anno_path.split('/')[-1][:-5] + '_' + str(frame_idx) + '.jpg', frame)
# 如果存在标注,则将标注信息写入到一个文本文件中,以便于后续训练yolo模型.
if len(frame_anno) != 0:
with open('./yolo-dataset/train/' + anno_path.split('/')[-1][:-5] + '_' + str(frame_idx) + '.txt', 'w') as up:
for category, bbox in zip(frame_anno['category'].values, frame_anno['bbox'].values):
category_idx = category_labels.index(category)
# 计算yolo标注格式,即格式化数据.
x_min, y_min, x_max, y_max = bbox
x_center = (x_min + x_max) / 2 / img_width
y_center = (y_min + y_max) / 2 / img_height
width = (x_max - x_min) / img_width
height = (y_max - y_min) / img_height
if x_center > 1:
print(bbox)
up.write(f'{category_idx} {x_center} {y_center} {width} {height}\n')
# 更新帧的索引,进入下一帧的while循环.
frame_idx += 1
这段代码的主要功能是从视频中提取帧,并将每个帧连同其标注转换为 YOLO 格式的数据集。每个帧被保存为 JPEG 图像,而其标注则被保存为相应的 .txt
文件,每行包含一个边界框的 YOLO 格式标注信息。这些文件会被保存在一个指定的目录中,从而构建出整个 YOLO 数据集。
代码解读:
1. ```for anno_path, video_path in zip(train_annos[:5], train_videos[:5]):```
- `train_annos` 和 `train_videos` 分别是包含训练集的标注文件路径和视频文件路径的列表。这里使用了 Python 的 `zip` 函数来同时迭代这两个列表,并且只处理前五个元素。
2. ```print(video_path)```
- 打印当前处理的视频文件路径。
3. ```anno_df = pd.read_json(anno_path)```
- 使用 Pandas 的 `read_json` 方法读取标注文件到一个 DataFrame 中。
4. ```cap = cv2.VideoCapture(video_path)```
- 创建一个 OpenCV 的 `VideoCapture` 对象,用来读取视频文件。
5. ```frame_idx = 0```
- 初始化帧索引。
6. ```while True:```
- 开始一个循环,直到视频结束。
7. ```ret, frame = cap.read()```
- 读取视频的下一帧。`ret` 是一个布尔值,指示是否成功读取帧;`frame` 是帧的内容。
8. ```if not ret: break```
- 如果无法读取下一帧,则跳出循环。
9. ```img_height, img_width = frame.shape[:2]```
- 获取帧的高度和宽度。
10. ```cv2.imwrite(...)```
- 将当前帧保存为 JPEG 图像文件。
11. ```frame_anno = anno_df[anno_df['frame_id'] == frame_idx]```
- 从标注 DataFrame 中筛选出对应当前帧的标注数据。
12. ```if len(frame_anno) != 0:```
- 如果该帧有标注,则继续执行下面的代码。
13. ```with open(...) as up:```
- 打开一个文本文件,准备写入 YOLO 格式的标注。
14. ```for category, bbox in zip(...):```
- 遍历该帧的所有标注。
15. ```category_idx = category_labels.index(category)```
- 获取类别标签对应的索引号。
16. ```x_min, y_min, x_max, y_max = bbox```
- 解包边界框坐标。
17. ```x_center, y_center, width, height```
- 计算 YOLO 标注所需的中心点坐标和宽高比例。
18. ```if x_center > 1: print(bbox)```
- 检查计算是否正确。如果 `x_center` 大于 1,则打印边界框坐标。
19. ```up.write(...)```
- 写入 YOLO 格式的标注到文件中。
20. ```frame_idx += 1```
- 更新帧索引。
4. YOLO模型的训练
Ultraalytics 是一个提供多种计算机视觉模型的库,包括 YOLO 系列。这段代码是一个简单的训练启动示例。
from ultralytics import YOLO
# 设置模型版本
model = YOLO("yolov8n.pt")
# 设定数据集和训练参数
results = model.train(data="yolo-dataset/yolo.yaml", epochs=2, imgsz=1080, batch=16)
# epoch指定了训练的总轮数 imgsz指定了训练图像的大小 batch指定了每个批次处理的图像数量,较大的批次可以加快训练速度,但也需要更多的内存。
box_loss
是边界框回归损失,用于评估预测的边界框与真实边界框之间的差异。cls_loss
是分类损失,用于评估类别预测的准确性。dfl_loss
是防御性损失,用于提高模型的泛化能力。
防御性损失:在机器学习和深度学习中,有一些方法和技术可以被视为“防御性”的措施,以保护模型免受对抗性攻击、过拟合等问题的影响。
泛化能力:泛化能力(Generalization Ability)是指机器学习模型在未见过的新数据上的表现能力。这是机器学习领域中一个非常重要的概念,因为它直接关系到模型的实际应用效果。
从输出结果来看,经过两个训练周期后,模型的边界框损失、分类损失和防御性损失都有所下降,这表明模型在训练过程中学习了如何更好地预测边界框和分类。同时,模型的 mAP50 和 mAP50-95 指标也有所提高,这表明模型的整体性能有所提升。
附:YOLO学习指南