如何将TensorFlow Lite构建为静态库并从单独的(CMake)项目链接到它?

时间:2019-03-12 16:06:23

标签: c++ tensorflow cmake bazel tensorflow-lite

通过将我的源代码添加到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目标,是因为BUILD中的tensorflow/lite/examples/minimal文件将它们作为依赖项,并且在我构建时它们对我有用 我在TF回购中使用Bazel编写的代码。不确定是否足够。

然后我手动收集包括dirs(具有丑陋的临时硬编码路径)和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文件似乎是错误的。

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

1 个答案:

答案 0 :(得分:2)

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

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

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

更新
包含全包TF Lite静态库的本机构建可以使用普通的旧make来非常类似于RPiiOSARM64的官方构建说明:
 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只会执行本机构建。可以在CMakeLists.txt中将此定制发票添加为自定义命令。