LiteRT は、ベンダー固有のコンパイラ、ランタイム、ライブラリの依存関係を操作することなく、ニューラル プロセッシング ユニット(NPU)を使用するための統合インターフェースを提供します。NPU アクセラレーションに LiteRT を使用すると、リアルタイム推論と大規模モデル推論のパフォーマンスが向上し、ゼロコピー ハードウェア バッファの使用によりメモリコピーが最小限に抑えられます。
使ってみる
従来の ML モデル
従来の ML モデルについては、次のデモアプリをご覧ください。
- 画像セグメンテーション 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 をご覧ください。
- 最新情報については、LiteRT で Qualcomm NPU のピーク パフォーマンスを引き出す をご覧ください。
MediaTek NeuroPilot
CompiledModelAPI を介した AOT コンパイルとオンデバイス コンパイルの実行をサポートします。- 設定の詳細については、MediaTek NeuroPilot をご覧ください。
- 最新情報については、 MediaTek NPU と LiteRT: 次世代のオンデバイス AI を強化する をご覧ください。
Intel OpenVino
CompiledModelAPI を介した AOT コンパイルとオンデバイス コンパイルの実行をサポートします。- 設定の詳細については、Intel OpenVino をご覧ください。
AOT コンパイルとオンデバイス コンパイル
LiteRT NPU は、特定のデプロイ要件を満たすために、AOT コンパイルとオンデバイス コンパイルの両方をサポートしています。
- オフライン(AOT)コンパイル: ターゲット SoC がわかっている大規模で複雑なモデルに最適です。 事前コンパイルを行うと、初期化コストが大幅に削減され、ユーザーがアプリを起動したときのメモリ使用量が削減されます。
- オンライン(オンデバイス)コンパイル: JIT コンパイルとも呼ばれます。これは、小規模モデルのプラットフォームに依存しないモデル配信に最適です。モデルは初期化中にユーザーのデバイスでコンパイルされるため、追加の準備手順は必要ありませんが、初回実行時のコストが高くなります。
AOT コンパイル オプションとオンデバイス コンパイル オプションの両方を使用してモデルをデプロイする方法は次のとおりです。
ステップ 1: ターゲット NPU SoC の AOT コンパイル
LiteRT AOT(事前)コンパイラを使用して、.tflite モデルをサポートされている SoC にコンパイルできます。また、1 回のコンパイル プロセスで複数の SoC ベンダーとバージョンを同時にターゲットにすることもできます。詳細については、 この LiteRT AOT コンパイル ノートブックをご覧ください。 省略可能ですが、デバイス上の初期化時間を短縮するため、大規模なモデルでは AOT コンパイルを強くおすすめします。この手順は、オンデバイス コンパイルでは必要ありません。
ステップ 2: Android の場合は Google Play でデプロイする
Android では、Google Play for On-device AI (PODAI)を使用して、モデルと NPU ランタイム ライブラリをアプリとともにデプロイします。
- オンデバイス コンパイルのモデルの場合: 元の .tflite モデルファイルをアプリの assets/ ディレクトリに直接追加します。
- 実装例については、 Segmentation オンデバイス コンパイル Kotlin アプリをご覧ください。
- AOT コンパイルのモデルの場合: LiteRT を使用して、コンパイル済みモデル
を 1 つの Google Play AI Pack にエクスポートします。
次に、AI パックを Google Play にアップロードして、正しいコンパイル済みモデルをユーザーのデバイスに自動的に配信します。
- コンパイル済みモデルを Play AI Pack にエクスポートする手順については、 LiteRT AOT コンパイル ノートブック をご覧ください。
- 実装例については、 Segmentation 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 の
手順
で、インストール時の配信とfast-follow 配信もご覧ください。
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
Gradle 構成に NPU ランタイム ライブラリを追加する
生成された 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 コンパイルはフォールバックもサポートしています。サポートされていないサブグラフは、指定されたとおりに CPU または GPU でシームレスに実行されるため、NPU での部分的な委任が可能です。
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 アクセラレーションを使用してアプリケーションの依存関係をビルドする必要があります。コア アプリケーション ロジック(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 ホスト用の 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属性を介して含まれます。
この設定により、コンパイルされたバイナリは、高速な ML 推論のために 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 メモリとの間でデータをコピーしないことで、ゼロコピーはエンドツーエンドのレイテンシを大幅に短縮できます。
次のコードは、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 ビルドのフィンガープリントが変更された。
- ユーザーが提供したモデルが変更された。
- コンパイル オプションが変更された。
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 |