承接移动端目标识别(2)

 

使用TensorFlow Lite在移动设备上运行

        在本节中,我们将向您展示如何使用TensorFlow Lite获得更小的模型,并允许您利用针对移动设备优化的操作。   

TensorFlow Lite是TensorFlow针对移动和嵌入式设备的轻量级解决方案。它支持端上的机器学习推理,具有低延迟和小二进制模型大小。

TensorFlow Lite使用了许多技术,例如允许更小和更快(定点数学)模型的量化内核。

        对于本节,您需要从源代码构建TensorFlow以获得对SSD模型的TensorFlow Lite支持。您还需要安装bazel构建工具。

(好像我以前博客有教程,不过网上的编译还是可能有各种问题,解决问题也算是base skill吧,多动手!)

为了使这些命令更容易运行,让我们设置一些环境变量:(设置环境变量,而不把一些变量直接写在代码里面也是安全和规范的方式)

  export CONFIG_FILE=PATH_TO_BE_CONFIGURED/pipeline.config  # pipeline.config 是使用tensorflow models object detection api中要配置的
  export CHECKPOINT_PATH=PATH_TO_BE_CONFIGURED/model.ckpt   # 训练后保存的模型文件。(我比较奇怪的是,这在pipeline.config中不是有的吗,可能还得继续往后看才知道。)
  export OUTPUT_DIR=/tmp/tflite                             # 输出的文件

这里的pipeline.config 我们选择:ssdlite_mobilenet_v2_coco.config (其实,下载model zoom里面ssdlite_mobilenet_v2_coco 有pipeline.config,我后面也用这个)
这里的model.ckpt我们从model zoom里面(就不用自己的模型啦)选择和pipeline对应的:ssdlite_mobilenet_v2_coco http://download.tensorflow.org/models/object_detection/ssdlite_mobilenet_v2_coco_2018_05_09.tar.gz
model zoom :https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md
output 就默认吧。

        我们从一个检查点开始,获得一个TensorFlow冻结图,其中包含我们可以与TensorFlow Lite一起使用的兼容操作。

        首先,您需要安装这些python库。然后,要获取冻结图,请使用以下命令从models / research目录运行export_tflite_ssd_graph.py脚本(为此我还红专门从源代码编译安装将tensorflow 1.3升级1.9):

 object_detection/export_tflite_ssd_graph.py \
    --pipeline_config_path=$CONFIG_FILE \
    --trained_checkpoint_prefix=$CHECKPOINT_PATH \
    --output_directory=$OUTPUT_DIR \
    --add_postprocessing_op=true

在/tmp/tflite目录中,我们现在应该看到两个文件:tflite_graph.pb(18.5MB)和tflite_graph.pbtxt(53.1MB)。请注意,
add_postprocessing标志使模型能够利用自定义优化的检测后处理操作,该操作可以被视为替换tf.image.non_max_suppression。
确保不要将在同一目录中的export_tflite_ssd_graph与export_inference_graph混淆。两个脚本都输出冻结的图形:export_tflite_ssd_graph将
输出我们可以直接输入到TensorFlow Lite的冻结(frozen)图形,并且是我们将要使用的图形。
接下来,我们将通过使用TensorFlow Lite优化转换器TOCO来获得TensorFlow Lite优化模型。这将通过以下命令将生成的冻结图形(tflite_graph.pb)转换为TensorFlow Lite  flatbuffer format(detect.tflite)。
对于量化模型,请从tensorflow /目录(就是源码编译的那个目录)运行(注意要使用bazel-0.12或以上的编译,我之前就是没有source ~/.bashrc 导致一直用的是bazel-0.5.4报错了。可以用bazel version看版本。):
bazel run --config=opt tensorflow/contrib/lite/toco:toco -- \
--input_file=$OUTPUT_DIR/tflite_graph.pb \
--output_file=$OUTPUT_DIR/detect.tflite \
--input_shapes=1,300,300,3 \
--input_arrays=normalized_input_image_tensor \
--output_arrays='TFLite_Detection_PostProcess','TFLite_Detection_PostProcess:1','TFLite_Detection_PostProcess:2','TFLite_Detection_PostProcess:3' \
--inference_type=QUANTIZED_UINT8 \
--mean_values=128 \
--std_values=128 \
--change_concat_input_ranges=false \
--allow_custom_ops


然后就进入漫长的编译等待(一般是第一次编译耗时,后面再运行就不会了)。其实,tensorflow也是根据需要的操作opeater进行编译的

INFO: Build completed successfully, 3249 total actions
2018-07-28 19:41:25.155435: I tensorflow/contrib/lite/toco/import_tensorflow.cc:1366] Converting unsupported operation: TFLite_Detection_PostProcess
2018-07-28 19:41:25.165617: I tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc:39] Before Removing unused ops: 1070 operators, 1570 arrays (0 quantized)
2018-07-28 19:41:25.194800: I tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc:39] Before general graph transformations: 1070 operators, 1570 arrays (0 quantized)
2018-07-28 19:41:25.224629: I tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc:39] After general graph transformations pass 1: 116 operators, 310 arrays (1 quantized)
2018-07-28 19:41:25.226254: I tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.cc:39] Before pre-quantization graph transformations: 116 operators, 310 arrays (1 quantized)
2018-07-28 19:41:25.227209: F tensorflow/contrib/lite/toco/tooling_util.cc:1589] Array FeatureExtractor/MobilenetV2/Conv/Relu6, which is an input to the DepthwiseConv operator producing the output array FeatureExtractor/MobilenetV2/expanded_conv/depthwise/Relu6, is lacking min/max data, which is necessary for quantization. Either target a non-quantized output format, or change the input graph to contain min/max information, or pass --default_ranges_min= and --default_ranges_max= if you do not care about the accuracy of results.
Aborted (core dumped)

此命令设置每个摄像机图像帧调整为300x300像素后,并输入张量normalized_input_image_tensor。量化模型的输出被命名 'TFLite_Detection_PostProcess', 'TFLite_Detection_PostProcess:1', 'TFLite_Detection_PostProcess:2', and 'TFLite_Detection_PostProcess:3' 并表示四个数组:detection_boxes,detection_classes,detection_scores和num_detections。此命令中使用的其他标志的文档在此处:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/lite/toco/g3doc/cmdline_reference.md。如果成功运行,您现在应该在/tmp/tflite目录中看到第三个文件名为detect.tflite(然后,发现是 0 bytes,什么情况??,不过unint8不行,下面float是可以的)。此文件包含图形和所有模型参数,可以通过Android设备上的TensorFlow Lite解释程序运行。对于浮点模型,请从tensorflow /目录运行:

bazel run --config=opt tensorflow/contrib/lite/toco:toco -- \
--input_file=$OUTPUT_DIR/tflite_graph.pb \
--output_file=$OUTPUT_DIR/detect.tflite \
--input_shapes=1,300,300,3 \
--input_arrays=normalized_input_image_tensor \
--output_arrays='TFLite_Detection_PostProcess','TFLite_Detection_PostProcess:1','TFLite_Detection_PostProcess:2','TFLite_Detection_PostProcess:3'  \
--inference_type=FLOAT \
--allow_custom_ops

然后输出的detect.tflite (18MB)


在Android上运行我们的模型
要在设备上运行我们的TensorFlow Lite模型,我们需要安装Android NDK和SDK。目前推荐的Android NDK版本为14b,可以在NDK Archives页面上找到(https://developer.android.com/ndk/downloads/older_releases.html#ndk-14b-downloads)。
Android SDK和构建工具可以单独下载,也可以作为Android Studio的一部分使用。要构建TensorFlow Lite Android演示,构建工具需要API> = 23(但它将在API> = 21的设备上运行)。其他详细信息可在TensorFlow Lite Android App页面上找到。
接下来,我们需要将应用程序指向新的detect.tflite文件,并为其指定新标签的名称。具体来说,我们将使用以下命令将TensorFlow Lite  flatbuffer 复制到app 资源目录:

cp /tmp/tflite/detect.tflite tensorflow/contrib/lite/java/demo/app/src/main/assets/
(官网上面是:cp /tmp/tflite/detect.tflite \
//tensorflow/contrib/lite/examples/android/app/src/main/assets )

我们还需要将新的labelmap labels_list.txt复制到assets目录,这里就直接用已经有的labels_mobilenet_quant_v1_224.txt。
我们现在将编辑BUILD文件以指向这个新模型。首先,打开BUILD文件tensorflow/contrib/lite/examples/android/BUILD。然后找到assets部分,
并替换该行,“@tflite_mobilenet_ssd_quant//detect.tflite”(默认情况下指向COCO预训练模型带有新TFLite模型的路径“tensorflow/contrib/lite/examples/android/assets/detect.tflite”。
最后,更改assets部分以使用新的标签映射(这个我没改哈)。
我们还需要告诉我们的应用程序使用新的标签映射。为此,在文本编辑器中打开
tensorflow/contrib/lite/examples/android/src/org/tensorflow/demo/DetectorActivity.java文件,找到TF_OD_API_LABELS_FILE的定义。
更新此路径以指向新的标签映射文件:“file///android_asset/labels_list.txt”。(没有就不用改这个操作,我没改)
请注意,如果量化了模型,则标志TF_OD_API_IS_QUANTIZED设置为true,如果模型是浮点,则标志TF_OD_API_IS_QUANTIZED设置为false(没有找到这个flag,估计是后面改掉了)。
现在,对于量化模型,DetectorActivity.java的这一新部分应如下所示:
  private static final boolean TF_OD_API_IS_QUANTIZED = true;(没有找到,就不处理)
  private static final String TF_OD_API_MODEL_FILE = "detect.tflite";
  private static final String TF_OD_API_LABELS_FILE = "file:///android_asset/labels_list.txt";(这个我保留原样"file:///android_asset/coco_labels_list.txt")
复制TensorFlow Lite文件并编辑BUILD和DetectorActivity.java文件后,您可以构建演示应用程序,从tensorflow目录运行此bazel命令:


 bazel build -c opt --config=android_arm{,64} --cxxopt='--std=c++11'  "//tensorflow/contrib/lite/examples/android:tflite_demo"
然后报错了:
bazel build -c opt --config=android_arm{,64} --cxxopt='--std=c++11' "//tensorflow/contrib/lite/examples/android:tflite_demo"
WARNING: The following configs were expanded more than once: [android, cross_compile]. For repeatable flags, repeats are counted twice and may lead to unexpected behavior.
WARNING: option '--crosstool_top' was expanded to from both option '--config=cuda' (source /home/lyz/code/tensorflow/.tf_configure.bazelrc) and option '--config=android_arm' (source command line options)
WARNING: option '--cpu' was expanded to from both option '--config=android_arm' (source command line options) and option '--config=android_arm64' (source command line options)
WARNING: option '--fat_apk_cpu' was expanded to from both option '--config=android_arm' (source command line options) and option '--config=android_arm64' (source command line options)
ERROR: No default_toolchain found for cpu 'arm64-v8a'. Valid cpus are: [
  k8,
  local,
  armeabi-v7a,
  x64_windows,
  x64_windows_msvc,
  x64_windows_msys,
  s390x,
  ios_x86_64,
]
将命令修改为(android知识不太懂,但是我的手机可以armeabi-v7a):

bazel build -c opt --config=armeabi-v7a --cxxopt='--std=c++11' "//tensorflow/contrib/lite/examples/android:tflite_demo"
还是报错:
~/code/tensorflow$ bazel build -c opt --config=armeabi-v7a --cxxopt='--std=c++11' "//tensorflow/contrib/lite/examples/android:tflite_demo"
INFO: Options provided by the client:
  Inherited 'common' options: --isatty=1 --terminal_columns=102
INFO: Reading rc options for 'build' from /home/lyz/code/tensorflow/tools/bazel.rc:
  'build' options: --distinct_host_configuration=false --define framework_shared_object=true --define=use_fast_cpp_protos=true \
--define=allow_oversize_protos=true --define=grpc_no_ares=true --spawn_strategy=standalone --genrule_strategy=standalone -c opt
INFO: Reading rc options for 'build' from /etc/bazel.bazelrc:
  'build' options: --action_env=PATH --action_env=LD_LIBRARY_PATH --action_env=TMPDIR --test_env=PATH --test_env=LD_LIBRARY_PATH
INFO: Reading rc options for 'build' from /home/lyz/code/tensorflow/.tf_configure.bazelrc:
  'build' options: --action_env PYTHON_BIN_PATH=/usr/bin/python --action_env PYTHON_LIB_PATH=/usr/lib/python2.7/dist-packages --
python_path=/usr/bin/python \
--define with_jemalloc=true --define with_gcp_support=true --action_env TF_NEED_OPENCL_SYCL=0 --action_env TF_NEED_CUDA=1 \
--action_env CUDA_TOOLKIT_PATH=/usr/local/cuda-8.0 --action_env TF_CUDA_VERSION=8.0 --action_env CUDNN_INSTALL_PATH=/usr/local/cuda-8.0 \
--action_env TF_CUDNN_VERSION=6 --action_env TF_NCCL_VERSION=1 --action_env TF_CUDA_COMPUTE_CAPABILITIES=5.2,5.2 \
--action_env LD_LIBRARY_PATH=:/usr/local/cuda/lib64 --action_env TF_CUDA_CLANG=0 --action_env GCC_HOST_COMPILER_PATH=/usr/bin/gcc \
--config=cuda --define grpc_no_ares=true --strip=always
INFO: Found applicable config definition build:cuda in file /home/lyz/code/tensorflow/tools/bazel.rc: --crosstool_top=@local_config_cuda//crosstool:toolchain 、
--define=using_cuda=true --define=using_cuda_nvcc=true
ERROR: Config value armeabi-v7a is not defined in any .rc file

现在通过(其实还没成功...)Android Debug Bridge(adb)在支持调试的Android手机上安装演示:
   adb install bazel-bin/tensorflow/contrib/lite/examples/android/tflite_demo.apk
-------------------------------------------------------------------------------------------------------------------这里暂时hold住
上面就是https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/running_on_mobile_tensorflowlite.md 的内容了,但是还是报错,就说明缺少了一些配置。
因为报错信息是:ERROR: Config value armeabi-v7a is not defined in any .rc file,回到之前tensorflow lite的介绍,并找到Android Demo App:https://www.tensorflow.org/mobile/tflite/demo_android?hl=zh-cn

Android演示应用
GitHub上提供了使用TensorFLow Lite的示例Android应用程序(https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/lite/java/demo)。该演示是一个示例相机应用程序,
使用量化的Mobilenet模型或浮点Inception-v3模型连续分类图像。要运行演示,需要运行Android 5.0(API 21)或更高版本的设备。
在演示应用程序中,使用TensorFlow Lite Java API进行推理。该演示应用程序实时对帧进行分类,显示最可能的分类。它还显示检测对象所用的时间。将演示应用程序添加到您的设备有三种方法:
1、下载预编译好的二进制APK。(http://download.tensorflow.org/deps/tflite/TfLiteCameraDemo.apk?hl=zh-cn)
2、使用Android Studio构建应用程序。
3、下载TensorFlow Lite的源代码和演示,并使用bazel构建它。


下载预先构建的二进制文件:尝试演示的最简单方法是下载预先构建的二进制APK。安装APK后,单击应用程序图标以启动该程序。第一次打开应用程序时,它会要求运行时权限以访问设备相机。演示应用程序打开设备的后置摄像头,识别摄像机视野中的物体。
在图像的底部(如果设备处于横向模式,则位于图像的左侧),它显示分类的前三个对象和分类延迟。

使用JCenter的TensorFlow Lite AAR在Android Studio中构建:使用Android Studio尝试更改项目代码并编译演示应用程序:
× 安装最新版本的Android Studio。
× 确保Android SDK版本大于26且NDK版本大于14(在Android Studio设置中)。
× 将tensorflow/contrib/lite/java/demo目录导入为新的Android Studio项目。
× 安装它请求的所有Gradle扩展。

现在您可以构建并运行演示应用程序。构建过程下载量化的Mobilenet TensorFlow Lite模型,并将其解压缩到assets目录:tensorflow/contrib/lite/java/demo/app/src/main/assets/。
TF Lite Android App页面上提供了一些其他详细信息(https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/lite/java/demo/README.md)。




报错信息为:

ERROR: /home/xxxx/code/tensorflow/third_party/clang_toolchain/cc_configure_clang.bzl:3:1: file '@bazel_tools//tools/cpp:cc_configure.bzl' does not contain symbol 'cc_autoconf_impl'
ERROR: error loading package '': Extension file 'third_party/clang_toolchain/cc_configure_clang.bzl' has errors
ERROR: error loading package '': Extension file 'third_party/clang_toolchain/cc_configure_clang.bzl' has errors

解决方案是:这是bazel版本的问题,参考这个:https://github.com/tensorflow/serving/issues/851,装过bazel 版本即可.


经过最后测试,是代码的问题,代码升级到最新,按照官网是可以的,接下来就是模型调整,压缩设计的问题了,可以开启落地之路啦