在运行 Android 8.1(API 级别 27)或更高版本的 Android 设备上,Android 神经网络 API (NNAPI) 可用。它为支持硬件加速器的 Android 设备上的 TensorFlow Lite 模型提供加速,包括
- 图形处理单元 (GPU)
- 数字信号处理器 (DSP)
- 神经处理单元 (NPU)
性能将根据设备上可用的特定硬件而有所不同。
本页面介绍了如何在 Java 和 Kotlin 中使用 TensorFlow Lite 解释器中的 NNAPI 代理。有关 Android C API,请参阅 Android 原生开发工具包文档.
在您自己的模型上尝试 NNAPI 代理
Gradle 导入
NNAPI 代理是 TensorFlow Lite Android 解释器的一部分,版本 1.14.0 或更高版本。您可以通过将以下内容添加到模块 gradle 文件中来将其导入到您的项目中
dependencies {
implementation 'org.tensorflow:tensorflow-lite:+'
}
初始化 NNAPI 代理
在初始化 TensorFlow Lite 解释器之前添加初始化 NNAPI 代理的代码。
Kotlin
import android.content.res.AssetManager
import org.tensorflow.lite.Interpreter
import org.tensorflow.lite.nnapi.NnApiDelegate
import java.io.FileInputStream
import java.io.IOException
import java.nio.MappedByteBuffer
import java.nio.channels.FileChannel
...
val options = Interpreter.Options()
var nnApiDelegate: NnApiDelegate? = null
// Initialize interpreter with NNAPI delegate for Android Pie or above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
nnApiDelegate = NnApiDelegate()
options.addDelegate(nnApiDelegate)
}
val assetManager = assets
// Initialize TFLite interpreter
val tfLite: Interpreter
try {
tfLite = Interpreter(loadModelFile(assetManager, "model.tflite"), options)
} catch (e: Exception) {
throw RuntimeException(e)
}
// Run inference
// ...
// Unload delegate
tfLite.close()
nnApiDelegate?.close()
...
@Throws(IOException::class)
private fun loadModelFile(assetManager: AssetManager, modelFilename: String): MappedByteBuffer {
val fileDescriptor = assetManager.openFd(modelFilename)
val inputStream = FileInputStream(fileDescriptor.fileDescriptor)
val fileChannel = inputStream.channel
val startOffset = fileDescriptor.startOffset
val declaredLength = fileDescriptor.declaredLength
return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength)
}
...
Java
import android.content.res.AssetManager;
import org.tensorflow.lite.Interpreter;
import org.tensorflow.lite.nnapi.NnApiDelegate;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
...
Interpreter.Options options = (new Interpreter.Options());
NnApiDelegate nnApiDelegate = null;
// Initialize interpreter with NNAPI delegate for Android Pie or above
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
nnApiDelegate = new NnApiDelegate();
options.addDelegate(nnApiDelegate);
}
AssetManager assetManager = getAssets();
// Initialize TFLite interpreter
try {
tfLite = new Interpreter(loadModelFile(assetManager, "model.tflite"), options);
} catch (Exception e) {
throw new RuntimeException(e);
}
// Run inference
// ...
// Unload delegate
tfLite.close();
if(null != nnApiDelegate) {
nnApiDelegate.close();
}
...
private MappedByteBuffer loadModelFile(AssetManager assetManager, String modelFilename) throws IOException {
AssetFileDescriptor fileDescriptor = assetManager.openFd(modelFilename);
FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());
FileChannel fileChannel = inputStream.getChannel();
long startOffset = fileDescriptor.getStartOffset();
long declaredLength = fileDescriptor.getDeclaredLength();
return fileChannel.map(FileChannel.MapMode.READ_ONLY, startOffset, declaredLength);
}
...
最佳实践
部署前测试性能
由于模型架构、大小、操作、硬件可用性和运行时硬件利用率,运行时性能可能会有很大差异。例如,如果应用程序大量使用 GPU 进行渲染,则 NNAPI 加速可能不会提高性能,因为存在资源争用。我们建议使用调试记录器运行简单的性能测试以测量推理时间。在生产环境中启用 NNAPI 之前,请在代表您的用户群的几个具有不同芯片组(制造商或来自同一制造商的型号)的手机上运行测试。
对于高级开发人员,TensorFlow Lite 还提供 适用于 Android 的模型基准测试工具.
创建设备排除列表
在生产环境中,NNAPI 可能无法按预期执行。我们建议开发人员维护一个设备列表,这些设备不应与特定模型一起使用 NNAPI 加速。您可以根据 "ro.board.platform"
的值创建此列表,您可以使用以下代码片段检索此值
String boardPlatform = "";
try {
Process sysProcess =
new ProcessBuilder("/system/bin/getprop", "ro.board.platform").
redirectErrorStream(true).start();
BufferedReader reader = new BufferedReader
(new InputStreamReader(sysProcess.getInputStream()));
String currentLine = null;
while ((currentLine=reader.readLine()) != null){
boardPlatform = line;
}
sysProcess.destroy();
} catch (IOException e) {}
Log.d("Board Platform", boardPlatform);
对于高级开发人员,请考虑通过远程配置系统维护此列表。TensorFlow 团队正在积极努力简化和自动化发现和应用最佳 NNAPI 配置的方法。
量化
量化通过使用 8 位整数或 16 位浮点数而不是 32 位浮点数进行计算来减小模型大小。8 位整数模型大小是 32 位浮点数版本的四分之一;16 位浮点数是大小的一半。量化可以显着提高性能,尽管该过程可能会牺牲一些模型精度。
有多种类型的训练后量化技术可用,但是,为了在当前硬件上获得最大支持和加速,我们建议使用 全整数量化。这种方法将权重和操作都转换为整数。此量化过程需要一个代表性数据集才能正常工作。
使用受支持的模型和操作
如果 NNAPI 代理不支持模型中的一些操作或参数组合,则框架仅在加速器上运行图的受支持部分。其余部分在 CPU 上运行,这会导致执行拆分。由于 CPU/加速器同步的成本很高,这可能会导致比在 CPU 上单独执行整个网络更慢的性能。
当模型仅使用 受支持的操作 时,NNAPI 的性能最佳。以下模型已知与 NNAPI 兼容
- MobileNet v1 (224x224) 图像分类 (浮点模型下载) (量化模型下载)
(专为移动和嵌入式视觉应用设计的图像分类模型) - MobileNet v2 SSD 目标检测 (下载)
(检测图像中多个目标并用边界框标记的图像分类模型) - MobileNet v1(300x300) 单次检测器 (SSD) 目标检测 (下载)
- PoseNet 姿势估计 (下载)
(估计图像或视频中人物姿势的视觉模型)
当模型包含动态大小的输出时,也不支持 NNAPI 加速。在这种情况下,您将收到类似的警告
ERROR: Attempting to use a delegate that only supports static-sized tensors \
with a graph that has dynamic-sized tensors.
启用 NNAPI CPU 实现
无法由加速器完全处理的图可以回退到 NNAPI CPU 实现。但是,由于这通常比 TensorFlow 解释器性能更低,因此此选项在 Android 10(API 级别 29)或更高版本的 NNAPI 代理中默认情况下处于禁用状态。要覆盖此行为,请在 NnApiDelegate.Options
对象中将 setUseNnapiCpu
设置为 true
。