如何将 TensorFlow Lite 构建为静态库并从单独的(CMake)项目链接到它?
Posted
技术标签:
【中文标题】如何将 TensorFlow Lite 构建为静态库并从单独的(CMake)项目链接到它?【英文标题】:How to build TensorFlow Lite as a static library and link to it from a separate (CMake) project? 【发布时间】:2019-08-03 04:34:51 【问题描述】:通过将我的源代码添加到tensorflow/lite/examples
,我已经成功构建了一个运行TF Lite 模型的简单C++ 应用程序,类似于the official C++ TF guide 建议的完整TF。现在我想将它构建为一个单独的项目(共享库),静态链接到 TF Lite 并使用 CMake 作为构建系统。
我尝试将自定义目标添加到我的CMakeLists.txt
,这将使用 Bazel 构建 TF Lite:
set(TENSORFLOW_DIR $CMAKE_SOURCE_DIR/thirdparty/tensorflow)
add_custom_target(TFLite
COMMAND bazel build //tensorflow/lite:framework
COMMAND bazel build //tensorflow/lite/kernels:builtin_ops
WORKING_DIRECTORY $TENSORFLOW_DIR)
我选择了这些 Bazel 目标,因为来自 tensorflow/lite/examples/minimal
的 BUILD
文件将它们作为依赖项,并且在我构建时它们对我有用
我在 TF repo 中使用 Bazel 的代码。不知道够不够。
然后我手动收集包含目录(带有那个丑陋的临时硬编码路径)和库:
set(TFLite_INCLUDES
$TENSORFLOW_DIR
~/.cache/bazel/_bazel_azymohliad/ec8567b83922796adb8477fcbb00a36a/external/flatbuffers/include)
set(TFLite_LIBS
$TENSORFLOW_DIR/bazel-bin/tensorflow/lite/libframework.pic.a)
target_include_directories(MyLib ... PRIVATE ... $TFLite_INCLUDES)
target_link_libraries(MyLib ... $TFLite_LIBS)
使用此配置,我在链接期间会收到许多对 TFLite 内容的未定义引用。我检查了nm
,libframework.pic.a
中确实缺少这些符号,我在 Bazel 输出的各种 .o
文件中发现了其中一些符号。手动选择所有这些 .o
文件似乎是错误的。
那么,是否可以像我尝试的那样从 CMake 很好地链接到 TF Lite?也许有一些神奇的bazel query include_dirs(//tensorflow/lite:framework)
命令可以为我提供所有必要包含目录的路径,以及用于链接库的类似命令,以便我可以将此信息传递给 CMake?
【问题讨论】:
只是评论,我认为您应该能够从 TensorFlow 树中的bazel-genfiles/external
收集 flatbuffers 标头(构建后),而不是 ~/.cache/...
。
啊等等,也许是另一个,你检查过bazel-bin/external
和bazel-tensorflow/external
吗?
不管怎样,关于你的问题,问题是每个.a
只包含其目标的.c
代码,而不是依赖项。另外,我也没有找到任何跟踪标题的好方法。我解决这个问题的方法是向 TF 树(在新的子目录中)添加一个代码文件和一个新目标,并依赖于我需要的内容。使用cc_library
,我不确定您是否可以通过选项获得包含所有内容的.a
,使用cc_binary
,您至少会在bazel-bin
下获得一个.params
文件,其中包含所有.a
依赖项可以扫描,或者你可以制作一个.so
(我个人现在在Windows上制作一个DLL)
关于标题,我曾经痛苦地列出了我需要复制的所有必要路径,几乎是通过反复试验。我现在要做的是我有自己的库包装器(一个非常简单的界面,我可以加载.pb
模型文件并针对给定的输入运行它),隐藏每个原生 TF 类型(主要是 pimpl)。它花了很多技巧,但现在我只需要我的几个头文件和这个 DLL。
这都是针对常规 TF 的,不是 TF Lite。现在有了TensorFlow for C,所以这项工作变得有点多余,但我认为 Lite 没有等价物,所以我认为相同的方法应该可以工作。
【参考方案1】:
我最终为 CMake 的 target_link_libraries
(在 TFLite_LIBS
中)手动列出了所有必要的 TFLite 对象文件,并且它可以工作。
我使用了一个简单的 shell 脚本来获取必要的目标文件列表。 首先,我将构建日志中的所有未定义引用收集到一个 bash 数组中,如下所示:
SYMBOLS=(\
'tflite::CombineHashes('\
'tflite::IsFlexOp('\
'tflite::ConvertArrayToTfLiteIntArray('\
'tflite::EqualArrayAndTfLiteIntArray('\
...
'tflite::ConvertVectorToTfLiteIntArray(')
然后对于该数组中的每个符号,我检查了 bazel 构建输出中的每个 *.o
文件:
for SYMBOL in $SYMBOLS[@]; do
for OBJ in $(find -L /path/to/tensorflow/bazel-bin/ -name '*.o'); do
nm -C $OBJ | grep "T $SYMBOL" > /dev/null && echo $OBJ
done
done | sort | uniq
并将输出添加到 CMake 中的TFLite_LIBS
(当然,使用正确的路径前缀)。在那之后,我得到了一个新的未定义引用部分,但经过几次迭代,它解决了所有问题。
也许我还可以从我最初的 in-tree 构建中的 *-params
文件中获取完整的依赖项列表,但快速检查显示它有一些冗余项,并且脚本只收集了必要的项。
对于包含位置,我用$TENSORFLOW_DIR/bazel-tensorflow/external/flatbuffers/include/
替换了 bazel 缓存中平面缓冲区的硬编码路径。感谢jdehesa 的提示。
更新:
全包 TF Lite 静态库的本机构建可以非常类似于使用普通旧 make 的 RPi、ios 或 ARM64 的官方构建说明:
1../tensorflow/lite/tools/make/download_dependencies.sh
2.make -f tensorflow/lite/tools/make/Makefile
输出库将存储为<tensorflow-root>/tensorflow/lite/tools/make/gen/<platform>/lib/libtensorflow-lite.a
。并且带有其标头的外部依赖项将进入<tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads
(例如flatbuffers
标头在<tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads/flatbuffers/include
中)。
指南没有提到可以直接调用 make 。有针对不同交叉编译目标的包装脚本,它们只需设置适当的变量并运行 make。但默认情况下,make 只会进行原生构建。这个 make 调用可以作为自定义命令添加到 CMakeLists.txt
。
【讨论】:
当我尝试使用使用更新方法构建的静态库时,出现未定义的引用错误:./tensorflow/tensorflow/lite/tools/make/gen/linux_x86_64/lib/libtensorflow- lite.a(nnapi_implementation.o): In function(anonymous namespace)::ASharedMemory_create(char const*, unsigned long)': nnapi_implementation.cc:(.text+0x14): undefined reference to
shm_open' 你知道这是从哪里来的吗?
好的,我发现有一个名为 build_lib.sh 的构建脚本似乎关闭了 nnapi。有了这个,我不再收到这个错误了。但是我想知道 nnapi 有什么用,是否仅在某些平台上受支持?
@Marcel_marcel1991,我真的不知道,抱歉。而且我仍然使用第一种方法:使用 bazel 构建,然后手动列出所有文件进行链接。我发现在多个平台上维护起来更容易。以上是关于如何将 TensorFlow Lite 构建为静态库并从单独的(CMake)项目链接到它?的主要内容,如果未能解决你的问题,请参考以下文章
使用 JAX 构建强化学习 agent,并借助 TensorFlow Lite 将其部署到 Android 应用中
使用 JAX 构建强化学习 agent,并借助 TensorFlow Lite 将其部署到 Android 应用中
如何将 HED 模型转换为 Tensorflow Lite 模型