mirror of
https://github.com/openmlsys/openmlsys-zh.git
synced 2026-04-04 19:28:32 +08:00
fix ch03 (#316)
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
:label:`dag`
|
||||
|
||||
早期的机器学习框架主要为了支持基于卷积神经网络的图像分类问题。这些神经网络的拓扑结构简单(神经网络层往往通过串行构建),他们的拓扑结构可以用简单的配置文件来表达(例如Caffe中基于Protocol
|
||||
Buffer格式的模型定义)。随着机器学习的进一步发展,模型的拓扑日益复杂(包括混合专家,生成对抗网络,多注意力模型)。这些模型复杂的拓扑结构(例如说,分支结构,带有条件的if-else循环)会影响模型算子的执行、自动化梯度计算(一般称为自动微分)以及训练参数的自动化判断。为此,我们需要一个更加通用的技术来执行任意机器学习模型。因此,计算图应运而生。综合来看,计算图对于一个机器学习框架提供了以下几个关键作用:
|
||||
Buffer格式的模型定义)。随着机器学习的进一步发展,模型的拓扑日益复杂(包括混合专家,生成对抗网络,多注意力模型)。这些复杂的模型拓扑结构(例如:分支结构,带有条件的if-else循环)会影响模型算子的执行、自动化梯度计算(一般称为自动微分)以及训练参数的自动化判断。为此,我们需要一个更加通用的技术来执行任意机器学习模型,计算图应运而生。综合来看,计算图对于一个机器学习框架提供了以下几个关键作用:
|
||||
|
||||
- **对于输入数据、算子和算子执行顺序的统一表达。**
|
||||
机器学习框架用户可以用多种高层次编程语言(Python,Julia和C++)来编写训练程序。这些高层次程序需要统一的表达成框架底层C和C++算子的执行。因此,计算图的第一个核心作用是可以作为一个统一的数据结构来表达用户用不同语言编写的训练程序。这个数据结构可以准确表述用户的输入数据、模型所带有的多个算子,以及算子之间的执行顺序。
|
||||
@@ -16,5 +16,5 @@ Buffer格式的模型定义)。随着机器学习的进一步发展,模型
|
||||
- **自动化计算梯度。**
|
||||
用户给定的训练程序仅仅包含了一个机器学习模型如何将用户输入(一般为训练数据)转化为输出(一般为损失函数)的过程。而为了训练这个模型,机器学习框架需要分析任意机器学习模型和其中的算子,找出自动化计算梯度的方法。计算图的出现让自动化分析模型定义和自动化计算梯度成为可能。
|
||||
|
||||
- **高效程序执行。**
|
||||
- **优化程序执行。**
|
||||
用户给定的模型程序往往是"串行化"地连接起来多个神经网络层。通过利用计算图来分析模型中算子的执行关系,机器学习框架可以更好地发现将算子进行异步执行的机会,从而以更快的速度完成模型程序的执行。
|
||||
@@ -1,6 +1,6 @@
|
||||
## 计算图的基本构成
|
||||
|
||||
计算图是用来表示深度学习网络模型在训练与推理过程中计算逻辑与状态的工具。计算框架在后端会将前端语言构建的神经网络模型前向计算与反向梯度计算以计算图的形式来进行表示。计算图由基本数据结构张量(Tensor)和基本运算单元算子(Operator)构成。在计算图中通常使用节点来表示算子,节点间的有向线段来表示张量状态,同时也描述了计算间的依赖关系。如 :numref:`simpledag`所示,将$\boldsymbol{Z}=relu(\boldsymbol{X}*\boldsymbol{Y})$转化为计算图表示,数据流将根据图中流向与算子进行前向计算和反向梯度计算来更新图中张量状态,以此达到训练模型的目的。
|
||||
计算图是用来表示深度学习网络模型在训练与推理过程中计算逻辑与状态的工具。计算框架在后端会将前端语言构建的神经网络模型前向计算与反向梯度计算以计算图的形式来进行表示。计算图由基本数据结构:张量(Tensor)和基本运算单元:算子(Operator)构成。在计算图中通常使用节点来表示算子,节点间的有向线段来表示张量状态,同时也描述了计算间的依赖关系。如 :numref:`simpledag`所示,将$\boldsymbol{Z}=relu(\boldsymbol{X}*\boldsymbol{Y})$转化为计算图表示,数据流将根据图中流向与算子进行前向计算和反向梯度计算来更新图中张量状态,以此达到训练模型的目的。
|
||||
|
||||

|
||||
:width:`300px`
|
||||
|
||||
@@ -32,9 +32,9 @@ def model(X, flag):
|
||||
|
||||
优化完成的计算图通过编译器后端根据计算硬件来生成适配的执行代码。在执行阶段,调用执行器接受输入数据,依据计算图调度算子执行训练或者推理任务。在训练任务调度算子执行时,由于在执行阶段已经编译获取模型整体结构,计算框架可以利用自动并行算法制定合理的模型切分与并行策略,进一步提高计算效率。
|
||||
|
||||
使用静态图构建模型,编译构建完整的计算图后,计算图可以进行序列化保存,并且再次执行时允许使用序列化模型直接进行训练或推理,不需要再次编译前端语言源代码。得益于编译器前端、中间表示、编译器后端多级的计算框架编译器体系结构,编译器后端可以将神经网络模型中间表示转换为不同硬件代码。结合计算图序列化和计算图可转换多种部署硬件代码两种特性,使得静态图模型可以直接部署在不同的硬件上面,提供高效的推理服务。
|
||||
使用静态图构建模型,编译构建完整的计算图后,计算图可以进行序列化保存,再次执行时允许使用序列化模型直接进行训练或推理,无需重新编译前端语言源代码。得益于编译器前端、中间表示、编译器后端多级的计算框架编译器体系结构,编译器后端可以将神经网络模型中间表示转换为不同硬件代码。结合计算图序列化和计算图可转换成多种硬件代码两种特性,静态图模型可以直接部署在不同的硬件上面,提供高效的推理服务。
|
||||
|
||||
尽管静态图具备强大的执行计算性能与直接部署能力,但是在部分计算框架中静态图模式下,使用前端语言编写神经网络模型以及定义模型训练过程代码较为繁琐,尤其掌握图内控制流方法具备一定的学习难度,因此熟练掌握并使用静态图模式对于初学者并不友好。其次,静态生成采用先编译后执行的方式,编译阶段和执行阶段分离,前端语言构建的神经网络模型经过编译后,计算图结构便固定执行阶段不再改变,并且经过优化用于执行的计算图结构与原始代码有较大的差距,导致代码中的错误难以定位到准确位置,增加了代码调试难度。此外在神经网络模型开发迭代环节,不能即时打印中间结果。若在源码中添加输出中间结果的代码,则需要将源码重新编译后,再调用执行器才能获取相关信息,降低了代码调试效率。而动态图模式则拥有更加灵活的特性,接下来讲解动态生成机制。
|
||||
尽管静态图具备强大的执行计算性能与直接部署能力,但是在部分计算框架中静态图模式下,使用前端语言编写神经网络模型以及定义模型训练过程代码较为繁琐,尤其掌握图内控制流方法具备一定的学习难度,因此熟练掌握并使用静态图模式对于初学者并不友好。其次,静态生成采用先编译后执行的方式,编译阶段和执行阶段分离,前端语言构建的神经网络模型经过编译后,计算图结构便固定执行阶段不再改变,并且经过优化用于执行的计算图结构与原始代码有较大的差距,导致代码中的错误难以定位到准确位置,增加了代码调试难度。此外在神经网络模型开发迭代环节,不能即时打印中间结果。若在源码中添加输出中间结果的代码,则需要将源码重新编译后,再调用执行器才能获取相关信息,降低了代码调试效率。而动态图模式则更加灵活,接下来讲解动态生成机制。
|
||||
|
||||
### 动态生成
|
||||
|
||||
@@ -44,7 +44,7 @@ def model(X, flag):
|
||||
:width:`600px`
|
||||
:label:`dynamic`
|
||||
|
||||
由于动态图模式的编程友好性,动态图被广大深度学习研究者青睐使用。接下来使用上一小节的伪代码来讲解动态生成和静态生成的区别。
|
||||
由于动态图模式的编程友好性,动态图深受广大深度学习研究者青睐。接下来使用上一小节的伪代码来讲解动态生成和静态生成的区别。
|
||||
|
||||
尽管静态图和动态图在前端语言表达上略有差异,但本质的区别在于静态生成和动态生成的编译执行过程不同。使用前端语言构建完成模型表达后,动态生成并不采用计算框架编译器生成完整的静态计算图,而是采用前端语言的解释器Python API调用计算框架,框架利用自身的算子分发功能,将Python调用的算子在相应的硬件如CPU、GPU、NPU等上进行加速计算,然后再将计算结果返回给前端。该过程并不产生静态的计算图,而是按照前端语言描述模型结构,按照计算依赖关系进行调度执行,动态生成临时的图拓扑结构。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user