『写在前面』 关于tf,一种常见的使用方式是:在线下使用TensorFlow的Python Binding搭建和训练模型,然后利用freeze_graph工具等工具输出*.pb文件(或使用tf.train.Saver保存成*.meta文件和checkpoint文件),最后在线上使用C++调用预训练好的模型进行inference。之前趟过一遍TF1.3.1,坑很多,有点后悔当时没有记录,主要还是在依赖包版本和系统兼容性上,当时是在CentOS
7下编译成功,MacOS下一直没弄成。最近又需要整理一版使用,果断选择了当前最新的1.11版来试验(貌似1.12也出了。。),果然坑少了很多,我首先在Mac下尝试了一下,具体细节记录如下,如有失误欢迎指正。
./autogen.sh
./configure --prefix=/usr/local
make -j4
sudo make install
\qquad 安装完毕,通过protoc --version
验证。
Eigen 免安装 直接引用源文件即可
bazel
brew install bazel
sh bazel-0.5.4-installer-darwin-x86_64.sh --prefix=/some/path
./configure
,根据自己实际情况进行选择,我是一路N下来的?bazel build -c opt --copt=-msse3 --copt=-msse4.1 --copt=-msse4.2 --copt=-mavx --copt=-mavx2 --copt=-mfma tensorflow:libtensorflow_cc.so
\qquad 如果服务器无法连接外网,则会因为无法下载所需的依赖包而导致build失败。
\qquad 解决方法是将所需依赖项依次下载到本地,然后修改rootdir/WORKSPACE
文件和rootdir/tensorflow/workspace.bzl
文件。同样在根目录执行上述编译指令,此时会自动从本地加载已经下载好的依赖包。
修改bzl文件等的方法,将urls一项修改为本地路径即可。例:
http_archive(
name = "io_bazel_rules_closure",
sha256 = "bc41b80486413aaa551860fc37471dbc0666e1dbb5236fb6177cb83b0c105846",
strip_prefix = "rules_closure-dec425a4ff3faf09a56c85d082e4eed05d8ce38f",
urls = [
"file:/home/xxx/tf_deps/dec425a4ff3faf09a56c85d082e4eed05d8ce38f.tar.gz",
],
)
\qquad 编译完成后,根目录结构如下:
\qquad 依次执行以下指令将所需头文件和库文件安装到系统目录或其他目录下:
mkdir /usr/local/include/google
cp -r tensorflow /usr/local/include/google
cp -r third_party /usr/local/include/google
cp -r bazel-genfiles /usr/local/include/google
cp -r bazel-bin/tensorflow/libtensorflow_cc.so /usr/local/lib/
\qquad 其实第一个cp其实只需要将tensorflow文件夹中的头文件拷走即可,命令行玩的不6所以就不献丑了。。以上是大多数blog中都会提及的文件,我在使用过程中发现新版本TF有一个小坑?会去找一个bazel输出目录下的头文件。
\qquad 在/private/var/tmp/
路径下有一个名字叫_bazel_username
的文件夹,在这个目录下找到和先前TF根目录bazel-bin链接的实际路径对应的那一长串(MD5?)的文件夹,将该文件夹下的???/external/com_google_absl/absl
统统拷走,同样拷到/usr/local/include/google
下就好了。
注意不但需要设置TF的include路径,还需要设置protobuf和eigen的路径。
set(Pjt_name cpp_tf)
cmake_minimum_required(VERSION 3.6)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES main.cpp)
set(TF_DIR /usr/local/include/google/)
set(Eigen_DIR <指到Eigen源码包一级>)
set(Protobuf_DIR ***/protobuf-3.6.0/src)
include_directories(${TF_DIR} ${Eigen_DIR} ${Protobuf_DIR})
link_directories(/usr/local/lib)
add_executable(${Pjt_name} ${SOURCE_FILES})
target_link_libraries(${Pjt_name} tensorflow_cc)
#include
#include
#include
using namespace std;
using namespace tensorflow;
int main()
{
Session* session;
Status status = NewSession(SessionOptions(), &session);
if (!status.ok()) {
cout << status.ToString() << "\n";
return 1;
}
cout << "Session successfully created.\n";
return 0;
}
关于预训练模型调用及其他TF C++ API的使用,后续有时间我会再整理补充,个人认为主要分为以下几步:加载模型及网络参数,构建输入Tensor,Run Session,处理输出。