diff --git a/chapter_data_processing/extension.md b/chapter_data_processing/extension.md index 016bb98..4ae9574 100644 --- a/chapter_data_processing/extension.md +++ b/chapter_data_processing/extension.md @@ -32,7 +32,7 @@ ds::Execute preprocessor({decode, resize, center_crop, normalize}, MapTargetDevi ret = preprocessor(image, &image); ``` -相比较Dvpp只支持图像的部分预处理操作,英伟达公司研发的DALI\[8\]是一个更加通用的基于GPU的数据预处理加速框架。DALI中包含如下三个核心概念: +相比较Dvpp只支持图像的部分预处理操作,英伟达公司研发的DALI :cite:`nvidia_dali`是一个更加通用的基于GPU的数据预处理加速框架。DALI中包含如下三个核心概念: - DataNode:表示一组Tensor的集合 @@ -85,7 +85,7 @@ outputs = pipe.run() - 由于大数据计算框架并不是完全针对机器学习场景,使得某些分布式预处理操作如全局的数据混洗无法被高效的实现。 为了更适配机器学习场景的数据预处理,分布式机器学习框架Ray借助其自身的任务调度能力实现了简单的分布式的数据预处理------ -Ray Dataset\[10\],由于数据预处理和训练处在同一个框架内,在降低了用户的编程负担的同时也通过数据的零拷贝共享消除了序列化/反序列化带来的额外开销。Ray Dataset支持如map、batch、map、filter等简单并行数据集变换算子、以及如mean等一些基础的聚合操作算子。同时Ray +Ray Dataset :cite:`moritz2018ray`,由于数据预处理和训练处在同一个框架内,在降低了用户的编程负担的同时也通过数据的零拷贝共享消除了序列化/反序列化带来的额外开销。Ray Dataset支持如map、batch、map、filter等简单并行数据集变换算子、以及如mean等一些基础的聚合操作算子。同时Ray Dataset也支持排序、随机打乱、GroupBy等全局混洗操作,该方案目前处在研究开发中,还未被广泛的采用,感兴趣的读者可以翻阅相关资料进一步的了解。 ```python diff --git a/chapter_data_processing/index.md b/chapter_data_processing/index.md index c7f1fb6..614d18b 100644 --- a/chapter_data_processing/index.md +++ b/chapter_data_processing/index.md @@ -27,5 +27,4 @@ performance data_order extension summary -reference ``` \ No newline at end of file diff --git a/chapter_data_processing/performance.md b/chapter_data_processing/performance.md index 831a721..59bd740 100644 --- a/chapter_data_processing/performance.md +++ b/chapter_data_processing/performance.md @@ -2,7 +2,7 @@ 在上一节中我们重点介绍了数据模块的编程抽象以及编程接口设计,确保用户可以方便的基于我们提供的API描述数据处理流程而不需要过多关注实现和执行细节。那么本节我们将进一步探究数据加载以及流水线调度执行等数据模块关键部分设计细节以确保用户能够拥有最优的数据处理性能。同时在本节内容中,我们也会贯穿现有主要机器学习系统的实践经验以帮助读者加深对这些关键设计方案的理解。 -如 :numref:`async_data_process` 所示,深度学习模型训练需要借助数据模块首先从存储设备中加载数据集,在内存中进行一系列的预处理变换,最终将处理好的数据集发送到加速器芯片上执行模型的计算,目前有大量的工作都着重于研究如何通过设计新的硬件或者应用算子编译等技术加速芯片上的模型计算,而在数据梳理流水的性能问题上鲜有涉及。但事实上很多情况下,数据预处理的执行时间往往在整个训练任务中占据着相当大的比例,导致GPU/华为昇腾Ascend等加速器无法被充分利用。研究数据表明,企业内数据中心的计算任务大约有30%的计算时间花费在数据预处理步骤\[5\],也有研究发现在一些公开数据集上的模型训练任务有65%的时间都花费在了数据预处理上\[6\],由此可以看出数据模块的性能对于整体训练吞吐率有着决定性的影响。 +如 :numref:`async_data_process` 所示,深度学习模型训练需要借助数据模块首先从存储设备中加载数据集,在内存中进行一系列的预处理变换,最终将处理好的数据集发送到加速器芯片上执行模型的计算,目前有大量的工作都着重于研究如何通过设计新的硬件或者应用算子编译等技术加速芯片上的模型计算,而在数据梳理流水的性能问题上鲜有涉及。但事实上很多情况下,数据预处理的执行时间往往在整个训练任务中占据着相当大的比例,导致GPU/华为昇腾Ascend等加速器无法被充分利用。研究数据表明,企业内数据中心的计算任务大约有30%的计算时间花费在数据预处理步骤 :cite:`murray2021tf`,也有研究发现在一些公开数据集上的模型训练任务有65%的时间都花费在了数据预处理上 :cite:`mohan2020analyzing`,由此可以看出数据模块的性能对于整体训练吞吐率有着决定性的影响。 ![数据加载、预处理、模型计算异步并行执行](../img/ch07/7.3/async_data_process.png) :width:`800px` @@ -128,7 +128,7 @@ for batch_idx, sample in enumerate(loader): print(sample) ``` -最后需要指出的是, Pytorch Dataloader的执行过程中涉及大量进程间通信,虽然为了加速这一步骤,Pytorch对Tensor类数据实现了基于共享内存的进程间通信机制。然而当通信数据量较大时,跨进程通信仍然会较大地影响端到端的数据预处理吞吐率性能。当然,这不是流水线并行自身的架构问题,而是由于CPython的全局解释器锁(Global Interpreter Lock, GIL)导致在Python层面实现流水线并行时只能采用进程并行。为了解决这个问题,目前Pytorch团队也在尝试通过移除CPython中的GIL来达到基于多线程实现流水线并行以提升通信效率的目的\[7\],感兴趣的读者可以选择继续深入了解。 +最后需要指出的是, Pytorch Dataloader的执行过程中涉及大量进程间通信,虽然为了加速这一步骤,Pytorch对Tensor类数据实现了基于共享内存的进程间通信机制。然而当通信数据量较大时,跨进程通信仍然会较大地影响端到端的数据预处理吞吐率性能。当然,这不是流水线并行自身的架构问题,而是由于CPython的全局解释器锁(Global Interpreter Lock, GIL)导致在Python层面实现流水线并行时只能采用进程并行。为了解决这个问题,目前Pytorch团队也在尝试通过移除CPython中的GIL来达到基于多线程实现流水线并行以提升通信效率的目的 :cite:`rmpygil`,感兴趣的读者可以选择继续深入了解。 #### 算子并行 @@ -144,7 +144,7 @@ for batch_idx, sample in enumerate(loader): :width:`800px` :label:`operator_parallisim` -现有机器学习系统的数据模块中,tf.data以及MindData均采用了算子并行的方案。由于对算力的利用更加充分、以及基于C++的高效数据流调度实现,算子并行的方案往往展示出更好的性能,tf.data的性能评测表明其相比较Pytorch的Dataloader有近两倍的性能优势\[5\]。 +现有机器学习系统的数据模块中,tf.data以及MindData均采用了算子并行的方案。由于对算力的利用更加充分、以及基于C++的高效数据流调度实现,算子并行的方案往往展示出更好的性能,tf.data的性能评测表明其相比较Pytorch的Dataloader有近两倍的性能优势 :cite:`murray2021tf`。 接下来我们以一段基于MindSpore实现本节开篇的数据预处理流程来展示如何在一个算子并行的数据流水线中设置各个算子的并行度。 ```python @@ -174,7 +174,7 @@ dataset = dataset.map(input_columns="image", operations=vision.HWC2CHW(), num_pa dataset = dataset.map(input_columns="label", operations=onehot_op) ``` -我们发现,虽然算子并行具备更高的性能潜力,但却需要我们对每一个算子设置合理并行参数。这不仅对用户提出了较高的要求,同时也增加了由于不合理的并行参数设置导致性能反而下降的风险。为了让用户更加轻松的使用算子并行,tf.data和MindData都增加了流水线关键参数动态调优功能,基于对流水线执行时的性能监控计算得到合理的参数以尽可能达到最优的数据预处理吞吐率\[5\]。 +我们发现,虽然算子并行具备更高的性能潜力,但却需要我们对每一个算子设置合理并行参数。这不仅对用户提出了较高的要求,同时也增加了由于不合理的并行参数设置导致性能反而下降的风险。为了让用户更加轻松的使用算子并行,tf.data和MindData都增加了流水线关键参数动态调优功能,基于对流水线执行时的性能监控计算得到合理的参数以尽可能达到最优的数据预处理吞吐率 :cite:`murray2021tf`。 #### 数据处理计算图优化 diff --git a/chapter_data_processing/program_model.md b/chapter_data_processing/program_model.md index 5e740b3..a80c93a 100644 --- a/chapter_data_processing/program_model.md +++ b/chapter_data_processing/program_model.md @@ -11,8 +11,8 @@ :label:`image_process_pipeline` -事实上,面向数据计算的编程抽象早已在通用数据并行计算系统领域中被广泛的研究并取得了相对统一的共识------那就是提供类LINQ式\[1\]的编程抽象,其最大的特点是让用户专注于描述基于数据集的生成与变换,而将这些操作的高效实现与调度执行交由数据系统的运行时负责。一些优秀的系统如Naiad\[2\], -Spark\[3\], DryadLINQ\[4\]等都采用了这种编程模型。我们以Spark为例子进行简要介绍。 +事实上,面向数据计算的编程抽象早已在通用数据并行计算系统领域中被广泛的研究并取得了相对统一的共识------那就是提供类LINQ式 :cite:`meijer2006linq` 的编程抽象,其最大的特点是让用户专注于描述基于数据集的生成与变换,而将这些操作的高效实现与调度执行交由数据系统的运行时负责。一些优秀的系统如Naiad :cite:`murray2013naiad`, +Spark :cite:`zaharia2010spark`, DryadLINQ :cite:`fetterly2009dryadlinq`等都采用了这种编程模型。我们以Spark为例子进行简要介绍。 Spark向用户提供了基于弹性分布式数据集(Resilient Distributed Dataset, RDD)概念的编程模型。一个RDD是一个只读的分布式数据集合,用户通过Spark的编程接口来主要描述RDD的创建及变换过程,我们以一个Spark示例进行展开讨论。下面展示了一段在一个日志文件中统计包含ERROR字段的行数的Spark代码,我们首先通过文件读取创建一个分布式的数据集file(前文提到RDD表示数据的集合,这里的file实际上是日志行的数据集合)。 我们对这个file数据集进行filter(过滤)运算得到新的只保留包含ERROR字段的日志行的数据集errs,接着我们对errs中的每一个数据进行map(映射)操作得到数据集ones,最后我们对ones数据集进行reduce操作得到了我们最终想要的统计结果,即file数据集中包含ERROR字段的日志行数。 @@ -32,7 +32,7 @@ val count = ones.reduce(_+_) :width:`800px` :label:`rdd_transformation_example` -主流机器学习系统中的数据模块同样也采用了类似的编程抽象,如TensorFlow的数据模块tf.data\[5\], +主流机器学习系统中的数据模块同样也采用了类似的编程抽象,如TensorFlow的数据模块tf.data :cite:`murray2021tf`, 以及MindSpore的数据模块MindData等。接下来我们以MindData的接口设计为例子来介绍如何面向机器学习这个场景设计好的编程抽象来帮助用户方便的构建模型训练中多种多样的数据处理流水线。 MindData是机器学习系统MindSpore的数据模块,主要负责完成机器学习模型训练中的数据预处理任务,MindData的向用户提供的核心编程抽象为基于Dataset(数据集)的变换处理。这里的Dataset是一个数据帧的概念(Data @@ -111,7 +111,7 @@ dataset = dataset.map(input_columns="label", operations=onehot_op) MindData中的数据预处理算子可以分为C层算子以及Python层算子,C层算子能提供较高的执行性能而Python层算子可以很方便借助丰富的第三方Python包进行开发。为了灵活地覆盖更多场景,MindData支持用户使用Python开发自定义算子,如果用户追求更高的性能,MindData也支持用户将开发的C层算子编译后以插件的形式注册到MindSpore的数据处理中进行调用。 -对于用户传入map、filter等数据集变换算子中的自定义数据处理算子,MindData的Pipeline启动后会通过创建的Python运行时来执行。需要指出的是自定义的Python算子需要保证需要保一个或多个输入、输出均是numpy.ndarray类型。具体执行过程中,当MindData的Pipeline的数据集变换中执行用户自定义的PyFunc算子时,会将输入数据以numpy.ndarray的类型传递给用户的PyFunc,自定义算子执行完毕后再以numpy.ndarray返回给MindData,在此期间,正在执行的数据集变换算子(如map、filter等)负责该PyFunc的运行时生命周期及异常判断。如果用户追求更高的性能,MindData也支持用户自定义C算子。dataset-plugin仓(插件仓)\[10\]为MindData的算子插件仓,囊括了为特定领域(遥感,医疗,气象等)量身制作的算子,该仓承载MindData的插件能力扩展,为用户编写MindData的新算子提供了便捷易用的入口,用户通过编写算子、编译、安装插件步骤,然后就可以在MindData +对于用户传入map、filter等数据集变换算子中的自定义数据处理算子,MindData的Pipeline启动后会通过创建的Python运行时来执行。需要指出的是自定义的Python算子需要保证需要保一个或多个输入、输出均是numpy.ndarray类型。具体执行过程中,当MindData的Pipeline的数据集变换中执行用户自定义的PyFunc算子时,会将输入数据以numpy.ndarray的类型传递给用户的PyFunc,自定义算子执行完毕后再以numpy.ndarray返回给MindData,在此期间,正在执行的数据集变换算子(如map、filter等)负责该PyFunc的运行时生命周期及异常判断。如果用户追求更高的性能,MindData也支持用户自定义C算子。dataset-plugin仓(插件仓) :cite:`minddata` 为MindData的算子插件仓,囊括了为特定领域(遥感,医疗,气象等)量身制作的算子,该仓承载MindData的插件能力扩展,为用户编写MindData的新算子提供了便捷易用的入口,用户通过编写算子、编译、安装插件步骤,然后就可以在MindData Pipeline的map操作中使用新开发的算子。 diff --git a/chapter_data_processing/reference.md b/chapter_data_processing/reference.md deleted file mode 100644 index ea6464e..0000000 --- a/chapter_data_processing/reference.md +++ /dev/null @@ -1,34 +0,0 @@ -## 引用 -\[1\] Meijer, E., Beckman, B., & Bierman, G. (2006, June). Linq: -reconciling object, relations and xml in the. net framework. In -Proceedings of the 2006 ACM SIGMOD international conference on -Management of data (pp. 706-706). - -\[2\] Murray, D. G., McSherry, F., Isaacs, R., Isard, M., Barham, P., & -Abadi, M. (2013, November). Naiad: a timely dataflow system. In -Proceedings of the Twenty-Fourth ACM Symposium on Operating Systems -Principles (pp. 439-455). - -\[3\] Zaharia, M., Chowdhury, M., Franklin, M. J., Shenker, S., & Stoica, -I. (2010). Spark: Cluster computing with working sets. HotCloud, -10(10-10), 95. - -\[4\] Fetterly, Y. Y. M. I. D., Budiu, M., Erlingsson, Ú., & Currey, P. -K. G. J. (2009). DryadLINQ: A system for general-purpose distributed -data-parallel computing using a high-level language. Proc. LSDS-IR, 8. - -\[5\] Murray, D. G., Simsa, J., Klimovic, A., & Indyk, I. (2021). tf. -data: A Machine Learning Data Processing Framework. arXiv preprint -arXiv:2101.12127. - -\[6\] Mohan, J., Phanishayee, A., Raniwala, A., & Chidambaram, V. (2020). -Analyzing and mitigating data stalls in DNN training. arXiv preprint -arXiv:2007.06775. - -\[7\] https://docs.google.com/document/d/18CXhDb1ygxg-YXNBJNzfzZsDFosB5e6BfnXLlejd9l0/edit#. - -\[8\] https://github.com/NVIDIA/DALI. - -\[9\] https://docs.ray.io/en/latest/data/dataset.html. - -\[10\] https://gitee.com/mindspore/dataset-plugin. \ No newline at end of file diff --git a/mlsys.bib b/mlsys.bib index ea0a898..dbe69b5 100644 --- a/mlsys.bib +++ b/mlsys.bib @@ -102,6 +102,22 @@ year={2011} } +@inproceedings{meijer2006linq, + title={Linq: reconciling object, relations and xml in the. net framework}, + author={Meijer, Erik and Beckman, Brian and Bierman, Gavin}, + booktitle={Proceedings of the 2006 ACM SIGMOD international conference on Management of data}, + pages={706--706}, + year={2006} +} + +@inproceedings{murray2013naiad, + title={Naiad: a timely dataflow system}, + author={Murray, Derek G and McSherry, Frank and Isaacs, Rebecca and Isard, Michael and Barham, Paul and Abadi, Mart{\'\i}n}, + booktitle={Proceedings of the Twenty-Fourth ACM Symposium on Operating Systems Principles}, + pages={439--455}, + year={2013} +} + @inproceedings{mnih2016asynchronous, title={Asynchronous methods for deep reinforcement learning}, author={Mnih, Volodymyr and Badia, Adria Puigdomenech and Mirza, Mehdi and Graves, Alex and Lillicrap, Timothy and Harley, Tim and Silver, David and Kavukcuoglu, Koray}, @@ -141,6 +157,59 @@ year={2018} } +@inproceedings{zaharia2010spark, + title={Spark: Cluster computing with working sets}, + author={Zaharia, Matei and Chowdhury, Mosharaf and Franklin, Michael J and Shenker, Scott and Stoica, Ion}, + booktitle={2nd USENIX Workshop on Hot Topics in Cloud Computing (HotCloud 10)}, + year={2010} +} + +@article{fetterly2009dryadlinq, + title={DryadLINQ: A system for general-purpose distributed data-parallel computing using a high-level language}, + author={Fetterly, Yuan Yu Michael Isard Dennis and Budiu, Mihai and Erlingsson, {\'U}lfar and Currey, Pradeep Kumar Gunda Jon}, + journal={Proc. LSDS-IR}, + volume={8}, + year={2009} +} + +@article{murray2021tf, + title={tf. data: A machine learning data processing framework}, + author={Murray, Derek G and Simsa, Jiri and Klimovic, Ana and Indyk, Ihor}, + journal={arXiv preprint arXiv:2101.12127}, + year={2021} +} + +@article{mohan2020analyzing, + title={Analyzing and mitigating data stalls in dnn training}, + author={Mohan, Jayashree and Phanishayee, Amar and Raniwala, Ashish and Chidambaram, Vijay}, + journal={arXiv preprint arXiv:2007.06775}, + year={2020} +} + +@misc{rmpygil + author = "Sam Gross", + title = "Multithreaded Python without the GIL", + howpublished = "Website", + year = {2021}, + note = {\url{https://docs.google.com/document/d/18CXhDb1ygxg-YXNBJNzfzZsDFosB5e6BfnXLlejd9l0/edit#heading=h.kcngwrty1lv}} +} + +@misc{nvidia_dali + author = "NVIDIA", + title = "DALI", + howpublished = "Website", + year = {2018}, + note = {\url{https://github.com/NVIDIA/DALI}} +} + +@misc{minddata + author = "HuaWei", + title = "Dataset Plugin", + howpublished = "Website", + year = {2020}, + note = {\url{https://gitee.com/mindspore/dataset-plugin}} +} + @article{liang2017ray, title={Ray rllib: A composable and scalable reinforcement learning library}, author={Liang, Eric and Liaw, Richard and Nishihara, Robert and Moritz, Philipp and Fox, Roy and Gonzalez, Joseph and Goldberg, Ken and Stoica, Ion},