[关闭]
@liweiliwei33 2019-03-01T03:28:44.000000Z 字数 4495 阅读 601

Android tensorflow 集成


编译 so 库 和 jar 包

1. 安装 bazel

参照官网教程

  1. # 1. 下载 Bazel binary installer named bazel-<version>-installer-linux-x86_64.sh
  2. # 2. Run the installer
  3. chmod +x bazel-<version>-installer-linux-x86_64.sh
  4. ./bazel-<version>-installer-linux-x86_64.sh --user
  5. # 3. 设置环境
  6. export PATH="$PATH:$HOME/bin"

2. 下载源码

  1. git clone https://github.com/tensorflow/tensorflow.git
  2. # 查看版本
  3. git checkout
  4. # 切到你想要的版本
  5. git checkout r1.7

3. 编译 libtensorflow_inference.so 文件

  1. bazel build -c opt //tensorflow/contrib/android:libtensorflow_inference.so \
  2. -- crosstool_top=//external:android/crosstool \
  3. -- host_crosstool_top=@bazel_tools//tools/cpp:toolchain \
  4. -- cpu=armeabi-v7a

这一步就一直报错,怀疑是不是没有装 NDK,然后开始瞎折腾。

安装 NDK
NDK 各版本下载
1. 下载Android NDK自解压包,
官方地址:
https://developer.android.com/ndk/downloads/index.html#download

  1. # 1. 下载:
  2. wget -c http://dl.google.com/android/ndk/android-ndk-r14b-linux-x86_64.bin
  3. # 2. 解压,将Android NDK压缩包解压到你想要的目录下,如 /opt/android/ndk/
  4. chmod a+x android-ndk-r14b-linux-x86_64.bin
  5. ./android-ndk-r14b-linux-x86_64.bin
  6. # 解压后目录结构为:/opt/android/ndk/android-ndk-r14b
  7. # 3. 配置PATH路径:
  8. sudo vim /etc/profile
  9. # 在文件末尾加入如下内容:
  10. #set NDK env
  11. export NDK_HOME=/opt/android/ndk/android-ndk-r14b
  12. export PATH=$NDK_HOME:$PATH
  13. # 4. 保存并退出
  14. source /etc/profile

回到 tensorflow 源码目录,编辑 WORKSPACE 文件

  1. #android_ndk_repository(
  2. # name="androidndk",
  3. # path="/opt/android/ndk/android-ndk-r14b",
  4. # # This needs to be 14 or higher to compile TensorFlow.
  5. # # Please specify API level to >= 21 to build for 64-bit
  6. # # archtectures or the Android NDK will automatically select biggest
  7. # # API level that it supports without notice.
  8. # # Note that the NDK version is not the API level.
  9. # api_level=14)

去掉注释,将 path 路径改为 NDK 路径. 编译,仍旧有错,试过r12版本的,也有错,注释掉也是一样的错,可能跟 NDK 没啥关系。
踩了 N 多坑后,将命令行可选项一个个删除,运行,最后,居然出现奇迹了,成功了。

  1. bazel build -c opt //tensorflow/contrib/android:libtensorflow_inference.so

可选项都去掉了,编译了很久。
编译完毕后,libtensorflow_inference.so的路径为:
/tensorflow/bazel-bin/tensorflow/contrib/android

4. 编译 jar 包

  1. bazel build //tensorflow/contrib/android:android_tensorflow_inference_java

提示没有安装 SDK
安装 SDK
SDK 下载网址

  1. # 1. 解压下载的压缩包
  2. tar -zxvf android-sdk_r24.4.1-linux.tgz
  3. # 2. 安装32位库
  4. sudo apt-get install -y libc6-i386 lib32stdc++6 lib32gcc1 lib32ncurses5 lib32z1
  5. # 3. 配置环境变量
  6. vim /etc/profile
  7. #set android environment
  8. export ANDROID_SDK_HOME=/home/XXX/android/sdk/android-sdk-linux
  9. export PATH=$PATH:${ANDROID_SDK_HOME}/tools
  10. export PATH=$PATH:${ANDROID_SDK_HOME}/platform-tools
  11. # 4. 执行
  12. source /etc/profile

提示没有安装 platform,进入到 android sdk 目录,运行 android,出现 SDK Manager,下载相应的 platform。
回到 tensorflow 源码目录,编辑 WORKSPACE 文件,api_level 与上面下载的 platform 一致。

  1. # Uncomment and update the paths in these entries to build the Android demo.
  2. android_sdk_repository(
  3. name = "androidsdk",
  4. api_level = 26,
  5. # Ensure that you have the build_tools_version below installed in the
  6. # SDK manager as it updates periodically.
  7. build_tools_version = "26.0.1",
  8. # Replace with path to Android SDK on your system
  9. path = "/opt/android/sdk/android-sdk-linux",
  10. )

编译完毕后,android_tensorflow_inference_java.jar的路径为:
/tensorflow/bazel-bin/tensorflow/contrib/android

Android Studio 环境搭建

将 jar 包放在 libs 文件夹下,新建 armeabi 文件夹,加 so 文件放里面,gradle 配置如下

  1. android{
  2. defaultConfig {
  3. # ...
  4. ndk{
  5. abiFilters "armeabi"
  6. }
  7. }
  8. sourceSets{
  9. main{
  10. jniLibs.srcDirs = ['libs']
  11. }
  12. }
  13. }
  14. dependencies {
  15. compile files('libs/libandroid_tensorflow_inference_java.jar')
  16. }

1. 版本不兼容

  1. Error:Error converting bytecode to dex:
  2. Cause: Dex cannot parse version 52 byte code.
  3. This is caused by library dependencies that have been compiled using Java 8 or above.
  4. If you are using the 'java' gradle plugin in a library submodule add
  5. targetCompatibility = '1.7'
  6. sourceCompatibility = '1.7'
  7. to that submodule's build.gradle file.

这个问题也是弄了半天,https://stackoverflow.com/questions/37020413/android-dex-cannot-parse-version-52-byte-code 上面的都试了,不行。
我使用的是 Studio 2.2 默认是 Java 7的环境,要支持 java 8,需要在 gradle 文件配置

  1. android{
  2. defaultConfig {
  3. # ...
  4. # 这个很重要,试了很多,就是忘了加这个,一直 bug
  5. jackOptions {
  6. enabled true
  7. }
  8. }
  9. compileOptions{
  10. sourceCompatibility JavaVersion.VERSION_1_8
  11. targetCompatibility JavaVersion.VERSION_1_8
  12. }
  13. }

jar 包兼容性解决后,又出现下面问题:

  1. java.lang.UnsatisfiedLinkError: dlopen failed: "/data/app/com.aiwac.app.skincare-OQIqPx4ktt9o8ZEG0l3Reg==/lib/arm/libtensorflow_inference.so" is 64-bit instead of 32-bit

可能还是因为编译 so 库时没有加可选项,看了下 so 文件100M 左右,而之前低版本的 so 文件才十几M。

换成java 8后,compile 'org.tensorflow:tensorflow-android:1.7.0' 成功。

网上找到了不同版本的 jar 和 so 文件
https://blog.csdn.net/qq_36440163/article/details/83060160#%C2%A0%204%EF%BC%8CJar%E6%96%87%E4%BB%B6%E5%92%8CSo%E6%96%87%E4%BB%B6%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88

替换自己编译的so文件后,终于成功了。

2. 模型压缩

为了在手机/嵌入式设备上使用深度学习模型,我们必须减少模型对内存的占用,减小推理时间和尽量减少耗电。
参照博客 Android TensorFlow 智能语音识别
为了对模型量化权重:
将模型改成protocol buffer文件
从源文件安装,构建tensorflow
在tensorflow目录下执行如下命令

  1. bazel build tensorflow/tools/graph_transforms:transform_graph
  2. bazel-bin/tensorflow/tools/graph_transforms/transform_graph \
  3. --in_graph="/home/liwei/b_graph.pb" \
  4. --out_graph="/home/liwei/mini_graph.pb" \
  5. --outputs="test/prob" \
  6. --transforms="quantize_weights"
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注