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