承接移动端目标识别(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)。
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 版本即可.
经过最后测试,是代码的问题,代码升级到最新,按照官网是可以的,接下来就是模型调整,压缩设计的问题了,可以开启落地之路啦