• 文件 >
  • 使用 ARM Ethos-U 後端建置並執行 ExecuTorch
捷徑

使用 ARM Ethos-U 後端建置並執行 ExecuTorch

我們建議您在之前完成的教學課程
您將在本教學課程中學到的內容

在本教學課程中,您將學習如何匯出適用於 ExecuTorch Arm Ethos-u 後端委派的簡單 PyTorch 模型,並在 Corstone FVP 模擬器上執行它。

警告

這個 ExecuTorch 後端委派(backend delegate)正在積極開發中。您可能會遇到一些不完善的地方,以及一些已記錄或計劃但尚未實現的功能。

提示

如果您已熟悉此委派,建議您直接跳到範例程式碼目錄 - https://github.com/pytorch/executorch/tree/main/examples/arm

先決條件

在開始之前,請確保您已具備所有必要的條件。

硬體

要成功完成本教學課程,您需要一台基於 Linux 的主機,並具有 Arm aarch64 或 x86_64 處理器架構。

目標設備將是一個嵌入式平台,具有 Arm Cortex-M CPU 和 Ethos-U NPU(ML 處理器)。本教學課程將向您展示如何在兩者上運行 PyTorch 模型。

我們將使用 固定虛擬平台 (FVP),模擬 Corstone-300(cs300) 和 Corstone-320(cs320) 系統。由於我們將使用 FVP(可以把它想像成虛擬硬體),因此本教學課程不需要任何真正的嵌入式硬體。

軟體

首先,您需要安裝 ExecuTorch。如果您尚未設定好可用的 ExecuTorch 開發環境,請依照建議的教學課程進行設定。

為了產生可以在嵌入式平台(真實或虛擬)上運行的軟體,我們需要一個用於交叉編譯的工具鏈,以及一個 Arm Ethos-U 軟體開發套件,其中包括用於 Ethos-U NPU 的 Vela 編譯器。

在接下來的章節中,我們將逐步介紹下載上述每個依賴項的步驟。

設定開發者環境

在本節中,我們將進行一次性的設定,例如下載和安裝必要的軟體,以及運行本教學課程中的 ExecuTorch 程式所需的平台支援檔案。

為此,我們將使用 examples/arm/setup.sh 腳本來以自動化的方式提取每個項目。建議在 conda 環境中運行該腳本。成功執行後,您可以直接跳到 下一步

如前所述,我們目前僅支援基於 Linux 的平台,且具有 x86_64 或 aarch64 處理器架構。讓我們確保我們確實位於支援的平台上。

uname -s
# Linux

uname -m
# x86_64 or aarch64

接下來,我們將逐步介紹 setup.sh 腳本執行的步驟,以便更好地了解開發設定。

下載並設定 Corstone-300 和 Corstone-320 FVP

固定虛擬平台 (FVP) 是預先配置的、功能準確的熱門系統配置模擬。在本教學課程中,我們對 Corstone-300 和 Corstone-320 系統感興趣。我們可以從 Arm 網站下載它。

注意

下載並運行 FVP 軟體,即表示您同意 FVP 使用者授權協議 (EULA)

要下載,我們可以從 這裡 下載 Corstone-300 Ecosystem FVPCorstone-320 Ecosystem FVP,或者 setup.sh 腳本會在 setup_fvp 函數下為您執行此操作。

下載並安裝 Arm GNU AArch32 Bare-Metal 工具鏈

與 FVP 類似,我們還需要一個工具鏈來交叉編譯 ExecuTorch 運行時、executor-runner 裸機應用程式,以及 Corstone-300/Corstone-320 平台上可用的 Cortex-M55/M85 CPU 的其餘裸機堆疊。

這些工具鏈可在 這裡 取得。在本教學課程中,我們將使用以 arm-none-eabi 為目標的 GCC 12.3。就像 FVP 一樣,setup.sh 腳本會為您下載工具鏈。請參閱 setup_toolchain 函數。

設定 Arm Ethos-U 軟體開發

這個 git 儲存庫是所有 Arm Ethos-U 軟體的根目錄。它旨在協助我們下載所需的儲存庫並將其放置在樹狀結構中。請參閱設定腳本的 setup_ethos_u 函數以取得更多詳細資訊。

完成後,您應該有一個可用的 FVP 模擬器、一個用於交叉編譯的功能性工具鏈,以及一個為裸機開發準備好的 Ethos-U 軟體開發設定。

安裝 Vela 編譯器

完成後,該腳本將透過為您安裝 Vela 編譯器來完成設定,詳細資訊位於 setup_vela 函數中。

安裝 TOSA 參考模型

這是設定過程的最後一步,使用 setup_tosa_reference_model 函數,setup.sh 腳本會為您安裝 TOSA 參考模型。

在設定結束時,如果一切順利,您的頂層開發目錄可能看起來像這樣,

.
├── 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-corstone300
│   ├── FVP_Corstone_SSE-300.sh
│   └── [...]
├── FVP-corstone320
│   ├── FVP_Corstone_SSE-320.sh
│   └── [...]
├── FVP_cs300.tgz
├── FVP_cs320.tgz
├── gcc.tar.xz
└── reference_model

將 PyTorch 模型轉換為 .pte 檔案

.pte 是一個二進位檔案,由 ExecuTorch 預先編譯 (AoT) 管道產生,該管道接收一個 PyTorch 模型 (torch.nn.Module),匯出它,運行各種傳遞,最後將其序列化為 .pte 檔案格式。這個二進位檔案通常由 ExecuTorch 運行時消耗。這份文件更深入地介紹了 ExecuTorch 軟體堆疊,包括 AoT 和運行時。

在本節中,我們將主要關注 AoT 流程,最終目標是產生一個 .pte 檔案。有一組導出配置,旨在針對運行時的不同後端。對於每個後端,AoT 流程都會產生一個唯一的 .pte 檔案。我們將探索幾個不同的配置,產生不同的 .pte 檔案,這些檔案對於我們的 Corstone-300 系統和可用的處理元件特別有趣。

在我們開始之前,讓我們先談談我們將使用的 PyTorch 模組。

PyTorch 範例模組

我們將使用幾個簡單的 PyTorch 模組來探索端到端流程。這些模組將在本教學課程中以各種不同的方式使用,並以它們的 <class_name> 來指代。

SoftmaxModule

這是一個非常簡單的 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 上運行網路的資料類型,因為它是一個僅支援整數的處理器。在這個例子中,我們明確地使用整數類型。對於這種流程的典型使用,網路是在浮點數中構建和訓練的,然後從浮點數量化為整數,以實現高效的推論。

MobileNetV2 模組

MobileNetV2 是一個常用於邊緣和行動裝置的網路。它也可以在 torchvision 中作為預設模型使用,因此我們可以使用下面的範例程式碼載入它。

from torchvision.models import mobilenet_v2  # @manual
from torchvision.models.mobilenetv2 import MobileNet_V2_Weights

mv2 = mobilenet_v2(weights=MobileNet_V2_Weights.DEFAULT)

有關更多詳細資訊,您可以參考 這裡 的程式碼片段。

非委派工作流程

在 ExecuTorch AoT 管道中,其中一種選擇是選擇後端。 ExecuTorch 提供了各種不同的後端。選擇後端是可選的,通常是為了針對給定模型計算要求的特定加速模式或硬體。如果沒有任何後端,ExecuTorch 執行期將會回退使用預設提供的一組高度可移植的運算子。

在具有專用加速的平台上,例如 Ethos-U55,預期非委派流程主要用於以下兩種情況:

  1. 當網路被設計成非常小,並且最適合單獨在 Cortex-M 上運行時。

  2. 當網路混合了可以針對 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

委派量化工作流程

在為委派量化網路(如 MobileNetV2)產生 .pte 檔案之前,我們需要構建 quantized_ops_aot_lib

SITE_PACKAGES="$(python3 -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())')"
CMAKE_PREFIX_PATH="${SITE_PACKAGES}/torch"

cd <executorch_root_dir>
mkdir -p cmake-out-aot-lib
cmake -DCMAKE_BUILD_TYPE=Release \
    -DEXECUTORCH_BUILD_XNNPACK=OFF \
    -DEXECUTORCH_BUILD_KERNELS_QUANTIZED=ON \
    -DEXECUTORCH_BUILD_KERNELS_QUANTIZED_AOT=ON \
    -DCMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH" \
    -DPYTHON_EXECUTABLE=python3 \
-Bcmake-out-aot-lib \
    "${et_root_dir}"

cmake --build cmake-out-aot-lib --parallel -- quantized_ops_aot_lib

在構建 quantized_ops_aot_lib 之後,我們可以運行以下腳本來產生 .pte 檔案。

python3 -m examples.arm.aot_arm_compiler --model_name="mv2" --delegate --quantize --so_library="$(find cmake-out-aot-lib -name libquantized_ops_aot_lib.so)"
# should produce ./mv2_arm_delegate.pte.pte

最後,我們應該有三個不同的 .pte 檔案。

  • 第一個包含 SoftmaxModule,沒有任何後端委派。

  • 第二個包含 AddModule,啟用 Arm Ethos-U 後端委派。

  • 第三個包含 量化的 MV2Model,也啟用 Arm Ethos-U 後端委派。

現在讓我們嘗試在裸機環境中的 Corstone-300 和 Corstone-320 平台上運行這些 .pte 檔案。

取得裸機可執行檔

在本節中,我們將介紹您需要執行的步驟,以構建運行時應用程式。然後,它會在目標設備上運行。在 executorch 儲存庫中,我們有一個正常運作的腳本,它執行完全相同的步驟。它位於 executorch/examples/arm/run.sh。我們將使用它來構建必要的組件,最後在 FVP 上運行先前產生的 PTE 檔案。

此外,在我們開始之前,請確保您已完成 ExecuTorch cmake 建置設定,以及設定開發環境的說明,如 先前 所述。

下面的方塊圖在高層次上展示了如何產生各種建置產物,並將它們連結在一起以產生最終的裸機可執行檔。

提示

run.sh 腳本中的 generate_pte_file 函數根據透過 --model_name 輸入參數提供的模型產生 .pte 檔案。

產生 ExecuTorch 函式庫

ExecuTorch 的 CMake 建置系統產生一組建置組件,這些組件對於我們包含並在 Ethos-U SDK 中 Corstone FVP 的裸機環境中運行 ExecuTorch 運行時至關重要。

文件詳細概述了每個獨立的建置部分。為了執行 .pte 檔案的任一變體,我們需要一組核心函式庫。以下是列表:

  • libexecutorch.a

  • libportable_kernels.a

  • libportable_ops_lib.a

要使用 Arm 後端委派呼叫指令來執行 .pte 檔案,我們需要 Arm 後端委派執行時間函式庫,即:

  • libexecutorch_delegate_ethos_u.a

這些函式庫是在 run.sh 腳本的 build_executorchbuild_quantization_aot_lib 函數中產生的。

在此函數中,EXECUTORCH_SELECT_OPS_LIST 將決定建置中包含的可攜式運算元的數量,並在執行期間可用。它必須與 .pte 檔案的需求相符,否則您將在執行期間收到 Missing Operator 錯誤。

例如,在上面的命令列中,要執行 SoftmaxModule,我們只包含了 softmax CPU 運算元。同樣地,要以非委派方式執行 AddModule,您需要 add op 等等。您可能已經意識到,對於將由 Arm 後端委派執行的委派運算元,我們不需要在此列表中包含這些運算元。這僅適用於非委派運算元。

提示

run.sh 腳本採用 --portable_kernels 選項,該選項提供了一種方式來提供要包含的可攜式核心的逗號分隔列表。

建置 executor_runner 裸機應用程式

SDK 目錄與 先前準備的相同。並且,我們將傳遞上面產生的 .pte 檔案(任何一個)。

請注意,如果您想更改模型或 .pte 檔案,則必須產生一個新的 executor-runner 二進位檔案。此限制來自於我們為 Corstone-300/Corstone-320 平台提供的受限裸機執行時間環境。

這是由 run.sh 中的 build_executorch_runner 函數執行的。

提示

run.sh 腳本採用 --target 選項,該選項提供了一種方式來提供特定目標,Corstone-300(ethos-u55-128) 或 Corstone-320(ethos-u85-128)。

在 Corstone FVP 平台上執行

一旦準備好 elf 檔案,無論使用哪個 .pte 檔案變體來產生裸機 elf 檔案。以下命令用於在 Corstone-320 FVP 上執行 MV2Model

ethos_u_build_dir=examples/arm/executor_runner/

elf=$(find ${ethos_u_build_dir} -name "arm_executor_runner")

FVP_Corstone_SSE-320_Ethos-U85                          \
    -C mps4_board.subsystem.ethosu.num_macs=${num_macs} \
    -C mps4_board.visualisation.disable-visualisation=1 \
    -C vis_hdlcd.disable_visualisation=1                \
    -C mps4_board.telnetterminal0.start_telnet=0        \
    -C mps4_board.uart0.out_file='-'                    \
    -C mps4_board.uart0.shutdown_on_eot=1               \
    -a "${elf}"                                         \
    --timelimit 120 || true # seconds- after which sim will kill itself

如果成功,模擬器應該在 shell 上產生類似以下內容:

I [executorch:arm_executor_runner.cpp:364] Model in 0x70000000 $
I [executorch:arm_executor_runner.cpp:366] Model PTE file loaded. Size: 4425968 bytes.
I [executorch:arm_executor_runner.cpp:376] Model buffer loaded, has 1 methods
I [executorch:arm_executor_runner.cpp:384] Running method forward
I [executorch:arm_executor_runner.cpp:395] Setup Method allocator pool. Size: 62914560 bytes.
I [executorch:arm_executor_runner.cpp:412] Setting up planned buffer 0, size 752640.
I [executorch:ArmBackendEthosU.cpp:79] ArmBackend::init 0x70000070
I [executorch:arm_executor_runner.cpp:445] Method loaded.
I [executorch:arm_executor_runner.cpp:447] Preparing inputs...
I [executorch:arm_executor_runner.cpp:461] Input prepared.
I [executorch:arm_executor_runner.cpp:463] Starting the model execution...
I [executorch:ArmBackendEthosU.cpp:118] ArmBackend::execute 0x70000070
I [executorch:ArmBackendEthosU.cpp:298] Tensor input/output 0 will be permuted
I [executorch:arm_perf_monitor.cpp:120] NPU Inferences : 1
I [executorch:arm_perf_monitor.cpp:121] Profiler report, CPU cycles per operator:
I [executorch:arm_perf_monitor.cpp:125] ethos-u : cycle_cnt : 1498202 cycles
I [executorch:arm_perf_monitor.cpp:132] Operator(s) total: 1498202 CPU cycles
I [executorch:arm_perf_monitor.cpp:138] Inference runtime: 6925114 CPU cycles total
I [executorch:arm_perf_monitor.cpp:140] NOTE: CPU cycle values and ratio calculations require FPGA and identical CPU/NPU frequency
I [executorch:arm_perf_monitor.cpp:149] Inference CPU ratio: 99.99 %
I [executorch:arm_perf_monitor.cpp:153] Inference NPU ratio: 0.01 %
I [executorch:arm_perf_monitor.cpp:162] cpu_wait_for_npu_cntr : 729 CPU cycles
I [executorch:arm_perf_monitor.cpp:167] Ethos-U PMU report:
I [executorch:arm_perf_monitor.cpp:168] ethosu_pmu_cycle_cntr : 5920305
I [executorch:arm_perf_monitor.cpp:171] ethosu_pmu_cntr0 : 359921
I [executorch:arm_perf_monitor.cpp:171] ethosu_pmu_cntr1 : 0
I [executorch:arm_perf_monitor.cpp:171] ethosu_pmu_cntr2 : 0
I [executorch:arm_perf_monitor.cpp:171] ethosu_pmu_cntr3 : 503
I [executorch:arm_perf_monitor.cpp:178] Ethos-U PMU Events:[ETHOSU_PMU_EXT0_RD_DATA_BEAT_RECEIVED, ETHOSU_PMU_EXT1_RD_DATA_BEAT_RECEIVED, ETHOSU_PMU_EXT0_WR_DATA_BEAT_WRITTEN, ETHOSU_PMU_NPU_IDLE]
I [executorch:arm_executor_runner.cpp:470] model_pte_loaded_size:     4425968 bytes.
I [executorch:arm_executor_runner.cpp:484] method_allocator_used:     1355722 / 62914560  free: 61558838 ( used: 2 % ) 
I [executorch:arm_executor_runner.cpp:491] method_allocator_planned:  752640 bytes
I [executorch:arm_executor_runner.cpp:493] method_allocator_loaded:   966 bytes
I [executorch:arm_executor_runner.cpp:494] method_allocator_input:    602116 bytes
I [executorch:arm_executor_runner.cpp:495] method_allocator_executor: 0 bytes
I [executorch:arm_executor_runner.cpp:498] temp_allocator_used:       0 / 1048576 free: 1048576 ( used: 0 % ) 
I executorch:arm_executor_runner.cpp:152] Model executed successfully.
I executorch:arm_executor_runner.cpp:156] 1 outputs:
Output[0][0]: -0.749744
Output[0][1]: -0.019224
Output[0][2]: 0.134570
...(Skipped)
Output[0][996]: -0.230691
Output[0][997]: -0.634399
Output[0][998]: -0.115345
Output[0][999]: 1.576386
I executorch:arm_executor_runner.cpp:177] Program complete, exiting.
I executorch:arm_executor_runner.cpp:179]

注意

run.sh 腳本提供了各種選項來選擇特定的 FVP 目標、使用所需的模型、選擇可攜式核心,並且可以使用 --help 參數進行探索。

重點

透過本教學課程,我們學習了如何使用 ExecuTorch 軟體從 PyTorch 匯出標準模型,並在精巧且功能完善的 ExecuTorch 執行時間上執行它,從而為將模型從 PyTorch 卸載到基於 Arm 的平台提供了一條順暢的路徑。

總而言之,有兩個主要流程:

  • 一個直接流程,使用內建於 ExecuTorch 的函式庫將工作卸載到 Cortex-M 上。

  • 一個委派流程,將圖表分割成 Cortex-M 的部分和可以卸載並在 Ethos-U 硬體上加速的部分。

這兩個流程都在不斷發展,從而實現了更多的使用案例和更好的效能。

常見問題

如果您在按照本教學課程操作時遇到任何錯誤或問題,請在 Github 上提交錯誤/問題。

文件

存取 PyTorch 的全面開發人員文件

檢視文件

教學課程

取得初學者和高級開發人員的深入教學課程

檢視教學課程

資源

尋找開發資源並獲得您的問題解答

檢視資源