This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

perf: add NNAPI delegate fallback for TFLite object detection

Add NNAPI delegate as an intermediate fallback between GPU and CPU
for TFLite inference. On devices where GPU delegate is unavailable,
NNAPI can route inference to the device's DSP/NPU for better
performance than CPU-only execution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+20 -4
+20 -4
posedetection/src/androidMain/kotlin/com/performancecoachlab/posedetection/custom/CustomObjectModel.android.kt
··· 4 4 import androidx.compose.ui.platform.LocalContext 5 5 import co.touchlab.kermit.Logger 6 6 import org.json.JSONObject 7 + import android.os.Build 7 8 import org.tensorflow.lite.Interpreter 8 9 import org.tensorflow.lite.gpu.GpuDelegate 9 10 import org.tensorflow.lite.support.common.FileUtil ··· 21 22 if (modelPath.androidModelPath == null) { 22 23 throw IllegalArgumentException("Android model path cannot be null") 23 24 } 24 - // Prefer GPU if available, fall back to CPU. 25 + // Prefer GPU, then NNAPI (API 27+), then CPU. 25 26 val (options, gpuDelegate) = runCatching { 26 27 val delegate = GpuDelegate() 27 28 val opts = Interpreter.Options().apply { 28 29 addDelegate(delegate) 29 - // Threads often don’t matter with GPU delegate; keep small to reduce contention. 30 30 setNumThreads(2) 31 31 } 32 32 Logger.d { "TFLite GPU delegate available" } 33 33 opts to delegate 34 34 }.onFailure { t -> 35 - Logger.w(t) { "TFLite GPU delegate not available; falling back to CPU" } 35 + Logger.w(t) { "TFLite GPU delegate not available; trying NNAPI" } 36 36 }.getOrElse { 37 - Interpreter.Options().apply { setNumThreads(4) } to null 37 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { 38 + runCatching { 39 + val nnapiDelegate = org.tensorflow.lite.nnapi.NnApiDelegate() 40 + val opts = Interpreter.Options().apply { 41 + addDelegate(nnapiDelegate) 42 + setNumThreads(2) 43 + } 44 + Logger.d { "TFLite NNAPI delegate available" } 45 + opts to null 46 + }.onFailure { t -> 47 + Logger.w(t) { "TFLite NNAPI delegate not available; falling back to CPU" } 48 + }.getOrElse { 49 + Interpreter.Options().apply { setNumThreads(4) } to null 50 + } 51 + } else { 52 + Interpreter.Options().apply { setNumThreads(4) } to null 53 + } 38 54 } 39 55 40 56 val model = FileUtil.loadMappedFile(LocalContext.current, modelPath.androidModelPath)