Skip to main content

litert-runtime

Creates an Android app that runs a .tflite model on the CPU or the GPU with the LiteRT CompiledModel API in Kotlin. Use this skill to build a new app around a vision, audio or embedding model, or to add on-device inference to an existing app - the dependency, where the model file goes, the inference class, the ViewModel and screen, and checking the output on a device.

معلومات المصدر

المستودع
google-ai-edge/litert-samples
آخر نشاط في المصدر
٩ أكتوبر ٢٠٢٦ في ٠٥:٤٧
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٤٦٥
التفرعات
١٢٢

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
4 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
litert-runtime
description
Creates an Android app that runs a .tflite model on the CPU or the GPU with the LiteRT CompiledModel API in Kotlin. Use this skill to build a new app around a vision, audio or embedding model, or to add on-device inference to an existing app - the dependency, where the model file goes, the inference class, the ViewModel and screen, and checking the output on a device.
license
Apache-2.0
metadata
{"last-updated":"2026-10-09","keywords":["LiteRT","CompiledModel","tflite","Android app","GPU"]}
This skill provides step-by-step guidance for building an Android app that runs a `.tflite` model with the LiteRT CompiledModel API (`com.google.ai.edge.litert:litert` 2.x; overview: https://ai.google.dev/edge/litert/android, sources: https://github.com/google-ai-edge/litert/blob/main/README.md) on the CPU or the GPU. The Interpreter API is not covered. For language models, use the `litert-lm` skill: https://github.com/google-ai-edge/litert-samples/blob/main/skills/litert-lm/SKILL.md (LiteRT-LM: https://github.com/google-ai-edge/LiteRT-LM/blob/main/README.md). ## Prerequisites - A Kotlin Android project (Android Studio's Empty Activity template is enough). The LiteRT 2.3.0 AARs declare `minSdk` 24. - The dependencies in the app-level `build.gradle.kts`, from Google Maven: `implementation("com.google.ai.edge.litert:litert:2.3.0")` and `implementation("com.google.ai.edge.litert:litert-gpu:2.3.0")`. From 2.3.0 the GPU accelerator is the second artifact: with `litert` alone the app builds, and `CompiledModel.create` with `Accelerator.GPU` throws `LiteRtException` because the APK has no GPU accelerator library (logcat: `GPU accelerator could not be loaded and registered`). No manifest entry is needed: `litert-api`, which `litert` depends on, declares the OpenCL driver libraries (`uses-native-library`) in its own manifest. - A `.tflite` model and its input requirements (input size, mean/std, channel order). Models with a LiteRT recipe: https://github.com/google-ai-edge/litert-samples/blob/main/models/README.md ## Detailed steps ### 1. Set up the project and place the model In the app-level `build.gradle.kts`, set `minSdk = 24` in `defaultConfig`. Put the model at `app/src/main/assets/model.tflite` (AGP stores `.tflite` files uncompressed by default). A model too large for the APK is delivered by Play for On-device AI (beta) as an AI pack, or downloaded by the app into `context.filesDir`: https://developer.android.com/google/play/on-device-ai (its bundletool `--local-testing` installs the packs without the store). An install-time AI pack is read through the `AssetManager`, as that page shows. A fast-follow or on-demand pack and a downloaded file are loaded from their path with `CompiledModel.create(filePath, CompiledModel.Options(accelerator), environment)` in place of the asset call in step 2. The pack's directory comes from the AI Delivery library (`com.google.android.play:ai-delivery`): `AiPackManagerFactory.getInstance(context).getPackLocation(name)?.assetsPath()`, null until the pack has downloaded. With 2.3.0 nothing is added to `gradle.properties`: `litert` 2.3.0 declares the namespace `com.google.ai.edge.litert.impl` and its dependency `litert-api` 2.3.0 declares `com.google.ai.edge.litert`, so AGP 9.x builds the project. With 2.2.0 or 2.1.6 both libraries declare `com.google.ai.edge.litert`, and AGP 9.x stops at `processDebugMainManifest` (https://github.com/google-ai-edge/LiteRT/issues/8474; AGP 8.x reports it as a warning and builds); for those two versions add `android.uniquePackageNames=false` to `gradle.properties`, and remove it when moving to 2.3.0, because it also hides the same clash between any other two libraries. Excluding `litert-api` instead does not work: `CompiledModel` and `Accelerator` are in it, and the build then fails at `compileDebugKotlin`. ### 2. Write the inference class ```kotlin import android.content.Context import com.google.ai.edge.litert.Accelerator import com.google.ai.edge.litert.CompiledModel import com.google.ai.edge.litert.Environment import com.google.ai.edge.litert.TensorBuffer const val INPUT_SIZE = 224 * 224 * 3 private val environment by lazy { Environment.create() } class Classifier(context: Context, accelerator: Accelerator) : AutoCloseable { private val model = CompiledModel.create(context.assets, "model.tflite", CompiledModel.Options(accelerator), environment) private val inputs = mutableListOf<TensorBuffer>() private val outputs = mutableListOf<TensorBuffer>() init { try { inputs += model.createInputBuffers() outputs += model.createOutputBuffers() infer(FloatArray(INPUT_SIZE)) } catch (e: Exception) { close() throw e } } fun infer(input: FloatArray): FloatArray { inputs[0].writeFloat(input) model.run(inputs, outputs) return outputs[0].readFloat() } override fun close() { (inputs + outputs).forEach { it.close() } model.close() } } ``` `Accelerator.CPU` needs nothing from the device. `Accelerator.GPU` compiles the graph for the GPU; when the GPU cannot take the model, the constructor throws `LiteRtException`: from `create` for an op the GPU does not support, and on the Android emulator (API 36, arm64) from `create` or from the buffers. A missing asset and a file that is not a model also throw `LiteRtException` from `create`. The buffers are created once with the model, reused for every inference and closed before the model. One `Environment` serves every model in the process and stays open, so LiteRT loads the GPU accelerator library once and not on every `create`. The constructor ends with one inference as the warm-up (the first GPU run includes shader compilation) and closes the model and its buffers if any step throws. `INPUT_SIZE` is the model's input element count: `writeFloat` throws on a longer array and writes a shorter one without an error, so a wrong size shows up as a wrong result. ### 3. Wire a ViewModel and the screen ```kotlin data class UiState(val ready: Boolean = false, val result: List<Float>? = null, val error: String? = null) class MainViewModel(app: Application) : AndroidViewModel(app) { private val executor = Executors.newSingleThreadExecutor() private val scope = CoroutineScope(SupervisorJob() + executor.asCoroutineDispatcher()) private var classifier: Classifier? = null private val _uiState = MutableStateFlow(UiState()) val uiState: StateFlow<UiState> = _uiState.asStateFlow() fun load(accelerator: Accelerator = Accelerator.CPU) { scope.launch { if (classifier != null) return@launch try { classifier = Classifier(getApplication<Application>(), accelerator) _uiState.value = UiState(ready = true) } catch (e: LiteRtException) { _uiState.value = UiState(error = e.message) } } } fun classify(input: FloatArray) { scope.launch { try { classifier?.infer(input)?.let { result -> _uiState.update { it.copy(result = result.toList(), error = null) } } } catch (e: LiteRtException) { _uiState.update { it.copy(error = e.message) } } } } override fun onCleared() { scope.launch { classifier?.close() }.invokeOnCompletion { scope.cancel() } executor.shutdown() } } ``` One single-thread executor owns the model: create, run and close happen only on it, never on the main thread. The ViewModel keeps its own scope because `viewModelScope` is cancelled before `onCleared()` runs, so a close launched there would not run; `onCleared()` cancels the scope once the close is done. `load()` does nothing when a model is already loaded, so the screen can call it again after a rotation; a `load()` that fails leaves `classifier` `null`. `classify()` reports a `LiteRtException` (package `com.google.ai.edge.litert`) in `error` and keeps the model. The screen below takes the picture (`bitmap`) from the photo picker or CameraX and runs `preprocess()` in the click handler (a few milliseconds for 224 by 224; move it onto the executor for bigger pictures); it does not fall back on its own: if `load(Accelerator.GPU)` ends in `error`, call `load(Accelerator.CPU)`. `viewModel()` and `collectAsStateWithLifecycle()` come from `androidx.lifecycle:lifecycle-viewmodel-compose` and `androidx.lifecycle:lifecycle-runtime-compose` (2.10.0); every import the code blocks need is listed in [imports](references/imports.md): ```kotlin @Composable fun MainScreen(bitmap: Bitmap, viewModel: MainViewModel = viewModel()) { val state by viewModel.uiState.collectAsStateWithLifecycle() LaunchedEffect(Unit) { viewModel.load(Accelerator.GPU) } Column { state.error?.let { Text(it) } Button(onClick = { viewModel.classify(preprocess(bitmap)) }, enabled = state.ready) { Text("Run") } state.result?.let { Text("Top class: ${it.indices.maxBy { i -> it[i] }}") } } } ``` ### 4. Preprocess by the model's input requirements Turn the bitmap into the model's input with [`preprocess()`](references/preprocess.md). Use the model's own size, mean/std, channel order and layout (that example is NHWC, RGB, scaled to -1..1); a wrong mean/std looks exactly like a broken model. An audio or embedding model replaces `preprocess()` with its own input encoding and keeps the inference class. ### 5. Run on a device and check the output Run the app on a physical device from Android Studio. Compare the app's output with the model's reference output for one fixed input, on the CPU first and then on the GPU; follow [verification](references/verify.md). Moving an existing Interpreter-API app to the CompiledModel API is a separate skill: https://github.com/google-ai-edge/litert-samples/blob/main/skills/litert-compiled-model-migration/SKILL.md
عرض على GitHub