ExecuTorch 執行時概述¶
本文討論 ExecuTorch 執行時的設計,該執行時在智慧手機、可穿戴裝置和嵌入式裝置等邊緣裝置上執行 ExecuTorch 程式檔案。主要執行 API 的程式碼位於 executorch/runtime/executor/ 路徑下。
在閱讀本文件之前,我們建議您閱讀 ExecuTorch 工作原理。
從最高層面來看,ExecuTorch 執行時負責
載入由模型 Lowering 過程中的
to_executorch()步驟生成的二進位制.pte程式檔案。執行實現 Lowered 模型的系列指令。
請注意,截至 2023 年末,ExecuTorch 執行時僅支援模型推理,尚不支援訓練。
此圖顯示了匯出和執行 ExecuTorch 程式的高層流程和所涉及的元件

執行時還負責
管理載入和執行期間使用的記憶體,可能跨越 SRAM 和 DRAM 等多個記憶體區域。
將諸如
"aten::add.out"之類的符號化運算子名稱對映到實現這些運算子語義的具體 C++ 函式或核心。將模型的預定部分分派給後端委託進行加速。
可選地在載入和執行期間收集效能分析資料。
設計目標¶
ExecuTorch 執行時設計用於執行在各種邊緣裝置上,從現代智慧手機 CPU 到資源受限的微控制器和 DSPs。它對將執行委託給一個或多個後端以利用特定於架構的最佳化和現代異構架構提供了頭等支援。它足夠小巧和可移植,可以直接在沒有作業系統、動態記憶體或執行緒的裸金屬嵌入式環境中執行。
低執行開銷¶
記憶體¶
核心執行時庫在不包含核心或後端構建時小於 50kB。
常量張量直接指向
.pte檔案資料,避免資料複製。這些資料塊的對齊方式可以在.pte檔案建立時調整。後端委託可以選擇在模型初始化後解除安裝其預編譯資料,從而降低峰值記憶體使用。
可變張量的記憶體佈局提前規劃,並打包到一小組使用者分配的緩衝區中,從而提供對記憶體位置的精細控制。這在具有異構記憶體層次結構的系統上特別有用,允許將資料放置到(例如)靠近將操作資料的核心的 SRAM 或 DRAM 中。
CPU¶
模型執行是對指令陣列的簡單迴圈,其中大多數是指向核心和後端委託的函式指標。這使得執行開銷很小,每個操作的開銷約為微秒到納秒級。
操作(如“add”或“conv3d”)的實現可以針對特定目標系統進行完全自定義,而無需修改原始模型或生成的
.pte檔案。
熟悉的 PyTorch 語義¶
ExecuTorch 是 PyTorch 堆疊的一等公民,並儘可能複用 API 和語義。
ExecuTorch 使用的 C++ 型別與核心 PyTorch 的
c10::和at::庫中的相應型別原始碼相容,ExecuTorch 提供aten_bridge用於在兩者之間轉換。這對於已經使用 PyTorch C++ 型別的專案可能會有所幫助。諸如
aten::add和aten::sigmoid之類的運算子在 ExecuTorch 和核心 PyTorch 之間的語義是相同的。ExecuTorch 提供測試框架以確保這一點,並幫助測試這些運算子未來的實現。
可移植的程式碼和架構¶
ExecuTorch 執行時在實現時考慮了可移植性,因此使用者可以將其構建到各種目標系統上。
C++ 語言考量¶
程式碼相容 C++17,以便與較舊的工具鏈一起使用。
執行時不使用異常或 RTTI,但也不排斥它們。
程式碼相容 GCC 和 Clang,也已使用多種專有嵌入式工具鏈構建過。
程式碼倉庫提供 CMake 構建系統,以便於整合。
作業系統考量¶
執行時不進行直接的系統呼叫。所有對記憶體、檔案、日誌和時鐘的訪問都透過執行時平臺抽象層 (PAL) 以及注入的介面(如 DataLoader 和 MemoryAllocator)進行抽象。有關詳細資訊,請參閱執行時 API 參考。
應用程式可以透過 MemoryManager、MemoryAllocator、HierarchicalAllocator 和 DataLoader 類控制所有記憶體分配。核心執行時不直接呼叫 malloc() 或 new,也不呼叫像 std::vector 這樣在底層進行分配的型別。這使得以下成為可能:
在沒有堆的環境中執行,但如果需要仍可使用堆。
在模型載入和執行期間避免堆上的同步。
控制不同型別資料使用哪個記憶體區域。例如,一組可變張量可以位於 SRAM 中,而另一組位於 DRAM 中。
輕鬆監控執行時使用了多少記憶體。
但是,請注意,特定的核心或後端實現可能會使用任意的執行時或作業系統功能。使用者應仔細查閱所使用的核心和後端庫的文件。
執行緒考量¶
核心執行時不進行執行緒操作或鎖定,也不使用執行緒區域性變數。但是,它與更高層級的同步機制配合良好。
每個
Program例項是不可變的,因此是完全執行緒安全的。多個執行緒可以併發訪問同一個Program例項。每個
Method例項是可變的但自包含的,因此是條件執行緒安全的。多個執行緒可以併發訪問和執行獨立的Method例項,但對單個例項的訪問和執行必須序列化。
但是,請注意
在
Program::load_method()期間可能會讀取兩個全域性表:核心登錄檔和後端登錄檔。實際上,這些表僅在程序/系統載入時修改,並且在第一個
Program載入之前實際處於凍結狀態。但某些應用程式可能需要了解這些表,特別是如果在程序/系統載入後手動修改它們。
特定的核心或後端實現可能有其自身的執行緒限制。使用者應仔細查閱所使用的核心和後端庫的文件。
延伸閱讀¶
有關 ExecuTorch 執行時的更多詳細資訊,請參閱