使用 ARM Ethos-U 后端构建和运行 ExecuTorch¶
在本教程中,您将学习如何为 ExecuTorch Arm Ethos-u 后端委托导出一个简单的 PyTorch 模型,并在 Corstone-300 FVP 模拟器上运行它。
警告
此 ExecuTorch 后端委托正在积极开发中。您可能会遇到一些粗糙的边缘和功能,这些边缘和特征可能已记录或计划但未实施。
提示
如果您已经熟悉此委托,则可能需要直接跳转到 examples 源目录 - https://github.com/pytorch/executorch/tree/main/examples/arm
先决条件¶
在我们开始之前,请确保您拥有所需的一切。
硬件¶
要成功完成本教程,您需要一台具有 Arm aarch64 或 x86_64 处理器架构的基于 Linux 的主机。
目标设备将是具有 Arm Cortex-M55 CPU 和 Ethos-U55 NPU(ML 处理器)的嵌入式平台。本教程将向您展示如何在两者上运行 PyTorch 模型。
我们将使用固定虚拟平台 (FVP) 来模拟 Corstone-300(cs300) 系统。由于我们将使用 FVP(将其视为虚拟硬件),因此本教程不需要任何真正的嵌入式硬件。
软件¶
首先,您需要安装 ExecuTorch。如果您还没有,请按照推荐的教程来设置一个有效的 ExecuTorch 开发环境。
为了生成可以在嵌入式平台(真实或虚拟)上运行的软件,我们需要一个用于交叉编译的工具链和一个 Arm Ethos-U 软件开发工具包,包括用于 Ethos-U NPU 的 Vela 编译器。
在以下部分中,我们将演练下载上面列出的每个依赖项的步骤。
设置开发人员环境¶
在本节中,我们将对本教程中运行 ExecuTorch 程序所需的平台支持文件进行一次性设置,例如下载和安装必要的软件。有两种方法可用:
方法 1:使用脚本以自动方式提取每个项目(推荐)。建议在 conda 环境中运行脚本。执行成功后,您可以直接进行下一步。
examples/arm/setup.sh
方法 2:按照指南逐步了解脚本的所有组件和逻辑。如果您打算显著更改流的行为,则可能需要使用此方法。
提示
在 ExecuTorch 存储库中,我们有一个正常运行的脚本,它遵循完全相同的步骤来加快速度。它位于 。如果方便,请随意使用它,或者如果手册说明中的某些步骤不是很清楚,请将其用作参考。examples/arm/setup.sh
如前所述,我们目前仅支持具有 x86_64 或 aarch64 处理器架构的基于 Linux 的平台。让我们确保我们确实在受支持的平台上。
uname -s
# Linux
uname -m
# x86_64 or aarch64
让我们创建一个空目录,并将其用作顶级开发目录。
下载并设置 Corstone-300 FVP¶
固定虚拟平台 (FVP) 是对常用系统配置的预配置、功能准确的模拟。在本教程中,我们对 Corstone-300 系统感兴趣。我们可以从 Arm 网站下载。
注意
下载和运行 FVP 软件,即表示您同意 FVP 最终用户许可协议 (EULA)。
要下载,我们可以从这里下载。或者,您可以下载我们测试的相同版本,如下所示,Corstone-300 Ecosystem FVP
# for aarch64
curl \
--output FVP_cs300.tgz \
'https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-300/FVP_Corstone_SSE-300_11.22_35_Linux64_armv8l.tgz?rev=b083dc5ac9c546899fbb7ccd67b74c17&hash=BFE589289ECF12B07192636382C15C01'
# for x86_64
curl \
--output FVP_cs300.tgz \
'https://developer.arm.com/-/media/Arm%20Developer%20Community/Downloads/OSS/FVP/Corstone-300/FVP_Corstone_SSE-300_11.22_20_Linux64.tgz?rev=018659bd574f4e7b95fa647e7836ccf4&hash=22A79103C6FA5FFA7AFF3BE0447F3FF9'
现在,将文件解压到新目录中,并运行提供的脚本,该脚本将安装 FVP。FVP_cs300.tgz
./FVP_Corstone_SSE-300.sh \
--i-agree-to-the-contained-eula \
--force \
--destination ./ \
--quiet \
--no-interactive
成功后,让我们确保 FVP 模拟器在 PATH 上可用,以备后用。
# for x86-64 hosts
export PATH=${PATH}:<install_dir>/FVP/models/Linux64_GCC-9.3
# for aarch64 hosts
export PATH=${PATH}:<install_dir>/FVP/models/Linux64_armv8l_GCC-9.3/
hash FVP_Corstone_SSE-300_Ethos-U55 # To make sure we are ready to use
下载并安装 Arm GNU AArch32 裸机工具链¶
与 FVP 类似,我们还需要一个工具链来交叉编译 ExecuTorch 运行时、执行程序运行器裸机应用程序,以及 Corstone-300 平台上可用的 Cortex-M55 CPU 裸机堆栈的其余部分。
这些工具链可在此处获得。我们将在本教程中使用 GCC 12.3 定位。就像 FVP 一样,要下载我们在顶级开发目录中测试的相同版本,arm-none-eabi
# for aarch64
curl \
--output gcc.tar.xz \
'https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/12.3.rel1/binrel/arm-gnu-toolchain-12.3.rel1-aarch64-arm-none-eabi.tar.xz'
# for x86_64
curl \
--output gcc.tar.xz \
'https://armkeil.blob.core.windows.net/developer/Files/downloads/gnu/12.3.rel1/binrel/arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-eabi.tar.xz'
下载后,您可以在新目录中提取其内容。然后,让我们确保工具链在 PATH 上可用,以备后用。
export PATH=${PATH}:/<install_dir>/arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-eabi/bin
export PATH=${PATH}:/<install_dir>/arm-gnu-toolchain-12.3.rel1-aarch64-arm-none-eabi/bin
hash arm-none-eabi-gcc # To make sure we are ready to use
设置 Arm Ethos-U 软件开发¶
此 git 存储库是所有 Arm Ethos-U 软件的根目录。这是为了帮助我们下载所需的存储库并将它们放在树结构中。在顶级 devlopment 目录中,
# Download the repo
git clone https://review.mlplatform.org/ml/ethos-u/ethos-u
cd ethos-u
# To align with the version we have tested
git reset --hard 0995223100e3da8011700f58e491f1bf59511e3c
# Download the necessary repos and properly install them
./fetch_externals.py fetch
# Download the Vela compiler
cd .. # To the top-level development dir
git clone https://review.mlplatform.org/ml/ethos-u/ethos-u-vela
完成此操作后,您应该有一个可用的 FVP 模拟器、一个用于交叉编译的功能性工具链,以及用于裸机开发的 Ethos-U 软件开发设置。
应用本地补丁¶
由于它正在积极开发中,我们为 Arm Ethos-u 软件开发工具包提供了一些补丁。让我们将它们应用于下载 SDK 和 Vela 编译器。
cd ethos-u # this is the top level Ethos-U software directory
# Let's patch core_platform repo
cd core_platform
git reset --hard 204210b1074071532627da9dc69950d058a809f4
git am -3 <path_to>/executorch/examples/arm/ethos-u-setup/core_platform/patches/*.patch
cd ../.. # To the top-level development dir
安装 TOSA 参考模型¶
git clone https://review.mlplatform.org/tosa/reference_model -b v0.80
cd reference_model
git submodule update --init --recursive
mkdir -p build
cd build
cmake ..
n=$(nproc)
make -j"$((n - 5))"
cd reference_model # Within the build directory
# Add tosa_reference_model to the path
export PATH=${PATH}:`pwd`
在设置结束时,如果一切顺利,您的顶级开发目录可能如下所示:
.
├── arm-gnu-toolchain-12.3.rel1-x86_64-arm-none-eabi # for x86-64 hosts
├── ethos-u
│ ├── core_platform
│ ├── core_software
│ ├── fetch_externals.py
│ └── [...]
├── ethos-u-vela
├── FVP
│ ├── FVP_Corstone_SSE-300.sh
│ └── [...]
├── FVP_cs300.tgz
├── gcc.tar.xz
└── reference_model
将 PyTorch 模型转换为文件.pte
¶
.pte
是由 ExecuTorch 预先 (AoT) 管道生成的二进制文件,方法是接收 PyTorch 模型 (torch.nn.Module),将其导出,运行各种传递,最后将其序列化为文件格式。此二进制文件通常由 ExecuTorch 运行时使用。本文档更深入地介绍了 AoT 和 Runtime 的 ExecuTorch 软件堆栈。.pte
在本节中,我们将主要关注 AoT 流,其最终目标是生成文件。有一组导出配置在运行时针对不同的后端。对于每个 AoT 流,AoT 流将生成一个唯一的文件。我们将探索几种不同的配置,生成不同的文件,特别是我们的 Corstone-300 系统和可用的处理元素。.pte
.pte
.pte
在开始之前,我们先谈谈我们将使用的 PyTorch 模块。
PyTorch 示例模块¶
我们将使用几个简单的 PyTorch 模块来探索端到端流程。在整个教程中,这些模块将以各种不同的方式使用,用它们的 .<class_name>
Softmax模块¶
这是一个非常简单的 PyTorch 模块,只有一个 Softmax 运算符。
import torch
class SoftmaxModule(torch.nn.Module):
def __init__(self):
super().__init__()
self.softmax = torch.nn.Softmax()
def forward(self, x):
z = self.softmax(x)
return z
使用 Python 环境(在同一台开发 Linux 计算机上)运行它,我们会得到预期的输出。
>>> m = SoftmaxModule()
>>> m(torch.ones(2,2))
tensor([[0.5000, 0.5000],
[0.5000, 0.5000]])
AddModule¶
让我们编写另一个简单的 PyTorch 模块,只包含一个 Add 运算符。
class AddModule(torch.nn.Module):
def __init__(self):
super().__init__()
def forward(self, x):
return x + x
使用 Python 环境(在同一台开发 Linux 计算机上)运行它,正如预期的那样,1 + 1 确实会产生 2。
>>> m = AddModule()
>>> m(torch.ones(5, dtype=torch.int32)) # integer types for non-quantized Ethos-U delegation
tensor([2, 2, 2, 2, 2], dtype=torch.int32)
请牢记这些模块的输入和输出。当我们通过其他方式降低并运行它,而不是在此 Linux 计算机上运行时,我们将使用相同的输入,并期望输出与此处显示的匹配。
提示
我们需要了解在 Ethos-U55 上运行网络的数据类型,因为它是一个纯整数处理器。在这个例子中,我们显式地使用了整数类型,因为这种流的典型用途是用浮点构建和训练网络,然后从浮点量化为整数以实现高效推理。
非委托工作流¶
在 ExecuTorch AoT 管道中,其中一个选项是选择后端。ExecuTorch 提供了各种不同的后端。选择 backend 是可选的,通常是为了针对给定模型计算要求的特定加速模式或硬件。如果没有任何后端,ExecuTorch 运行时将回退到使用一组高度可移植的运算符(默认情况下可用)。
预计在具有专用加速的平台上(如 Ethos-U55),非委托流将用于两种主要情况:
当网络设计为非常小且最适合单独在 Cortex-M 上运行时。
当网络混合了可以针对 NPU 的操作和不能针对 NPU 的操作时,例如 Ethos-U55 支持整数运算,因此浮点 softmax 将回退到 CPU 上执行。
在这个流程中,没有任何后端委托,为了说明 ExecuTorch 运行时以及运算符库的可移植性,我们将在生成过程中跳过指定后端。.pte
以下脚本将用作帮助程序实用程序,帮助我们生成文件。这在目录中可用。.pte
examples/arm
python3 -m examples.arm.aot_arm_compiler --model_name="softmax"
# This should produce ./softmax.pte
委派工作流¶
通过与 Arm 合作,我们为 ExecuTorch 引入了一个新的 Arm 后端委托。此后端正在积极开发中,在撰写本文时可用的功能集有限。
通过在 ExecuTorch AoT 导出管道中包括以下步骤来生成文件,我们可以启用此后端委托。.pte
from executorch.backends.arm.arm_backend import generate_ethosu_compile_spec
graph_module_edge.exported_program = to_backend(
model.exported_program,
ArmPartitioner(generate_ethosu_compile_spec("ethos-u55-128")))
与非委托流类似,相同的脚本将作为帮助程序实用程序来帮助我们生成文件。请注意启用调用的选项。.pte
--delegate
to_backend
python3 -m examples.arm.aot_arm_compiler --model_name="add" --delegate
# should produce ./add_arm_delegate.pte
最后,我们应该有两个不同的文件。第一个使用 SoftmaxModule,没有任何后端委托。第二个版本使用 AddModule 并启用了 Arm Ethos-U 后端委托。现在,让我们尝试在裸机环境中的 Corstone-300 平台上运行这些文件。.pte
.pte
获取裸机可执行文件¶
在本节中,我们将介绍构建运行时应用程序所需经历的步骤。然后,它将在目标设备上运行。
提示
在 executorch 存储库中,我们有一个正常运行的脚本,它执行完全相同的步骤。它位于 。如果方便,请随意使用它,或者如果手册说明中的某些步骤不是很清楚,请将其用作参考。executorch/examples/arm/run.sh
此外,在我们开始之前,请确保您已完成 ExecuTorch cmake 构建设置,以及前面描述的设置开发环境的说明。
下面的框图概括地演示了如何生成各种构建工件并将其链接在一起以生成最终的裸机可执行文件。
生成 ExecuTorch 库¶
ExecuTorch 的 CMake 构建系统生成了一组构建块,这些构建块对于我们在 Ethos-U SDK 的 Corstone-300 裸机环境中包含和运行 ExecuTorch 运行时至关重要。
本文档提供了每个构建件的详细概述。要运行文件的任一变体,我们需要一组核心库。这是一个列表,.pte
libexecutorch.a
libportable_kernels.a
libportable_ops_lib.a
要使用 Arm 后端委托调用指令运行文件,我们需要 Arm 后端委托运行时库,即.pte
libexecutorch_delegate_ethos_u.a
要生成这些库,请使用以下命令:
# Empty and already created
cd <executorch_source_root_dir>
# Use provided cmake toolchain for bare-metal builds
toolchain_cmake=<executorch_source_root_dir>/examples/arm/ethos-u-setup/arm-none-eabi-gcc.cmake
cmake \
-DBUCK2=${buck2} \
-DCMAKE_INSTALL_PREFIX=<executorch_build_dir> \
-DEXECUTORCH_BUILD_EXECUTOR_RUNNER=OFF \
-DCMAKE_BUILD_TYPE=Release \
-DEXECUTORCH_ENABLE_LOGGING=ON \
-DEXECUTORCH_BUILD_ARM_BAREMETAL=ON \
-DEXECUTORCH_BUILD_EXTENSION_RUNNER_UTIL=ON \
-DFLATC_EXECUTABLE="$(which flatc)" \
-DCMAKE_TOOLCHAIN_FILE="${toolchain_cmake}" \
-B<executorch_build_dir> \
<executorch_source_root_dir>
cmake --build <executorch_build_dir> --target install --config Release
cmake \
-DCMAKE_INSTALL_PREFIX=<executorch_build_dir> \
-DCMAKE_BUILD_TYPE=Release \
-DEXECUTORCH_SELECT_OPS_LIST="aten::_softmax.out" \
-DCMAKE_TOOLCHAIN_FILE="${toolchain_cmake}" \
-B<executorch_build_dir>/examples/arm \
<executorch_source_root_dir>/examples/arm
cmake --build <executorch_build_dir>/examples/arm --config Release
EXECUTORCH_SELECT_OPS_LIST
将决定构建中包含的可移植操作符的数量,并在运行时可用。它必须与文件的要求匹配,否则您将在运行时收到错误。.pte
Missing Operator
例如,在上面的命令行中,为了运行 SoftmaxModule,我们只包含了 softmax CPU 运算符。同样,要以非委托方式运行 AddModule,您需要 add op 等。您可能已经意识到,对于将由 Arm 后端委托执行的委托运算符,我们不需要在此列表中包含这些运算符。这仅适用于非委托运算符。
构建 executor_runner 裸机应用程序¶
SDK 目录与之前准备的目录相同。并且,我们将传递上面生成的文件(其中任何一个)。.pte
请注意,如果要更改模型或文件,则必须生成新的二进制文件。此约束来自我们为 Corstone-300 平台提供的受约束裸机运行时环境。executor-runner
.pte
cd <executorch_source_root_dir>
cd examples/arm/executor_runner
cmake \
-DCMAKE_TOOLCHAIN_FILE="${toolchain_cmake}" \
-DTARGET_CPU=cortex-m55 \
-B build \
-DETHOS_SDK_PATH:PATH=<ethos-u_clone_directory> \
-DET_DIR_PATH:PATH=<executorch_source_root_dir> \
-DET_BUILD_DIR_PATH:PATH=<executorch_build_dir> \
-DET_PTE_FILE_PATH:PATH=<path_to_pte_file_of_choice> \
-DPYTHON_EXECUTABLE=$(which python3)
cmake --build build -- arm_executor_runner
在 Corstone-300 FVP 平台上运行¶
准备好 elf 后,无论使用何种文件变体来生成裸机精灵,您都可以使用以下命令运行.pte
ethos_u_build_dir=examples/arm/executor_runner/
elf=$(find ${ethos_u_build_dir} -name "arm_executor_runner")
FVP_Corstone_SSE-300_Ethos-U55 \
-C ethosu.num_macs=128 \
-C mps3_board.visualisation.disable-visualisation=1 \
-C mps3_board.telnetterminal0.start_telnet=0 \
-C mps3_board.uart0.out_file='-' \
-a "${elf}" \
--timelimit 10 # seconds - after which sim will kill itself
如果成功,模拟器应在 shell 上生成类似于以下内容的内容:
Ethos-U rev 136b7d75 --- Apr 12 2023 13:44:01
(C) COPYRIGHT 2019-2023 Arm Limited
ALL RIGHTS RESERVED
I executorch:runner.cpp:64] Model PTE file loaded. Size: 960 bytes.
I executorch:runner.cpp:70] Model buffer loaded, has 1 methods
I executorch:runner.cpp:78] Running method forward
I executorch:runner.cpp:95] Setting up planned buffer 0, size 32.
I executorch:runner.cpp:110] Method loaded.
I executorch:runner.cpp:112] Preparing inputs...
I executorch:runner.cpp:114] Input prepared.
I executorch:runner.cpp:116] Starting the model execution...
I executorch:runner.cpp:121] Model executed successfully.
I executorch:runner.cpp:125] 1 outputs:
Output[0][0]: 0.500000
Output[0][1]: 0.500000
Output[0][2]: 0.500000
Output[0][3]: 0.500000
Application exit code: 0.
EXITTHESIM
Info: Simulation is stopping. Reason: CPU time has been exceeded.
在此示例中,我们使用为 SoftmaxModule 生成的文件运行二进制文件,我们确实看到了在 FVP 模拟器上的 Corstone-300 虚拟硬件上运行的裸机二进制文件生成的预期结果。executor_runner
softmax.pte
如果使用 AddModule 的委托文件重新运行相同的 FVP 命令,即 - 你可能会得到类似下面的内容,同样是预期的结果。请注意打印有 prefix 的消息,它们表示后端已成功初始化,并且 AddModule 中的运算符已在 Ethos-U55 NPU 上执行。.pte
add_arm_delegate.pte
ArmBackend::
add
.pte
Ethos-U rev 136b7d75 --- Apr 12 2023 13:44:01
(C) COPYRIGHT 2019-2023 Arm Limited
ALL RIGHTS RESERVED
I executorch:runner.cpp:64] Model PTE file loaded. Size: 2208 bytes.
I executorch:runner.cpp:70] Model buffer loaded, has 1 methods
I executorch:runner.cpp:78] Running method forward
I executorch:runner.cpp:95] Setting up planned buffer 0, size 64.
I executorch:ArmBackendEthosU.cpp:51] ArmBackend::init 0x11000050
I executorch:runner.cpp:110] Method loaded.
I executorch:runner.cpp:112] Preparing inputs...
I executorch:runner.cpp:114] Input prepared.
I executorch:runner.cpp:116] Starting the model execution...
I executorch:ArmBackendEthosU.cpp:103] ArmBackend::execute 0x11000050
I executorch:runner.cpp:121] Model executed successfully.
I executorch:runner.cpp:125] 1 outputs:
Output[0][0]: 2
Output[0][1]: 2
Output[0][2]: 2
Output[0][3]: 2
Output[0][4]: 2
Application exit code: 0.
EXITTHESIM
Info: Simulation is stopping. Reason: CPU time has been exceeded.
要点¶
通过本教程,我们学习了如何使用 ExecuTorch 软件从 PyTorch 导出标准模型,并在紧凑且功能齐全的 ExecuTorch 运行时上运行它,从而为将模型从 PyTorch 卸载到基于 Arm 的平台提供平滑的路径。
概括地说,有两个主要流程:
一个直接流程,它使用 ExecuTorch 中内置的库将工作卸载到 Cortex-M 上。
一个委托流,将图形划分为 Cortex-M 部分和可在 Ethos-U 硬件上卸载和加速的部分。
这两个流程都在不断发展,从而支持更多的用例和更好的性能。