LiteRT 提供了一个统一的接口来使用神经处理单元 (NPU),而无需您浏览特定于供应商的编译器、运行时或库依赖项。使用 LiteRT 进行 NPU 加速可提升实时推理和大型模型推理的性能,并通过使用零复制硬件缓冲区来最大限度地减少内存副本。
开始使用
经典机器学习模型
对于经典机器学习模型,请参阅以下演示应用。
- 图像分割 Kotlin 应用: AOT 和 设备端(JIT) 编译。
- 图像分割 C++ 应用:同一应用中的 AOT 和设备端 (JIT) 编译。
生成式 AI 模型
对于生成式 AI 模型,请参阅以下演示和指南:
- EmbeddingGemma 语义相似度 C++ 应用: CPU/GPU/NPU 推理。
- 关于使用 LiteRT-LM 运行 LLM 的指南。
NPU 供应商
LiteRT 支持以下供应商的 NPU 加速:
Google Tensor
- 通过
CompiledModelAPI 支持 AOT 执行。 - 如需了解设置详情,请参阅 Google Tensor。
Qualcomm AI Engine Direct
- 通过
CompiledModelAPI 支持 AOT 和设备端编译执行。 - 如需了解设置详情,请参阅 Qualcomm AI Engine Direct。
- 如需了解最新更新,请参阅 Unlocking Peak Performance on Qualcomm NPU with LiteRT 。
MediaTek NeuroPilot
- 通过
CompiledModelAPI 支持 AOT 和设备端编译执行。 - 如需了解设置详情,请参阅 MediaTek NeuroPilot。
- 如需了解最新更新,请参阅 MediaTek NPU and LiteRT: Powering the next generation of on-device AI 。
Intel OpenVino
- 通过
CompiledModelAPI 支持 AOT 和设备端编译执行。 - 如需了解设置详情,请参阅 Intel OpenVino。
AOT 和设备端编译
LiteRT NPU 同时支持 AOT 和设备端编译,以满足您的特定部署要求:
- 离线 (AOT) 编译:最适合目标 SoC 已知的大型复杂模型 。预先编译可显著降低初始化费用,并在用户启动应用时降低内存用量。
- 在线(设备端)编译:也称为 JIT 编译。非常适合小型模型的平台无关模型分发。模型在初始化期间在用户设备上编译,无需额外的准备步骤,但首次运行费用较高。
您可以使用 AOT 或设备端编译选项部署模型,具体方法如下:
第 1 步:针对目标 NPU SoC 进行 AOT 编译
您可以使用 LiteRT AOT(预先)编译器将 .tflite 模型编译为受支持的 SoC。您还可以在单个编译过程中同时面向多个 SoC 供应商和版本。如需了解详情,请参阅 此 LiteRT AOT 编译笔记本。 虽然是可选步骤,但强烈建议对较大的模型进行 AOT 编译,以缩短设备端初始化时间。设备端编译不需要此步骤。
第 2 步:如果使用 Android,则通过 Google Play 进行部署
在 Android 上,使用 Google Play for On-device AI (PODAI) 将 模型和 NPU 运行时库与应用一起部署。
- 对于设备端编译的模型:将原始 .tflite 模型文件
直接添加到应用的 assets/ 目录中。
- 如需查看示例实现,请参阅 Segmentation on-device compilation Kotlin App。
- 对于 AOT 编译的模型:使用 LiteRT 将编译后的模型导出到单个 Google Play AI Pack 中。
然后,您将 AI Pack 上传到 Google Play,以自动将正确的编译模型分发到用户的设备。
- 如需了解如何将编译后的模型导出到 Play AI Pack 中,请参阅 LiteRT AOT 编译笔记本 。
- 如需查看示例实现,请参阅 Segmentation AOT compilation Kotlin App。
- 对于 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 build 配置中:
// 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
将 AI Pack 添加到 Gradle 配置中
将生成的 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 cpuGpuModelProvider =
ModelProvider.staticModel(
ModelProvider.Type.ASSET,
"model/my_model_cpu_gpu.tflite",
if (accelerator != Accelerator.NPU) accelerator else Accelerator.CPU,
)
val qualcommNpuModelProvider =
AiPackModelProvider(context, "my_model", "model/my_model.tflite")
{
buildSet {
if (
accelerator == Accelerator.NPU && NpuCompatibilityChecker.Qualcomm.isDeviceSupported()
)
add(Accelerator.NPU)
}
}
val mtkNpuModelProvider =
AiPackModelProvider(context, "my_model_mtk", "model/my_model.tflite")
{
buildSet {
if (
accelerator == Accelerator.NPU && NpuCompatibilityChecker.Mediatek.isDeviceSupported()
)
add(Accelerator.NPU)
}
}
val googleTensorTpuModelProvider =
AiPackModelProvider(context, "my_model", "model/my_model.tflite")
{
buildSet {
if (accelerator == Accelerator.NPU &&
NpuCompatibilityChecker.GoogleTensor.isDeviceSupported()
)
add(Accelerator.NPU)
}
}
val aiPackModelProvider =
ModelSelector(cpuGpuModelProvider, mtkNpuModelProvider, qualcommNpuModelProvider, googleTensorTpuModelProvider)
.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/
google_tensor_runtime/...
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:google_tensor_runtime")
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:google_tensor_runtime")
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 上运行模型。 它还提供了一个强大的内置回退机制:您可以指定 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++ 跨平台中运行
如需查看示例实现,请参阅 Asynchronous segmentation C++ App。
Bazel build 依赖项
C++ 用户必须使用 LiteRT NPU 加速构建应用的依赖项。封装核心应用逻辑(例如 main.cc)的 cc_binary
规则需要以下运行时组件:
- 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 主机(如
libQnnHtp.so、libQnnHtpPrepare.so)的 Qualcomm AI RT (QAIRT) 库以及相应的 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 内存复制数据,零复制可以显著缩短端到端延迟时间。
以下代码是使用 AHardwareBuffer 实现零复制 NPU 的示例,可将数据直接传递给 NPU。此实现避免了对 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 支持对 .tflite 模型进行 NPU 设备端(称为 JIT)编译。
在无法提前编译模型的情况下,JIT
编译尤其有用。
不过,JIT 编译可能会产生一些延迟时间和内存开销,以便按需将用户提供的模型转换为 NPU 字节码指令。为了最大限度地减少对性能的影响,可以缓存 NPU 编译工件。
启用缓存后,LiteRT 将仅在需要时触发模型的重新编译,例如:
- 供应商的 NPU 编译器插件版本已更改;
- Android build 指纹已更改;
- 用户提供的模型已更改;
- 编译选项已更改。
如需启用 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 |