如何在 (Android Studio) NDK (C / C++ API) 中 运行 进行 Tensorflow-Lite 推理?
How to run a Tensorflow-Lite inference in (Android Studio) NDK (C / C++ API)?
信息
- 我从 Keras 构建了一个 Tensorflow (TF) 模型并将其转换为 Tensorflow-Lite (TFL)
- 我在 Android Studio 中构建了一个 Android 应用程序并使用 Java API 到 运行 TFL 模型
- 在 Java 应用程序中,我使用了 TFL 支持库(参见 here),以及来自 JCenter 的 TensorFlow Lite AAR,方法是在我的
build.gradle
下包含 implementation 'org.tensorflow:tensorflow-lite:+'
依赖项
推理时间不是很好,所以现在我想在 Android 的 NDK 中使用 TFL。
所以我在 Android Studio 的 NDK 中构建了 Java 应用程序的精确副本,现在我试图在项目中包含 TFL 库。我按照 TensorFlow-Lite's Android guide 并在本地构建了 TFL 库(并获得了一个 AAR 文件),并将该库包含在 Android Studio 的 NDK 项目中。
现在我试图在我的 C++ 文件中使用 TFL 库,方法是在代码中尝试 #include
它,但我收到一条错误消息:cannot find tensorflow
(或我使用的任何其他名称我正在尝试使用,根据我在 CMakeLists.txt
文件中给它的名称)。
文件
应用build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.ndk.tflite"
minSdkVersion 28
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
}
}
ndk {
abiFilters 'arm64-v8a'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
// tf lite
aaptOptions {
noCompress "tflite"
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// tflite build
compile(name:'tensorflow-lite', ext:'aar')
}
项目build.gradle:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.2'
}
}
allprojects {
repositories {
google()
jcenter()
// native tflite
flatDir {
dirs 'libs'
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp )
add_library( # Sets the name of the library.
tensorflow-lite
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp )
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
target_link_libraries( # Specifies the target library.
native-lib tensorflow-lite
# Links the target library to the log library
# included in the NDK.
${log-lib} )
native-lib.cpp:
#include <jni.h>
#include <string>
#include "tensorflow"
extern "C" JNIEXPORT jstring JNICALL
Java_com_xvu_f32c_1jni_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
class FlatBufferModel {
// Build a model based on a file. Return a nullptr in case of failure.
static std::unique_ptr<FlatBufferModel> BuildFromFile(
const char* filename,
ErrorReporter* error_reporter);
// Build a model based on a pre-loaded flatbuffer. The caller retains
// ownership of the buffer and should keep it alive until the returned object
// is destroyed. Return a nullptr in case of failure.
static std::unique_ptr<FlatBufferModel> BuildFromBuffer(
const char* buffer,
size_t buffer_size,
ErrorReporter* error_reporter);
};
进度
我也尝试遵循这些:
- Problems with using tensorflow lite C++ API in Android Studio Project
- Android C++ NDK : some shared libraries refuses to link in runtime
但就我而言,我使用 Bazel 来构建 TFL 库。
尝试构建 (label_image) 的分类演示,我设法构建它并 adb push
到我的设备,但是在尝试 运行 时出现以下错误:
ERROR: Could not open './mobilenet_quant_v1_224.tflite'.
Failed to mmap model ./mobilenet_quant_v1_224.tflite
- 我关注了 zimenglyu's post:试图在
WORKSPACE
中设置 android_sdk_repository
/ android_ndk_repository
得到了一个错误:WORKSPACE:149:1: Cannot redefine repository after any load statement in the WORKSPACE file (for repository 'androidsdk')
,并将这些语句定位在不同的位置places 导致了同样的错误。
- 我删除了对
WORKSPACE
的这些更改并继续使用 zimenglyu 的 post:我编译了 libtensorflowLite.so
,并编辑了 CMakeLists.txt
以便 libtensorflowLite.so
文件被引用,但遗漏了 FlatBuffer
部分。 Android 项目编译成功,但没有明显变化,我仍然无法包含任何 TFLite 库。
尝试编译 TFL,我在 tensorflow/tensorflow/lite/BUILD
中添加了 cc_binary
(在 label_image example 之后):
cc_binary(
name = "native-lib",
srcs = [
"native-lib.cpp",
],
linkopts = tflite_experimental_runtime_linkopts() + select({
"//tensorflow:android": [
"-pie",
"-lm",
],
"//conditions:default": [],
}),
deps = [
"//tensorflow/lite/c:common",
"//tensorflow/lite:framework",
"//tensorflow/lite:string_util",
"//tensorflow/lite/delegates/nnapi:nnapi_delegate",
"//tensorflow/lite/kernels:builtin_ops",
"//tensorflow/lite/profiling:profiler",
"//tensorflow/lite/tools/evaluation:utils",
] + select({
"//tensorflow:android": [
"//tensorflow/lite/delegates/gpu:delegate",
],
"//tensorflow:android_arm64": [
"//tensorflow/lite/delegates/gpu:delegate",
],
"//conditions:default": [],
}),
)
并尝试为 x86_64
构建它,然后 arm64-v8a
我收到错误消息:cc_toolchain_suite rule @local_config_cc//:toolchain: cc_toolchain_suite '@local_config_cc//:toolchain' does not contain a toolchain for cpu 'x86_64'
.
检查第 47 行中的 external/local_config_cc/BUILD
(其中提供了错误):
cc_toolchain_suite(
name = "toolchain",
toolchains = {
"k8|compiler": ":cc-compiler-k8",
"k8": ":cc-compiler-k8",
"armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a",
"armeabi-v7a": ":cc-compiler-armeabi-v7a",
},
)
这是仅有的 2 个 cc_toolchain
。在存储库中搜索 "cc-compiler-" 我只找到了“aarch64”,我认为它适用于 64 位 ARM,但 "x86_64" 没有。虽然有 "x64_windows",但我在 Linux.
尝试像这样使用 aarch64 构建:
bazel build -c opt --fat_apk_cpu=aarch64 --cpu=aarch64 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain //tensorflow/lite/java:tensorflow-lite
导致错误:
ERROR: /.../external/local_config_cc/BUILD:47:1: in cc_toolchain_suite rule @local_config_cc//:toolchain: cc_toolchain_suite '@local_config_cc//:toolchain' does not contain a toolchain for cpu 'aarch64'
使用 Android Studio 中的库:
我能够通过更改构建配置中的 soname
并使用 CMakeLists.txt
中的完整路径来为 x86_64
体系结构构建库。这导致 .so
共享库。另外 - 我能够使用 TFLite Docker 容器为 arm64-v8a
构建库,通过调整 aarch64_makefile.inc
文件,但我没有更改任何构建选项,并让 build_aarch64_lib.sh
无论它构建什么。这导致了一个 .a
静态库。
所以现在我有两个 TFLite 库,但我仍然无法使用它们(例如,我不能 #include "..."
任何东西)。
尝试构建项目时,仅使用 x86_64
可以正常工作,但尝试包含 arm64-v8a
库会导致忍者错误:'.../libtensorflow-lite.a', needed by '.../app/build/intermediates/cmake/debug/obj/armeabi-v7a/libnative-lib.so', missing and no known rule to make it
.
不同的方法 - build/compile 源文件 Gradle:
- 我在 Android Studio
中创建了一个原生 C++ 项目
- 我从 Tensorflow 的
lite
目录中获取了基本的 C/C++ 源文件和 headers,并在 app/src/main/cpp
中创建了一个类似的结构,其中包括(A) tensorflow、(B) absl 和 (C) flatbuffers 文件
- 我将所有 tensorflow header 文件中的
#include "tensorflow/...
行更改为相对路径,以便编译器可以找到它们。
- 在应用程序的
build.gradle
中,我为 .tflite
文件添加了 no-compression 行:aaptOptions { noCompress "tflite" }
- 我在应用程序中添加了一个
assets
目录
- 在
native-lib.cpp
中我添加了some example code from the TFLite website
- 尝试使用包含的源文件构建项目(构建目标是
arm64-v8a
)。
我得到一个错误:
/path/to/Android/Sdk/ndk/20.0.5594570/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1/memory:2339: error: undefined reference to 'tflite::impl::Interpreter::~Interpreter()'
在<memory>
中,第2339行是"delete __ptr;"
行:
_LIBCPP_INLINE_VISIBILITY void operator()(_Tp* __ptr) const _NOEXCEPT {
static_assert(sizeof(_Tp) > 0,
"default_delete can not delete incomplete type");
static_assert(!is_void<_Tp>::value,
"default_delete can not delete incomplete type");
delete __ptr;
}
问题
如何在 Android Studio 中包含 TFLite 库,以便 运行 来自 NDK 的 TFL 推理?
或者 - 我如何使用 gradle(目前使用 cmake)构建和编译源文件?
我通过以下方式将 Native TFL 与 C-API 结合使用:
设置:
- 下载最新版本TensorFlow Lite AAR file
- 将下载的
.arr
文件的文件类型更改为 .zip
并解压文件以获取共享库(.so
文件)
- 从 TFL repository
中的 c
目录下载所有 header 文件
- 在 Android Studio 中创建一个 Android C++ 应用程序
- 在
app/src/main
中创建一个 jni
目录(New
-> Folder
-> JNI Folder
)并在 sub-directories 中创建架构它(例如 arm64-v8a
或 x86_64
)
- 将所有 header 文件放入
jni
目录(架构目录旁边),并将共享库放入架构 directory/ies
- 打开
CMakeLists.txt
文件并包含 TFL 库的 add_library
节,set_target_properties
节中的共享库路径和 header 中的include_directories
节(见下文,在注释部分)
- 同步Gradle
用法:
在native-lib.cpp
中包括header,例如:
#include "../jni/c_api.h"
#include "../jni/common.h"
#include "../jni/builtin_ops.h"
TFL函数可以直接调用,例如:
TfLiteModel * model = TfLiteModelCreateFromFile(full_path);
TfLiteInterpreter * interpreter = TfLiteInterpreterCreate(model);
TfLiteInterpreterAllocateTensors(interpreter);
TfLiteTensor * input_tensor =
TfLiteInterpreterGetInputTensor(interpreter, 0);
const TfLiteTensor * output_tensor =
TfLiteInterpreterGetOutputTensor(interpreter, 0);
TfLiteStatus from_status = TfLiteTensorCopyFromBuffer(
input_tensor,
input_data,
TfLiteTensorByteSize(input_tensor));
TfLiteStatus interpreter_invoke_status = TfLiteInterpreterInvoke(interpreter);
TfLiteStatus to_status = TfLiteTensorCopyToBuffer(
output_tensor,
output_data,
TfLiteTensorByteSize(output_tensor));
备注:
- 在此设置中使用了 SDK 版本 29
cmake
环境也包括cppFlags "-frtti -fexceptions"
CMakeLists.txt
示例:
set(JNI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../jni)
add_library(tflite-lib SHARED IMPORTED)
set_target_properties(tflite-lib
PROPERTIES IMPORTED_LOCATION
${JNI_DIR}/${ANDROID_ABI}/libtfl.so)
include_directories( ${JNI_DIR} )
target_link_libraries(
native-lib
tflite-lib
...)
我也曾为 Android 构建 TF Lite C++ APIs 而苦苦挣扎。幸运的是,我设法让它发挥作用。
问题是我们需要在 运行 执行 bazel build ...
命令之前配置 Bazel 构建过程。 TF Lite Android 快速入门指南没有提到它。
分步指南 (https://github.com/cuongvng/TF-Lite-Cpp-API-for-Android):
第 1 步:Install Bazel
第 2 步:克隆 TensorFlow repo
git clone https://github.com/tensorflow/tensorflow
cd ./tensorflow/
- 步骤 3:配置 Android 构建
在 运行 执行
bazel build ...
命令之前,您需要配置构建过程。通过执行
./configure
configure
文件位于 tensorflow 目录的根目录下,您在第 2 步 cd
进入该目录。
现在你必须在命令行输入一些配置:
$ ./configure
You have bazel 3.7.2-homebrew installed.
Please specify the location of python. [Default is /Library/Developer/CommandLineTools/usr/bin/python3]: /Users/cuongvng/opt/miniconda3/envs/style-transfer-tf-lite/bin/python
首先是python的位置,因为./configure
执行的是.configure.py
文件。
选择安装了Numpy的位置,否则后面的构建会失败。
这里我指向conda环境的python可执行文件。
接下来,
Found possible Python library paths:
/Users/cuongvng/opt/miniconda3/envs/style-transfer-tf-lite/lib/python3.7/site-packages
Please input the desired Python library path to use. Default is [/Users/cuongvng/opt/miniconda3/envs/style-transfer-tf-lite/lib/python3.7/site-packages]
我按 Enter
使用默认站点包,其中包含构建 TF 所需的库。
接下来,
Do you wish to build TensorFlow with ROCm support? [y/N]: N
No ROCm support will be enabled for TensorFlow.
Do you wish to build TensorFlow with CUDA support? [y/N]: N
No CUDA support will be enabled for TensorFlow.
Do you wish to download a fresh release of clang? (Experimental) [y/N]: N
Clang will not be downloaded.
Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -Wno-sign-compare]:
如上所示键入,在最后一行键入 Enter
。
然后它会询问您是否为 Android 构建配置 ./WORKSPACE,键入 y 添加配置。
Would you like to interactively configure ./WORKSPACE for Android builds? [y/N]: y
Searching for NDK and SDK installations.
Please specify the home path of the Android NDK to use. [Default is /Users/cuongvng/library/Android/Sdk/ndk-bundle]: /Users/cuongvng/Library/Android/sdk/ndk/21.1.6352462
这是 Android NDK(版本 21.1.6352462)在我本地机器上的主路径。
注意,当你ls
路径时,它必须包含platforms
,例如:
$ ls /Users/cuongvng/Library/Android/sdk/ndk/21.1.6352462
CHANGELOG.md build ndk-stack prebuilt source.properties wrap.sh
NOTICE meta ndk-which python-packages sources
NOTICE.toolchain ndk-build package.xml shader-tools sysroot
README.md ndk-gdb platforms simpleperf toolchains
现在我忽略生成的警告,然后选择最低 NDK API 级别
WARNING: The NDK version in /Users/cuongvng/Library/Android/sdk/ndk/21.1.6352462 is 21, which is not supported by Bazel (officially supported versions: [10, 11, 12, 13, 14, 15, 16, 17, 18]). Please use another version. Compiling Android targets may result in confusing errors.
Please specify the (min) Android NDK API level to use. [Available levels: ['16', '17', '18', '19', '21', '22', '23', '24', '26', '27', '28', '29']] [Default is 21]: 29
下一个
Please specify the home path of the Android SDK to use. [Default is /Users/cuongvng/library/Android/Sdk]: /Users/cuongvng/Library/Android/sdk
Please specify the Android SDK API level to use. [Available levels: ['28', '29', '30']] [Default is 30]: 30
Please specify an Android build tools version to use. [Available versions: ['29.0.2', '29.0.3', '30.0.3', '31.0.0-rc1']] [Default is 31.0.0-rc1]: 30.0.3
这就是 Android 构建配置的全部内容。为以后出现的所有问题选择 N
:
- 第 4 步:构建共享库 (
.so
)
现在您可以 运行 bazel build 命令为您的目标架构生成库:
bazel build -c opt --config=android_arm //tensorflow/lite:libtensorflowlite.so
# or
bazel build -c opt --config=android_arm64 //tensorflow/lite:libtensorflowlite.so
它应该没有错误。
生成的库将保存在 ./bazel-bin/tensorflow/lite/libtensorflowlite.so
.
信息
- 我从 Keras 构建了一个 Tensorflow (TF) 模型并将其转换为 Tensorflow-Lite (TFL)
- 我在 Android Studio 中构建了一个 Android 应用程序并使用 Java API 到 运行 TFL 模型
- 在 Java 应用程序中,我使用了 TFL 支持库(参见 here),以及来自 JCenter 的 TensorFlow Lite AAR,方法是在我的
build.gradle
下包含implementation 'org.tensorflow:tensorflow-lite:+'
依赖项
推理时间不是很好,所以现在我想在 Android 的 NDK 中使用 TFL。
所以我在 Android Studio 的 NDK 中构建了 Java 应用程序的精确副本,现在我试图在项目中包含 TFL 库。我按照 TensorFlow-Lite's Android guide 并在本地构建了 TFL 库(并获得了一个 AAR 文件),并将该库包含在 Android Studio 的 NDK 项目中。
现在我试图在我的 C++ 文件中使用 TFL 库,方法是在代码中尝试 #include
它,但我收到一条错误消息:cannot find tensorflow
(或我使用的任何其他名称我正在尝试使用,根据我在 CMakeLists.txt
文件中给它的名称)。
文件
应用build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.ndk.tflite"
minSdkVersion 28
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
}
}
ndk {
abiFilters 'arm64-v8a'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
// tf lite
aaptOptions {
noCompress "tflite"
}
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
version "3.10.2"
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// tflite build
compile(name:'tensorflow-lite', ext:'aar')
}
项目build.gradle:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.2'
}
}
allprojects {
repositories {
google()
jcenter()
// native tflite
flatDir {
dirs 'libs'
}
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.4.1)
add_library( # Sets the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp )
add_library( # Sets the name of the library.
tensorflow-lite
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
native-lib.cpp )
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log )
target_link_libraries( # Specifies the target library.
native-lib tensorflow-lite
# Links the target library to the log library
# included in the NDK.
${log-lib} )
native-lib.cpp:
#include <jni.h>
#include <string>
#include "tensorflow"
extern "C" JNIEXPORT jstring JNICALL
Java_com_xvu_f32c_1jni_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
class FlatBufferModel {
// Build a model based on a file. Return a nullptr in case of failure.
static std::unique_ptr<FlatBufferModel> BuildFromFile(
const char* filename,
ErrorReporter* error_reporter);
// Build a model based on a pre-loaded flatbuffer. The caller retains
// ownership of the buffer and should keep it alive until the returned object
// is destroyed. Return a nullptr in case of failure.
static std::unique_ptr<FlatBufferModel> BuildFromBuffer(
const char* buffer,
size_t buffer_size,
ErrorReporter* error_reporter);
};
进度
我也尝试遵循这些:
- Problems with using tensorflow lite C++ API in Android Studio Project
- Android C++ NDK : some shared libraries refuses to link in runtime
但就我而言,我使用 Bazel 来构建 TFL 库。
尝试构建 (label_image) 的分类演示,我设法构建它并 adb push
到我的设备,但是在尝试 运行 时出现以下错误:
ERROR: Could not open './mobilenet_quant_v1_224.tflite'.
Failed to mmap model ./mobilenet_quant_v1_224.tflite
- 我关注了 zimenglyu's post:试图在
WORKSPACE
中设置android_sdk_repository
/android_ndk_repository
得到了一个错误:WORKSPACE:149:1: Cannot redefine repository after any load statement in the WORKSPACE file (for repository 'androidsdk')
,并将这些语句定位在不同的位置places 导致了同样的错误。 - 我删除了对
WORKSPACE
的这些更改并继续使用 zimenglyu 的 post:我编译了libtensorflowLite.so
,并编辑了CMakeLists.txt
以便libtensorflowLite.so
文件被引用,但遗漏了FlatBuffer
部分。 Android 项目编译成功,但没有明显变化,我仍然无法包含任何 TFLite 库。
尝试编译 TFL,我在 tensorflow/tensorflow/lite/BUILD
中添加了 cc_binary
(在 label_image example 之后):
cc_binary(
name = "native-lib",
srcs = [
"native-lib.cpp",
],
linkopts = tflite_experimental_runtime_linkopts() + select({
"//tensorflow:android": [
"-pie",
"-lm",
],
"//conditions:default": [],
}),
deps = [
"//tensorflow/lite/c:common",
"//tensorflow/lite:framework",
"//tensorflow/lite:string_util",
"//tensorflow/lite/delegates/nnapi:nnapi_delegate",
"//tensorflow/lite/kernels:builtin_ops",
"//tensorflow/lite/profiling:profiler",
"//tensorflow/lite/tools/evaluation:utils",
] + select({
"//tensorflow:android": [
"//tensorflow/lite/delegates/gpu:delegate",
],
"//tensorflow:android_arm64": [
"//tensorflow/lite/delegates/gpu:delegate",
],
"//conditions:default": [],
}),
)
并尝试为 x86_64
构建它,然后 arm64-v8a
我收到错误消息:cc_toolchain_suite rule @local_config_cc//:toolchain: cc_toolchain_suite '@local_config_cc//:toolchain' does not contain a toolchain for cpu 'x86_64'
.
检查第 47 行中的 external/local_config_cc/BUILD
(其中提供了错误):
cc_toolchain_suite(
name = "toolchain",
toolchains = {
"k8|compiler": ":cc-compiler-k8",
"k8": ":cc-compiler-k8",
"armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a",
"armeabi-v7a": ":cc-compiler-armeabi-v7a",
},
)
这是仅有的 2 个 cc_toolchain
。在存储库中搜索 "cc-compiler-" 我只找到了“aarch64”,我认为它适用于 64 位 ARM,但 "x86_64" 没有。虽然有 "x64_windows",但我在 Linux.
尝试像这样使用 aarch64 构建:
bazel build -c opt --fat_apk_cpu=aarch64 --cpu=aarch64 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain //tensorflow/lite/java:tensorflow-lite
导致错误:
ERROR: /.../external/local_config_cc/BUILD:47:1: in cc_toolchain_suite rule @local_config_cc//:toolchain: cc_toolchain_suite '@local_config_cc//:toolchain' does not contain a toolchain for cpu 'aarch64'
使用 Android Studio 中的库:
我能够通过更改构建配置中的 soname
并使用 CMakeLists.txt
中的完整路径来为 x86_64
体系结构构建库。这导致 .so
共享库。另外 - 我能够使用 TFLite Docker 容器为 arm64-v8a
构建库,通过调整 aarch64_makefile.inc
文件,但我没有更改任何构建选项,并让 build_aarch64_lib.sh
无论它构建什么。这导致了一个 .a
静态库。
所以现在我有两个 TFLite 库,但我仍然无法使用它们(例如,我不能 #include "..."
任何东西)。
尝试构建项目时,仅使用 x86_64
可以正常工作,但尝试包含 arm64-v8a
库会导致忍者错误:'.../libtensorflow-lite.a', needed by '.../app/build/intermediates/cmake/debug/obj/armeabi-v7a/libnative-lib.so', missing and no known rule to make it
.
不同的方法 - build/compile 源文件 Gradle:
- 我在 Android Studio 中创建了一个原生 C++ 项目
- 我从 Tensorflow 的
lite
目录中获取了基本的 C/C++ 源文件和 headers,并在app/src/main/cpp
中创建了一个类似的结构,其中包括(A) tensorflow、(B) absl 和 (C) flatbuffers 文件 - 我将所有 tensorflow header 文件中的
#include "tensorflow/...
行更改为相对路径,以便编译器可以找到它们。 - 在应用程序的
build.gradle
中,我为.tflite
文件添加了 no-compression 行:aaptOptions { noCompress "tflite" }
- 我在应用程序中添加了一个
assets
目录 - 在
native-lib.cpp
中我添加了some example code from the TFLite website - 尝试使用包含的源文件构建项目(构建目标是
arm64-v8a
)。
我得到一个错误:
/path/to/Android/Sdk/ndk/20.0.5594570/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/c++/v1/memory:2339: error: undefined reference to 'tflite::impl::Interpreter::~Interpreter()'
在<memory>
中,第2339行是"delete __ptr;"
行:
_LIBCPP_INLINE_VISIBILITY void operator()(_Tp* __ptr) const _NOEXCEPT {
static_assert(sizeof(_Tp) > 0,
"default_delete can not delete incomplete type");
static_assert(!is_void<_Tp>::value,
"default_delete can not delete incomplete type");
delete __ptr;
}
问题
如何在 Android Studio 中包含 TFLite 库,以便 运行 来自 NDK 的 TFL 推理?
或者 - 我如何使用 gradle(目前使用 cmake)构建和编译源文件?
我通过以下方式将 Native TFL 与 C-API 结合使用:
设置:
- 下载最新版本TensorFlow Lite AAR file
- 将下载的
.arr
文件的文件类型更改为.zip
并解压文件以获取共享库(.so
文件) - 从 TFL repository 中的
- 在 Android Studio 中创建一个 Android C++ 应用程序
- 在
app/src/main
中创建一个jni
目录(New
->Folder
->JNI Folder
)并在 sub-directories 中创建架构它(例如arm64-v8a
或x86_64
) - 将所有 header 文件放入
jni
目录(架构目录旁边),并将共享库放入架构 directory/ies - 打开
CMakeLists.txt
文件并包含 TFL 库的add_library
节,set_target_properties
节中的共享库路径和 header 中的include_directories
节(见下文,在注释部分) - 同步Gradle
c
目录下载所有 header 文件
用法:
在native-lib.cpp
中包括header,例如:
#include "../jni/c_api.h"
#include "../jni/common.h"
#include "../jni/builtin_ops.h"
TFL函数可以直接调用,例如:
TfLiteModel * model = TfLiteModelCreateFromFile(full_path);
TfLiteInterpreter * interpreter = TfLiteInterpreterCreate(model);
TfLiteInterpreterAllocateTensors(interpreter);
TfLiteTensor * input_tensor =
TfLiteInterpreterGetInputTensor(interpreter, 0);
const TfLiteTensor * output_tensor =
TfLiteInterpreterGetOutputTensor(interpreter, 0);
TfLiteStatus from_status = TfLiteTensorCopyFromBuffer(
input_tensor,
input_data,
TfLiteTensorByteSize(input_tensor));
TfLiteStatus interpreter_invoke_status = TfLiteInterpreterInvoke(interpreter);
TfLiteStatus to_status = TfLiteTensorCopyToBuffer(
output_tensor,
output_data,
TfLiteTensorByteSize(output_tensor));
备注:
- 在此设置中使用了 SDK 版本 29
cmake
环境也包括cppFlags "-frtti -fexceptions"
CMakeLists.txt
示例:
set(JNI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../jni)
add_library(tflite-lib SHARED IMPORTED)
set_target_properties(tflite-lib
PROPERTIES IMPORTED_LOCATION
${JNI_DIR}/${ANDROID_ABI}/libtfl.so)
include_directories( ${JNI_DIR} )
target_link_libraries(
native-lib
tflite-lib
...)
我也曾为 Android 构建 TF Lite C++ APIs 而苦苦挣扎。幸运的是,我设法让它发挥作用。
问题是我们需要在 运行 执行 bazel build ...
命令之前配置 Bazel 构建过程。 TF Lite Android 快速入门指南没有提到它。
分步指南 (https://github.com/cuongvng/TF-Lite-Cpp-API-for-Android):
第 1 步:Install Bazel
第 2 步:克隆 TensorFlow repo
git clone https://github.com/tensorflow/tensorflow
cd ./tensorflow/
- 步骤 3:配置 Android 构建
在 运行 执行
bazel build ...
命令之前,您需要配置构建过程。通过执行
./configure
configure
文件位于 tensorflow 目录的根目录下,您在第 2 步 cd
进入该目录。
现在你必须在命令行输入一些配置:
$ ./configure
You have bazel 3.7.2-homebrew installed.
Please specify the location of python. [Default is /Library/Developer/CommandLineTools/usr/bin/python3]: /Users/cuongvng/opt/miniconda3/envs/style-transfer-tf-lite/bin/python
首先是python的位置,因为./configure
执行的是.configure.py
文件。
选择安装了Numpy的位置,否则后面的构建会失败。
这里我指向conda环境的python可执行文件。
接下来,
Found possible Python library paths:
/Users/cuongvng/opt/miniconda3/envs/style-transfer-tf-lite/lib/python3.7/site-packages
Please input the desired Python library path to use. Default is [/Users/cuongvng/opt/miniconda3/envs/style-transfer-tf-lite/lib/python3.7/site-packages]
我按 Enter
使用默认站点包,其中包含构建 TF 所需的库。
接下来,
Do you wish to build TensorFlow with ROCm support? [y/N]: N
No ROCm support will be enabled for TensorFlow.
Do you wish to build TensorFlow with CUDA support? [y/N]: N
No CUDA support will be enabled for TensorFlow.
Do you wish to download a fresh release of clang? (Experimental) [y/N]: N
Clang will not be downloaded.
Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is -Wno-sign-compare]:
如上所示键入,在最后一行键入 Enter
。
然后它会询问您是否为 Android 构建配置 ./WORKSPACE,键入 y 添加配置。
Would you like to interactively configure ./WORKSPACE for Android builds? [y/N]: y
Searching for NDK and SDK installations.
Please specify the home path of the Android NDK to use. [Default is /Users/cuongvng/library/Android/Sdk/ndk-bundle]: /Users/cuongvng/Library/Android/sdk/ndk/21.1.6352462
这是 Android NDK(版本 21.1.6352462)在我本地机器上的主路径。
注意,当你ls
路径时,它必须包含platforms
,例如:
$ ls /Users/cuongvng/Library/Android/sdk/ndk/21.1.6352462
CHANGELOG.md build ndk-stack prebuilt source.properties wrap.sh
NOTICE meta ndk-which python-packages sources
NOTICE.toolchain ndk-build package.xml shader-tools sysroot
README.md ndk-gdb platforms simpleperf toolchains
现在我忽略生成的警告,然后选择最低 NDK API 级别
WARNING: The NDK version in /Users/cuongvng/Library/Android/sdk/ndk/21.1.6352462 is 21, which is not supported by Bazel (officially supported versions: [10, 11, 12, 13, 14, 15, 16, 17, 18]). Please use another version. Compiling Android targets may result in confusing errors.
Please specify the (min) Android NDK API level to use. [Available levels: ['16', '17', '18', '19', '21', '22', '23', '24', '26', '27', '28', '29']] [Default is 21]: 29
下一个
Please specify the home path of the Android SDK to use. [Default is /Users/cuongvng/library/Android/Sdk]: /Users/cuongvng/Library/Android/sdk
Please specify the Android SDK API level to use. [Available levels: ['28', '29', '30']] [Default is 30]: 30
Please specify an Android build tools version to use. [Available versions: ['29.0.2', '29.0.3', '30.0.3', '31.0.0-rc1']] [Default is 31.0.0-rc1]: 30.0.3
这就是 Android 构建配置的全部内容。为以后出现的所有问题选择 N
:
- 第 4 步:构建共享库 (
.so
) 现在您可以 运行 bazel build 命令为您的目标架构生成库:
bazel build -c opt --config=android_arm //tensorflow/lite:libtensorflowlite.so
# or
bazel build -c opt --config=android_arm64 //tensorflow/lite:libtensorflowlite.so
它应该没有错误。
生成的库将保存在 ./bazel-bin/tensorflow/lite/libtensorflowlite.so
.