我已经成功构建了一个运行TF Lite模型的简单C ++应用程序,通过将我的源添加到tensorflow/lite/examples
,类似于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 repo中使用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)
命令,它会给我所有必要的包括dirs的路径,以及类似的命令,以便库链接反对,以便我可以将此信息传递给CMake?
我最终手动为CMake的target_link_libraries
(在TFLite_LIBS
中)列出了所有必要的TFLite对象文件,并且它有效。
我使用一个简单的shell脚本来获取必要的目标文件列表。首先,我将构建日志中的所有未定义引用收集到bash-array中,如下所示:
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缓存中的flatbuffers。感谢jdehesa的提示。
更新:
全包TF Lite静态库的本机构建可以使用普通旧制作非常类似于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会做本机构建。这使得invokation可以作为CMakeLists.txt
中的自定义命令添加。