将 Edge 部署到 Android 教程

您需要构建的内容

在本教程中,您将下载使用 AutoML Vision Edge 创建和导出的自定义 TensorFlow Lite 模型。然后,您将运行一个使用该模型识别花卉图片的预制 Android 应用。

最终产品的移动设备屏幕截图
图片来源:Felipe Venâncio,“拍摄于我母亲的花园”CC BY 2.0,应用中显示的图片)。

目标

在本入门级端到端演示中,您将使用代码执行以下操作:

  • 在使用 TFLite 解释器的 Android 应用中运行预训练模型。

准备工作

通过 AutoML Vision Edge 训练模型

您必须先按照 Edge 设备模型快速入门中的说明从 AutoML Vision Edge 训练和导出 TF Lite 模型,然后才能将模型部署到 Edge 设备。

完成快速入门后,您应该已经导出以下经过训练的模型文件:TF Lite 文件、标签文件和元数据文件,如下所示。

Cloud Storage TF Lite 模型文件

安装 TensorFlow

在开始学习本教程之前,您需要安装如下软件:

如果您已经安装了 Python 并且可以正常使用,请运行以下命令下载此软件:

pip install --upgrade  "tensorflow==1.7.*"
pip install PILLOW

如果在该过程中遇到问题,请参考 TensorFlow 官方文档

克隆 Git 代码库

使用命令行,通过以下命令克隆 Git 代码库:

git clone https://github.com/googlecodelabs/tensorflow-for-poets-2

导航到代码库的本地克隆的目录(tensorflow-for-poets-2 目录)。您将从此目录运行以下所有代码示例:

cd tensorflow-for-poets-2

设置 Android 应用

安装 Android Studio

如有必要,请在本地安装 Android Studio 3.0+

使用 Android Studio 打开项目

按照以下步骤,使用 Android Studio 打开项目:

  1. 打开 Android Studio Android Studio“启动”图标。 该工具加载后,从以下弹出式窗口中选择 Android Studio“打开项目”图标“打开现有 Android Studio 项目”(Open an existing Android Studio project):

    Android Studio“打开项目”弹出式窗口

  2. 在文件选择器中,从您的工作目录中选择 tensorflow-for-poets-2/android/tflite

  3. 首次打开项目时,您会看到一个“Gradle 同步”(Gradle Sync) 弹出式窗口,询问您是否要使用 Gradle 封装容器。选择“确定”(OK)。

    Android Studio“打开项目”弹出式窗口

试运行应用

该应用可以在真机 Android 设备上运行,也可以在 Android Studio 模拟器中运行。

设置 Android 设备

除非您已启用“开发者模式”和“USB 调试”,否则您无法将该应用从 Android Studio 加载到您的手机上。

如需完成此一次性设置流程,请按说明操作。

为模拟器设置相机访问权限(可选)

如果您选择使用模拟器而不是真机 Android 设备,Android Studio 可帮助您轻松设置模拟器。

由于此应用使用相机,请将模拟器的相机设置为使用计算机的相机(而不是默认的测试模式)。

如需设置模拟器的相机,您需要在“Android 虚拟设备管理器”(Android Virtual Device Manager)(您可以通过 虚拟设备管理器图标 按钮访问此服务)中创建一个新设备。从 ADVM 主页面中选择“创建虚拟设备”(Create Virtual Device):

Android Studio“创建虚拟设备”选项

然后在“验证配置”(Verify Configuration) 页面(虚拟设备设置的最后一页)上,选择“显示高级设置”(Show Advanced Settings):

Android Studio“创建虚拟设备”选项

显示高级设置后,您可以将两个相机源设置为使用主机的网络摄像头:

Android Studio“选择相机源”选项

运行原始应用

在对应用进行任何更改之前,请运行与代码库一并提供的版本。

如需启动构建和安装过程,请运行 Gradle 同步。

“Gradle 同步”图标

运行 Gradle 同步后,请选择播放按钮 Android Studio“播放”图标

选择播放按钮后,您需要从以下弹出式窗口中选择您的设备:

“选择设备”弹出式窗口

选择设备后,您必须允许 Tensorflow Demo 访问您的相机和文件:

“允许访问相机”窗口

现在应用已安装完毕,点击应用图标 Android Studio 应用图标 即可启动。此版本的应用使用基于 1000 个 ImageNet 类别进行预训练的标准 MobileNet。

输出应如下所示:

运行测试应用

运行自定义应用

默认应用设置使用标准 MobileNet 将图片归为 1000 个 ImageNet 类别中的某个类别,无需重新训练。

现在请进行修改,以便应用将 AutoML Vision Edge 创建的模型用于您的自定义图片类别。

将模型文件添加到项目中

此演示版项目配置为在 android/tflite/app/src/main/assets/ 目录中搜索 graph.litelabels.txt 文件。

使用以下命令将这两个原始文件替换为您的版本:

cp [Downloads]/model.tflite android/tflite/app/src/main/assets/graph.lite
cp [Downloads]/dict.txt  android/tflite/app/src/main/assets/labels.txt

修改应用

此应用使用 float 模型,而由 AutoML Vision Edge 创建的模型是量化模型。您需要对代码进行一些更改,以便让此应用使用该模型。

在类别成员定义和 ImageClassifier 初始化程序中,将 labelProbArrayfilterLabelProbArray 的数据类型从 float 更改为 byte。

private byte[][] labelProbArray = null;
private byte[][] filterLabelProbArray = null;

labelProbArray = new byte[1][labelList.size()];
filterLabelProbArray = new byte[FILTER_STAGES][labelList.size()];

ImageClassifier 初始化程序中,根据 int8 类型分配 imgData

    imgData =
        ByteBuffer.allocateDirect(
            DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE);

printTopKLabels() 中将 labelProbArray 的数据类型从 int8 转换为 float:

  private String printTopKLabels() {
    for (int i = 0; i < labelList.size(); ++i) {
      sortedLabels.add(
          new AbstractMap.SimpleEntry<>(labelList.get(i), (float)labelProbArray[0][i]));
      if (sortedLabels.size() > RESULTS_TO_SHOW) {
        sortedLabels.poll();
      }
    }
    String textToShow = "";
    final int size = sortedLabels.size();
    for (int i = 0; i < size; ++i) {
      Map.Entry<String, Float> label = sortedLabels.poll();
      textToShow = String.format("\n%s: %4.2f",label.getKey(),label.getValue()) + textToShow;
    }
    return textToShow;
  }

运行应用

在 Android Studio 中运行 Gradle 同步,以便构建系统找到您的文件:

“Gradle 同步”图标

运行 Gradle 同步后,像之前一样选择播放 Android Studio“播放”图标 来开始构建和安装过程。

输出应如下所示:

最终产品的移动设备屏幕截图
图片来源: Felipe Venâncio,“拍摄于我母亲的花园”CC BY 2.0,应用中显示的图片)。

您可以同时按住电源音量调低按钮进行屏幕截图。

使用以下方法测试更新后的应用:将相机对准不同的花卉图片,查看分类是否正确。

工作原理

现在,您已运行该应用,请检查特定于 TensorFlow Lite 的代码。

TensorFlow-Android AAR

此应用使用预编译的 TFLite Android ARchive (AAR)。此 AAR 托管在 jcenter 上。

模块的 build.gradle 文件中的以下行引入项目中 TensorFlow bintray maven 代码库的最新 AAR 版本。

build.gradle

repositories {
    maven {
        url 'https://google.bintray.com/tensorflow'
    }
}

dependencies {
    // ...
    compile 'org.tensorflow:tensorflow-lite:+'
}

您可以使用以下代码块来指示 Android 资源打包工具不应压缩 .lite.tflite 资源。这非常重要,因为 .lite 文件会进行内存映射,而文件压缩后无法实现这一点。

build.gradle

android {
    aaptOptions {
        noCompress "tflite"
        noCompress "lite"
    }
}

使用 TFLite Java API

与 TFLite 连接的代码全部包含在 ImageClassifier.java 中。

设置

需要注意的第一个块是 ImageClassifier 的构造函数:

ImageClassifier.java

ImageClassifier(Activity activity) throws IOException {
    tflite = new Interpreter(loadModelFile(activity));
    labelList = loadLabelList(activity);
    imgData =
        ByteBuffer.allocateDirect(
            4 * DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE);
    imgData.order(ByteOrder.nativeOrder());
    labelProbArray = new float[1][labelList.size()];
    Log.d(TAG, "Created a Tensorflow Lite Image Classifier.");
}

有些行需要特别注意。

以下行会创建 TFLite 解释器:

ImageClassifier.java

tflite = new Interpreter(loadModelFile(activity));

此行会实例化 TFLite 解释器。此解释器的工作方式类似于 tf.Session(对熟悉 TensorFlow 的人而言,不在 TFLite 中)。 向此解释器传递一个包含该模型的 MappedByteBuffer。 本地函数 loadModelFile 会创建一个包含活动的 graph.lite 资源文件的 MappedByteBuffer

以下行会创建输入数据缓冲区:

ImageClassifier.java

imgData = ByteBuffer.allocateDirect(
    4 * DIM_BATCH_SIZE * DIM_IMG_SIZE_X * DIM_IMG_SIZE_Y * DIM_PIXEL_SIZE);

该 byte 缓冲区会相应调整大小,以包含转换为 float 类型的图片数据。 此解释器可直接接受 float 数组作为输入,但 ByteBuffer 效率更高,因为它避免了解释器中出现额外副本。

以下行会加载标签列表并创建输出缓冲区:

labelList = loadLabelList(activity);
//...
labelProbArray = new float[1][labelList.size()];

输出缓冲区是一个 float 数组,每个标签都有一个元素,此模型会在其中写入输出概率。

运行模型

涉及的第二个代码块是 classifyFrame 方法。 此方法接受 Bitmap 作为输入、运行模型,并返回要在应用中输出的文本。

ImageClassifier.java

String classifyFrame(Bitmap bitmap) {
 // ...
 convertBitmapToByteBuffer(bitmap);
 // ...
 tflite.run(imgData, labelProbArray);
 // ...
 String textToShow = printTopKLabels();
 // ...
}

该方法有三个作用。首先,该方法会转换 Bitmap 输入并将其复制到 imgData ByteBuffer,以便输入到模型。然后,该方法会调用解释器的 run 方法,将输入缓冲区和输出数组作为参数传递。解释器会将输出数组中的值设置为针对每个类别计算的概率。输入和输出节点由先前创建 .lite 模型文件的 toco 转换步骤的参数定义。

后续步骤

您现在已经使用 Edge 模型完成了 Android 花卉分类应用的演示。您对图片分类应用进行了测试,然后对其进行了修改并获取了示例注释。然后您查看了特定于 TensorFlow Lite 的代码来了解基础功能。

  • 参阅官方文档代码库,详细了解 TFLite。
  • 尝试使用此演示版应用的量化版本,通过更小的软件包实现功能更强大的模型。
  • 尝试使用一些其他 TFLite 就绪模型,包括语音热词检测器和设备版智能回复。
  • 查看 TensorFlow 的使用入门文档,详细了解 TensorFlow 的一般信息。