Android TensorFlowLite sdk接入详细记录

2,133 阅读4分钟
原文链接: click.aliyun.com

前言

最近在研究ML的相关内容,开始在Android应用中接入TensorFlowLite。花了不少时间,添了不少坑,如果是裸的空项目接入还好,如果是现有的线上产品的接入,还是会有不少问题需要处理的,而且过程中,很多错误,网上的结论都是错误的,这个流程是我手把手一步步走的~亲测靠谱

先看效果


图片名称

接入sdk

开始只是以为简单的接入TensorFlowLite的 aar,

发现TensorFlowLite使用了JAVA 8的类属性,之前我们的Android工程使用的是gradle 2.3,需要加入JackOption,但是打开之后,整体编译特别慢,而且经常GC too many time,导致编译崩溃,因为最后添加了jack的dex转换,我们工程大的情况下20分钟是出不来的。。。

决定升级gradle到3.X

升级gradle3.X

开始直接升级到了gradle 4.1, Android build tool升级到了3.1.3,因为很久没有琢磨gradle了。

发现有3个主要的显式变化,还有很多编译器的改动,加入了D8,aapt2,编译速度有很大的提升。

1. compile改成implementation,test和debug的依赖也以此类推,子模块可以不用改动,而且日志里 
    写的到2018年底,全面废除compile,我们提前改了吧。
2. 第二个注解库,需要显式声明,具体样式如下

    compile 'org.weex.plugin:processor:1.0.2'
    annotationProcessor 'org.weex.plugin:processor:1.0.2'
    
3. 子库里的依赖,可以通过一个processer属性配置,依赖该子模块的主模块需要添加
      javaCompileOptions {
        annotationProcessorOptions {
            includeCompileClasspath true
        }
    }

终于可以编译了:

然后发现通过AndroidStudio直接运行,会因为安全图片无法加载,阿里郎登录就直接崩溃,排查了一下,发现是因为InstantRun导致,新版里面增量编译导致了这个问题,于是关闭了InstanceRun,ok,加密图片ok

加入TensorFlowLite的sdk

这个时候加入sdk,发现直接崩溃,报了一个C++层的错误,开始以为是模型被压缩了,导致加载模型报错了,网上查结论只是说换一个版本的TensorFlowLite的sdk,版本从+换成0.1,换了依然崩溃。

仔细分析了下原因,发现网上的各个解决方案都不太正确,其实是JNI层的问题,首先这个so有没有加载成功,我把apk解压缩,就会发现,其实是因为lib里面libtensorflowlite_jni.so没有armeabi的so,导致的。。。

研究了一波TensorFlowLite的aar,发现只打包了

  armeabi-v7a, arm64-v8a, x86, x86-64

那只有修改ndk的abi支持类型咯,但是发现如果修改了ndk配置,那很多应用中用到的armeabi的so的sdk就无法运行,我只能自己编译一个armeabi的so来使用了。

编译TensorFlowLite自己生成libtensorflowlite_jni.so

既然官方的aar没有对应的so,又是开源的,那我自己编译一个so出来吧,

查看文档,先安装bazel,通过brew可以很快的安装

现在TensorFlow的根目录的WORKSPACE添加android配置项目,注意这个地方是新增

接着配置好Androidsdk 和 Android Ndk的路径,我之前用NDK14编译最新代码会有问题,所以换成了16,不用17,目前的17会有别的问题。。。

android_sdk_repository (
    name = "androidsdk ",
    api_level = 23,
    build_tools_version = "26.0.1 ",
    path = "/Users/XXX/Library/Android/sdk ",
)

android_ndk_repository(
    name = "androidndk ",
    path = "/Users/XXX/Library/Android/sdk/ndk-bundle ",
    api_level = 16,
)

安装完bazel之后,再安装Xcode(刚换的电脑,所以还没有Xcode,也算是踩到另一个坑),最新版本,然后又报了一个找不到的错误stdlib官方组件的问题。

这个地方一定要注意一点,如果你安装了xcode的组件,然后还是报依赖错误,很有可能是因为你clone的姿势不对
一定要这么clone

git clone --recurse-submodules https://github.com/tensorflow/tensorflow.git

编译的过程中碰到的几个问题,也发出来吧

this rule is missing dependency declarations for the following files included by 'external/flatbuffers/src/util.cpp':
  '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/stdlib.h'

这个之后,通过cat /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/stdlib.h

会提示安装Xcode的CPP组件库

一波安装之后

在一切准备好之后,就可以按照下面这个命令行去进行TensorFlow的so编译了,因为官方库里没有armeabi的so,而集团里又没有指定机型的,所以只有自己动手丰衣足食

bazel build --cxxopt='--std=c++11' //tensorflow/contrib/lite/java:tensorflowlite --crosstool_top=//external:android/crosstool --host_crosstool_top=@bazel_tools//tools/cpp:toolchain --cpu=armeabi

编译生成的产物在这个路径下:

bazel-bin/tensorflow/contrib/lite/java/libtensorflowlite_jni.so
bazel-bin/tensorflow/contrib/lite/java/libtensorflowlitelib.jar

ok,在完全准备之后,我们先把demo的activity给接入一下,测试一下效果,OK,全部跑通~

然后就可以看到之前的那个图片了。