架构和组件¶
本页面介绍了 ExecuTorch 及其各个组件的技术架构。本文档面向将 PyTorch 模型部署到边缘设备的工程师。
背景
为了在具有多样化硬件、关键功耗要求和实时处理需求的设备上实现人工智能,单一的单体解决方案并不可行。因此,需要一种模块化、分层和可扩展的架构。ExecuTorch 定义了一个简化的工作流程来准备(导出、转换和编译)和执行 PyTorch 程序,并提供了有主见的开箱即用默认组件以及用于自定义的明确定义的入口点。这种架构极大地提高了可移植性,使工程师能够使用高性能、轻量级的跨平台运行时,该运行时可以轻松集成到不同的设备和平台中。
概述¶
将 PyTorch 模型部署到设备上有三个阶段:程序准备、运行时准备和程序执行,如下图所示,其中包含多个用户入口点。我们将在本文档中单独讨论每个步骤。
图 1. 该图说明了三个阶段——程序准备、运行时准备和程序执行。
程序准备¶
ExecuTorch 将 PyTorch 的灵活性和可用性扩展到边缘设备。它利用 PyTorch 2 编译器和导出功能(TorchDynamo、AOTAutograd、量化、动态形状、控制流等)来准备 PyTorch 程序以在设备上执行。
程序准备通常简称为 AOT(提前编译),因为程序导出、转换和编译是在程序最终使用 C++ 编写的 ExecuTorch 运行时执行之前完成的。为了拥有轻量级的运行时和较低的执行开销,我们将尽可能多的工作推迟到 AOT。
从程序源代码开始,以下是您完成程序准备将要经过的步骤。
程序源代码¶
导出¶
要将程序部署到设备,工程师需要一个图表示来编译模型以在各种后端上运行。使用 torch.export()
,将生成一个具有 ATen 方言的 EXIR(导出中间表示)。所有 AOT 编译都基于此 EXIR,但在如下文所述的降低路径中可以具有多个方言。
ATen 方言。PyTorch Edge 基于 PyTorch 的 Tensor 库 ATen,该库具有清晰的有效执行合同。ATen 方言是由完全符合 ATen 的 ATen 节点表示的图。允许自定义运算符,但必须在调度器中注册。它是扁平化的,没有模块层次结构(大模块中的子模块),但源文件和模块层次结构保留在元数据中。这种表示也是 autograd 安全的。
可选地,可以在将整个 ATen 图转换为 Core ATen 之前应用量化,无论是 QAT(量化感知训练)还是 PTQ(训练后量化)。量化有助于减小模型大小,这对于边缘设备很重要。
Core ATen 方言。ATen 有成千上万的运算符。对于某些基本变换和内核库实现来说,它不是理想的。ATen 方言图中的运算符被分解为基本运算符,以便运算符集(op set)更小,并且可以应用更多基本变换。Core ATen 方言也是可序列化的,并且可以像下面详细介绍的那样转换为 Edge 方言。
Edge 编译¶
上面讨论的导出过程在对代码最终将在其上执行的边缘设备无关的图上运行。在 Edge 编译步骤中,我们处理特定于 Edge 的表示。
Edge 方言。所有运算符要么符合具有 dtype 和内存布局信息的 ATen 运算符(表示为
dim_order
),要么是注册的自定义运算符。标量被转换为 Tensor。这些规范允许后续步骤专注于更小的 Edge 域。此外,它还支持基于特定 dtypes 和内存布局的选择性构建。
使用 Edge 方言,有两种目标感知的方法可以将图进一步降低到Backend 方言。此时,特定硬件的委托(delegates)可以执行许多操作。例如,iOS 上的 Core ML、高通上的 QNN 或 Arm 上的 TOSA 可以重写图。此级别的选项是
Backend 委托。将图(完整或部分)编译到特定后端的入口点。在此转换期间,编译后的图将被语义上等效的图替换。在运行时稍后将编译后的图卸载到后端(也称为
delegated
)以提高性能。用户定义的通道。用户还可以执行目标特定的变换。此类的良好示例包括内核融合、异步行为、内存布局转换等。
编译为 ExecuTorch 程序¶
上述 Edge 程序适合编译,但不适合运行时环境。设备上部署工程师可以降低图,使其能够被运行时高效加载和执行。
在大多数 Edge 环境中,动态内存分配/释放会产生显著的性能和功耗开销。可以使用 AOT 内存规划和静态执行图来避免这种情况。
ExecuTorch 运行时是静态的(就图表示而言,但仍然支持控制流和动态形状)。为了避免输出创建和返回,所有函数式运算符表示都被转换为 out 变体(输出作为参数传递)。
可选地,用户可以应用自己的内存规划算法。例如,对于嵌入式系统,可以有特定的内存层次结构层。用户可以根据该内存层次结构进行自定义内存规划。
程序将以我们的 ExecuTorch 运行时能够识别的格式发出。
最后,发出的程序可以序列化为 flatbuffer 格式。
运行时准备¶
有了序列化程序和提供的内核库(用于运算符调用)或后端库(用于委托调用),模型部署工程师现在可以为运行时准备程序。
ExecuTorch 具有选择性构建 API,用于构建仅链接程序使用的内核的运行时,这可以显著减小最终应用程序的二进制文件大小。
程序执行¶
ExecuTorch 运行时是用 C++ 编写的,具有最少的依赖项,以实现可移植性和执行效率。由于程序已在 AOT 中得到充分准备,核心运行时组件最少,包括:
平台抽象层
日志记录和可选的性能分析
执行数据类型
内核和后端注册表
内存管理
Executor 是加载程序和执行程序的入口点。执行从这个非常精简的运行时触发相应的运算符内核或后端执行。
开发者工具¶
通过上述流程,用户应该能够高效地从研究过渡到生产。生产力对于用户编写、优化和部署其模型至关重要。我们提供 ExecuTorch 开发者工具 来提高生产力。开发者工具未显示在图中。相反,它是一套涵盖所有三个阶段的开发者工作流程的工具。
在程序准备和执行期间,用户可以使用 ExecuTorch 开发者工具来分析、调试或可视化程序。由于端到端流程都在 PyTorch 生态系统中,用户可以将性能数据与图可视化以及对程序源代码和模型层次结构的直接引用相关联和显示。我们认为这是快速迭代并将 PyTorch 程序降低到边缘设备和环境的关键组件。