趣玩互娱

yolov3目标检测结果图文字乱码



目录

  • 引言
  • 第一步:读取yaml配置文件
  • 第二步创建Dataset和DataLoader
  • 初始化图片文件名和标注文件名集合
  • 加载标注文件
  • 加载图片
  • 最后一步:读取数据到网络
  • 总结


本文以YOLOV5目标检测算法作为例子,探讨当数据集为图片集组成的文件夹时具体的数据集加载方式。

yolov5的.yaml配置文件主要用来配置数据集、测试集、验证集的路径以及待检测物体的种类和名称。以coco数据集的.yaml文件举例:

在读取数据集之前首先需要读取.yaml文件中的这些信息,在train.py中Config模块中完成这一步骤。

check_dataset函数中,将训练集、验证集、测试集的路径拼凑出来,最后封装成一个Dictionary返回给data_dict变量,因此train_path, val_path就是完整的训练集和验证集目录。YOLOV5也是通过之前文章详细讲过的Dataset+DataLoader组合对数据进行加载和预处理。

初始化图片文件名和标注文件名集合

create_dataLoader函数会同时返回dataset和DataLoader,YOLOV5的数据集与MNIST数据集的不同就在于YOLOV5对数据加载有着不同的选择方式通过cache参数进行控制,具体代码如下:

这段代码说明它并不是直接将图片数据加载到内存中,而是首先通过文件夹将文件夹下所有的文件名字添加到一个列表下。再判断文件名是否是图像格式的文件名,将文件名做一个筛选然后再保存到im_files变量中,这里需要将一下的是python中的glob.glob()函数是递归的遍历整个目录下的子目录和文件,随后保存与通配符匹配的文件名。这种方式在文件数目非常大的时候是延迟较大的,而如果是在分布式文件系统上,这样的方式对性能的影响就更加大了,不过大部分的AI工作者对训练性能上的研究仍然是集中在GPU算力这方面的,因为数据集的大小始终不足以达到在时间耗费上的占比引起足够的重视。

加载标注文件

首先将图片的文件路径通过img2label()函数替换成label的路径。
上面的代码实现了一种对标注信息缓存的机制,为了方便在下次使用中不用重新加载标注信息,因此对标注信息做一个缓存。cache_labels()的功能就是如此:

cache_labels()采用线程池,多个线程运行verify_image_label()函数,值得一提的是verify_image_label()函数是用于对图像文件和标注文件进行检查的函数,涉及到检查那么就一定会去访问源文件,它的源代码如下:

可以看到在verify_image_label()函数中会逐个的读取图像文件和Lables文件进行检查,值得注意的是这个函数对图像文件进行了两次读取,一次是以Image对象的方式读取,用于对图像进行检测和修复以及获取图片的shape。一次是以二进制的方法读取,用于检测图像是否损坏。也就是说每次的图片和标注信息的检查都会读取两次图片文件和一次标注文件,这里的图片检查对文件的频繁访问肯定是会对数据集读取性能造成影响的。
最后verify_image_label()函数将没有问题的图片路径和标注信息返回。cache_labels()函数获取过后做简单的处理,以{图像路径:标注信息}的方式将数据存储到磁盘上。

cache文件的读取,会重新读取之前图像数据集的检查情况,对于不合格的图像和标注,会从图像路径列表中直接删除,也就是采用cache中合法的图像路径列表。读取cache文件的代码如下:

加载图片

MNIST数据集的数据加载方式是在初始化时候将所有的图片数据全部加载到内存中,而yolov5目标检测算法的数据集加载方式并不是固定的,可以通过cache参数选择数据的加载和存储方式。

当cache==‘raw’时表示会将全部数据缓存到内存中,之后会判断内存是否足够存储所有数据。如果足够会计算需要的内存总量并且将所有的图片文件全部加载到内存。

load_image函数的实现如下:

可以看到当图片数据不在内存中时,会查看是否之前有将数据处理过并保存成.npy文件(.npy 文件是NumPy库中用于保存单个多维数组数据的二进制文件格式。和图像文件相比.npy 文件具有更小的文件大小和更快的读写速度,因为它以二进制格式存储数据。),如果有则直接加载。没有就会通过opencv库的图像加载函数将图片加载到内存中。
当cache_images='disk’时,会将图片读取并且以二进制形式保存到磁盘中。cache_images_to_disk 函数的实现如下:

可以看到cache_images_to_disk()函数也是将图像挨个读取到内存并且以二进制形式保存回磁盘。

当数据访问方式确定后,剩下的工作就是利用DataLoader加载数据,具体的代码分析之前的文章有讲过这里就不再赘述。值得一提的是,在不使用加权图像策略的情况下,yolov5采用的是InfiniteDataLoader。它是DataLoader的子类,与DataLoader不同的是InfiniteDataLoader 是一种无限循环的数据加载器,它会持续地提供数据样本,直到人为地停止数据加载过程(手动退出循环)。最后来看一下dataset中的__getitem__()代码吧,在之前的文章我说过,这个是数据加载的最核心的代码。

可以看到__getitem__()函数依旧是使用的上面的load_image()方法。
当既没有设置将图像数据全部加载到内存也没有设置以二进制的方式重新保存到磁盘时,会逐个加载图像。加载图像的方式,都是通过文件路径队列直接读取

加载数据首先通过文件夹路径,匹配所有文件路径添加到一个队列。
首先会对队列里面的所有文件做检查,这里会读取两次图像文件和一次标注文件。并将合法的文件信息以{图像路径:标签}的方式保存到磁盘中,方便下次训练读取。
对于图像的加载当设置为全部加载到内存时,会在dataset初始化时判断能否加入,再全部加载。当设置为加载图片到磁盘时,会读取图片并将图片重新以二进制的方式存储到磁盘。
当既没有设置将图像数据全部加载到内存也没有设置以二进制的方式重新保存到磁盘时,就对每个图片逐个加载,加载图像的方式,都是通过文件路径队列直接读取。
在整个训练过程中对于数据集的读取和存储都是有很多次的,而当数据过大,本地磁盘无法全部容纳的情况下,多次的数据存储和读取肯定会对整体性能有影响。


发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Powered By Z-BlogPHP 1.7.3 Theme By 爱墙纸

Copyright Your 趣玩互娱 www.hsjyny.com Rights Reserved.