diff --git a/chapter_data_processing/index.md b/chapter_data_processing/index.md index 594c073e..3559c620 100644 --- a/chapter_data_processing/index.md +++ b/chapter_data_processing/index.md @@ -1,21 +1,20 @@ # 数据处理框架 -在前两个章节中,我们介绍了编译器前后端的相关内容,详细地阐述了源程序到目标程序的转换优化过程。除了让芯片在训练/推理过程中高性能地运行,我们还需要将数据高效地发送给芯片,以实现全流程的性能最优。机器学习模型训练和推理需要从存储设备(如本地磁盘和内存、远端的存储系统等)中加载数据集,对数据集进行一系列处理变换,将处理结果发送到GPU或者华为昇腾Ascend等加速器中完成模型计算,该流程的任何一个步骤出现性能问题都会对训练和推理的吞吐率造成负面影响。本章我们将核心介绍如何设计、并实现一个面向机器学习场景的数据系统,以帮助用户轻松构建各种复杂的数据处理流水线(Data -Pipeline),同时我们的数据系统要有足够高的执行性能,以确保数据预处理步骤不会成为模型训练和推理的性能瓶颈。 +机器学习框架需从各种存储设备(例如本地磁盘、内存或远程存储系统)中加载数据集,处理数据,并将处理后的结果发送至加速器以完成模型的训练与推理。在本章中,我们将探讨如何设计一个专为机器学习场景打造的数据处理模块,协助用户构建适用于各种应用的数据流水线。此外,数据流水线需具备高性能,确保数据处理不会成为模型训练和推理过程中的瓶颈。 -本章主要从易用性、高效性和保序性三个维度展开介绍机器学习系统中的数据模块。在前两个小节中,我们首先讨论如何构建一个易用的数据模块。包括如何设计编程抽象,使得用户通过短短几行代码便可以描述一个复杂的预处理过程;以及如何做到既内置丰富算子提升易用性,又可以灵活支持用户使用自定义算子覆盖长尾需求。用户构建好数据处理流程后,数据模块需要负责高效的调度执行数据流水线,以达到最优的数据处理吞吐率。高效的执行数据流水线是一个具有挑战性的任务,我们既要面临数据读取部分的I/O性能问题,又要解决数据处理部分的计算性能问题。针对上述挑战,我们将分别介绍面向高吞吐率读取性能的数据文件格式设计,以及能够充分发挥多核CPU算力的并行架构设计。不仅如此,和常规数据并行计算任务不同的是,大部分机器学习场景对于数据的输入输出顺序有着特殊的`保序性`的要求,我们将会使用一节的内容来介绍什么是保序性,以及如何在数据模块的并行架构中设计相应组件计来满足该特性需求。学习了上述的内容后,读者将会对如何构建一个面向机器学习场景高效易用的数据模块有深刻的理解。最后,作为拓展内容,我们将以目前学术界和业界的一些实践经验来介绍当单机处理性能达不到要求时,该如何去扩展我们的数据处理模块以满足训练性能需求。本章学习目标包括: +本章将从易用性、高效性和保序性三个方面介绍数据处理模块。首先,我们将探讨如何实现易用性,包括设计编程模型以简化数据流水线定义,以及支持自定义算子,以满足多样化的数据处理需求。在完成数据流水线构建之后,我们将讨论如何实现高效性。这涉及设计数据文件格式以支持高吞吐率读取,以及构建并行数据处理架构,充分发挥多 CPU 和多 GPU 的并行计算能力。最后,我们将讨论数据保序性对机器学习的重要性,以及如何在并行数据处理架构中确保保序性的实现。作为扩展内容,我们将介绍如何利用分布式计算解决单机性能无法满足数据处理需求的问题。本章的学习目标包括: -- 了解机器学习数据模块架构中的关键组件及其功能 +- 掌握数据处理模块中的组件及其功能。 -- 了解不同数据模块用户编程接口的设计 +- 掌握数据处理模块编程接口的设计原理。 -- 掌握面向高性能数据读取的数据文件格式设计 +- 掌握支持高性能数据读取的数据文件格式设计。 -- 掌握机器学习系统数据模块并行架构 +- 掌握常用的并行数据处理架构设计。 -- 掌握机器学习系统数据模块数据保序性含义及其解决方案 +- 掌握数据保序性含义及其实现方法。 -- 了解两种单机数据处理性能扩展方案 +- 了解单机数据处理性能扩展方法。 ```toc @@ -27,4 +26,4 @@ performance data_order extension summary -``` \ No newline at end of file +``` diff --git a/chapter_data_processing/performance.md b/chapter_data_processing/performance.md index 13f48f2e..33f10c6d 100644 --- a/chapter_data_processing/performance.md +++ b/chapter_data_processing/performance.md @@ -36,8 +36,6 @@ :width:`800px` :label:`file_random_access` -#### MindRecord介绍 - MindRecord是MindSpore推出的统一数据格式,目标是归一化用户的数据集,优化训练数据的读取过程。该文件格式具备如下特征: - 实现多变的用户数据统一存储、访问,训练数据读取更加简便。 diff --git a/chapter_data_processing/program_model.md b/chapter_data_processing/program_model.md index a528aa70..deaf9cd1 100644 --- a/chapter_data_processing/program_model.md +++ b/chapter_data_processing/program_model.md @@ -1,10 +1,10 @@ ## 易用性设计 -本节我们主要介绍如何设计一个易用的机器学习系统数据模块。正如前文所言,易用性既要求数据模块提供好的编程抽象和接口使得用户可以方便的构建一个数据处理流水,同时还要支持用户灵活地在数据流水中注册使用自定义算子以满足丰富多变的特殊需求,接下来我们将从编程接口抽象和自定义算子注册机制两个方面来展开探讨。 +本节将主要介绍如何设计一个易用的机器学习系统数据模块。正如前文所言,易用性既要求 数据模块提供好的编程模型和接口使得用户可以方便地构建一个数据处理流水,同时还要支持用 户灵活地在数据流水中插入使用自定义算子以满足丰富多变的处理需求,接下来将从编程接口抽 象和自定义算子注册机制两个方面来展开探讨数据模块的易用性设计。 ### 编程抽象与接口 - :numref:`image_process_pipeline` 我们展示的是一个训练图片分类模型的经典数据预处理流水线。我们从存储设备中加载数据集后,对数据集中的图片数据进行解码、缩放、旋转、正规化、通道变换等一系列操作,对数据集的标签也进行特定的预处理操作,最终将处理好的数据发送到芯片上进行模型的计算。我们希望数据模块提供的编程抽象具备足够高的层次,以使得用户可以通过短短几行代码就能描述清楚数据处理的逻辑,不需要陷入过度的、重复的数据处理实现细节当中。同时又要确保这一套高层次的抽象具备足够通用性,以满足多样的数据预处理需求。在我们得到一个好的编程抽象后,我们将会以基于MindSpore的数据模块提供的编程接口实现下图所描述的数据预处理流水线的代码片段为例子来展示一个优秀的编程抽象对用户编程负担的减轻是有多么大的作用。 + :numref:`image_process_pipeline` 展示的是一个图像分类模型训练中的经典数据预处理步骤。数据模块从存储设备中加 载数据集后,对数据集中的图片数据进行解码、缩放、旋转、正规化、通道变换等一系列操作, 对数据集的标签也进行特定的预处理操作,最终将处理好的数据发送到芯片上进行模型的计算。 我们希望数据模块提供的编程模型具备足够高的层次,使得用户可以通过短短几行代码就能描述 清楚数据处理的逻辑,不需要陷入过度的、重复的数据处理细节实现当中。同时又要确保这一套 高层次的抽象具备足够通用性,以满足多样的数据预处理需求。 ![数据预处理示例](../img/ch07/7.2/image_process_pipeline.png) :width:`800px` diff --git a/chapter_data_processing/requirements.md b/chapter_data_processing/requirements.md index 2c665b51..c5ae2ff3 100644 --- a/chapter_data_processing/requirements.md +++ b/chapter_data_processing/requirements.md @@ -1,7 +1,6 @@ ## 概述 -机器学习场景中的数据处理是一个典型的ETL(Extract, Transform, -Load)过程,第一个阶段(Extract)需要从存储设备中加载数据集,第二个阶段(Transform)完成对数据集的变换处理。虽然不同的机器学习系统在构建数据模块时采用了不同的技术方案,但其核心都会包含数据加载、数据混洗、数据变换、数据mini-batch组装以及数据发送等关键组件。其中每个组件的功能介绍如下所示: +机器学习场景中的数据处理是一个典型的提取-变换-加载(Extract-Transform-Load,ETL)过程,提取阶段从存储设备中完成数据集加载,变换阶段完成对数据集的变换处理。虽然不同的机器学习框架在构建数据处理模块时采用了不同的技术方案,但其核心都会包含数据加载、数据混洗、数据变换、数据下批次组装以及向加速器发送数据等关键组件(如图7.1所示)。其中每个组件的功能介绍如下: - **数据加载组件(Load)**:负责从存储设备中加载读取数据集,需要同时考虑存储设备的多样性(如本地磁盘/内存,远端磁盘和内存等)和数据集格式的多样性(如csv格式,txt格式等)。根据机器学习任务的特点,AI框架也提出了统一的数据存储格式(如谷歌TFRecord, 华为MindRecord等)以提供更高性能的数据读取。 @@ -22,12 +21,12 @@ Load)过程,第一个阶段(Extract)需要从存储设备中加载数据 #### 易用性 -AI模型训练/推理过程中涉及到的数据处理非常灵活:一方面,不同的应用场景中数据集类型千差万别,特点各异,在加载数据集时,数据模块要支持图像、文本、音频、视频等多种类型的特定存储格式,还要支持内存、本地磁盘、分布式文件系统以及对象存储系统等多种存储设备类型,模块需要对上述复杂情况下数据加载中的IO差异进行抽象统一,减少用户的学习成本。另一方面,不同的数据类型往往也有着不同的数据处理需求。现有常见机器学习任务中,图像任务常常对图像进行缩放、翻转、模糊化等处理,文本任务需要对文本进行切分、向量化等操作,而语音任务需要对语音进行快速傅立叶变换、混响增强、变频等预处理。为帮助用户解决绝大部分场景下的数据处理需求,数据模块需要支持足够丰富的面向各种类型的数据预处理算子。然而新的算法和数据处理需求在不断快速涌现,我们需要支持用户在数据模块中方便的使用自定义处理算子,以应对数据模块未覆盖到的场景,达到灵活性和高效性的最佳平衡。 +机器学习模型训练/推理过程中涉及到的数据处理非常灵活:一方面,不同的应用场景中数据集类型千差万别,特点各异。在加载数据集时,数据模块不仅要支持图像、文本、音频、视频 等多种类型存储格式,还要支持内存、本地磁盘、分布式文件系统以及对象存储系统等多种存储 类型。为减少用户学习成本,数据模块需要对上述复杂情况下数据加载进行抽象统一。另一方面, 不同类型的数据往往也有着不同的数据处理方式。常见机器学习任务中,图像任务常常需要进行 图像缩放、图像翻转、图像模糊化等处理,文本任务需要对文本进行切分、向量化等操作,而语 音任务又需要对语音进行快速傅立叶变换、混响增强、变频等预处理。为帮助用户解决绝大部分 场景下的数据处理需求,数据模块需要支持足够丰富的面向各种类型的数据预处理算子。然而新 的算法和数据处理需求在不断快速涌现,还需要支持用户在数据模块中方便的使用自定义处理算 子,以应对数据模块未覆盖到的场景,达到灵活性和高效性的平衡。 #### 高效性 -由于GPU/华为昇腾Ascend等常见AI加速器主要面向Tensor数据类型计算,并不具备通用的数据处理能力,现有主流机器学习系统数据模块通常选择使用CPU进行数据流水线的执行。理想情况下,在每个训练迭代步开始之前,数据模块都需要将数据准备好、以减少加速器因为等待数据而阻塞的时间消耗。然而数据流水线中的数据加载和数据预处理常常面临着具有挑战性的I/O性能和CPU计算性能问题,数据模块需要设计具备支持随机读取且具备高读取吞吐率的文件格式来解决数据读取瓶颈问题,同时还需要设计合理的并行架构来高效的执行数据流水线,以解决计算性能问题。为达到高性能的训练吞吐率,主流机器学习系统均采用数据处理与模型计算进行异步执行,以掩盖数据预处理的延迟。 +由于GPU/华为昇腾Ascend等常见 AI 加速器主要面向 Tensor(向量)数据类型计算,现 有主流机器学习系统数据模块通常选择使用 CPU 进行数据处理流水线的执行。理想情况下,在 每个训练迭代步开始之前,数据模块都需要将数据准备好、以减少加速器因为等待数据而阻塞 的时间消耗。然而数据流水线中的数据加载和数据预处理常常面临着具有挑战性的 I/O 性能和 CPU 计算性能问题,数据模块需要设计具备支持随机读取且具备高读取吞吐率的文件格式来解 决数据读取瓶颈问题,同时还需要设计合理的并行架构来高效地执行数据流水线,以解决计算性 能问题。为达到高性能的数据吞吐率,主流机器学习系统均采用数据处理与模型计算进行异步执 行,以掩盖数据预处理的延迟。 #### 保序性 -和常规的数据并行计算任务所不同的是,机器学习模型训练对数据输入顺序敏感。使用随机梯度下降算法训练模型时,通常在每一轮需要按照一种伪随机顺序向模型输入数据,并且在多轮训练(Epoch)中每一轮按照不同的随机顺序向模型输入数据。由于模型最终的参数对输入数据的顺序敏感,为了帮助用户更好的调试和确保不同次实验的可复现性,我们需要在系统中设计相应机制使得数据最终送入模型的顺序由数据混洗组件的数据输出顺序唯一确定,不会由于并行数据变换而带来最终数据模块的数据输出顺序不确定。我们将在后文中对于保序性的要求和具体实现细节展开探讨。 +和常规的数据并行计算任务所不同的是,机器学习模型训练对数据输入顺序敏感。使用随机 梯度下降算法训练模型时,通常在每一轮需要按照一种伪随机顺序向模型输入数据,并且在多轮 训练 (Epoch) 中每一轮按照不同的随机顺序向模型输入数据。由于模型最终的参数对输入数据 的顺序敏感,为了帮助用户更好的调试和确保不同次实验的可复现性,数据模块需要在系统中设 计相应机制使得数据最终送入模型的顺序由数据混洗组件的数据输出顺序唯一确定,不会由于并 行数据变换处理导致最终数据模块的数据输出顺序不确定。后文中对于保序性的要求和具体实现 细节会展开探讨。 diff --git a/chapter_data_processing/summary.md b/chapter_data_processing/summary.md index 83d3126c..6da7159a 100644 --- a/chapter_data_processing/summary.md +++ b/chapter_data_processing/summary.md @@ -1,8 +1,4 @@ ## 总结 -本章我们围绕着易用性、高效性和保序性三个维度展开研究如何设计实现机器学习系统中的数据预处理模块。在易用性维度我们重点探讨了数据模块的编程模型,通过借鉴历史上优秀的并行数据处理系统的设计经验,我们认为基于描述数据集变换的编程抽象较为适合作为数据模块的编程模型,在具体的系统实现中,我们不仅要在上述的编程模型的基础上提供足够多内置算子方便用户的数据预处理编程,同时还要考虑如何支持用户方便的使用自定义算子。在高效性方面,我们从数据读取和计算两个方面分别介绍了特殊文件格式设计和计算并行架构设计。我们也使用我们在前几章中学习到的模型计算图编译优化技术来优化用户的数据预处理计算图,以进一步的达到更高的数据处理吞吐率。机器学习场景中模型对数据输入顺序敏感,于是衍生出来保序性这一特殊性质,我们在本章中对此进行了分析并通过MindSpore中的Connector的特殊约束实现来展示真实系统实现中如何确保保序性。最后,我们也针对部分情况下单机CPU数据预处理性能的问题,介绍了当前基于异构处理加速的纵向扩展方案,和基于分布式数据预处理的横向扩展方案,我们相信读者学习了本章后能够对机器学习系统中的数据模块有深刻的认知,也对数据模块未来面临的挑战有所了解。 +本章我们围绕着易用性、高效性和保序性三个维度展开研究如何设计实现机器学习系统中的 数据预处理模块。在易用性维度我们重点探讨了数据模块的编程模型,通过借鉴历史上优秀的并 行数据处理系统的设计经验,我们认为基于描述数据集变换的编程模型较为适合作为数据模块 的编程模型,在具体的系统实现中,我们不仅要在上述的编程模型的基础上提供足够多内置算子 方便的用户的数据预处理编程,同时还要考虑如何支持用户方便的使用自定义算子。在高效性方 面,我们从数据读取和计算、两个分别介绍了特殊文件格式设计和计算并行架构设计。我们也使 用我们在前几章中学习到的模型计算图编译优化技术来优化用户的数据预处理计算图,以进一步 的达到更高的数据处理吞吐率。机器学习场景中模型对数据输入顺序敏感,于是衍生出来保序性 这一特殊性质,我们在本章中对此进行了分析并通过 MindSpore 中的 Connector 的特殊约束实现来展示真实系统实现中如何确保保序性。最后,我们也针对部分情况下单机 CPU 数据预处理 性能的问题,介绍了当前基于异构处理加速的纵向扩展方案,和基于分布式数据预处理的横向扩 展方案,我们相信读者学习了本章后能够对机器学习系统中的数据模块有深刻的认知,也对数据 模块未来面临的挑战有所了解。 -## 扩展阅读 - -- 流水线粒度并行实现示例建议阅读 [Pytorch DataLoader](https://github.com/pytorch/pytorch/tree/master/torch/utils/data)。 -- 算子粒度并行实现示例建议阅读 [MindData](https://gitee.com/mindspore/mindspore/tree/master/mindspore/ccsrc/minddata)。 \ No newline at end of file