Loading...
Loading...
Configures and implements LiteRT (.tflite) on-device inference on Android in Kotlin using the CompiledModel API on CPU and GPU. Use this skill for any Android LiteRT or .tflite task, including Gradle setup, image classification or vision/audio/embedding helpers, TensorBuffer reuse, CPU memory optimization, Bitmap preprocessing, AndroidViewModel GPU-to-CPU fallback with warm-up on a single-thread dispatcher, LiteRT in Google Play services (play-services-litert), migrating from legacy org.tensorflow.lite.Interpreter, GpuDelegate, or play-services-tflite, and latency benchmarking. Don't use for running generative text LLMs with .litertlm files or for Python model conversion.
npx skill4agent add android/skills litert-runtime.tflitecom.google.ai.edge.litert:litertorg.tensorflow.lite.Interpreter.litertlmlitert-lmminSdk24com.google.android.gms:play-services-litertimplementation("com.google.ai.edge.litert:litert:2.3.0")implementation("com.google.ai.edge.litert:litert-gpu:2.3.0")litertCompiledModel.createCompiledModel.Options(Accelerator.GPU)LiteRtExceptionCompiledModel.Options(Accelerator.GPU, Accelerator.CPU)GPU accelerator could not be loaded and registeredlitert-apilitertuses-native-library.tfliteCompiledModelTensorBuffercreateInputBufferscreateOutputBuffersCompiledModelmodel.runmodel.runoutputs[0].readFloatinitclosecatchCompiledModelTensorBufferMetadataExtractororg.tensorflow.liteorg.tensorflow.liteDataTypeGpuDelegateModel.Device.GPUCompiledModel.Options(Accelerator.GPU, Accelerator.CPU)libs.versions.tomlgradle.propertiesapp/build.gradle.ktsorg.tensorflow.liteEnvironmentenvironment17.0.0./gradlew assembleDebug--dry-runCould not find com.google.android.gms:play-services-litert:17.0.0MetadataExtractorFileUtilImageProcessorTensorImageTensorLabelminSdkapp/build.gradle.ktsapp/src/main/assets/model.tflite.tflitecontext.filesDirbundletool --local-testingAssetManagerfilePathCompiledModel.create(filePath, CompiledModel.Options(accelerator), environment)com.google.android.play:ai-deliveryAiPackManagerFactory.getInstance(context).getPackLocation(name)?.assetsPath()nullgradle.propertieslitertcom.google.ai.edge.litert.impllitert-apicom.google.ai.edge.litertcom.google.ai.edge.litertprocessDebugMainManifestandroid.uniquePackageNames=falsegradle.propertieslitert-apiCompiledModelAcceleratorlitert-apicompileDebugKotlinCompiledModelTensorBufferAutoCloseableimport 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.CPUAccelerator.GPULiteRtExceptioncreatecreateLiteRtExceptioncreateEnvironmentcreateinitINPUT_SIZEwriteFloatint8uint8writeInt8readInt8TensorBufferwriteFloatreadFloatcreate(context.assets, ...)context.noBackupFilesDircreate(filePath, ...)xnnPackWeightCachePathxnnPackFlags = 0x230x30x200x20int8uint8cpuOptionsAndroidViewModelAccelerator.CPUimport android.app.Application
import androidx.lifecycle.AndroidViewModel
import com.google.ai.edge.litert.Accelerator
import com.google.ai.edge.litert.LiteRtException
import java.util.concurrent.Executors
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
data class UiState(
val ready: Boolean = false,
val accelerator: Accelerator = Accelerator.CPU,
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(preferred: Accelerator = Accelerator.GPU) {
scope.launch {
if (classifier != null) return@launch
val appContext = getApplication<Application>()
val selected = try {
classifier = Classifier(appContext, preferred)
preferred
} catch (e: LiteRtException) {
if (preferred != Accelerator.CPU) {
try {
classifier = Classifier(appContext, Accelerator.CPU)
Accelerator.CPU
} catch (cpuError: LiteRtException) {
_uiState.value = UiState(error = cpuError.message)
return@launch
}
} else {
_uiState.value = UiState(error = e.message)
return@launch
}
}
_uiState.value = UiState(ready = true, accelerator = selected)
}
}
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()
}
}ViewModelviewModelScopeonClearedonClearedscopecloseloadloadclassifiernullclassifyLiteRtExceptioncom.google.ai.edge.literterrorbitmappreprocesspreprocessviewModelcollectAsStateWithLifecycleandroidx.lifecycle:lifecycle-viewmodel-composeandroidx.lifecycle:lifecycle-runtime-composeimport android.graphics.Bitmap
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.google.ai.edge.litert.Accelerator
@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.accelerator})")
}
state.result?.let { scores ->
Text("Top class: ${scores.indices.maxBy { i -> scores[i] }}")
}
}
}Bitmappreprocess-1.0..1.0meanstdimport android.graphics.Bitmap
fun preprocess(
bitmap: Bitmap,
size: Int = 224,
mean: Float = 127.5f,
std: Float = 127.5f
): FloatArray {
val scaled = checkNotNull(
Bitmap.createScaledBitmap(bitmap, size, size, true)
.copy(Bitmap.Config.ARGB_8888, false)
)
val pixels = IntArray(size * size).also {
scaled.getPixels(it, 0, size, 0, 0, size, size)
}
val out = FloatArray(size * size * 3)
pixels.forEachIndexed { i, p ->
out[i * 3] = ((p shr 16 and 0xFF) - mean) / std
out[i * 3 + 1] = ((p shr 8 and 0xFF) - mean) / std
out[i * 3 + 2] = ((p and 0xFF) - mean) / std
}
return out
}Bitmap.Config.ARGB_8888ImageDecoderBitmap.Config.HARDWAREUrigetPixelsHARDWAREpreprocessAccelerator.CPUAccelerator.GPUorg.tensorflow.lite.Interpreterorg.tensorflow:tensorflow-lite*com.google.ai.edge.litert:litertCompiledModelplay-services-tflite-javaam instrumentconnectedDebugAndroidTestplay-services-litertcom.google.ai.edge.litert:litert-support:2.3.0org.tensorflow.lite.supportcom.google.ai.edge.litert.supportGpuDelegateCompiledModel.Options(Accelerator.GPU, Accelerator.CPU)Accelerator.CPUsetNumThreads(n)cpuOptions = CompiledModel.CpuOptions(numThreads = n)InterpreterFileUtil.loadMappedFileClassifierCompiledModel.Options(Accelerator.GPU, Accelerator.CPU)org.tensorflow.liteorg.tensorflow.liteorg.tensorflow.lite.DataTypeDataTypeTensorImage(DataType.FLOAT32)TensorBuffer.createFixedSizeTensorLabelpreprocessCompiledModelorg.tensorflow.liteCompiledModelTensorBufferTensorBuffermodel.runoutputs[0].readFloatorg.tensorflow:tensorflow-lite*org.tensorflow:tensorflow-lite-supportcom.google.ai.edge.litert:*org.tensorflow.lite.*Accelerator.GPUcom.google.ai.edge.litert:litert-gpu:2.3.0com.google.ai.edge.litert:litert:2.3.0xnnPackFlags = 0x200x30x23minSdk24com.google.ai.edge.litert:litert:2.3.0com.google.ai.edge.litert:litert-gpu:2.3.0app/build.gradle.ktsorg.tensorflow:tensorflow-lite*org.tensorflow.lite.*CompiledModel.createmodel.runcloseTensorBuffermodel.closeinitloadAccelerator.CPUAccelerator.GPULiteRtException./gradlew assembleDebugxnnPackFlags = 0x23