如果你想在Android上用JNI跑TensorFlow神经网络,就需要把TensorFlow Lite编译成C++的动态链接库。由于烹饪技法奇特,凡人非三五天难以编译出来。
本大厨历经艰辛,达到彼岸。今天把烹饪过程详述于此,以示后来者。(有问题留言共同讨论)
sudo apt install curl gnupg
curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
sudo apt update
sudo apt install bazel
sudo apt-get update
sudo apt-get install crossbuild-essential-arm64
https://developer.android.google.cn/ndk/downloads?hl=zh-cn
解压出来放在一个妥当的位置(路径不要有中文)。记下路径。
https://developer.android.com/studio/
(想办法也要下载正版的哟)同样,解压出来放在一个妥当的位置(路径不要有中文)。记下路径。
进入到tensorflow解压出来的目录下,运行下载依赖的脚本
./tensorflow/lite/tools/make/download_dependencies.sh
还是在tensorflow的根目录里面,运行配置文件
./configure
这是会让你配置很多东西,前两个是python的路径,他们给的一般是正确的,直接回车。
中间会让你配置很多杂七杂八的,咱们不需要,直接输入No:N
最重要的一步,就是当出现配置Android时,要输入yes:y
然后会让你配置Android NDK的路径,把你开始解压出来的路径复制进去。回车。然后他会识别到版本,让你确认。回车就行。
然后会让你配置Android SDK的路径,和上一步一样,把解压路径复制进去。
我们希望输出的是一个动态链接库,即.so文件,所以,要配置
打开tensorflow/lite/BUILD
文件配置输出的选项,在末尾添加如下内容:
cc_binary(
name = "libtensorflowLite.so",
linkopts = ["-shared", "-Wl,-soname=libtensorflowLite.so"],
visibility = ["//visibility:public"],
linkshared = 1,
copts = tflite_copts(),
deps = [
":framework",
"//tensorflow/lite/kernels:builtin_ops",
],
)
目前Android的主流架构是armeabi-v7a
和arm64-v8a
,所以只要交叉编译这两个就行了,过程也很简单,
先炒第一盘菜,在tensorflow根目录运行:
# "armeabi-v7a"
bazel build -c opt //tensorflow/lite:libtensorflowLite.so --config=android_arm --cxxopt="-std=c++11"
会在tensorflow/bazel-bin/tensorflow/lite/
目录下生成一个libtensorflowLite.so
文件。
在桌面上新建一个文件夹 叫armeabi-v7a,把编译生成的libtensorflowLite.so
文件拷贝进去。因为原来的位置马上就要删了。
洗锅(清理环境),准备炒下一盆菜
# 洗锅
bazel clean
再编译arm64-v8a
的动态库
# arm64-v8a
bazel build -c opt //tensorflow/lite:libtensorflowLite.so --config=android_arm64 --cxxopt="-std=c++11"
同样在桌面上新建一个文件夹,叫arm64-v8a
,把新输出的在tensorflow/bazel-bin/tensorflow/lite/
目录下的libtensorflowLite.so
文件拷贝进去。
最后把文件夹整理成这样:
只有一个动态链接库也是没法用的,我们还需要有头文件,只有靠头文件才能找到对应的库。
头文件从哪里来呢,很简单,把tensorflow/lite
中所有的.h
文件和他们的层级目录全部整理出来。
也有个简单的方法,用shell脚本,进入到tensorflow
中,运行
# 找到所有的 .h文件,全压缩到一个headers.tar中
find ./lite -name "*.h" | tar -cf headers.tar -T -
还有一个重要的头文件faltbuffer,它是tf lite的一个依赖库,也需要整理头文件出来。这个库位于tensorflow/lite/tools/make/downloads/flatbuffers
,把里面的include文件夹全部拷贝出来,放在一个flatbuffers文件夹里面。
include/flatbuffers/
最后把我们的库整理进去
# tf lite 的库名字
add_library(tflite
STATIC
IMPORTED
)
# # tf lite库的位置
set_target_properties(tflite
PROPERTIES
IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/../nativeLibs/${CMAKE_ANDROID_ARCH_ABI}/libtensorflowLite.so
)
# 头文件位置也要找到
include_directories(${CMAKE_SOURCE_DIR}/../include)
# 绑定到我们的主库上
target_link_libraries(
native-lib # 这个是你自己的库名字
tflite )
点赞免单,哈哈哈
明天继续炒怎么在android中用这个库。