TensorFlow Lite NNAPI 委托

Android Neural Networks API (NNAPI) 在所有运行 Android 8.1(API 级别 27)或更高版本的 Android 设备上可用。在具有支持的硬件加速器的 Android 设备上,它可以为 TensorFlow Lite 模型提供加速。支持的硬件加速器包括:

  • 图形处理单元 (GPU)
  • 数字信号处理器 (DSP)
  • 神经处理单元 (NPU)

根据设备上可用的特定硬件,性能可能有所不同。

本页介绍在 Java 和 Kotlin 中如何将 NNAPI 委托与 TensorFlow Lite 解释器结合使用。对于 Android C API,请参阅 Android Native Development Kit 文档

在自己的模型上尝试 NNAPI 委托

Gradle 导入

NNAPI 委托是 TensorFlow Lite Android 解释器(1.14.0 或更高版本)的一部分。您可以通过将以下代码添加到模块的 Gradle 文件,将其导入项目:

dependencies {
   implementation 'org.tensorflow:tensorflow-lite:2.0.0'
}

初始化 NNAPI 委托

添加以下代码,先初始化 NNAPI 委托,然后再初始化 TensorFlow Lite 解释器。

注:虽然从 API 级别 27 (Android Oreo MR1) 开始就支持 NNAPI,但是,在 API 级别 28 (Android Pie) 及以后的版本上,对运算的支持大有改善。因此,对于大多数情形,我们建议开发者为 Android Pie 或更高的版本使用 NNAPI 委托。

import org.tensorflow.lite.Interpreter;
import org.tensorflow.lite.nnapi.NnApiDelegate;

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);
}

// Initialize TFLite interpreter
try {
    tfLite = new Interpreter(loadModelFile(assetManager, modelFilename), options);
} catch (Exception e) {
    throw new RuntimeException(e);
}

// Run inference
// ...

// Unload delegate
tfLite.close();
if(null != nnApiDelegate) {
    nnApiDelegate.close();
}

最佳做法

在部署前测试性能

由于模型架构、大小、运算、硬件可用性和运行时硬件利用率不同,运行时性能可能会有显著差异。例如,如果某个应用使用大量 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 兼容:

当模型包含动态大小的输出时,也不支持 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