LiteRT 提供統一介面,可使用神經處理單元 (NPU),不必瀏覽特定供應商的編譯器、執行階段或程式庫依附元件。使用 LiteRT 進行 NPU 加速,可提升即時和大型模型推論的效能,並透過零複製硬體緩衝區的使用,盡量減少記憶體副本。
開始使用
- 如要瞭解傳統機器學習模型,請參閱下列示範應用程式。
- 圖片分割 Kotlin 應用程式:分別提供 AOT 編譯和裝置端 (JIT) 編譯的範例。
- 非同步區隔 C++ 應用程式:在同一個應用程式中示範 AOT 編譯和裝置端 (JIT) 編譯。
- 如要瞭解大型語言模型 (LLM),請參閱指南,瞭解如何使用 LiteRT-LM 在 NPU 上執行 LLM。
NPU 供應商
LiteRT 支援下列供應商的 NPU 加速功能:
Qualcomm AI Engine Direct
- 透過
CompiledModelAPI 支援 AOT 和裝置端編譯執行。 - 如需設定詳情,請參閱「Qualcomm AI Engine Direct」。
- 如需最新資訊,請參閱「使用 LiteRT 解鎖 Qualcomm NPU 的最高效能」。
MediaTek NeuroPilot
- 透過
CompiledModelAPI 支援 AOT 和裝置端編譯執行。 - 如需設定詳情,請參閱「MediaTek NeuroPilot」。
- 如需最新消息,請參閱「MediaTek NPU and LiteRT: Powering the next generation of on-device AI」。
Google Tensor
Google Tensor SDK 目前處於實驗存取階段。請按這裡註冊。
預先編譯和裝置端編譯
LiteRT NPU 支援 AOT 和裝置端編譯,可滿足特定部署需求:
- 離線 (AOT) 編譯:最適合用於目標 SoC 已知的大型複雜模型。預先編譯可大幅降低初始化成本,並在使用者啟動應用程式時減少記憶體用量。
- 線上 (裝置端) 編譯:又稱為 JIT 編譯。這非常適合用於小型模型的平台無關模型發布。模型會在初始化期間編譯到使用者的裝置上,不需要額外的準備步驟,但首次執行的成本較高。
以下指南將以三個步驟,說明如何部署 AOT 和裝置端編譯。
步驟 1:針對目標 NPU SoC 進行 AOT 編譯
您可以使用 LiteRT AOT (預先) 編譯器,將 .tflite 模型編譯為支援的 SoC。您也可以在單一編譯程序中,同時指定多個 SoC 供應商和版本。詳情請參閱這份 LiteRT AOT 編譯筆記本。雖然預先編譯是選用功能,但我們強烈建議對大型模型使用這項功能,以縮短裝置上的初始化時間。裝置端編譯不需要執行這個步驟。
步驟 2:如果是 Android 裝置,請透過 Google Play 部署
在 Android 上,使用 Google Play 裝置端 AI (PODAI),將模型和 NPU 執行階段程式庫與應用程式一併部署。
- 適用於裝置端編譯的模型:直接將原始 .tflite 模型檔案新增至應用程式的 assets/ 目錄。
- 如需實作範例,請參閱「Segmentation on-device compilation Kotlin App」。
- 針對 AOT 編譯模型:使用 LiteRT 將編譯模型匯出為單一 Google Play AI Pack。接著,將 AI 套件上傳至 Google Play,系統就會自動將正確的編譯模型傳送至使用者裝置。
- 如要瞭解如何將編譯後的模型匯出至 Play AI Pack,請參閱 LiteRT AOT 編譯筆記本。
- 請參閱區隔 AOT 編譯 Kotlin 應用程式中的實作範例。
- 如要使用 NPU 執行階段程式庫,請使用 Play Feature Delivery 將正確的執行階段程式庫發布至使用者的裝置。
請參閱下列章節,瞭解如何透過 Play AI Pack 和 Play Feature Delivery 部署。
使用 Play AI Pack 部署 AOT 模型
下列步驟將引導您使用 Play AI Pack 部署 AOT 編譯模型。
將 AI Pack 新增至專案
將 AI Pack 複製到 Gradle 專案的根目錄,即可將 AI Pack 匯入 Gradle 專案。例如:
my_app/
...
ai_packs/
my_model/...
my_model_mtk/...
將每個 AI Pack 新增至 Gradle 建構設定:
// my_app/ai_packs/my_model/build.gradle.kts
plugins { id("com.android.ai-pack") }
aiPack {
packName = "my_model" // ai pack dir name
dynamicDelivery { deliveryType = "on-demand" }
}
// Add another build.gradle.kts for my_model_mtk/ as well
在 Gradle 設定中新增 AI Pack
將產生的 AI Pack 中的 device_targeting_configuration.xml 複製到主要應用程式模組的目錄。然後更新 settings.gradle.kts:
// my_app/setting.gradle.kts
...
// AI Packs
include(":ai_packs:my_model")
include(":ai_packs:my_model_mtk")
更新 build.gradle.kts:
// my_app/build.gradle.kts
android {
...
defaultConfig {
...
// API level 31+ is required for NPU support.
minSdk = 31
}
// AI Packs
assetPacks.add(":ai_packs:my_model")
assetPacks.add(":ai_packs:my_model_mtk")
}
設定隨選提供功能的 AI Pack
隨選傳送功能可讓您在執行階段要求模型,如果模型只用於特定使用者流程,這項功能就非常實用。模型會下載到應用程式的內部儲存空間。在 build.gradle.kts 檔案中設定 Android AI Pack 功能後,請檢查裝置功能。另請參閱 PODAI 的操作說明,瞭解安裝時提供和以快速追蹤的方式提供。
val env = Environment.create(BuiltinNpuAcceleratorProvider(context))
val modelProvider = AiPackModelProvider(
context, "my_model", "model/my_model.tflite") {
if (NpuCompatibilityChecker.Qualcomm.isDeviceSupported())
setOf(Accelerator.NPU) else setOf(Accelerator.CPU, Accelerator.GPU)
}
val mtkModelProvider = AiPackModelProvider(
context, "my_model_mtk", "model/my_model_mtk.tflite") {
if (NpuCompatibilityChecker.Mediatek.isDeviceSupported())
setOf(Accelerator.NPU) else setOf()
}
val modelSelector = ModelSelector(modelProvider, mtkModelProvider)
val model = modelSelector.selectModel(env)
val compiledModel = CompiledModel.create(
model.getPath(),
CompiledModel.Options(model.getCompatibleAccelerators()),
env,
)
透過 Play Feature Delivery 部署 NPU 執行階段程式庫
Play Feature Delivery 支援多種提供選項,可最佳化初始下載大小,包括安裝時提供、隨選提供、符合條件時提供和即時提供。以下是基本安裝時提交指南。
在專案中新增 NPU 執行階段程式庫
下載 litert_npu_runtime_libraries.zip (適用於 AOT 編譯) 或 litert_npu_runtime_libraries_jit.zip (適用於裝置端編譯),並在專案的根目錄中解壓縮:
my_app/
...
litert_npu_runtime_libraries/
mediatek_runtime/...
qualcomm_runtime_v69/...
qualcomm_runtime_v73/...
qualcomm_runtime_v75/...
qualcomm_runtime_v79/...
qualcomm_runtime_v81/...
fetch_qualcomm_library.sh
執行指令碼,下載 NPU 支援程式庫。舉例來說,請針對 Qualcomm NPU 執行下列指令:
$ ./litert_npu_runtime_libraries/fetch_qualcomm_library.sh
將 NPU 執行階段程式庫新增至 Gradle 設定
將產生的 AI Pack 中的 device_targeting_configuration.xml 複製到主要應用程式模組的目錄。然後更新 settings.gradle.kts:
// my_app/setting.gradle.kts
...
// NPU runtime libraries
include(":litert_npu_runtime_libraries:runtime_strings")
include(":litert_npu_runtime_libraries:mediatek_runtime")
include(":litert_npu_runtime_libraries:qualcomm_runtime_v69")
include(":litert_npu_runtime_libraries:qualcomm_runtime_v73")
include(":litert_npu_runtime_libraries:qualcomm_runtime_v75")
include(":litert_npu_runtime_libraries:qualcomm_runtime_v79")
include(":litert_npu_runtime_libraries:qualcomm_runtime_v81")
更新 build.gradle.kts:
// my_app/build.gradle.kts
android {
...
defaultConfig {
...
// API level 31+ is required for NPU support.
minSdk = 31
// NPU only supports arm64-v8a
ndk { abiFilters.add("arm64-v8a") }
// Needed for Qualcomm NPU runtime libraries
packaging { jniLibs { useLegacyPackaging = true } }
}
// Device targeting
bundle {
deviceTargetingConfig = file("device_targeting_configuration.xml")
deviceGroup {
enableSplit = true // split bundle by #group
defaultGroup = "other" // group used for standalone APKs
}
}
// NPU runtime libraries
dynamicFeatures.add(":litert_npu_runtime_libraries:mediatek_runtime")
dynamicFeatures.add(":litert_npu_runtime_libraries:qualcomm_runtime_v69")
dynamicFeatures.add(":litert_npu_runtime_libraries:qualcomm_runtime_v73")
dynamicFeatures.add(":litert_npu_runtime_libraries:qualcomm_runtime_v75")
dynamicFeatures.add(":litert_npu_runtime_libraries:qualcomm_runtime_v79")
dynamicFeatures.add(":litert_npu_runtime_libraries:qualcomm_runtime_v81")
}
dependencies {
// Dependencies for strings used in the runtime library modules.
implementation(project(":litert_npu_runtime_libraries:runtime_strings"))
...
}
步驟 3:使用 LiteRT 執行階段在 NPU 上進行推論
LiteRT 可抽象化針對特定 SoC 版本開發的複雜性,讓您只需幾行程式碼,就能在 NPU 上執行模型。此外,LiteRT 也提供強大的內建備援機制:您可以指定 CPU、GPU 或兩者做為選項,如果 NPU 無法使用,LiteRT 就會自動使用這些選項。方便的是,AOT 編譯也支援回溯。可提供 NPU 的部分委派功能,讓不支援的子圖在 CPU 或 GPU 上順暢執行 (視指定情況而定)。
以 Kotlin 執行
如需實作範例,請參閱下列試用版應用程式:
新增 Android 依附元件
您可以將最新的 LiteRT Maven 套件新增至 build.gradle 依附元件:
dependencies {
...
implementation("com.google.ai.edge.litert:litert:+")
}
執行階段整合
// 1. Load model and initialize runtime.
// If NPU is unavailable, inference will fallback to GPU.
val model =
CompiledModel.create(
context.assets,
"model/mymodel.tflite",
CompiledModel.Options(Accelerator.NPU, Accelerator.GPU)
)
// 2. Pre-allocate input/output buffers
val inputBuffers = model.createInputBuffers()
val outputBuffers = model.createOutputBuffers()
// 3. Fill the first input
inputBuffers[0].writeFloat(...)
// 4. Invoke
model.run(inputBuffers, outputBuffers)
// 5. Read the output
val outputFloatArray = outputBuffers[0].readFloat()
在 C++ 跨平台中執行
如需實作範例,請參閱非同步分割 C++ 應用程式。
Bazel 建構依附元件
C++ 使用者必須使用 LiteRT NPU 加速功能,建構應用程式的依附元件。cc_binary 規則,可封裝核心應用程式邏輯 (例如 main.cc) 需要下列執行階段元件:
- LiteRT C API 共用程式庫:
data屬性必須包含 LiteRT C API 共用程式庫 (//litert/c:litert_runtime_c_api_shared_lib) 和 NPU 的廠商專屬調度共用物件 (//litert/vendors/qualcomm/dispatch:dispatch_api_so)。 - NPU 專屬後端程式庫:例如適用於 Android 主機的 Qualcomm AI RT (QAIRT) 程式庫 (如
libQnnHtp.so、libQnnHtpPrepare.so),以及對應的 Hexagon DSP 程式庫 (libQnnHtpV79Skel.so)。這可確保 LiteRT 執行階段能將運算作業卸載至 NPU。 - 屬性依附元件:
deps屬性會連結至必要的編譯時間依附元件,例如 LiteRT 的張量緩衝區 (//litert/cc:litert_tensor_buffer) 和 NPU 派遣層的 API (//litert/vendors/qualcomm/dispatch:dispatch_api)。這可讓應用程式程式碼透過 LiteRT 與 NPU 互動。 - 模型檔案和其他資產:透過
data屬性納入。
完成這項設定後,編譯的二進位檔就能動態載入並使用 NPU,加快機器學習推論速度。
設定 NPU 環境
部分 NPU 後端需要執行階段依附元件或程式庫。使用已編譯模型 API 時,LiteRT 會透過 Environment 物件整理這些需求。請使用下列程式碼找出適當的 NPU 程式庫或驅動程式:
// Provide a dispatch library directory (following is a hypothetical path) for the NPU
std::vector<Environment::Option> environment_options = {
{
Environment::OptionTag::DispatchLibraryDir,
"/usr/lib64/npu_dispatch/"
}
};
LITERT_ASSIGN_OR_RETURN(auto env, Environment::Create(absl::MakeConstSpan(environment_options)));
執行階段整合
下列程式碼片段顯示以 C++ 實作整個程序的基礎方式:
// 1. Load the model that has NPU-compatible ops
LITERT_ASSIGN_OR_RETURN(auto model, Model::Load("mymodel_npu.tflite"));
// 2. Create a compiled model with NPU acceleration
// See following section on how to set up NPU environment
LITERT_ASSIGN_OR_RETURN(auto compiled_model,
CompiledModel::Create(env, model, kLiteRtHwAcceleratorNpu));
// 3. Allocate I/O buffers
LITERT_ASSIGN_OR_RETURN(auto input_buffers, compiled_model.CreateInputBuffers());
LITERT_ASSIGN_OR_RETURN(auto output_buffers, compiled_model.CreateOutputBuffers());
// 4. Fill model inputs (CPU array -> NPU buffers)
float input_data[] = { /* your input data */ };
input_buffers[0].Write<float>(absl::MakeConstSpan(input_data, /*size*/));
// 5. Run inference
compiled_model.Run(input_buffers, output_buffers);
// 6. Access model output
std::vector<float> data(output_data_size);
output_buffers[0].Read<float>(absl::MakeSpan(data));
透過 NPU 加速,實現零複製
使用零複製功能時,NPU 可直接存取自身記憶體中的資料,不需要 CPU 明確複製該資料。零複製可避免將資料複製到 CPU 記憶體,以及從 CPU 記憶體複製資料,因此能大幅縮短端對端延遲時間。
以下程式碼是 Zero-Copy NPU 的實作範例,可將資料直接傳遞至 NPU。AHardwareBuffer這項實作方式可避免耗費資源的 CPU 記憶體往返行程,大幅減少推論作業負擔。
// Suppose you have AHardwareBuffer* ahw_buffer
LITERT_ASSIGN_OR_RETURN(auto tensor_type, model.GetInputTensorType("input_tensor"));
LITERT_ASSIGN_OR_RETURN(auto npu_input_buffer, TensorBuffer::CreateFromAhwb(
env,
tensor_type,
ahw_buffer,
/* offset = */ 0
));
std::vector<TensorBuffer> input_buffers{npu_input_buffer};
LITERT_ASSIGN_OR_RETURN(auto output_buffers, compiled_model.CreateOutputBuffers());
// Execute the model
compiled_model.Run(input_buffers, output_buffers);
// Retrieve the output (possibly also an AHWB or other specialized buffer)
auto ahwb_output = output_buffers[0].GetAhwb();
串連多個 NPU 推論
如果是複雜的管道,您可以串連多個 NPU 推論。由於每個步驟都使用適合加速器的緩衝區,管道大多會留在 NPU 管理的記憶體中:
// compiled_model1 outputs into an AHWB
compiled_model1.Run(input_buffers, intermediate_buffers);
// compiled_model2 consumes that same AHWB
compiled_model2.Run(intermediate_buffers, final_outputs);
NPU 裝置端編譯快取
LiteRT 支援在裝置端 (稱為 JIT) 編譯 .tflite 模型,並在 NPU 上執行。如果無法預先編譯模型,JIT 編譯就特別有用。
不過,JIT 編譯可能會產生一些延遲和記憶體負擔,以便將使用者提供的模型即時轉換為 NPU 位元碼指令。為盡量減少對效能的影響,可以快取 NPU 編譯構件。
啟用快取後,LiteRT 只會在必要時觸發模型重新編譯,例如:
- 供應商的 NPU 編譯器外掛程式版本已變更;
- Android 版本指紋已變更;
- 使用者提供的模型已變更;
- 編譯選項已變更。
如要啟用 NPU 編譯快取,請在環境選項中指定 CompilerCacheDir 環境標記。這個值必須設為應用程式現有的可寫入路徑。
const std::array environment_options = {
litert::Environment::Option{
/*.tag=*/litert::Environment::OptionTag::CompilerPluginLibraryDir,
/*.value=*/kCompilerPluginLibSearchPath,
},
litert::Environment::Option{
litert::Environment::OptionTag::DispatchLibraryDir,
kDispatchLibraryDir,
},
// 'kCompilerCacheDir' will be used to store NPU-compiled model
// artifacts.
litert::Environment::Option{
litert::Environment::OptionTag::CompilerCacheDir,
kCompilerCacheDir,
},
};
// Create an environment.
LITERT_ASSERT_OK_AND_ASSIGN(
auto environment, litert::Environment::Create(environment_options));
// Load a model.
auto model_path = litert::testing::GetTestFilePath(kModelFileName);
LITERT_ASSERT_OK_AND_ASSIGN(auto model,
litert::Model::CreateFromFile(model_path));
// Create a compiled model, which only triggers NPU compilation if
// required.
LITERT_ASSERT_OK_AND_ASSIGN(
auto compiled_model, litert::CompiledModel::Create(
environment, model, kLiteRtHwAcceleratorNpu));
延遲時間和記憶體節省量範例:
NPU 編譯所需的時間和記憶體會因多種因素而異,例如基礎 NPU 晶片、輸入模型的複雜度等。
下表比較需要 NPU 編譯時,以及因快取而可略過編譯時,執行階段的初始化時間和記憶體用量。在一個範例裝置上,我們取得以下資訊:
| TFLite 模型 | 使用 NPU 編譯初始化模型 | 使用快取編譯進行模型初始化 | 使用 NPU 編譯初始化記憶體用量 | 使用快取編譯初始化記憶體 |
|---|---|---|---|---|
| torchvision_resnet152.tflite | 7465.22 毫秒 | 198.34 毫秒 | 1525.24 MB | 355.07 MB |
| torchvision_lraspp_mobilenet_v3_large.tflite | 1592.54 毫秒 | 166.47 毫秒 | 254.90 MB | 33.78 MB |
我們會在其他裝置上取得下列資訊:
| TFLite 模型 | 使用 NPU 編譯初始化模型 | 使用快取編譯進行模型初始化 | 使用 NPU 編譯初始化記憶體用量 | 使用快取編譯初始化記憶體 |
|---|---|---|---|---|
| torchvision_resnet152.tflite | 2766.44 毫秒 | 379.86 毫秒 | 653.54 MB | 501.21 MB |
| torchvision_lraspp_mobilenet_v3_large.tflite | 784.14 毫秒 | 231.76 毫秒 | 113.14 MB | 67.49 MB |