美文网首页
YOLOv5学习(二):数据集加载

YOLOv5学习(二):数据集加载

作者: 云深沧海暮 | 来源:发表于2021-02-26 14:24 被阅读0次

    数据加载

    yolov5的数据加载部分由create_dataloader函数实现(位于utils/datasets.py),其中关于数据增强和加载的部分主要由LoadImagesAndLabels和InfiniteDataLoader负责,并基于torch_distributed_zero_first(rank)进行不同进程之间的数据同步。

    数据同步

    在yolov5的模型训练中涉及了多进程并行运算。其中,主进程实现数据的预读取并缓存,然后其它子进程则从缓存中读取数据并进行一系列运算。为了完成数据的正常同步,yolov5中基于torch.distributed.barrier()函数实现了上下文管理器torch_distributed_zero_first:

    @contextmanager
    def torch_distributed_zero_first(local_rank: int):
        """
        Decorator to make all processes in distributed training wait for each local_master to do something.
        """
        if local_rank not in [-1, 0]:
            torch.distributed.barrier()
        yield
        if local_rank == 0:
            torch.distributed.barrier()
    

    torch_distributed_zero_first使用方式:

    with torch_distributed_zero_first(rank):
         dataset = LoadImagesAndLabels(......)
    

    rank表示当前的进程号,主进程由编号0表示,子进程则由编号1、2、3...等表示。上述代码的运行逻辑:

    1. 进入torch_distributed_zero_first(rank)上下文作用域;
    2. 判断当前进程号local_rank是否为-1或0,如果不是则说明为子进程,运行torch.distributed.barrier()等待主进程的数据处理完毕,如果是则当前为主进程,不需要等待;
    3. yield后,运行with作用域范围内的代码;
    4. 作用域范围内代码运行完成后,继续yield的后续操作,判断当前进程号是否为0(即是否为主进程),如果是,则运行torch.distributed.barrier()可以解开其它子进程的阻塞。

    注意 对于torch.distributed.barrier()函数的作用可以参考https://stackoverflow.com/questions/59760328/how-does-torch-distributed-barrier-work进行理解。

    数据增强

    数据增强相关的方法在LoadImagesAndLabels类中实现。

    Rectangular Training

    通常YOLO系列网络的输入都是预处理后的方形图像数据,如416 * 416、608 * 608。当原始图像为矩形时,会将其填充为方形(如下图:方形输入),但是填充的灰色区域其实就是冗余信息,不论是在训练还是推理阶段,这些冗余信息都会增加耗时。

    方形输入

    为了减少图像的冗余数据,输入图像由方形改为矩形(如下图:矩形输入):将长边resize为固定尺寸(如416),短边按同样比例resize,然后把短边的尺寸尽量少地填充为32的倍数。

    矩形输入

    这种方法在推理阶段称为矩形推理(Rectangular Inference),在训练阶段则称为矩形训练(Rectangular Training)。推理阶段直接对图像进行resize和pad就行,但是训练阶段输入的是一个批次的图像集合,需要保持批次内的图像尺寸一致,因此处理逻辑相对复杂一些。

    代码:

            if self.rect:
                # Sort by aspect ratio
                # 首先根据高宽比排序,就可以保证每个batch内的图像高宽比相近。
                s = self.shapes  # wh
                ar = s[:, 1] / s[:, 0]  # aspect ratio    高/宽
                irect = ar.argsort()
                self.img_files = [self.img_files[i] for i in irect]
                self.label_files = [self.label_files[i] for i in irect]
                self.labels = [self.labels[i] for i in irect]
                self.shapes = s[irect]  # wh
                ar = ar[irect]
    
                # Set training image shapes
                shapes = [[1, 1]] * nb    # hw
                for i in range(nb):
                    ari = ar[bi == i]
                    mini, maxi = ari.min(), ari.max()
                    if maxi < 1:    # 高宽比最大值都小于1,则说明batch内的图全都是高小于宽
                        shapes[i] = [maxi, 1]   # 设置宽为固定比例1,高的比例为maxi
                    elif mini > 1:   # 高宽比最小值都大于1,说明batch内的图都是高>宽
                        shapes[i] = [1, 1 / mini]    # 设置高为固定比例1,宽的比例为1 / mini
    

    运行逻辑:

    1. 根据数据集中所有图像的shape计算高宽比ar;
    2. 对长宽比ar进行argsort,即对ar内的元素进行排序(升序),并针对排序后的元素对应取得其在ar中的索引,构成索引序列irect;
    3. 根据索引序列irect取得排序后的self.img_files、self.label_files、self.labels 、self.shapes和ar;
    4. 初始化nb(即batch数量)个shape为[1,1],组成shapes;
    5. 从ar中对应取出每个batch的高宽比列表ari,取其中的最大、最小值;
    6. 如果当前batch的高宽比最大值小于1,则将shapes内该batch对应的值设为[maxi, 1],而如果最大值<=1且最小值>1,则设置为[1, 1 / mini],如果都不符合默认[1,1]。

    参考:https://github.com/ultralytics/yolov3/issues/232

    Mosaic

    未完待续

    相关文章

      网友评论

          本文标题:YOLOv5学习(二):数据集加载

          本文链接:https://www.haomeiwen.com/subject/hxgrfltx.html