原文链接:
Object Detection with YOLO: Hands-on Tutorial - neptune.ai
https://neptune.ai/blog/object-detection-with-yolo-hands-on-tutorial
目标检测作为计算机视觉中的一项任务
我们在生活中每天都会遇到物体。环顾四周,您会发现周围有多个物体。作为人类,您可以轻松检测和识别您看到的每个物体。这是自然的,不需要太多努力。
然而,对于计算机来说,检测物体是一项需要复杂解决方案的任务。对于计算机而言,“检测对象”意味着处理输入图像(或视频中的单个帧)并使用有关图像上的对象及其位置的信息进行响应。在计算机视觉方面,我们将这两个任务称为分类和定位。我们希望计算机说出给定图像上呈现的对象类型以及它们的确切位置。
已经开发了多种解决方案来帮助计算机检测物体。今天,我们将探索一种称为 YOLO 的最先进算法,它可以在实时速度下实现高精度。特别是,我们将学习如何在 TensorFlow / Keras 中的自定义数据集上训练此算法。
首先,让我们看看YOLO到底是什么以及它以什么闻名。
YOLO 作为实时物体检测器
什么是YOLO?
YOLO 是“You Only Look Once”的首字母缩写词(不要将它与《辛普森一家》中的 You Only Live Once混淆)。顾名思义,一次“查看”就足以找到图像上的所有对象并识别它们。
在机器学习术语中,我们可以说所有对象都是通过一次算法运行检测到的。它是通过将图像划分为网格并预测网格中每个单元格的边界框和类别概率来完成的。如果我们想使用 YOLO 进行汽车检测,则网格和预测的边界框可能如下所示:
上图仅包含过滤后获得的最终框集。值得注意的是,YOLO 的原始输出包含许多同一个对象的边界框。这些盒子的形状和大小各不相同。如下图所示,一些框在捕获目标对象方面做得更好,而算法提供的其他框则表现不佳。
为了选择给定对象的最佳边界框,应用了非最大抑制 (NMS)算法。
YOLO 预测的所有框都有一个与之相关的置信水平。NMS 使用这些置信度值来移除那些低确定性预测的框。通常,这些都是以低于 0.5 的置信度预测的框。
当所有不确定的边界框都被移除后,只剩下置信度高的框。为了在表现最好的候选者中选择最好的一个,NMS 选择具有最高置信度的框并计算它如何与周围的其他框相交。如果交叉点高于特定阈值级别,则删除置信度较低的边界框。如果 NMS 比较两个具有低于选定阈值的交集的框,则两个框都保留在最终预测中。
YOLO 与其他检测器相比
尽管在 YOLO 的引擎盖下使用了卷积神经网络 (CNN),但它仍然能够以实时性能检测对象。这要归功于 YOLO 能够在单阶段方法中同时进行预测。
其他较慢的对象检测算法(如Faster R-CNN)通常使用两阶段方法:
- 在第一阶段,选择有兴趣的图像区域。这些是图像中可能包含任何对象的部分;
- 在第二阶段,每个区域都使用卷积神经网络进行分类。
通常,图像上有很多区域带有对象。所有这些区域都被发送到分类。分类是一项耗时的操作,这就是为什么两阶段目标检测方法与单阶段检测相比执行速度较慢的原因。
YOLO 不会选择图像中有趣的部分,没有必要这样做。相反,它在单个前向网络中预测整个图像的边界框和类别。
下面你可以看到 YOLO 与其他流行的检测器相比有多快。
YOLO的版本
YOLO 于 2015 年由 Joseph Redmon 在其题为“你只看一次:统一的实时对象检测”的研究论文中首次提出。
从那时起,YOLO 发展了很多。2016 年,Joseph Redmon在“YOLO9000: Better, Faster, Stronger”中描述了第二个 YOLO 版本。
在第二次 YOLO 更新大约两年后,约瑟夫提出了另一个网络升级。他的论文《YOLOv3: An Incremental Improvement》引起了许多计算机工程师的关注,并在机器学习社区中走红。
2020 年,Joseph Redmon 决定停止研究计算机视觉,但这并没有阻止 YOLO 被其他人开发。同年,由三名工程师(Alexey Bochkovskiy、Chien-Yao Wang、Hong-Yuan Mark Liao)组成的团队设计了 YOLO 的第四个版本,比以前更快、更准确。他们的发现在他们于 2020 年 4 月 23 日发表的“ YOLOv4:目标检测的最佳速度和准确性”论文中有所描述。
在第 4 版发布两个月后,独立开发者 Glenn Jocher 宣布了 YOLO 的第 5 版。这一次,没有发表研究论文。该网络作为 PyTorch 实现在 Jocher 的GitHub 页面上可用。第五个版本的准确度与第四个版本几乎相同,但速度更快。
最后,在 2020 年 7 月,我们又获得了 YOLO 的另一个重大更新。在一篇题为“ PP-YOLO: An Effective and Efficient Implementation of Object Detector ”的论文中,翔龙和团队提出了新版本的YOLO。YOLO的本次迭代基于第3个模型版本,性能超过了YOLO v4。
在本教程中,我们将仔细研究 YOLOv4 及其实现。为什么是 YOLOv4?三个原因:
- 它在机器学习社区中得到广泛认可;
- 该版本已在广泛的检测任务中证明了其高性能;
- YOLOv4 已在多个流行框架中实现,包括我们将使用的 TensorFlow 和 Keras。
YOLO 应用示例
在我们进入本文的实践部分,实现我们自定义的基于 YOLO 的对象检测器之前,我想向您展示几个很酷的 YOLOv4 实现,然后我们将进行我们的实现。
注意预测的速度和准确性!
这是第一个令人印象深刻的例子 YOLOv4 可以做什么,检测来自不同游戏和电影场景的多个对象。
或者,您可以查看此对象检测演示 从现实生活中的相机视图。
YOLO 作为 TensorFlow 和 Keras 中的物体检测器
机器学习中的 TensorFlow 和 Keras 框架
框架在每个信息技术领域都是必不可少的。机器学习也不例外。ML 市场上有几个成熟的参与者,它们帮助我们简化了整体编程体验。PyTorch、scikit-learn、TensorFlow、Keras、MXNet 和 Caffe 只是一些值得一提的。
今天,我们将与 TensorFlow/Keras 密切合作。毫不奇怪,这两个是机器学习领域中最受欢迎的框架之一。这主要是因为 TensorFlow 和 Keras 都提供了丰富的开发能力。这两个框架彼此非常相似。在不深入细节的情况下,要记住的关键是 Keras 只是 TensorFlow 框架的包装器。
YOLO 在 TensorFlow 和 Keras 中的实现
在撰写本文时,在 TensorFlow/Keras 后端有 808 个具有 YOLO 实现的存储库。YOLO 版本 4 是我们将要实现的。将搜索限制为仅 YOLO v4,我得到了55 个存储库。
仔细浏览所有这些,我找到了一个有趣的候选人继续。
这个实现是由taipingeric和jimmyaspire开发的。如果您之前使用过 TensorFlow 和 Keras,这将非常简单且非常直观。
要开始使用此实现,只需将 repo 克隆到本地计算机。接下来,我将向您展示如何开箱即用地使用 YOLO,以及如何训练您自己的自定义对象检测器。
如何开箱即用地运行预先训练好的 YOLO 并获得结果
查看repo的“快速入门”部分,您可以看到要启动并运行模型,我们只需将 YOLO 作为类对象导入并加载模型权重:
代码语言:javascript复制from models import Yolov4
model = Yolov4(weight_path='yolov4.weights',
class_name_path='class_names/coco_classes.txt')
请注意,您需要提前手动下载模型权重。YOLO 自带的模型权重文件来自 COCO 数据集,可在 GitHub的AlexeyAB 官方暗网项目页面获得。您可以通过此链接直接下载权重。
紧接着,该模型已完全准备好在推理模式下处理图像。只需将 predict() 方法用于您选择的图像。该方法是 TensorFlow 和 Keras 框架的标准方法。
代码语言:javascript复制pred = model.predict('input.jpg')
例如对于这个输入图像:
我得到以下模型输出:
模型所做的预测以方便的 Pandas DataFrame 形式返回。我们获取每个检测到的对象的类名、框大小和坐标:
predict() 方法中有多个参数,让我们指定是否要使用预测的边界框、每个对象的文本名称等绘制图像。查看 predict() 方法附带的文档字符串以获取熟悉我们可用的内容:
您应该期望您的模型只能检测严格限于 COCO 数据集的对象类型。要了解预训练的 YOLO 模型能够检测到哪些对象类型,请查看 .../yolo-v4-tf.kers/class_names/ 中的 coco_classes.txt 文件。那里有 80 种对象类型。
如何训练您的自定义 YOLO 对象检测模型
任务说明
要设计对象检测模型,您需要知道要检测的对象类型。这应该是您要为其创建检测器的有限数量的对象类型。在我们进行实际模型开发时,最好准备一份对象类型列表。
理想情况下,您还应该有一个带注释的数据集,其中包含您感兴趣的对象。该数据集将用于训练检测器并对其进行验证。如果您还没有数据集或注释,请不要担心,我会告诉您在哪里以及如何获取它。
数据集和注释
从哪里获取数据
如果您有要使用的带注释的数据集,请跳过这一部分并继续阅读下一章。但是,如果您的项目需要数据集,我们现在将探索您可以获得数据的在线资源。
你在哪个领域工作并不重要,很有可能已经有一个开源数据集可以用于你的项目。
我推荐的第一个资源是Abhishek Annamraju 撰写的“来自不同行业领域的 50 多个对象检测数据集”文章,他为时尚、零售、体育、医学等行业收集了精彩的注释数据集。
其他两个寻找数据的好地方是paperwithcode.com和roboflow.com,它们提供对用于对象检测的高质量数据集的访问。
查看上述资产以收集您需要的数据或丰富您已有的数据集。
如何为YOLO标注数据
如果您的图像数据集没有注释,您必须自己完成注释工作。这种手动操作非常耗时,因此请确保您有足够的时间来完成。
作为注释工具,您可能会考虑多个选项。就个人而言,我会建议使用多个选项。是一款轻量级易用的图像标注工具,可以直接输出YOLO模型的标注。
如何将其他格式的数据转换为YOLO
YOLO 的注解是txt 文件的形式。YOLO 的 txt 文件中的每一行必须具有以下格式:
代码语言:javascript复制image1.jpg 10,15,345 , 284 , 0
image2.jpg 100,94,613 , 814,0 31 , 420,220 , 540 , 1
我们可以从 txt 文件中拆分每一行,看看它由什么组成:
- 一行的第一部分指定图像的基本名称:image1.jpg , image2.jpg
- 一行的第二部分定义了边界框坐标和类标签。例如,10,15,345,284,0为XMIN,YMIN,XMAX,YMAX,状态类标识码
- 如果给定的图像上有多个对象,则图像基名旁边将有多个框和类标签,并以空格分隔。
边界框坐标是一个明确的概念,但是指定类标签的class_id编号呢?每个class_id都与另一个 txt 文件中的特定类相关联。例如,预训练的 YOLO 带有coco_classes.txt文件,如下所示:
代码语言:javascript复制person
bicycle
car
motorbike
aeroplane
bus
...
类文件中的行数必须与您的检测器要检测的类数相匹配。编号从 0 开始,这意味着classes 文件中第一个类的class_id编号将为 0。放置在 classes txt 文件中第二行的类的编号将为 1。
现在您知道 YOLO 的注释是什么样的了。要继续创建自定义对象检测器,我敦促您现在做两件事:
- 创建一个 classes txt 文件,您将在其中包含您希望检测器检测的类。请记住,课程顺序很重要。
- 创建一个带有注释的 txt 文件。如果您已经有了 VOC 格式 (.XMLs) 的注释,您可以使用此文件从 XML 转换为 YOLO。
将数据拆分为子集
与往常一样,我们希望将数据集分成 2 个子集:用于训练和验证。它可以简单地完成:
代码语言:javascript复制from utils import read_annotation_lines
train_lines, val_lines = read_annotation_lines( '../path2annotations/annot.txt' , test_size= 0.1 )
创建数据生成器
当数据被拆分后,我们可以进行数据生成器的初始化。我们将为每个数据文件提供一个数据生成器。在我们的例子中,我们将有一个用于训练子集和验证子集的生成器。
以下是数据生成器的创建方式:
代码语言:javascript复制from utils import DataGenerator FOLDER_PATH
= '../dataset/img'
class_name_path = '../class_names/bccd_classes.txt'
data_gen_train = DataGenerator(train_lines, class_name_path,
FOLDER_PATH ) data_gen_val = DataGenerator(val_lines, class_name_path), FOLDER_PATH
总而言之,数据拆分和生成器创建的完整代码如下所示:
代码语言:javascript复制from utils import read_annotation_lines, DataGenerator
train_lines, val_lines = read_annotation_lines( '../path2annotations/annot.txt' , test_size= 0.1 ) FOLDER_PATH
= '../dataset/img'
class_name_path = '
.. = DataGenerator(train_lines, class_name_path,
FOLDER_PATH ) data_gen_val = DataGenerator(val_lines, class_name_path, FOLDER_PATH)
模型训练所需的安装和设置
让我们谈谈创建自己的对象检测器必不可少的先决条件:
- 您的计算机上应该已经安装了 Python。如果您需要安装它,我建议您遵循 Anaconda 的官方指南;
- 如果您的计算机具有支持 CUDA 的 GPU(NVIDIA 制造的 GPU),则需要一些相关的库来支持基于 GPU 的训练。如果您需要启用 GPU 支持,请查看NVIDIA 网站上的指南。您的目标是为您的操作系统安装最新版本的 CUDA Toolkit 和 cuDNN;
- 你可能想要组织一个独立的虚拟环境来工作。这个项目需要安装 TensorFlow 2。所有其他库将在稍后介绍;
- 至于我,我正在 Jupyter Notebook 开发环境中构建和训练我的 YOLOv4 模型。尽管 Jupyter Notebook 似乎是一个合理的选择,但如果您愿意,也可以考虑在您选择的 IDE 中进行开发。
模型训练
先决条件
现在你应该有:
- 数据集的拆分;
- 两个数据生成器初始化;
- 包含类的 txt 文件。
模型对象初始化
要为训练工作做好准备,请初始化 YOLOv4 模型对象。确保您使用None作为weight_path参数的值。在此步骤中,您还应该提供类 txt 文件的路径。这是我在项目中使用的初始化代码:
代码语言:javascript复制class_name_path = 'path2project_folder/model_data/scans_file.txt'
model = Yolov4(weight_path= None ,
class_name_path=class_name_path)
上述模型初始化导致创建具有默认参数集的模型对象。考虑通过将字典作为值传递给config模型参数来更改模型的配置。
Config为 YOLOv4 模型指定了一组参数。
默认模型配置是一个很好的起点,但您可能想尝试其他配置以获得更好的模型质量。
特别是,我强烈建议尝试使用anchors和img_size。锚点指定将用于捕获对象的锚点的几何形状。锚点的形状与对象形状的匹配度越好,模型性能就越高。
在某些情况下,增加img_size也可能有用。请记住,图像越高,模型进行推理的时间就越长。
如果您想使用 Neptune 作为跟踪工具,您还应该初始化一个实验运行,如下所示:
代码语言:javascript复制import neptune.new as neptune
run = neptune.init(project='projects/my_project',
api_token=my_token)
定义回调
TensorFlow 和 Keras 让我们可以使用回调来监控训练进度、设置检查点和管理训练参数(例如学习率)。
在拟合模型之前,定义对您的目的有用的回调。确保指定存储模型检查点和相关日志的路径。以下是我在我的一个项目中的做法:
代码语言:javascript复制 # defining pathes and callbacks
dir4saving = 'path2checkpoint/checkpoints'
os.makedirs(dir4saving, exist_ok = True)
logdir = 'path4logdir/logs'
os.makedirs(logdir, exist_ok = True)
name4saving = 'epoch_{epoch:02d}-val_loss-{val_loss:.4f}.hdf5'
filepath = os.path.join(dir4saving, name4saving)
rLrCallBack = keras.callbacks.ReduceLROnPlateau(monitor = 'val_loss',
factor = 0.1,
patience = 5,
verbose = 1)
tbCallBack = keras.callbacks.TensorBoard(log_dir = logdir,
histogram_freq = 0,
write_graph = False,
write_images = False)
mcCallBack_loss = keras.callbacks.ModelCheckpoint(filepath,
monitor = 'val_loss',
verbose = 1,
save_best_only = True,
save_weights_only = False,
mode = 'auto',
period = 1)
esCallBack = keras.callbacks.EarlyStopping(monitor = 'val_loss',
mode = 'min',
verbose = 1,
patience = 10)
您可能已经注意到,在上述回调中,TensorBoard 被用作跟踪工具。考虑使用 Neptune 作为更高级的实验跟踪工具。如果是这样,请不要忘记初始化另一个回调以启用与 Neptune 的集成:
代码语言:javascript复制from neptune.new.integrations.tensorflow_keras import NeptuneCallback
neptune_cbk = NeptuneCallback(run=run, base_namespace='metrics')
拟合模型
要开始训练工作,只需使用TensorFlow / Keras 中的标准fit()方法拟合模型对象。以下是我开始训练模型的方法:
代码语言:javascript复制model.fit(data_gen_train,
initial_epoch= 0 ,
epochs
= 10000 , val_data_gen=data_gen_val,
callbacks=[rLrCallBack,
tbCallBack,
mcCallBack_loss,
esCallBack,
neptune_cbk]
)
训练开始后,您将看到一个标准进度条。
训练过程将在每个 epoch 结束时评估模型。如果你使用一组类似于我在拟合时初始化和传入的回调,那些在较低损失方面显示模型改进的检查点将被保存到指定的目录中。
如果没有发生错误并且训练过程顺利,训练作业将因为训练周期数结束而停止,或者如果提前停止回调检测到没有进一步的模型改进并停止整个过程。
在任何情况下,您最终都应该有多个模型检查点。我们想从所有可用的中选择最好的一个并将其用于推理。
在推理模式下训练的自定义模型
在推理模式下运行经过训练的模型类似于开箱即用地运行预训练模型。
您初始化一个模型对象,传入最佳检查点的路径以及带有类的 txt 文件的路径。这是我的项目的模型初始化的样子:
代码语言:javascript复制from models import Yolov4
model = Yolov4(weight_path='path2checkpoint/checkpoints/epoch_48-val_loss-0.061.hdf5',
class_name_path='path2classes_file/my_yolo_classes.txt')
模型初始化后,只需对您选择的图像使用 predict() 方法即可获得预测。回顾一下,模型所做的检测以一种方便的 Pandas DataFrame 形式返回。我们获取每个检测到的对象的类名、框大小和坐标。
结论
您刚刚学习了如何创建自定义 YOLOv4 对象检测器。我们已经完成了端到端的过程,从数据收集、注释和转换开始。您对第四个 YOLO 版本以及它与其他检测器的不同之处有足够的了解。
现在没有什么能阻止您在 TensorFlow 和 Keras 中训练您自己的模型。您知道从哪里获得预训练模型以及如何开始训练工作。
在我即将发表的文章中,我将向您展示一些有助于提高最终模型质量的最佳实践和生活窍门。和我们在一起!
作者:Anton Morgunov,机器学习爱好者的计算机视觉工程师。对计算机视觉充满热情。