前言
最近在研究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,全部跑通~
然后就可以看到之前的那个图片了。