在CentOS 7.2上编译TensorFlow 1.4版本的C++动态库,以及整理相应的头文件。完成后,只需要库文件以及头文件即可用C++ API调用TensorFlow. 这样的好处是自己的工程可以自由选择编译工具,而不需要依赖谷歌的构建工具Bazel.
基本依赖
- 安装Java
$ java -version
java version "1.8.0_144"
- 编译安装Bazel
TensorFlow要用Bazel来进行构建,所以要先安装Bazel,后面我们编译好动态库后,就可以摆脱Bazel这个依赖了。Bazel的编译安装很简单,最终得到的是self-contained Bazel binary,按照官网教程即可。
$ bazel version
Build label: 0.7.0- (@non-git)
- 安装其他依赖
TensorFlow官网,源码编译安装的教程中,提到要安装一些Python依赖。这里建议用virtualenv或者其他的Python运行环境管理工具来做隔离,专门为这个动态库的编译建一个新的Python运行环境,否则会把机器的Python环境搞得比较乱。
sudo yum install python-devel # ubuntu是python-dev
pip install six
pip install numpy
pip instal wheel
编译libtensorflow_cc.so
git clone
获取TensorFlow的源码。当然,也可以直接去TensorFlow Release的页面上找相应版本的源码:
git clone https://github.com/tensorflow/tensorflow
cd tensorflow
git checkout r1.4
编译之前,要进行一系列的配置,包括Python路径等等:
./configure
编译C++ API所需的库,期间Bazel需要联网下载许多依赖,时间有点长:
bazel build --config=opt //tensorflow:libtensorflow_cc.so
编译正常完成后,会在bazel-bin/tensorflow/
文件夹下生产libtensorflow_cc.so
和libtensorflow_framework.so
这两个动态库文件。
编译Protobuf和Eigen
# protobuf
mkdir /tmp/proto
./tensorflow/contrib/makefile/download_dependencies.sh
cd tensorflow/contrib/makefile/downloads/protobuf/
./autogen.sh
./configure --prefix=/tmp/proto/
make
make install
# eigen
mkdir /tmp/eigen
cd ../eigen
mkdir build_dir
cd build_dir
cmake -DCMAKE_INSTALL_PREFIX=/tmp/eigen/ ../
make install
cd ../../../../../..
整理库文件和头文件
把编译得到的库文件以及分散在各个地方的头文件整理集中起来。
- 库文件
mkdir -p ../tf_test/lib
cp bazel-bin/tensorflow/libtensorflow_cc.so ../tf_test/lib/
cp bazel-bin/tensorflow/libtensorflow_framework.so ../tf_test/lib/ # 之前编译r0.12和r1.3版本的库,只需要libtensorflow_cc.so,1.4版本的似乎分成了两个so文件,即还需要libtensorflow_framework.so
cp /tmp/proto/lib/libprotobuf.a ../tf_test/lib/
- 头文件
mkdir -p ../tf_test/include/tensorflow
cp -r bazel-genfiles/* ../tf_test/include/
cp -r tensorflow/cc ../tf_test/include/tensorflow
cp -r tensorflow/core ../tf_test/include/tensorflow
cp -r third_party ../tf_test/include
cp -r /tmp/proto/include/* ../tf_test/include
cp -r /tmp/eigen/include/eigen3/* ../tf_test/include
上面是从1.3版本的这个教程里提到的目录,但是对于1.4以后的版本,似乎还缺少nsync的头文件,这点在这个教程里有提到:
cp -r tensorflow/contrib/makefile/downloads/nsync/public ../tf_test/include/external/nsync/public
不需要的.cc文件可以删掉:
cd ../tf_test/
find . -name "*.cc" -type f -delete
测试示例
准备好库文件和相应的头文件后,可以编译测试示例:
示例代码tf_test/test.cc
:
#include "tensorflow/cc/client/client_session.h"
#include "tensorflow/cc/ops/standard_ops.h"
#include "tensorflow/core/framework/tensor.h"
int main() {
using namespace tensorflow;
using namespace tensorflow::ops;
Scope root = Scope::NewRootScope();
// Matrix A = [3 2; -1 0]
auto A = Const(root, { {3.f, 2.f}, {-1.f, 0.f}});
// Vector b = [3 5]
auto b = Const(root, { {3.f, 5.f}});
// v = Ab^T
auto v = MatMul(root.WithOpName("v"), A, b, MatMul::TransposeB(true));
std::vector<Tensor> outputs;
ClientSession session(root);
// Run and fetch v
TF_CHECK_OK(session.Run({v}, &outputs));
// Expect outputs[0] == [19; -3]
LOG(INFO) << outputs[0].matrix<float>();
return 0;
}
$ pwd
/some/where/tf_test
$ ls
include lib test.cc
$ g++ -std=c++11 -I./include -I./include/external/nsync/public -L./lib test.cc -ltensorflow_cc -ltensorflow_framework -o test
$ ./test
正确的情况下,应该会输出19 -3,还会输出类似Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA
的信息,这涉及到CPU指令优化的问题,可以在编译动态库的时候进行指令优化,具体可以看TensorFlow官网的教程,这里就不展开了。
后记
TensorFlow的版本升级迭代比较频繁,网上各个版本的C++动态库编译及涉及到的头文件位置都不太一样。本人还看过一个教程,先基于源码编译TensorFlow的pip包,用pip安装TensorFlow之后,再去安装目录(/usr/lib/python2.7/site-packages/tensorflow/include)
下找头文件。总之,遇到编译的问题,可以google问题的解法,比较各人的环境配置总会存在差异的地方。