#Tensorflow C++库的编译和使用方法
网上编译或者安装Tensorflow的教程大多数都是Python相关的,有少量C或者C++的,但版本又比较老不适合最新的Tensorflow教程,本博记录如何在Linux上从源码编译并使用Tensorflow库:
- 准备工作
- 选择ubuntu14.04或者16.04做开发机
- 因为这是google支持的官方linux版本;选择其他linux版本也是可以的,但如果有坑(肯定有坑,tensorflow并不是一个成熟的开源产品),google可能不会给你解决,即使你自己解决了,google也不会合并到官方版中去,这样就意味着要么你必须自己维护fix。我就发现了其他版本上的好几个问题反馈给google,google都说非官方版本,有时间的时候再处理。
- bazel安装
- 最简单的方式是下载bazel代码自己编译,不然会遇到各种库和gcc的匹配问题,到bazel官网下载https://github.com/bazelbuild/bazel/releases,必须下载dist版本,不然不让编。。。
- 下载后运行./compile.sh
- 如果发现有gcc报rep指令出错,必须升级binutils到22以上版本;可能需要安装jdk1.8,到oracle官网下载安装
- 升级binutils到22以上版本
- wget http://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2;
- tar -xjf binutils-2.25.1.tar.bz2;
- cd binutils-2.25.1;
- make; make install
- 选择ubuntu14.04或者16.04做开发机
- 下载代码
- 到github下载tensorflow源码
- 编译
- ./configure;
- 可以一路回车。需要注意的就是是否需要GPU,需要的话就选上,不需要就不用选;另外一点就是根据你的产品CPU选择编译优化选项,默认是-march=native,如果你的编译机器和产品运行机器的CPU一样,则可以选,但如果CPU不一样,则要根据你的产品机器的CPU选择优化选项,我配置的是-march=core-avx2
- 用bazel进行build
- bazel build -c opt --verbose_failures //tensorflow:libtensorflow_cc.so,若编译c版本则为bazel build -c opt --verbose_failures //tensorflow:libtensorflow.so
- –verbose_failures是为了当编译有错的时候,可以看到出错时的编译命令,方便查找原因或向google反馈
- 用makefile进行编译
- 到tensorflow/contrib/makefile目录下运行build_all_linux.sh,其他平台比如ios,android版本的编译脚本也在这个目录下,运行对应脚本即可
- ./configure;
- 测试
- 如果是在ubuntu14.04和16.04上编译,基本上不会碰到什么问题,如果不是那问题很多,各种编译工具和库版本不匹配的问题,只能慢慢解决,还是建议用ubuntu。
- 编译完以后,就可以测试了:
- 用makefile编译的,可以在tensorflow/contrib/makefile/gen/bin/目录下,看到编译成功的测试程序,运行该程序,需要到tensorflow下载tensorflow_inception_graph.pb文件(https://github.com/martinwicke/tensorflow-tutorial/blob/master/tensorflow_inception_graph.pb),然后作为命令行参数输入:
./gen/bin/benchmark --graph=~/test_data/tensorflow_inception_graph.pb - 用bazel编译的可以在tensorflow/cc/example目录下,
- 写一个BUILD文件和测试程序代码,如:
load("//tensorflow:tensorflow.bzl", "tf_cc_binary")
tf_cc_binary(
name = "example",
srcs = ["example.cc"],
deps = [
"//tensorflow/cc:cc_ops",
"//tensorflow/cc:client_session",
"//tensorflow/core:tensorflow",
],
)
//tensorflow/cc/example/example.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;
}
编译成功后在tensorflow目录下,运行:
bazel run -c opt //tensorflow/cc/example:example
- 把编译的c++库和头文件用到你自己的产品中
- 自己去编译的目的肯定不是为了编译而编译,而是为了把google的tensorflow库或者你优化过的tensorflow库用到你的产品中,有两种方法:1是用google的bazel系统,把自己的项目放到bazel tensorflow里;2.是把编译好的库拿到自己产品的编译环境中。最好管理的就是第2种方法,但也是比较麻烦的。因为tensorflow在这方面可用性实在太差,没有一个统一的目录存放对外的头文件,没有一个统一的地方存放编译好的库。网上很多文章提到的头文件和库都已经过时,如果按照那些方法,都没法使用tensorflow的库。
- 基于tensorflow的测试用例,我们有方法知道最完整的库和头文件的路径:
- 修改tensorflow/contrib/makefile下的Makefile,用到你的项目中
- 利用makefile编译时打印的命令行查看需要的头文件目录和库的名称,需要的编译选项,而且无论tensorflow的版本怎么变化,我们都能拿到最全的库和头文件。比如我在编译的时候,最后能看到这样的命令:
gcc --std=c++11 -DIS_SLIM_BUILD -fno-exceptions -DNDEBUG -O3 -march=native -fPIC -I. -I/home/yourpath/tensorflow/contrib/makefile/downloads/ -I/home/yourpath/tensorflow/contrib/makefile/downloads/eigen -I/home/yourpath/tensorflow/contrib/makefile/downloads/gemmlowp -I/home/yourpath/tensorflow/contrib/makefile/downloads/nsync/public -I/home/yourpath/tensorflow/contrib/makefile/downloads/fft2d -I/home/yourpath/tensorflow/contrib/makefile/downloads/double_conversion -I/home/yourpath/tensorflow/contrib/makefile/gen/proto/ -I/home/yourpath/tensorflow/contrib/makefile/gen/proto_text/ -I/home/yourpath/tensorflow/contrib/makefile/gen/protobuf-host/include -I/usr/local/include -o /home/yourpath/tensorflow/contrib/makefile/gen/bin/benchmark /home/yourpath/tensorflow/contrib/makefile/gen/obj/tensorflow/core/util/reporter.o /home/yourpath/tensorflow/contrib/makefile/gen/obj/tensorflow/tools/benchmark/benchmark_model.o /home/yourpath/tensorflow/contrib/makefile/gen/obj/tensorflow/tools/benchmark/benchmark_model_main.o -L/home/yourpath/tensorflow/contrib/makefile/gen/protobuf-host/lib -Wl,--allow-multiple-definition -Wl,--whole-archive /home/yourpath/tensorflow/contrib/makefile/gen/lib/libtensorflow-core.a -Wl,--no-whole-archive tensorflow/contrib/makefile/downloads/nsync/builds/default.linux.c++11/nsync.a -lstdc++ -lprotobuf -lz -lm -ldl -lpthread