如何将TensorFlow Lite构建为静态库并从单独的(CMake)项目链接到它? [英] How to build TensorFlow Lite as a static library and link to it from a separate (CMake) project?

查看:989
本文介绍了如何将TensorFlow Lite构建为静态库并从单独的(CMake)项目链接到它?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过将我的源代码添加到tensorflow/lite/examples,类似于官方C ++ TF指南建议的完整TF.现在,我想将其构建为一个单独的项目(共享库),以静态方式链接到TF Lite,并使用CMake作为构建系统.

I've successfully built a simple C++ app running TF Lite model by adding my sources to tensorflow/lite/examples, similarly to what the official C++ TF guide suggests for full TF. Now I want to build it as a separate project (shared library) linking to TF Lite statically and using CMake as a build system.

我试图向我的CMakeLists.txt添加自定义目标,这将使用Bazel构建TF Lite:

I tried to add a custom target to my CMakeLists.txt, which would build TF Lite with Bazel:

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回购中使用Bazel编写的代码.不确定是否足够.

I chose those Bazel targets because the BUILD file from tensorflow/lite/examples/minimal has them as dependencies, and they work for me when I build my code with Bazel within TF repo. Not sure if that's enough.

然后我手动收集包括dirs(具有丑陋的临时硬编码路径)和libs:

Then I manually collect include dirs (with that ugly temporarily hardcoded path) and libs:

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文件似乎是错误的.

And with this configuration, I get many undefined references to TFLite stuff during linkage. I checked with nm and those symbols are indeed missing in libframework.pic.a, I found some of them in various .o files in Bazel output. Manually picking all those .o files seems wrong.

那么,是否有可能像我想的那样从CMake很好地链接到TF Lite?也许有一些神奇的bazel query include_dirs(//tensorflow/lite:framework)命令可以为我提供所有必要的包含目录的路径,以及一个类似的库链接命令,以便我可以将此信息传递给CMake?

So, is it possible to link nicely to TF Lite from CMake like I'm trying to? Maybe is there some magical bazel query include_dirs(//tensorflow/lite:framework) command which would give me paths to all the necessary include dirs, and a similar command for libraries to link against so that I could pass this info to CMake?

推荐答案

我最终为CMake的target_link_libraries(在TFLite_LIBS中)手动列出了所有必需的TFLite对象文件,并且可以正常工作.

I ended up listing all necessary TFLite object files manually for CMake's target_link_libraries (in the TFLite_LIBS) and it works.

我使用了一个简单的shell脚本来获取必要的目标文件列表. 首先,我将构建日志中所有未定义的引用收集到bash数组中,如下所示:

I used a simple shell script to get the list of necessary object files. First I collected all undefined references from build log into a bash-array as following:

SYMBOLS=(\
    'tflite::CombineHashes('\
    'tflite::IsFlexOp('\
    'tflite::ConvertArrayToTfLiteIntArray('\
    'tflite::EqualArrayAndTfLiteIntArray('\
    ...
    'tflite::ConvertVectorToTfLiteIntArray(')

然后对于该数组中的每个符号,我遍历了bazel build输出中的每个*.o文件:

Then for every symbol in that array, I went through every *.o file in bazel build output:

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中(当然具有正确的路径前缀).之后,我得到了未定义引用的新部分,但是经过几次迭代,它解决了所有问题.

and added the output to TFLite_LIBS in CMake (with correct path prefix, of course). After that, I got a new portion of undefined references, but after a few iterations, it resolved everything.

也许我也可以从我最初的树内构建中的*-params文件中获取依赖项的完整列表,但是快速检查表明它具有一些冗余项,并且脚本仅收集了必要的项.

Probably I could also obtain the full list of dependencies from *-params file from my initial in-tree build, but a quick check showed that it had some redundant items, and the script collected only the necessary ones.

对于包含位置,我用${TENSORFLOW_DIR}/bazel-tensorflow/external/flatbuffers/include/替换了硬编码到bazel缓存中平面缓冲区的路径.感谢 jdehesa 的提示.

For include locations, I replaced that hardcoded path to flatbuffers in bazel cache with ${TENSORFLOW_DIR}/bazel-tensorflow/external/flatbuffers/include/. Thanks jdehesa for the hint.

更新:
全包式TF Lite静态库的本机构建可以非常类似于 RPi iOS

UPDATE:
The native build of all-inclusive TF Lite static library can be done very similar to official build instructions for RPi, iOS or ARM64 using plain old make:
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中).

The output library will be stored as <tensorflow-root>/tensorflow/lite/tools/make/gen/<platform>/lib/libtensorflow-lite.a. And the external dependencies with their headers would go into <tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads (for example flatbuffers headers are in <tensorflow-root>/tensorflow/tensorflow/lite/tools/make/downloads/flatbuffers/include).

指南没有提到可以直接调用make.有针对不同交叉编译目标的包装器脚本,它们仅设置适当的变量并运行make.但是默认情况下,make只会执行本机构建.可以在CMakeLists.txt中将此定制发票添加为自定义命令.

Guide doesn't mention that make could be called directly. There are wrapper-scripts for different cross-compilation targets, which just set appropriate variables and run make. But by default make would just do native build. This make invokation can be added as a custom command in CMakeLists.txt.

这篇关于如何将TensorFlow Lite构建为静态库并从单独的(CMake)项目链接到它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆