• 文档 >
  • ExecuTorch 的高级架构和组件
快捷方式

ExecuTorch 高级架构和组件

本页介绍了 ExecuTorch 的技术架构及其各个组件。本文档的目标读者是将 PyTorch 模型部署到边缘设备的工程师。

背景

为了针对具有多样化硬件、严格功耗要求和实时处理需求的设备端 AI,单一的整体解决方案是不切实际的。相反,模块化、分层和可扩展的架构是理想的选择。ExecuTorch 定义了一个简化的工作流程来准备(导出、转换和编译)和执行 PyTorch 程序,其中包含有主见的开箱即用默认组件和用于自定义的明确定义的入口点。这种架构极大地提高了可移植性,使工程师能够使用高性能、轻量级、跨平台运行时,轻松集成到不同的设备和平台中。

概述

将 PyTorch 模型部署到设备端分为三个阶段:程序准备、运行时准备和程序执行,如下图所示,其中包含多个用户入口点。我们将在本文档中分别讨论每个步骤。

图 1. 该图说明了三个阶段 - 程序准备、运行时准备和程序执行。

程序准备

ExecuTorch 扩展了 PyTorch 的灵活性和可用性,使其能够应用于边缘设备。它利用 PyTorch 2 编译器和导出功能(TorchDynamoAOTAutograd量化动态形状控制流 等)来准备在设备上执行的 PyTorch 程序。

程序准备通常简称为 AOT(提前编译),因为在最终使用 C++ 编写的 ExecuTorch 运行时运行程序之前,会执行程序的导出、转换和编译。为了获得轻量级运行时和较小的执行开销,我们尽可能将工作推送到 AOT。

从程序源代码开始,以下是完成程序准备的步骤。

程序源代码

  • 与所有 PyTorch 用例一样,ExecuTorch 从模型编写开始,创建标准的 nn.Module eager 模式 PyTorch 程序。

  • 导出特定的帮助程序用于表示高级功能,例如 控制流(例如,用于跟踪 if-else 两个分支的帮助程序函数)和 动态形状(例如,数据相关的动态形状约束)。

导出

为了将程序部署到设备,工程师需要一个图形表示,用于编译模型以在各种后端上运行。使用 torch.export(),生成一个带有 ATen 方言的 EXIR(导出中间表示)。所有 AOT 编译都基于此 EXIR,但可以沿着降级路径具有多种方言,如下详述。

  • ATen 方言。PyTorch Edge 基于 PyTorch 的张量库 ATen,该库对高效执行具有明确的约定。ATen 方言是由完全符合 ATen 规范的 ATen 节点表示的图形。允许使用自定义运算符,但必须在调度程序中注册。它是扁平的,没有模块层次结构(较大模块中的子模块),但源代码和模块层次结构保留在元数据中。此表示也是自动微分安全的。

  • 可选地,在转换为核心 ATen 之前,可以将量化(QAT(量化感知训练)或 PTQ(训练后量化))应用于整个 ATen 图。量化有助于减小模型大小,这对于边缘设备非常重要。

  • 核心 ATen 方言。ATen 有数千个运算符。对于某些基本转换和内核库实现来说,这并不理想。ATen 方言图中的运算符被分解为基本运算符,以便运算符集(op set)更小,并且可以应用更多基本转换。核心 ATen 方言也是可序列化的,并且可以转换为边缘方言,如下详述。

边缘编译

上面讨论的导出过程在与最终执行代码的边缘设备无关的图形上运行。在边缘编译步骤中,我们处理特定于边缘的表示。

  • 边缘方言。所有运算符要么符合带有 dtype 加内存布局信息的 ATen 运算符(表示为 dim_order),要么是注册的自定义运算符。标量转换为张量。这些规范允许后续步骤专注于较小的边缘域。此外,它还支持基于特定 dtype 和内存布局的选择性构建。

使用边缘方言,有两种感知目标的方式可以将图形进一步降级为后端方言。此时,特定硬件的委托可以执行许多操作。例如,iOS 上的 Core ML、Qualcomm 上的 QNN 或 Arm 上的 TOSA 可以重写图形。此级别的选项包括

  • 后端委托。用于将图形(全部或部分)编译为特定后端的入口点。编译后的图形在此转换期间与语义等效的图形交换。编译后的图形稍后将在运行时卸载到后端(也称为 delegated),以提高性能。

  • 用户定义的 Pass。用户也可以执行特定于目标的转换。这方面的典型示例包括内核融合、异步行为、内存布局转换等。

编译为 ExecuTorch 程序

上面的边缘程序适用于编译,但不适用于运行时环境。设备端部署工程师可以降级图形,以便运行时可以高效加载和执行该图形。

在大多数边缘环境中,动态内存分配/释放具有显著的性能和功耗开销。可以使用 AOT 内存规划和静态执行图来避免这种情况。

  • ExecuTorch 运行时是静态的(在图形表示的意义上,但仍然支持控制流和动态形状)。为了避免输出创建和返回,所有函数式运算符表示都转换为 out 变体(输出作为参数传递)。

  • 可选地,用户可以应用自己的内存规划算法。例如,嵌入式系统可能存在特定的内存层次结构。用户可以根据该内存层次结构进行自定义内存规划。

  • 程序以我们的 ExecuTorch 运行时可以识别的格式发出。

最后,发出的程序可以序列化为 flatbuffer 格式。

运行时准备

借助序列化的程序和提供的内核库(用于运算符调用)或后端库(用于委托调用),模型部署工程师现在可以为运行时准备程序。

ExecuTorch 具有选择性构建 API,用于构建仅链接到程序使用的内核的运行时,这可以显著节省生成的应用程序中的二进制文件大小。

程序执行

ExecuTorch 运行时是用 C++ 编写的,具有最少的依赖项,以实现可移植性和执行效率。由于程序已通过 AOT 充分准备,因此核心运行时组件非常少,包括

  • 平台抽象层

  • 日志记录和可选的分析

  • 执行数据类型

  • 内核和后端注册表

  • 内存管理

Executor 是加载程序并执行程序的入口点。执行从这个非常小的运行时触发相应的运算符内核或后端执行。

开发者工具

用户应该可以高效地使用上述流程从研究到生产。对于用户编写、优化和部署模型而言,生产力至关重要。我们提供 ExecuTorch 开发者工具 来提高生产力。开发者工具不在图中。相反,它是一套涵盖所有三个阶段的开发者工作流程的工具集。

在程序准备和执行期间,用户可以使用 ExecuTorch 开发者工具来分析、调试或可视化程序。由于端到端流程在 PyTorch 生态系统内,因此用户可以将性能数据与图形可视化以及对程序源代码和模型层次结构的直接引用相关联并显示出来。我们认为这是快速迭代和将 PyTorch 程序降级到边缘设备和环境的关键组件。

文档

访问 PyTorch 的全面开发者文档

查看文档

教程

获取面向初学者和高级开发者的深度教程

查看教程

资源

查找开发资源并获得问题解答

查看资源